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 + -
显示快捷键?