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

📄 tc35815.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef DEBUG		if (lp->rfd_cur != next_rfd)			printk("rfd_cur = %p, next_rfd %p\n",			       lp->rfd_cur, next_rfd);#endif	}	/* re-enable BL/FDA Exhaust interrupts. */	if (fd_free_count) {		struct tc35815_regs __iomem *tr =			(struct tc35815_regs __iomem *)dev->base_addr;		u32 en, en_old = tc_readl(&tr->Int_En);		en = en_old | Int_FDAExEn;		if (buf_free_count)			en |= Int_BLExEn;		if (en != en_old)			tc_writel(en, &tr->Int_En);	}#ifdef TC35815_NAPI	return received;#endif}#ifdef TC35815_NAPIstatic int tc35815_poll(struct napi_struct *napi, int budget){	struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);	struct net_device *dev = lp->dev;	struct tc35815_regs __iomem *tr =		(struct tc35815_regs __iomem *)dev->base_addr;	int received = 0, handled;	u32 status;	spin_lock(&lp->lock);	status = tc_readl(&tr->Int_Src);	do {		tc_writel(status, &tr->Int_Src);	/* write to clear */		handled = tc35815_do_interrupt(dev, status, limit);		if (handled >= 0) {			received += handled;			if (received >= budget)				break;		}		status = tc_readl(&tr->Int_Src);	} while (status);	spin_unlock(&lp->lock);	if (received < budget) {		netif_rx_complete(dev, napi);		/* enable interrupts */		tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);	}	return received;}#endif#ifdef NO_CHECK_CARRIER#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)#else#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)#endifstatic voidtc35815_check_tx_stat(struct net_device *dev, int status){	struct tc35815_local *lp = dev->priv;	const char *msg = NULL;	/* count collisions */	if (status & Tx_ExColl)		lp->stats.collisions += 16;	if (status & Tx_TxColl_MASK)		lp->stats.collisions += status & Tx_TxColl_MASK;#ifndef NO_CHECK_CARRIER	/* TX4939 does not have NCarr */	if (lp->boardtype == TC35815_TX4939)		status &= ~Tx_NCarr;#ifdef WORKAROUND_LOSTCAR	/* WORKAROUND: ignore LostCrS in full duplex operation */	if ((lp->timer_state != asleep && lp->timer_state != lcheck)	    || lp->fullduplex)		status &= ~Tx_NCarr;#endif#endif	if (!(status & TX_STA_ERR)) {		/* no error. */		lp->stats.tx_packets++;		return;	}	lp->stats.tx_errors++;	if (status & Tx_ExColl) {		lp->stats.tx_aborted_errors++;		msg = "Excessive Collision.";	}	if (status & Tx_Under) {		lp->stats.tx_fifo_errors++;		msg = "Tx FIFO Underrun.";		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {			lp->lstats.tx_underrun++;			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {				struct tc35815_regs __iomem *tr =					(struct tc35815_regs __iomem *)dev->base_addr;				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);				msg = "Tx FIFO Underrun.Change Tx threshold to max.";			}		}	}	if (status & Tx_Defer) {		lp->stats.tx_fifo_errors++;		msg = "Excessive Deferral.";	}#ifndef NO_CHECK_CARRIER	if (status & Tx_NCarr) {		lp->stats.tx_carrier_errors++;		msg = "Lost Carrier Sense.";	}#endif	if (status & Tx_LateColl) {		lp->stats.tx_aborted_errors++;		msg = "Late Collision.";	}	if (status & Tx_TxPar) {		lp->stats.tx_fifo_errors++;		msg = "Transmit Parity Error.";	}	if (status & Tx_SQErr) {		lp->stats.tx_heartbeat_errors++;		msg = "Signal Quality Error.";	}	if (msg && netif_msg_tx_err(lp))		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);}/* This handles TX complete events posted by the device * via interrupts. */static voidtc35815_txdone(struct net_device *dev){	struct tc35815_local *lp = dev->priv;	struct TxFD *txfd;	unsigned int fdctl;	txfd = &lp->tfd_base[lp->tfd_end];	while (lp->tfd_start != lp->tfd_end &&	       !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {		int status = le32_to_cpu(txfd->fd.FDStat);		struct sk_buff *skb;		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);		if (netif_msg_tx_done(lp)) {			printk("%s: complete TxFD.\n", dev->name);			dump_txfd(txfd);		}		tc35815_check_tx_stat(dev, status);		skb = fdsystem != 0xffffffff ?			lp->tx_skbs[fdsystem].skb : NULL;#ifdef DEBUG		if (lp->tx_skbs[lp->tfd_end].skb != skb) {			printk("%s: tx_skbs mismatch.\n", dev->name);			panic_queues(dev);		}#else		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);#endif		if (skb) {			lp->stats.tx_bytes += skb->len;			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);			lp->tx_skbs[lp->tfd_end].skb = NULL;			lp->tx_skbs[lp->tfd_end].skb_dma = 0;#ifdef TC35815_NAPI			dev_kfree_skb_any(skb);#else			dev_kfree_skb_irq(skb);#endif		}		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;		txfd = &lp->tfd_base[lp->tfd_end];#ifdef DEBUG		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {			printk("%s: TxFD FDNext invalid.\n", dev->name);			panic_queues(dev);		}#endif		if (fdnext & FD_Next_EOL) {			/* DMA Transmitter has been stopping... */			if (lp->tfd_end != lp->tfd_start) {				struct tc35815_regs __iomem *tr =					(struct tc35815_regs __iomem *)dev->base_addr;				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;				struct TxFD* txhead = &lp->tfd_base[head];				int qlen = (lp->tfd_start + TX_FD_NUM					    - lp->tfd_end) % TX_FD_NUM;#ifdef DEBUG				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {					printk("%s: TxFD FDCtl invalid.\n", dev->name);					panic_queues(dev);				}#endif				/* log max queue length */				if (lp->lstats.max_tx_qlen < qlen)					lp->lstats.max_tx_qlen = qlen;				/* start DMA Transmitter again */				txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);#ifdef GATHER_TXINT				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);#endif				if (netif_msg_tx_queued(lp)) {					printk("%s: start TxFD on queue.\n",					       dev->name);					dump_txfd(txfd);				}				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);			}			break;		}	}	/* If we had stopped the queue due to a "tx full"	 * condition, and space has now been made available,	 * wake up the queue.	 */	if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))		netif_wake_queue(dev);}/* The inverse routine to tc35815_open(). */static inttc35815_close(struct net_device *dev){	struct tc35815_local *lp = dev->priv;	netif_stop_queue(dev);#ifdef TC35815_NAPI	napi_disable(&lp->napi);#endif	/* Flush the Tx and disable Rx here. */	del_timer(&lp->timer);		/* Kill if running	*/	tc35815_chip_reset(dev);	free_irq(dev->irq, dev);	tc35815_free_queues(dev);	return 0;}/* * Get the current statistics. * This may be called with the card open or closed. */static struct net_device_stats *tc35815_get_stats(struct net_device *dev){	struct tc35815_local *lp = dev->priv;	struct tc35815_regs __iomem *tr =		(struct tc35815_regs __iomem *)dev->base_addr;	if (netif_running(dev)) {		/* Update the statistics from the device registers. */		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);	}	return &lp->stats;}static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr){	struct tc35815_local *lp = dev->priv;	struct tc35815_regs __iomem *tr =		(struct tc35815_regs __iomem *)dev->base_addr;	int cam_index = index * 6;	u32 cam_data;	u32 saved_addr;	saved_addr = tc_readl(&tr->CAM_Adr);	if (netif_msg_hw(lp)) {		int i;		printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);		for (i = 0; i < 6; i++)			printk(" %02x", addr[i]);		printk("\n");	}	if (index & 1) {		/* read modify write */		tc_writel(cam_index - 2, &tr->CAM_Adr);		cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;		cam_data |= addr[0] << 8 | addr[1];		tc_writel(cam_data, &tr->CAM_Data);		/* write whole word */		tc_writel(cam_index + 2, &tr->CAM_Adr);		cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];		tc_writel(cam_data, &tr->CAM_Data);	} else {		/* write whole word */		tc_writel(cam_index, &tr->CAM_Adr);		cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];		tc_writel(cam_data, &tr->CAM_Data);		/* read modify write */		tc_writel(cam_index + 4, &tr->CAM_Adr);		cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;		cam_data |= addr[4] << 24 | (addr[5] << 16);		tc_writel(cam_data, &tr->CAM_Data);	}	tc_writel(saved_addr, &tr->CAM_Adr);}/* * Set or clear the multicast filter for this adaptor. * num_addrs == -1	Promiscuous mode, receive all packets * num_addrs == 0	Normal mode, clear multicast list * num_addrs > 0	Multicast mode, receive normal and MC packets, *			and do best-effort filtering. */static voidtc35815_set_multicast_list(struct net_device *dev){	struct tc35815_regs __iomem *tr =		(struct tc35815_regs __iomem *)dev->base_addr;	if (dev->flags&IFF_PROMISC)	{#ifdef WORKAROUND_100HALF_PROMISC		/* With some (all?) 100MHalf HUB, controller will hang		 * if we enabled promiscuous mode before linkup... */		struct tc35815_local *lp = dev->priv;		int pid = lp->phy_addr;		if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))			return;#endif		/* Enable promiscuous mode */		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);	}	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3)	{		/* CAM 0, 1, 20 are reserved. */		/* Disable promiscuous mode, use normal mode. */		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);	}	else if(dev->mc_count)	{		struct dev_mc_list* cur_addr = dev->mc_list;		int i;		int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);		tc_writel(0, &tr->CAM_Ctl);		/* Walk the address list, and load the filter */		for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {			if (!cur_addr)				break;			/* entry 0,1 is reserved. */			tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);			ena_bits |= CAM_Ena_Bit(i + 2);		}		tc_writel(ena_bits, &tr->CAM_Ena);		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);	}	else {		tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);	}}static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	struct tc35815_local *lp = dev->priv;	strcpy(info->driver, MODNAME);	strcpy(info->version, DRV_VERSION);	strcpy(info->bus_info, pci_name(lp->pci_dev));}static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct tc35815_local *lp = dev->priv;	spin_lock_irq(&lp->lock);	mii_ethtool_gset(&lp->mii, cmd);	spin_unlock_irq(&lp->lock);	return 0;}static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct tc35815_local *lp = dev->priv;	int rc;#if 1	/* use our negotiation method... */	/* Verify the settings we care about. */	if (cmd->autoneg != AUTONEG_ENABLE &&	    cmd->autoneg != AUTONEG_DISABLE)		return -EINVAL;	if (cmd->autoneg == AUTONEG_DISABLE &&	    ((cmd->speed != SPEED_100 &&	      cmd->speed != SPEED_10) ||	     (cmd->duplex != DUPLEX_HALF &&	      cmd->duplex != DUPLEX_FULL)))		return -EINVAL;	/* Ok, do it to it. */	spin_lock_irq(&lp->lock);	del_timer(&lp->timer);	tc35815_start_auto_negotiation(dev, cmd);	spin_unlock_irq(&lp->lock);	rc = 0;#else	spin_lock_irq(&lp->lock);	rc = mii_ethtool_sset(&lp->mii, cmd);	spin_unlock_irq(&lp->lock);#endif	return rc;}static int tc35815_nway_reset(struct net_device *dev){	struct tc35815_local *lp = dev->priv;	int

⌨️ 快捷键说明

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