⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 forcedeth.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
							NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {				if (Flags & NV_TX2_UNDERFLOW)					np->stats.tx_fifo_errors++;				if (Flags & NV_TX2_CARRIERLOST)					np->stats.tx_carrier_errors++;				np->stats.tx_errors++;			} else {				np->stats.tx_packets++;				np->stats.tx_bytes += np->tx_skbuff[i]->len;			}		}		pci_unmap_single(np->pci_dev, np->tx_dma[i],					np->tx_skbuff[i]->len,					PCI_DMA_TODEVICE);		dev_kfree_skb_irq(np->tx_skbuff[i]);		np->tx_skbuff[i] = NULL;		np->nic_tx++;	}	if (np->next_tx - np->nic_tx < TX_LIMIT_START)		netif_wake_queue(dev);}/* * nv_tx_timeout: dev->tx_timeout function * Called with dev->xmit_lock held. */static void nv_tx_timeout(struct net_device *dev){	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,			readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);	spin_lock_irq(&np->lock);	/* 1) stop tx engine */	nv_stop_tx(dev);	/* 2) check that the packets were not sent already: */	nv_tx_done(dev);	/* 3) if there are dead entries: clear everything */	if (np->next_tx != np->nic_tx) {		printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);		nv_drain_tx(dev);		np->next_tx = np->nic_tx = 0;		writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);		netif_wake_queue(dev);	}	/* 4) restart tx engine */	nv_start_tx(dev);	spin_unlock_irq(&np->lock);}static void nv_rx_process(struct net_device *dev){	struct fe_priv *np = get_nvpriv(dev);	u32 Flags;	for (;;) {		struct sk_buff *skb;		int len;		int i;		if (np->cur_rx - np->refill_rx >= RX_RING)			break;	/* we scanned the whole ring - do not continue */		i = np->cur_rx % RX_RING;		Flags = le32_to_cpu(np->rx_ring[i].FlagLen);		len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver);		dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",					dev->name, np->cur_rx, Flags);		if (Flags & NV_RX_AVAIL)			break;	/* still owned by hardware, */		/*		 * the packet is for us - immediately tear down the pci mapping.		 * TODO: check if a prefetch of the first cacheline improves		 * the performance.		 */		pci_unmap_single(np->pci_dev, np->rx_dma[i],				np->rx_skbuff[i]->len,				PCI_DMA_FROMDEVICE);		{			int j;			dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);			for (j=0; j<64; j++) {				if ((j%16) == 0)					dprintk("\n%03x:", j);				dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);			}			dprintk("\n");		}		/* look at what we actually got: */		if (np->desc_ver == DESC_VER_1) {			if (!(Flags & NV_RX_DESCRIPTORVALID))				goto next_pkt;			if (Flags & NV_RX_MISSEDFRAME) {				np->stats.rx_missed_errors++;				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX_CRCERR) {				np->stats.rx_crc_errors++;				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX_OVERFLOW) {				np->stats.rx_over_errors++;				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX_ERROR) {				/* framing errors are soft errors, the rest is fatal. */				if (Flags & NV_RX_FRAMINGERR) {					if (Flags & NV_RX_SUBSTRACT1) {						len--;					}				} else {					np->stats.rx_errors++;					goto next_pkt;				}			}		} else {			if (!(Flags & NV_RX2_DESCRIPTORVALID))				goto next_pkt;			if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX2_CRCERR) {				np->stats.rx_crc_errors++;				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX2_OVERFLOW) {				np->stats.rx_over_errors++;				np->stats.rx_errors++;				goto next_pkt;			}			if (Flags & NV_RX2_ERROR) {				/* framing errors are soft errors, the rest is fatal. */				if (Flags & NV_RX2_FRAMINGERR) {					if (Flags & NV_RX2_SUBSTRACT1) {						len--;					}				} else {					np->stats.rx_errors++;					goto next_pkt;				}			}		}		/* got a valid packet - forward it to the network core */		skb = np->rx_skbuff[i];		np->rx_skbuff[i] = NULL;		skb_put(skb, len);		skb->protocol = eth_type_trans(skb, dev);		dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",					dev->name, np->cur_rx, len, skb->protocol);		netif_rx(skb);		dev->last_rx = jiffies;		np->stats.rx_packets++;		np->stats.rx_bytes += len;next_pkt:		np->cur_rx++;	}}/* * nv_change_mtu: dev->change_mtu function * Called with dev_base_lock held for read. */static int nv_change_mtu(struct net_device *dev, int new_mtu){	if (new_mtu > ETH_DATA_LEN)		return -EINVAL;	dev->mtu = new_mtu;	return 0;}/* * nv_set_multicast: dev->set_multicast function * Called with dev->xmit_lock held. */static void nv_set_multicast(struct net_device *dev){	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	u32 addr[2];	u32 mask[2];	u32 pff;	memset(addr, 0, sizeof(addr));	memset(mask, 0, sizeof(mask));	if (dev->flags & IFF_PROMISC) {		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		pff = NVREG_PFF_PROMISC;	} else {		pff = NVREG_PFF_MYADDR;		if (dev->flags & IFF_ALLMULTI || dev->mc_list) {			u32 alwaysOff[2];			u32 alwaysOn[2];			alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0xffffffff;			if (dev->flags & IFF_ALLMULTI) {				alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0;			} else {				struct dev_mc_list *walk;				walk = dev->mc_list;				while (walk != NULL) {					u32 a, b;					a = le32_to_cpu(*(u32 *) walk->dmi_addr);					b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4]));					alwaysOn[0] &= a;					alwaysOff[0] &= ~a;					alwaysOn[1] &= b;					alwaysOff[1] &= ~b;					walk = walk->next;				}			}			addr[0] = alwaysOn[0];			addr[1] = alwaysOn[1];			mask[0] = alwaysOn[0] | alwaysOff[0];			mask[1] = alwaysOn[1] | alwaysOff[1];		}	}	addr[0] |= NVREG_MCASTADDRA_FORCE;	pff |= NVREG_PFF_ALWAYS;	spin_lock_irq(&np->lock);	nv_stop_rx(dev);	writel(addr[0], base + NvRegMulticastAddrA);	writel(addr[1], base + NvRegMulticastAddrB);	writel(mask[0], base + NvRegMulticastMaskA);	writel(mask[1], base + NvRegMulticastMaskB);	writel(pff, base + NvRegPacketFilterFlags);	dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n",		dev->name);	nv_start_rx(dev);	spin_unlock_irq(&np->lock);}static int nv_update_linkspeed(struct net_device *dev){	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	int adv, lpa;	int newls = np->linkspeed;	int newdup = np->duplex;	int mii_status;	int retval = 0;	u32 control_1000, status_1000, phyreg;	/* BMSR_LSTATUS is latched, read it twice:	 * we want the current value.	 */	mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);	mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);	if (!(mii_status & BMSR_LSTATUS)) {		dprintk(KERN_DEBUG "%s: no link detected by phy - falling back to 10HD.\n",				dev->name);		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;		newdup = 0;		retval = 0;		goto set_speed;	}	/* check auto negotiation is complete */	if (!(mii_status & BMSR_ANEGCOMPLETE)) {		/* still in autonegotiation - configure nic for 10 MBit HD and wait. */		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;		newdup = 0;		retval = 0;		dprintk(KERN_DEBUG "%s: autoneg not completed - falling back to 10HD.\n", dev->name);		goto set_speed;	}	retval = 1;	if (np->gigabit == PHY_GIGABIT) {		control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);		status_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_SR, MII_READ);		if ((control_1000 & ADVERTISE_1000FULL) &&			(status_1000 & LPA_1000FULL)) {		dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",				dev->name);			newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000;			newdup = 1;			goto set_speed;		}	}	adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);	lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);	dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",				dev->name, adv, lpa);	/* FIXME: handle parallel detection properly */	lpa = lpa & adv;	if (lpa & LPA_100FULL) {		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;		newdup = 1;	} else if (lpa & LPA_100HALF) {		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;		newdup = 0;	} else if (lpa & LPA_10FULL) {		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;		newdup = 1;	} else if (lpa & LPA_10HALF) {		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;		newdup = 0;	} else {		dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa);		newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;		newdup = 0;	}set_speed:	if (np->duplex == newdup && np->linkspeed == newls)		return retval;	dprintk(KERN_INFO "%s: changing link setting from %d/%d to %d/%d.\n",			dev->name, np->linkspeed, np->duplex, newls, newdup);	np->duplex = newdup;	np->linkspeed = newls;	if (np->gigabit == PHY_GIGABIT) {		phyreg = readl(base + NvRegRandomSeed);		phyreg &= ~(0x3FF00);		if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)			phyreg |= NVREG_RNDSEED_FORCE3;		else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)			phyreg |= NVREG_RNDSEED_FORCE2;		else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)			phyreg |= NVREG_RNDSEED_FORCE;		writel(phyreg, base + NvRegRandomSeed);	}	phyreg = readl(base + NvRegPhyInterface);	phyreg &= ~(PHY_HALF|PHY_100|PHY_1000);	if (np->duplex == 0)		phyreg |= PHY_HALF;	if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)		phyreg |= PHY_100;	else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)		phyreg |= PHY_1000;	writel(phyreg, base + NvRegPhyInterface);	writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),		base + NvRegMisc1);	pci_push(base);	writel(np->linkspeed, base + NvRegLinkSpeed);	pci_push(base);	return retval;}static void nv_linkchange(struct net_device *dev){	if (nv_update_linkspeed(dev)) {		if (netif_carrier_ok(dev)) {			nv_stop_rx(dev);		} else {			netif_carrier_on(dev);			printk(KERN_INFO "%s: link up.\n", dev->name);		}		nv_start_rx(dev);	} else {		if (netif_carrier_ok(dev)) {			netif_carrier_off(dev);			printk(KERN_INFO "%s: link down.\n", dev->name);			nv_stop_rx(dev);		}	}}static void nv_link_irq(struct net_device *dev){	u8 *base = get_hwbase(dev);	u32 miistat;	miistat = readl(base + NvRegMIIStatus);	writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);	dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat);	if (miistat & (NVREG_MIISTAT_LINKCHANGE))		nv_linkchange(dev);	dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);}static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs){	struct net_device *dev = (struct net_device *) data;	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	u32 events;	int i;	dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);	for (i=0; ; i++) {		events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;		writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);		pci_push(base);		dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);		if (!(events & np->irqmask))			break;		if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {			spin_lock(&np->lock);			nv_tx_done(dev);			spin_unlock(&np->lock);		}		if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {			nv_rx_process(dev);			if (nv_alloc_rx(dev)) {				spin_lock(&np->lock);				if (!np->in_shutdown)					mod_timer(&np->oom_kick, jiffies + OOM_REFILL);				spin_unlock(&np->lock);			}		}		if (events & NVREG_IRQ_LINK) {			spin_lock(&np->lock);			nv_link_irq(dev);			spin_unlock(&np->lock);		}		if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {			spin_lock(&np->lock);			nv_linkchange(dev);			spin_unlock(&np->lock);			np->link_timeout = jiffies + LINK_TIMEOUT;		}		if (events & (NVREG_IRQ_TX_ERR)) {			dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",						dev->name, events);		}		if (events & (NVREG_IRQ_UNKNOWN)) {			printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",						dev->name, events);		}		if (i > max_interrupt_work) {			spin_lock(&np->lock);			/* disable interrupts on the nic */			writel(0, base + NvRegIrqMask);			pci_push(base);			if (!np->in_shutdown)				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);			spin_unlock(&np->lock);			break;		}	}	dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);	return IRQ_RETVAL(i);}static void nv_do_nic_poll(unsigned long data){	struct net_device *dev = (struct net_device *) data;	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	disable_irq(dev->irq);	/* FIXME: Do we need synchronize_irq(dev->irq) here? */	/*	 * reenable interrupts on the nic, we have to do this before calling	 * nv_nic_irq because that may decide to do otherwise	 */	writel(np->irqmask, base + NvRegIrqMask);	pci_push(base);	nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);	enable_irq(dev->irq);}static int nv_open(struct net_device *dev){	struct fe_priv *np = get_nvpriv(dev);	u8 *base = get_hwbase(dev);	int ret, oom, i;	dprintk(KERN_DEBUG "nv_open: begin\n");	/* 1) erase previous misconfiguration */	/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */	writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);	writel(0, base + NvRegMulticastAddrB);	writel(0, base + NvRegMulticastMaskA);	writel(0, base + NvRegMulticastMaskB);	writel(0, base + NvRegPacketFilterFlags);

⌨️ 快捷键说明

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