static int macb_recv(struct eth_device *netdev) { struct macb_device *macb = to_macb(netdev); unsigned int rx_tail = macb->rx_tail; void *buffer; int length; int wrapped = 0; u32 status; for (;;) { macb_invalidate_ring_desc(macb, RX); if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) return -1; status = macb->rx_ring[rx_tail].ctrl; if (status & RXBUF_FRAME_START) { if (rx_tail != macb->rx_tail) reclaim_rx_buffers(macb, rx_tail); wrapped = 0; } if (status & RXBUF_FRAME_END) { buffer = macb->rx_buffer + 128 * macb->rx_tail; length = status & RXBUF_FRMLEN_MASK; macb_invalidate_rx_buffer(macb); if (wrapped) { unsigned int headlen, taillen; headlen = 128 * (MACB_RX_RING_SIZE - macb->rx_tail); taillen = length - headlen; memcpy((void *)NetRxPackets[0], buffer, headlen); memcpy((void *)NetRxPackets[0] + headlen, macb->rx_buffer, taillen); buffer = (void *)NetRxPackets[0]; } NetReceive(buffer, length); if (++rx_tail >= MACB_RX_RING_SIZE) rx_tail = 0; reclaim_rx_buffers(macb, rx_tail); } else { if (++rx_tail >= MACB_RX_RING_SIZE) { wrapped = 1; rx_tail = 0; } } barrier(); } return 0; }
static int _macb_recv(struct macb_device *macb, uchar **packetp) { unsigned int next_rx_tail = macb->next_rx_tail; void *buffer; int length; u32 status; macb->wrapped = false; for (;;) { macb_invalidate_ring_desc(macb, RX); if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED)) return -EAGAIN; status = macb->rx_ring[next_rx_tail].ctrl; if (status & RXBUF_FRAME_START) { if (next_rx_tail != macb->rx_tail) reclaim_rx_buffers(macb, next_rx_tail); macb->wrapped = false; } if (status & RXBUF_FRAME_END) { buffer = macb->rx_buffer + 128 * macb->rx_tail; length = status & RXBUF_FRMLEN_MASK; macb_invalidate_rx_buffer(macb); if (macb->wrapped) { unsigned int headlen, taillen; headlen = 128 * (MACB_RX_RING_SIZE - macb->rx_tail); taillen = length - headlen; memcpy((void *)net_rx_packets[0], buffer, headlen); memcpy((void *)net_rx_packets[0] + headlen, macb->rx_buffer, taillen); *packetp = (void *)net_rx_packets[0]; } else { *packetp = buffer; } if (++next_rx_tail >= MACB_RX_RING_SIZE) next_rx_tail = 0; macb->next_rx_tail = next_rx_tail; return length; } else { if (++next_rx_tail >= MACB_RX_RING_SIZE) { macb->wrapped = true; next_rx_tail = 0; } } barrier(); } }
static int macb_send(struct eth_device *netdev, void *packet, int length) { struct macb_device *macb = to_macb(netdev); unsigned long paddr, ctrl; unsigned int tx_head = macb->tx_head; int i; paddr = dma_map_single(packet, length, DMA_TO_DEVICE); ctrl = length & TXBUF_FRMLEN_MASK; ctrl |= TXBUF_FRAME_END; if (tx_head == (MACB_TX_RING_SIZE - 1)) { ctrl |= TXBUF_WRAP; macb->tx_head = 0; } else { macb->tx_head++; } macb->tx_ring[tx_head].ctrl = ctrl; macb->tx_ring[tx_head].addr = paddr; barrier(); macb_flush_ring_desc(macb, TX); /* Do we need check paddr and length is dcache line aligned? */ flush_dcache_range(paddr, paddr + length); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); /* * I guess this is necessary because the networking core may * re-use the transmit buffer as soon as we return... */ for (i = 0; i <= MACB_TX_TIMEOUT; i++) { barrier(); macb_invalidate_ring_desc(macb, TX); ctrl = macb->tx_ring[tx_head].ctrl; if (ctrl & TXBUF_USED) break; udelay(1); } dma_unmap_single(packet, length, paddr); if (i <= MACB_TX_TIMEOUT) { if (ctrl & TXBUF_UNDERRUN) printf("%s: TX underrun\n", netdev->name); if (ctrl & TXBUF_EXHAUSTED) printf("%s: TX buffers exhausted in mid frame\n", netdev->name); } else { printf("%s: TX timeout\n", netdev->name); } /* No one cares anyway */ return 0; }
static void reclaim_rx_buffers(struct macb_device *macb, unsigned int new_tail) { unsigned int i; i = macb->rx_tail; macb_invalidate_ring_desc(macb, RX); while (i > new_tail) { macb->rx_ring[i].addr &= ~RXADDR_USED; i++; if (i > MACB_RX_RING_SIZE) i = 0; } while (i < new_tail) { macb->rx_ring[i].addr &= ~RXADDR_USED; i++; } barrier(); macb_flush_ring_desc(macb, RX); macb->rx_tail = new_tail; }