pcnet32.c

来自「linux 内核源代码」· C语言 代码 · 共 2,361 行 · 第 1/5 页

C
2,361
字号
			lp->tx_ring[x].misc = 0;			/* put DA and SA into the skb */			for (i = 0; i < 6; i++)				*packet++ = dev->dev_addr[i];			for (i = 0; i < 6; i++)				*packet++ = dev->dev_addr[i];			/* type */			*packet++ = 0x08;			*packet++ = 0x06;			/* packet number */			*packet++ = x;			/* fill packet with data */			for (i = 0; i < data_len; i++)				*packet++ = i;			lp->tx_dma_addr[x] =			    pci_map_single(lp->pci_dev, skb->data, skb->len,					   PCI_DMA_TODEVICE);			lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);			wmb();	/* Make sure owner changes after all others are visible */			lp->tx_ring[x].status = cpu_to_le16(status);		}	}	x = a->read_bcr(ioaddr, 32);	/* set internal loopback in BCR32 */	a->write_bcr(ioaddr, 32, x | 0x0002);	/* set int loopback in CSR15 */	x = a->read_csr(ioaddr, CSR15) & 0xfffc;	lp->a.write_csr(ioaddr, CSR15, x | 0x0044);	teststatus = cpu_to_le16(0x8000);	lp->a.write_csr(ioaddr, CSR0, CSR0_START);	/* Set STRT bit */	/* Check status of descriptors */	for (x = 0; x < numbuffs; x++) {		ticks = 0;		rmb();		while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {			spin_unlock_irqrestore(&lp->lock, flags);			msleep(1);			spin_lock_irqsave(&lp->lock, flags);			rmb();			ticks++;		}		if (ticks == 200) {			if (netif_msg_hw(lp))				printk("%s: Desc %d failed to reset!\n",				       dev->name, x);			break;		}	}	lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);	/* Set STOP bit */	wmb();	if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {		printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);		for (x = 0; x < numbuffs; x++) {			printk(KERN_DEBUG "%s: Packet %d:\n", dev->name, x);			skb = lp->rx_skbuff[x];			for (i = 0; i < size; i++) {				printk("%02x ", *(skb->data + i));			}			printk("\n");		}	}	x = 0;	rc = 0;	while (x < numbuffs && !rc) {		skb = lp->rx_skbuff[x];		packet = lp->tx_skbuff[x]->data;		for (i = 0; i < size; i++) {			if (*(skb->data + i) != packet[i]) {				if (netif_msg_hw(lp))					printk(KERN_DEBUG					       "%s: Error in compare! %2x - %02x %02x\n",					       dev->name, i, *(skb->data + i),					       packet[i]);				rc = 1;				break;			}		}		x++;	}      clean_up:	*data1 = rc;	pcnet32_purge_tx_ring(dev);	x = a->read_csr(ioaddr, CSR15);	a->write_csr(ioaddr, CSR15, (x & ~0x0044));	/* reset bits 6 and 2 */	x = a->read_bcr(ioaddr, 32);	/* reset internal loopback */	a->write_bcr(ioaddr, 32, (x & ~0x0002));#ifdef CONFIG_PCNET32_NAPI	if (netif_running(dev)) {		pcnet32_netif_start(dev);		pcnet32_restart(dev, CSR0_NORMAL);	} else {		pcnet32_purge_rx_ring(dev);		lp->a.write_bcr(ioaddr, 20, 4);	/* return to 16bit mode */	}	spin_unlock_irqrestore(&lp->lock, flags);#else	if (netif_running(dev)) {		spin_unlock_irqrestore(&lp->lock, flags);		pcnet32_open(dev);	} else {		pcnet32_purge_rx_ring(dev);		lp->a.write_bcr(ioaddr, 20, 4);	/* return to 16bit mode */		spin_unlock_irqrestore(&lp->lock, flags);	}#endif	return (rc);}				/* end pcnet32_loopback_test  */static void pcnet32_led_blink_callback(struct net_device *dev){	struct pcnet32_private *lp = netdev_priv(dev);	struct pcnet32_access *a = &lp->a;	ulong ioaddr = dev->base_addr;	unsigned long flags;	int i;	spin_lock_irqsave(&lp->lock, flags);	for (i = 4; i < 8; i++) {		a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);	}	spin_unlock_irqrestore(&lp->lock, flags);	mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);}static int pcnet32_phys_id(struct net_device *dev, u32 data){	struct pcnet32_private *lp = netdev_priv(dev);	struct pcnet32_access *a = &lp->a;	ulong ioaddr = dev->base_addr;	unsigned long flags;	int i, regs[4];	if (!lp->blink_timer.function) {		init_timer(&lp->blink_timer);		lp->blink_timer.function = (void *)pcnet32_led_blink_callback;		lp->blink_timer.data = (unsigned long)dev;	}	/* Save the current value of the bcrs */	spin_lock_irqsave(&lp->lock, flags);	for (i = 4; i < 8; i++) {		regs[i - 4] = a->read_bcr(ioaddr, i);	}	spin_unlock_irqrestore(&lp->lock, flags);	mod_timer(&lp->blink_timer, jiffies);	set_current_state(TASK_INTERRUPTIBLE);	/* AV: the limit here makes no sense whatsoever */	if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)))		data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ);	msleep_interruptible(data * 1000);	del_timer_sync(&lp->blink_timer);	/* Restore the original value of the bcrs */	spin_lock_irqsave(&lp->lock, flags);	for (i = 4; i < 8; i++) {		a->write_bcr(ioaddr, i, regs[i - 4]);	}	spin_unlock_irqrestore(&lp->lock, flags);	return 0;}/* * lp->lock must be held. */static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,		int can_sleep){	int csr5;	struct pcnet32_private *lp = netdev_priv(dev);	struct pcnet32_access *a = &lp->a;	ulong ioaddr = dev->base_addr;	int ticks;	/* really old chips have to be stopped. */	if (lp->chip_version < PCNET32_79C970A)		return 0;	/* set SUSPEND (SPND) - CSR5 bit 0 */	csr5 = a->read_csr(ioaddr, CSR5);	a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);	/* poll waiting for bit to be set */	ticks = 0;	while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {		spin_unlock_irqrestore(&lp->lock, *flags);		if (can_sleep)			msleep(1);		else			mdelay(1);		spin_lock_irqsave(&lp->lock, *flags);		ticks++;		if (ticks > 200) {			if (netif_msg_hw(lp))				printk(KERN_DEBUG				       "%s: Error getting into suspend!\n",				       dev->name);			return 0;		}	}	return 1;}/* * process one receive descriptor entry */static void pcnet32_rx_entry(struct net_device *dev,			     struct pcnet32_private *lp,			     struct pcnet32_rx_head *rxp,			     int entry){	int status = (short)le16_to_cpu(rxp->status) >> 8;	int rx_in_place = 0;	struct sk_buff *skb;	short pkt_len;	if (status != 0x03) {	/* There was an error. */		/*		 * There is a tricky error noted by John Murphy,		 * <murf@perftech.com> to Russ Nelson: Even with full-sized		 * buffers it's possible for a jabber packet to use two		 * buffers, with only the last correctly noting the error.		 */		if (status & 0x01)	/* Only count a general error at the */			dev->stats.rx_errors++;	/* end of a packet. */		if (status & 0x20)			dev->stats.rx_frame_errors++;		if (status & 0x10)			dev->stats.rx_over_errors++;		if (status & 0x08)			dev->stats.rx_crc_errors++;		if (status & 0x04)			dev->stats.rx_fifo_errors++;		return;	}	pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4;	/* Discard oversize frames. */	if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {		if (netif_msg_drv(lp))			printk(KERN_ERR "%s: Impossible packet size %d!\n",			       dev->name, pkt_len);		dev->stats.rx_errors++;		return;	}	if (pkt_len < 60) {		if (netif_msg_rx_err(lp))			printk(KERN_ERR "%s: Runt packet!\n", dev->name);		dev->stats.rx_errors++;		return;	}	if (pkt_len > rx_copybreak) {		struct sk_buff *newskb;		if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {			skb_reserve(newskb, 2);			skb = lp->rx_skbuff[entry];			pci_unmap_single(lp->pci_dev,					 lp->rx_dma_addr[entry],					 PKT_BUF_SZ - 2,					 PCI_DMA_FROMDEVICE);			skb_put(skb, pkt_len);			lp->rx_skbuff[entry] = newskb;			lp->rx_dma_addr[entry] =					    pci_map_single(lp->pci_dev,							   newskb->data,							   PKT_BUF_SZ - 2,							   PCI_DMA_FROMDEVICE);			rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);			rx_in_place = 1;		} else			skb = NULL;	} else {		skb = dev_alloc_skb(pkt_len + 2);	}	if (skb == NULL) {		if (netif_msg_drv(lp))			printk(KERN_ERR			       "%s: Memory squeeze, dropping packet.\n",			       dev->name);		dev->stats.rx_dropped++;		return;	}	skb->dev = dev;	if (!rx_in_place) {		skb_reserve(skb, 2);	/* 16 byte align */		skb_put(skb, pkt_len);	/* Make room */		pci_dma_sync_single_for_cpu(lp->pci_dev,					    lp->rx_dma_addr[entry],					    pkt_len,					    PCI_DMA_FROMDEVICE);		skb_copy_to_linear_data(skb,				 (unsigned char *)(lp->rx_skbuff[entry]->data),				 pkt_len);		pci_dma_sync_single_for_device(lp->pci_dev,					       lp->rx_dma_addr[entry],					       pkt_len,					       PCI_DMA_FROMDEVICE);	}	dev->stats.rx_bytes += skb->len;	skb->protocol = eth_type_trans(skb, dev);#ifdef CONFIG_PCNET32_NAPI	netif_receive_skb(skb);#else	netif_rx(skb);#endif	dev->last_rx = jiffies;	dev->stats.rx_packets++;	return;}static int pcnet32_rx(struct net_device *dev, int budget){	struct pcnet32_private *lp = netdev_priv(dev);	int entry = lp->cur_rx & lp->rx_mod_mask;	struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];	int npackets = 0;	/* If we own the next entry, it's a new packet. Send it up. */	while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) {		pcnet32_rx_entry(dev, lp, rxp, entry);		npackets += 1;		/*		 * The docs say that the buffer length isn't touched, but Andrew		 * Boyd of QNX reports that some revs of the 79C965 clear it.		 */		rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ);		wmb();	/* Make sure owner changes after others are visible */		rxp->status = cpu_to_le16(0x8000);		entry = (++lp->cur_rx) & lp->rx_mod_mask;		rxp = &lp->rx_ring[entry];	}	return npackets;}static int pcnet32_tx(struct net_device *dev){	struct pcnet32_private *lp = netdev_priv(dev);	unsigned int dirty_tx = lp->dirty_tx;	int delta;	int must_restart = 0;	while (dirty_tx != lp->cur_tx) {		int entry = dirty_tx & lp->tx_mod_mask;		int status = (short)le16_to_cpu(lp->tx_ring[entry].status);		if (status < 0)			break;	/* It still hasn't been Txed */		lp->tx_ring[entry].base = 0;		if (status & 0x4000) {			/* There was a major error, log it. */			int err_status = le32_to_cpu(lp->tx_ring[entry].misc);			dev->stats.tx_errors++;			if (netif_msg_tx_err(lp))				printk(KERN_ERR				       "%s: Tx error status=%04x err_status=%08x\n",				       dev->name, status,				       err_status);			if (err_status & 0x04000000)				dev->stats.tx_aborted_errors++;			if (err_status & 0x08000000)				dev->stats.tx_carrier_errors++;			if (err_status & 0x10000000)				dev->stats.tx_window_errors++;#ifndef DO_DXSUFLO			if (err_status & 0x40000000) {				dev->stats.tx_fifo_errors++;				/* Ackk!  On FIFO errors the Tx unit is turned off! */				/* Remove this verbosity later! */				if (netif_msg_tx_err(lp))					printk(KERN_ERR					       "%s: Tx FIFO error!\n",					       dev->name);				must_restart = 1;			}#else			if (err_status & 0x40000000) {				dev->stats.tx_fifo_errors++;				if (!lp->dxsuflo) {	/* If controller doesn't recover ... */					/* Ackk!  On FIFO errors the Tx unit is turned off! */					/* Remove this verbosity later! */					if (netif_msg_tx_err(lp))						printk(KERN_ERR						       "%s: Tx FIFO error!\n",						       dev->name);					must_restart = 1;				}			}#endif		} else {			if (status & 0x1800)				dev->stats.collisions++;			dev->stats.tx_packets++;		}		/* We must free the original skb */		if (lp->tx_skbuff[entry]) {			pci_unmap_single(lp->pci_dev,					 lp->tx_dma_addr[entry],					 lp->tx_skbuff[entry]->					 len, PCI_DMA_TODEVICE);			dev_kfree_skb_any(lp->tx_skbuff[entry]);			lp->tx_skbuff[entry] = NULL;			lp->tx_dma_addr[entry] = 0;		}		dirty_tx++;	}	delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);	if (delta > lp->tx_ring_size) {		if (netif_msg_drv(lp))			printk(KERN_ERR			       "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",			       dev->name, dirty_tx, lp->cur_tx,			       lp->tx_full);		dirty_tx += lp->tx_ring_size;		delta -= lp->tx_ring_size;	}	if (lp->tx_full &&	    netif_queue_stopped(dev) &&	    delta < lp->tx_ring_size - 2) {		/* The ring is no longer full, clear tbusy. */		lp->tx_full = 0;		netif_wake_queue(dev);	}	lp->dirty_tx = dirty_tx;	return must_restart;}#ifdef CONFIG_PCNET32_NAPIstatic int pcnet32_poll(struct napi_struct *napi, int budget){	struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi);	struct net_device *dev = lp->dev;	unsigned long ioaddr = dev->base_addr;	unsigned long flags;	int work_done;	u16 val;	work_done = pcnet32_rx(dev, budget);	spin_lock_irqsave(&lp->lock, flags);	if (pcnet32_tx(dev)) {		/* reset the chip to clear the error condition, then restart */		lp->a.reset(ioaddr);		lp->a.write_csr(ioaddr, CSR4, 0x0915);	/* auto tx pad */		pcnet32_restart(dev, CSR0_START);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?