macb.c
来自「linux 内核源代码」· C语言 代码 · 共 1,302 行 · 第 1/3 页
C
1,302 行
/* Mark DMA descriptors from begin up to and not including end as unused */static void discard_partial_frame(struct macb *bp, unsigned int begin, unsigned int end){ unsigned int frag; for (frag = begin; frag != end; frag = NEXT_RX(frag)) bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); wmb(); /* * When this happens, the hardware stats registers for * whatever caused this is updated, so we don't have to record * anything. */}static int macb_rx(struct macb *bp, int budget){ int received = 0; unsigned int tail = bp->rx_tail; int first_frag = -1; for (; budget > 0; tail = NEXT_RX(tail)) { u32 addr, ctrl; rmb(); addr = bp->rx_ring[tail].addr; ctrl = bp->rx_ring[tail].ctrl; if (!(addr & MACB_BIT(RX_USED))) break; if (ctrl & MACB_BIT(RX_SOF)) { if (first_frag != -1) discard_partial_frame(bp, first_frag, tail); first_frag = tail; } if (ctrl & MACB_BIT(RX_EOF)) { int dropped; BUG_ON(first_frag == -1); dropped = macb_rx_frame(bp, first_frag, tail); first_frag = -1; if (!dropped) { received++; budget--; } } } if (first_frag != -1) bp->rx_tail = first_frag; else bp->rx_tail = tail; return received;}static int macb_poll(struct napi_struct *napi, int budget){ struct macb *bp = container_of(napi, struct macb, napi); struct net_device *dev = bp->dev; int work_done; u32 status; status = macb_readl(bp, RSR); macb_writel(bp, RSR, status); work_done = 0; if (!status) { /* * This may happen if an interrupt was pending before * this function was called last time, and no packets * have been received since. */ netif_rx_complete(dev, napi); goto out; } dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", (unsigned long)status, budget); if (!(status & MACB_BIT(REC))) { dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); netif_rx_complete(dev, napi); goto out; } work_done = macb_rx(bp, budget); if (work_done < budget) netif_rx_complete(dev, napi); /* * We've done what we can to clean the buffers. Make sure we * get notified when new packets arrive. */out: macb_writel(bp, IER, MACB_RX_INT_FLAGS); /* TODO: Handle errors */ return work_done;}static irqreturn_t macb_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct macb *bp = netdev_priv(dev); u32 status; status = macb_readl(bp, ISR); if (unlikely(!status)) return IRQ_NONE; spin_lock(&bp->lock); while (status) { /* close possible race with dev_close */ if (unlikely(!netif_running(dev))) { macb_writel(bp, IDR, ~0UL); break; } if (status & MACB_RX_INT_FLAGS) { if (netif_rx_schedule_prep(dev, &bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers */ macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); __netif_rx_schedule(dev, &bp->napi); } } if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND))) macb_tx(bp); /* * Link change detection isn't possible with RMII, so we'll * add that if/when we get our hands on a full-blown MII PHY. */ if (status & MACB_BIT(HRESP)) { /* * TODO: Reset the hardware, and maybe move the printk * to a lower-priority context as well (work queue?) */ printk(KERN_ERR "%s: DMA bus error: HRESP not OK\n", dev->name); } status = macb_readl(bp, ISR); } spin_unlock(&bp->lock); return IRQ_HANDLED;}static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct macb *bp = netdev_priv(dev); dma_addr_t mapping; unsigned int len, entry; u32 ctrl;#ifdef DEBUG int i; dev_dbg(&bp->pdev->dev, "start_xmit: len %u head %p data %p tail %p end %p\n", skb->len, skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb)); dev_dbg(&bp->pdev->dev, "data:"); for (i = 0; i < 16; i++) printk(" %02x", (unsigned int)skb->data[i]); printk("\n");#endif len = skb->len; spin_lock_irq(&bp->lock); /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(bp) < 1) { netif_stop_queue(dev); spin_unlock_irq(&bp->lock); dev_err(&bp->pdev->dev, "BUG! Tx Ring full when queue awake!\n"); dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", bp->tx_head, bp->tx_tail); return 1; } entry = bp->tx_head; dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry); mapping = dma_map_single(&bp->pdev->dev, skb->data, len, DMA_TO_DEVICE); bp->tx_skb[entry].skb = skb; bp->tx_skb[entry].mapping = mapping; dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n", skb->data, (unsigned long)mapping); ctrl = MACB_BF(TX_FRMLEN, len); ctrl |= MACB_BIT(TX_LAST); if (entry == (TX_RING_SIZE - 1)) ctrl |= MACB_BIT(TX_WRAP); bp->tx_ring[entry].addr = mapping; bp->tx_ring[entry].ctrl = ctrl; wmb(); entry = NEXT_TX(entry); bp->tx_head = entry; macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); if (TX_BUFFS_AVAIL(bp) < 1) netif_stop_queue(dev); spin_unlock_irq(&bp->lock); dev->trans_start = jiffies; return 0;}static void macb_free_consistent(struct macb *bp){ if (bp->tx_skb) { kfree(bp->tx_skb); bp->tx_skb = NULL; } if (bp->rx_ring) { dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; } if (bp->tx_ring) { dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; } if (bp->rx_buffers) { dma_free_coherent(&bp->pdev->dev, RX_RING_SIZE * RX_BUFFER_SIZE, bp->rx_buffers, bp->rx_buffers_dma); bp->rx_buffers = NULL; }}static int macb_alloc_consistent(struct macb *bp){ int size; size = TX_RING_SIZE * sizeof(struct ring_info); bp->tx_skb = kmalloc(size, GFP_KERNEL); if (!bp->tx_skb) goto out_err; size = RX_RING_BYTES; bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, &bp->rx_ring_dma, GFP_KERNEL); if (!bp->rx_ring) goto out_err; dev_dbg(&bp->pdev->dev, "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); size = TX_RING_BYTES; bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, &bp->tx_ring_dma, GFP_KERNEL); if (!bp->tx_ring) goto out_err; dev_dbg(&bp->pdev->dev, "Allocated TX ring of %d bytes at %08lx (mapped %p)\n", size, (unsigned long)bp->tx_ring_dma, bp->tx_ring); size = RX_RING_SIZE * RX_BUFFER_SIZE; bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, &bp->rx_buffers_dma, GFP_KERNEL); if (!bp->rx_buffers) goto out_err; dev_dbg(&bp->pdev->dev, "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); return 0;out_err: macb_free_consistent(bp); return -ENOMEM;}static void macb_init_rings(struct macb *bp){ int i; dma_addr_t addr; addr = bp->rx_buffers_dma; for (i = 0; i < RX_RING_SIZE; i++) { bp->rx_ring[i].addr = addr; bp->rx_ring[i].ctrl = 0; addr += RX_BUFFER_SIZE; } bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP); for (i = 0; i < TX_RING_SIZE; i++) { bp->tx_ring[i].addr = 0; bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); } bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); bp->rx_tail = bp->tx_head = bp->tx_tail = 0;}static void macb_reset_hw(struct macb *bp){ /* Make sure we have the write buffer for ourselves */ wmb(); /* * Disable RX and TX (XXX: Should we halt the transmission * more gracefully?) */ macb_writel(bp, NCR, 0); /* Clear the stats registers (XXX: Update stats first?) */ macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); /* Clear all status flags */ macb_writel(bp, TSR, ~0UL); macb_writel(bp, RSR, ~0UL); /* Disable all interrupts */ macb_writel(bp, IDR, ~0UL); macb_readl(bp, ISR);}static void macb_init_hw(struct macb *bp){ u32 config; macb_reset_hw(bp); __macb_set_hwaddr(bp); config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ if (bp->dev->flags & IFF_PROMISC) config |= MACB_BIT(CAF); /* Copy All Frames */ if (!(bp->dev->flags & IFF_BROADCAST)) config |= MACB_BIT(NBC); /* No BroadCast */ macb_writel(bp, NCFGR, config); /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, bp->rx_ring_dma); macb_writel(bp, TBQP, bp->tx_ring_dma); /* Enable TX and RX */ macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); /* Enable interrupts */ macb_writel(bp, IER, (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) | MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE) | MACB_BIT(TXERR) | MACB_BIT(TCOMP) | MACB_BIT(ISR_ROVR) | MACB_BIT(HRESP)));}/* * The hash address register is 64 bits long and takes up two * locations in the memory map. The least significant bits are stored * in EMAC_HSL and the most significant bits in EMAC_HSH. * * The unicast hash enable and the multicast hash enable bits in the * network configuration register enable the reception of hash matched * frames. The destination address is reduced to a 6 bit index into * the 64 bit hash register using the following hash function. The * hash function is an exclusive or of every sixth bit of the * destination address. * * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] * * da[0] represents the least significant bit of the first byte * received, that is, the multicast/unicast indicator, and da[47] * represents the most significant bit of the last byte received. If * the hash index, hi[n], points to a bit that is set in the hash * register then the frame will be matched according to whether the * frame is multicast or unicast. A multicast match will be signalled * if the multicast hash enable bit is set, da[0] is 1 and the hash * index points to a bit set in the hash register. A unicast match * will be signalled if the unicast hash enable bit is set, da[0] is 0 * and the hash index points to a bit set in the hash register. To * receive all multicast frames, the hash register should be set with * all ones and the multicast hash enable bit should be set in the * network configuration register. */static inline int hash_bit_value(int bitnr, __u8 *addr){ if (addr[bitnr / 8] & (1 << (bitnr % 8))) return 1; return 0;}/* * Return the hash index value for the specified address. */static int hash_get_index(__u8 *addr){ int i, j, bitval; int hash_index = 0; for (j = 0; j < 6; j++) { for (i = 0, bitval = 0; i < 8; i++) bitval ^= hash_bit_value(i*6 + j, addr);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?