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

📄 ns83820.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
		do_intr = 1;		dev->tx_intr_idx = (dev->tx_intr_idx + NR_TX_DESC/4) % NR_TX_DESC;	}	nr_free -= nr_frags;	if (nr_free < MIN_TX_DESC_FREE) {		dprintk("stop_queue - last entry(%p)\n", ndev);		netif_stop_queue(ndev);		stopped = 1;	}	frag = skb_shinfo(skb)->frags;	if (!nr_frags)		frag = NULL;	extsts = 0;	if (skb->ip_summed == CHECKSUM_HW) {		extsts |= EXTSTS_IPPKT;		if (IPPROTO_TCP == skb->nh.iph->protocol)			extsts |= EXTSTS_TCPPKT;		else if (IPPROTO_UDP == skb->nh.iph->protocol)			extsts |= EXTSTS_UDPPKT;	}	len = skb->len;	if (nr_frags)		len -= skb->data_len;	buf = pci_map_single(dev->pci_dev, skb->data, len, PCI_DMA_TODEVICE);	first_desc = dev->tx_descs + (free_idx * DESC_SIZE);	for (;;) {		volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE);		u32 residue = 0;		dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,			(unsigned long long)buf);		last_idx = free_idx;		free_idx = (free_idx + 1) % NR_TX_DESC;		desc[DESC_LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));		desc_addr_set(desc + DESC_BUFPTR, buf);		desc[DESC_EXTSTS] = cpu_to_le32(extsts);		cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);		cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;		cmdsts |= len;		desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);		if (residue) {			buf += len;			len = residue;			continue;		}		if (!nr_frags)			break;		buf = pci_map_page(dev->pci_dev, frag->page,				   frag->page_offset,				   frag->size, PCI_DMA_TODEVICE);		dprintk("frag: buf=%08Lx  page=%08lx offset=%08lx\n",			(long long)buf, (long) page_to_pfn(frag->page),			frag->page_offset);		len = frag->size;		frag++;		nr_frags--;	}	dprintk("done pkt\n");	spin_lock_irq(&dev->tx_lock);	dev->tx_skbs[last_idx] = skb;	first_desc[DESC_CMDSTS] |= cpu_to_le32(CMDSTS_OWN);	dev->tx_free_idx = free_idx;	atomic_inc(&dev->nr_tx_skbs);	spin_unlock_irq(&dev->tx_lock);	kick_tx(dev);	/* Check again: we may have raced with a tx done irq */	if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))		netif_start_queue(ndev);	/* set the transmit start time to catch transmit timeouts */	ndev->trans_start = jiffies;	return 0;}static void ns83820_update_stats(struct ns83820 *dev){	u8 *base = dev->base;	/* the DP83820 will freeze counters, so we need to read all of them */	dev->stats.rx_errors		+= readl(base + 0x60) & 0xffff;	dev->stats.rx_crc_errors	+= readl(base + 0x64) & 0xffff;	dev->stats.rx_missed_errors	+= readl(base + 0x68) & 0xffff;	dev->stats.rx_frame_errors	+= readl(base + 0x6c) & 0xffff;	/*dev->stats.rx_symbol_errors +=*/ readl(base + 0x70);	dev->stats.rx_length_errors	+= readl(base + 0x74) & 0xffff;	dev->stats.rx_length_errors	+= readl(base + 0x78) & 0xffff;	/*dev->stats.rx_badopcode_errors += */ readl(base + 0x7c);	/*dev->stats.rx_pause_count += */  readl(base + 0x80);	/*dev->stats.tx_pause_count += */  readl(base + 0x84);	dev->stats.tx_carrier_errors	+= readl(base + 0x88) & 0xff;}static struct net_device_stats *ns83820_get_stats(struct net_device *ndev){	struct ns83820 *dev = PRIV(ndev);	/* somewhat overkill */	spin_lock_irq(&dev->misc_lock);	ns83820_update_stats(dev);	spin_unlock_irq(&dev->misc_lock);	return &dev->stats;}static int ns83820_ethtool_ioctl (struct ns83820 *dev, void __user *useraddr){	u32 ethcmd;	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))		return -EFAULT;	switch (ethcmd) {	case ETHTOOL_GDRVINFO:		{			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };			strcpy(info.driver, "ns83820");			strcpy(info.version, VERSION);			strcpy(info.bus_info, pci_name(dev->pci_dev));			if (copy_to_user(useraddr, &info, sizeof (info)))				return -EFAULT;			return 0;		}	/* get link status */	case ETHTOOL_GLINK: {		struct ethtool_value edata = { ETHTOOL_GLINK };		u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;		if (cfg & CFG_LNKSTS)			edata.data = 1;		else			edata.data = 0;		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	default:		break;	}	return -EOPNOTSUPP;}static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd){	struct ns83820 *dev = PRIV(ndev);	switch(cmd) {	case SIOCETHTOOL:		return ns83820_ethtool_ioctl(dev, rq->ifr_data);	default:		return -EOPNOTSUPP;	}}static void ns83820_mib_isr(struct ns83820 *dev){	spin_lock(&dev->misc_lock);	ns83820_update_stats(dev);	spin_unlock(&dev->misc_lock);}static void ns83820_do_isr(struct net_device *ndev, u32 isr);static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs){	struct net_device *ndev = data;	struct ns83820 *dev = PRIV(ndev);	u32 isr;	dprintk("ns83820_irq(%p)\n", ndev);	dev->ihr = 0;	isr = readl(dev->base + ISR);	dprintk("irq: %08x\n", isr);	ns83820_do_isr(ndev, isr);	return IRQ_HANDLED;}static void ns83820_do_isr(struct net_device *ndev, u32 isr){	struct ns83820 *dev = PRIV(ndev);#ifdef DEBUG	if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))		Dprintk("odd isr? 0x%08x\n", isr);#endif	if (ISR_RXIDLE & isr) {		dev->rx_info.idle = 1;		Dprintk("oh dear, we are idle\n");		ns83820_rx_kick(ndev);	}	if ((ISR_RXDESC | ISR_RXOK) & isr) {		prefetch(dev->rx_info.next_rx_desc);		spin_lock_irq(&dev->misc_lock);		dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);		writel(dev->IMR_cache, dev->base + IMR);		spin_unlock_irq(&dev->misc_lock);		tasklet_schedule(&dev->rx_tasklet);		//rx_irq(ndev);		//writel(4, dev->base + IHR);	}	if ((ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr)		ns83820_rx_kick(ndev);	if (unlikely(ISR_RXSOVR & isr)) {		//printk("overrun: rxsovr\n");		dev->stats.rx_fifo_errors ++;	}	if (unlikely(ISR_RXORN & isr)) {		//printk("overrun: rxorn\n");		dev->stats.rx_fifo_errors ++;	}	if ((ISR_RXRCMP & isr) && dev->rx_info.up)		writel(CR_RXE, dev->base + CR);	if (ISR_TXIDLE & isr) {		u32 txdp;		txdp = readl(dev->base + TXDP);		dprintk("txdp: %08x\n", txdp);		txdp -= dev->tx_phy_descs;		dev->tx_idx = txdp / (DESC_SIZE * 4);		if (dev->tx_idx >= NR_TX_DESC) {			printk(KERN_ALERT "%s: BUG -- txdp out of range\n", ndev->name);			dev->tx_idx = 0;		}		/* The may have been a race between a pci originated read		 * and the descriptor update from the cpu.  Just in case, 		 * kick the transmitter if the hardware thinks it is on a 		 * different descriptor than we are.		 */		if (dev->tx_idx != dev->tx_free_idx)			kick_tx(dev);	}	/* Defer tx ring processing until more than a minimum amount of	 * work has accumulated	 */	if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {		do_tx_done(ndev);		/* Disable TxOk if there are no outstanding tx packets.		 */		if ((dev->tx_done_idx == dev->tx_free_idx) &&		    (dev->IMR_cache & ISR_TXOK)) {			spin_lock_irq(&dev->misc_lock);			dev->IMR_cache &= ~ISR_TXOK;			writel(dev->IMR_cache, dev->base + IMR);			spin_unlock_irq(&dev->misc_lock);		}	}	/* The TxIdle interrupt can come in before the transmit has	 * completed.  Normally we reap packets off of the combination	 * of TxDesc and TxIdle and leave TxOk disabled (since it 	 * occurs on every packet), but when no further irqs of this 	 * nature are expected, we must enable TxOk.	 */	if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {		spin_lock_irq(&dev->misc_lock);		dev->IMR_cache |= ISR_TXOK;		writel(dev->IMR_cache, dev->base + IMR);		spin_unlock_irq(&dev->misc_lock);	}	/* MIB interrupt: one of the statistics counters is about to overflow */	if (unlikely(ISR_MIB & isr))		ns83820_mib_isr(dev);	/* PHY: Link up/down/negotiation state change */	if (unlikely(ISR_PHY & isr))		phy_intr(ndev);#if 0	/* Still working on the interrupt mitigation strategy */	if (dev->ihr)		writel(dev->ihr, dev->base + IHR);#endif}static void ns83820_do_reset(struct ns83820 *dev, u32 which){	Dprintk("resetting chip...\n");	writel(which, dev->base + CR);	do {		schedule();	} while (readl(dev->base + CR) & which);	Dprintk("okay!\n");}static int ns83820_stop(struct net_device *ndev){	struct ns83820 *dev = PRIV(ndev);	/* FIXME: protect against interrupt handler? */	del_timer_sync(&dev->tx_watchdog);	/* disable interrupts */	writel(0, dev->base + IMR);	writel(0, dev->base + IER);	readl(dev->base + IER);	dev->rx_info.up = 0;	synchronize_irq(dev->pci_dev->irq);	ns83820_do_reset(dev, CR_RST);	synchronize_irq(dev->pci_dev->irq);	spin_lock_irq(&dev->misc_lock);	dev->IMR_cache &= ~(ISR_TXURN | ISR_TXIDLE | ISR_TXERR | ISR_TXDESC | ISR_TXOK);	spin_unlock_irq(&dev->misc_lock);	ns83820_cleanup_rx(dev);	ns83820_cleanup_tx(dev);	return 0;}static void ns83820_tx_timeout(struct net_device *ndev){	struct ns83820 *dev = PRIV(ndev);        u32 tx_done_idx, *desc;	unsigned long flags;	local_irq_save(flags);	tx_done_idx = dev->tx_done_idx;	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);	printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",		ndev->name,		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));#if defined(DEBUG)	{		u32 isr;		isr = readl(dev->base + ISR);		printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache);		ns83820_do_isr(ndev, isr);	}#endif	do_tx_done(ndev);	tx_done_idx = dev->tx_done_idx;	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);	printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",		ndev->name,		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));	local_irq_restore(flags);}static void ns83820_tx_watch(unsigned long data){	struct net_device *ndev = (void *)data;	struct ns83820 *dev = PRIV(ndev);#if defined(DEBUG)	printk("ns83820_tx_watch: %u %u %d\n",		dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)		);#endif	if (time_after(jiffies, ndev->trans_start + 1*HZ) &&	    dev->tx_done_idx != dev->tx_free_idx) {		printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n",			ndev->name,			dev->tx_done_idx, dev->tx_free_idx,			atomic_read(&dev->nr_tx_skbs));		ns83820_tx_timeout(ndev);	}	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);}static int ns83820_open(struct net_device *ndev){	struct ns83820 *dev = PRIV(ndev);	unsigned i;	u32 desc;	int ret;	dprintk("ns83820_open\n");	writel(0, dev->base + PQCR);	ret = ns83820_setup_rx(ndev);	if (ret)		goto failed;	memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);	for (i=0; i<NR_TX_DESC; i++) {		dev->tx_descs[(i * DESC_SIZE) + DESC_LINK]				= cpu_to_le32(				  dev->tx_phy_descs				  + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);	}	dev->tx_idx = 0;	dev->tx_done_idx = 0;	desc = dev->tx_phy_descs;	writel(0, dev->base + TXDP_HI);	writel(desc, dev->base + TXDP);	init_timer(&dev->tx_watchdog);	dev->tx_watchdog.data = (unsigned long)ndev;	dev->tx_watchdog.function = ns83820_tx_watch;	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);	netif_start_queue(ndev);	/* FIXME: wait for phy to come up */	return 0;failed:	ns83820_stop(ndev);	return ret;}static void ns83820_getmac(struct ns83820 *dev, u8 *mac){	unsigned i;	for (i=0; i<3; i++) {		u32 data;#if 0	/* I've left this in as an example of how to use eeprom.h */		data = eeprom_readw(&dev->ee, 0xa + 2 - i);#else		/* Read from the perfect match memory: this is loaded by		 * the chip from the EEPROM via the EELOAD self test.		 */		writel(i*2, dev->base + RFCR);		data = readl(dev->base + RFDR);#endif		*mac++ = data;		*mac++ = data >> 8;	}}static int ns83820_change_mtu(struct net_device *ndev, int new_mtu){	if (new_mtu > RX_BUF_SIZE)		return -EINVAL;	ndev->mtu = new_mtu;	return 0;}static void ns83820_set_multicast(struct net_device *ndev){	struct ns83820 *dev = PRIV(ndev);	u8 *rfcr = dev->base + RFCR;	u32 and_mask = 0xffffffff;	u32 or_mask = 0;	u32 val;	if (ndev->flags & IFF_PROMISC)		or_mask |= RFCR_AAU | RFCR_AAM;	else		and_mask &= ~(RFCR_AAU | RFCR_AAM);	if (ndev->flags & IFF_ALLMULTI)		or_mask |= RFCR_AAM;	else		and_mask &= ~RFCR_AAM;	spin_lock_irq(&dev->misc_lock);	val = (readl(rfcr) & and_mask) | or_mask;	/* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */	writel(val & ~RFCR_RFEN, rfcr);	writel(val, rfcr);	spin_unlock_irq(&dev->misc_lock);}static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enable, u32 done, u32 fail){	struct ns83820 *dev = PRIV(ndev);	int timed_out = 0;	long start;	u32 status;	int loops = 0;	dprintk("%s: start %s\n", ndev->name, name);	start = jiffies;	writel(enable, dev->base + PTSCR);	for (;;) {		loops++;		status = readl(dev->base + PTSCR);		if (!(status & enable))			break;		if (status & done)			break;		if (status & fail)			break;		if ((jiffies - start) >= HZ) {			timed_out = 1;			break;		}		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(1);	}	if (status & fail)		printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n",			ndev->name, name, status, fail);	else if (timed_out)		printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n",			ndev->name, name, status);	dprintk("%s: done %s in %d loops\n", ndev->name, name, loops);}#ifdef PHY_CODE_IS_FINISHEDstatic void ns83820_mii_write_bit(struct ns83820 *dev, int bit){	/* drive MDC low */	dev->MEAR_cache &= ~MEAR_MDC;	writel(dev->MEAR_cache, dev->base + MEAR);	readl(dev->base + MEAR);

⌨️ 快捷键说明

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