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

📄 smc911x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (status & INT_STS_RDFO_) {			if (!IS_REV_A(lp->revision)) {				SMC_GET_MAC_CR(cr);				cr &= ~MAC_CR_RXEN_;				SMC_SET_MAC_CR(cr);				rx_overrun=1;				DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);				dev->stats.rx_errors++;				dev->stats.rx_fifo_errors++;			}			SMC_ACK_INT(INT_STS_RDFO_);		}		/* Handle receive condition */		if ((status & INT_STS_RSFL_) || rx_overrun) {			unsigned int fifo;			DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name);			fifo = SMC_GET_RX_FIFO_INF();			pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16;			DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n",				dev->name, pkts, fifo & 0xFFFF );			if (pkts != 0) {#ifdef SMC_USE_DMA				unsigned int fifo;				if (lp->rxdma_active){					DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,						"%s: RX DMA active\n", dev->name);					/* The DMA is already running so up the IRQ threshold */					fifo = SMC_GET_FIFO_INT() & ~0xFF;					fifo |= pkts & 0xFF;					DBG(SMC_DEBUG_RX,						"%s: Setting RX stat FIFO threshold to %d\n",						dev->name, fifo & 0xff);					SMC_SET_FIFO_INT(fifo);				} else#endif				smc911x_rcv(dev);			}			SMC_ACK_INT(INT_STS_RSFL_);		}		/* Handle transmit FIFO available */		if (status & INT_STS_TDFA_) {			DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name);			SMC_SET_FIFO_TDA(0xFF);			lp->tx_throttle = 0;#ifdef SMC_USE_DMA			if (!lp->txdma_active)#endif				netif_wake_queue(dev);			SMC_ACK_INT(INT_STS_TDFA_);		}		/* Handle transmit done condition */#if 1		if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) {			DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC,				"%s: Tx stat FIFO limit (%d) /GPT irq\n",				dev->name, (SMC_GET_FIFO_INT() & 0x00ff0000) >> 16);			smc911x_tx(dev);			SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);			SMC_ACK_INT(INT_STS_TSFL_);			SMC_ACK_INT(INT_STS_TSFL_ | INT_STS_GPT_INT_);		}#else		if (status & INT_STS_TSFL_) {			DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq \n", dev->name, );			smc911x_tx(dev);			SMC_ACK_INT(INT_STS_TSFL_);		}		if (status & INT_STS_GPT_INT_) {			DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n",				dev->name,				SMC_GET_IRQ_CFG(),				SMC_GET_FIFO_INT(),				SMC_GET_RX_CFG());			DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x "				"Data FIFO Used 0x%04x Stat FIFO 0x%08x\n",				dev->name,				(SMC_GET_RX_FIFO_INF() & 0x00ff0000) >> 16,				SMC_GET_RX_FIFO_INF() & 0xffff,				SMC_GET_RX_STS_FIFO_PEEK());			SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);			SMC_ACK_INT(INT_STS_GPT_INT_);		}#endif		/* Handle PHY interrupt condition */		if (status & INT_STS_PHY_INT_) {			DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);			smc911x_phy_interrupt(dev);			SMC_ACK_INT(INT_STS_PHY_INT_);		}	} while (--timeout);	/* restore mask state */	SMC_SET_INT_EN(mask);	DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n",		dev->name, 8-timeout);	spin_unlock_irqrestore(&lp->lock, flags);	DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout);	return IRQ_HANDLED;}#ifdef SMC_USE_DMAstatic voidsmc911x_tx_dma_irq(int dma, void *data){	struct net_device *dev = (struct net_device *)data;	struct smc911x_local *lp = netdev_priv(dev);	struct sk_buff *skb = lp->current_tx_skb;	unsigned long flags;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name);	/* Clear the DMA interrupt sources */	SMC_DMA_ACK_IRQ(dev, dma);	BUG_ON(skb == NULL);	dma_unmap_single(NULL, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE);	dev->trans_start = jiffies;	dev_kfree_skb_irq(skb);	lp->current_tx_skb = NULL;	if (lp->pending_tx_skb != NULL)		smc911x_hardware_send_pkt(dev);	else {		DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,			"%s: No pending Tx packets. DMA disabled\n", dev->name);		spin_lock_irqsave(&lp->lock, flags);		lp->txdma_active = 0;		if (!lp->tx_throttle) {			netif_wake_queue(dev);		}		spin_unlock_irqrestore(&lp->lock, flags);	}	DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,		"%s: TX DMA irq completed\n", dev->name);}static voidsmc911x_rx_dma_irq(int dma, void *data){	struct net_device *dev = (struct net_device *)data;	unsigned long ioaddr = dev->base_addr;	struct smc911x_local *lp = netdev_priv(dev);	struct sk_buff *skb = lp->current_rx_skb;	unsigned long flags;	unsigned int pkts;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name);	/* Clear the DMA interrupt sources */	SMC_DMA_ACK_IRQ(dev, dma);	dma_unmap_single(NULL, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE);	BUG_ON(skb == NULL);	lp->current_rx_skb = NULL;	PRINT_PKT(skb->data, skb->len);	dev->last_rx = jiffies;	skb->protocol = eth_type_trans(skb, dev);	dev->stats.rx_packets++;	dev->stats.rx_bytes += skb->len;	netif_rx(skb);	spin_lock_irqsave(&lp->lock, flags);	pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16;	if (pkts != 0) {		smc911x_rcv(dev);	}else {		lp->rxdma_active = 0;	}	spin_unlock_irqrestore(&lp->lock, flags);	DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,		"%s: RX DMA irq completed. DMA RX FIFO PKTS %d\n",		dev->name, pkts);}#endif	 /* SMC_USE_DMA */#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling receive - used by netconsole and other diagnostic tools * to allow network i/o with interrupts disabled. */static void smc911x_poll_controller(struct net_device *dev){	disable_irq(dev->irq);	smc911x_interrupt(dev->irq, dev);	enable_irq(dev->irq);}#endif/* Our watchdog timed out. Called by the networking layer */static void smc911x_timeout(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	int status, mask;	unsigned long flags;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	spin_lock_irqsave(&lp->lock, flags);	status = SMC_GET_INT();	mask = SMC_GET_INT_EN();	spin_unlock_irqrestore(&lp->lock, flags);	DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x \n",		dev->name, status, mask);	/* Dump the current TX FIFO contents and restart */	mask = SMC_GET_TX_CFG();	SMC_SET_TX_CFG(mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);	/*	 * Reconfiguring the PHY doesn't seem like a bad idea here, but	 * smc911x_phy_configure() calls msleep() which calls schedule_timeout()	 * which calls schedule().	 Hence we use a work queue.	 */	if (lp->phy_type != 0) {		if (schedule_work(&lp->phy_configure)) {			lp->work_pending = 1;		}	}	/* We can accept TX packets again */	dev->trans_start = jiffies;	netif_wake_queue(dev);}/* * This routine will, depending on the values passed to it, * either make it accept multicast packets, go into * promiscuous mode (for TCPDUMP and cousins) or accept * a select set of multicast packets */static void smc911x_set_multicast_list(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	unsigned int multicast_table[2];	unsigned int mcr, update_multicast = 0;	unsigned long flags;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	spin_lock_irqsave(&lp->lock, flags);	SMC_GET_MAC_CR(mcr);	spin_unlock_irqrestore(&lp->lock, flags);	if (dev->flags & IFF_PROMISC) {		DBG(SMC_DEBUG_MISC, "%s: RCR_PRMS\n", dev->name);		mcr |= MAC_CR_PRMS_;	}	/*	 * Here, I am setting this to accept all multicast packets.	 * I don't need to zero the multicast table, because the flag is	 * checked before the table is	 */	else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) {		DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name);		mcr |= MAC_CR_MCPAS_;	}	/*	 * This sets the internal hardware table to filter out unwanted	 * multicast packets before they take up memory.	 *	 * The SMC chip uses a hash table where the high 6 bits of the CRC of	 * address are the offset into the table.	If that bit is 1, then the	 * multicast packet is accepted.  Otherwise, it's dropped silently.	 *	 * To use the 6 bits as an offset into the table, the high 1 bit is	 * the number of the 32 bit register, while the low 5 bits are the bit	 * within that register.	 */	else if (dev->mc_count)  {		int i;		struct dev_mc_list *cur_addr;		/* Set the Hash perfec mode */		mcr |= MAC_CR_HPFILT_;		/* start with a table of all zeros: reject all */		memset(multicast_table, 0, sizeof(multicast_table));		cur_addr = dev->mc_list;		for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {			u32 position;			/* do we have a pointer here? */			if (!cur_addr)				break;			/* make sure this is a multicast address -				shouldn't this be a given if we have it here ? */			if (!(*cur_addr->dmi_addr & 1))				 continue;			/* upper 6 bits are used as hash index */			position = ether_crc(ETH_ALEN, cur_addr->dmi_addr)>>26;			multicast_table[position>>5] |= 1 << (position&0x1f);		}		/* be sure I get rid of flags I might have set */		mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);		/* now, the table can be loaded into the chipset */		update_multicast = 1;	} else	 {		DBG(SMC_DEBUG_MISC, "%s: ~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n",			dev->name);		mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);		/*		 * since I'm disabling all multicast entirely, I need to		 * clear the multicast list		 */		memset(multicast_table, 0, sizeof(multicast_table));		update_multicast = 1;	}	spin_lock_irqsave(&lp->lock, flags);	SMC_SET_MAC_CR(mcr);	if (update_multicast) {		DBG(SMC_DEBUG_MISC,			"%s: update mcast hash table 0x%08x 0x%08x\n",			dev->name, multicast_table[0], multicast_table[1]);		SMC_SET_HASHL(multicast_table[0]);		SMC_SET_HASHH(multicast_table[1]);	}	spin_unlock_irqrestore(&lp->lock, flags);}/* * Open and Initialize the board * * Set up everything, reset the card, etc.. */static intsmc911x_open(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	/*	 * Check that the address is valid.  If its not, refuse	 * to bring the device up.	 The user must specify an	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx	 */	if (!is_valid_ether_addr(dev->dev_addr)) {		PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__);		return -EINVAL;	}	/* reset the hardware */	smc911x_reset(dev);	/* Configure the PHY, initialize the link state */	smc911x_phy_configure(&lp->phy_configure);	/* Turn on Tx + Rx */	smc911x_enable(dev);	netif_start_queue(dev);	return 0;}/* * smc911x_close * * this makes the board clean up everything that it can * and not talk to the outside world.	 Caused by * an 'ifconfig ethX down' */static int smc911x_close(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	netif_stop_queue(dev);	netif_carrier_off(dev);	/* clear everything */	smc911x_shutdown(dev);	if (lp->phy_type != 0) {		/* We need to ensure that no calls to		 * smc911x_phy_configure are pending.		 * flush_scheduled_work() cannot be called because we		 * are running with the netlink semaphore held (from		 * devinet_ioctl()) and the pending work queue		 * contains linkwatch_event() (scheduled by		 * netif_carrier_off() above). linkwatch_event() also		 * wants the netlink semaphore.		 */		while (lp->work_pending)			schedule();		smc911x_phy_powerdown(dev, lp->mii.phy_id);	}	if (lp->pending_tx_skb) {		dev_kfree_skb(lp->pending_tx_skb);		lp->pending_tx_skb = NULL;	}	return 0;}/* * Ethtool support */static intsmc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd){	struct smc911x_local *lp = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	int ret, status;	unsigned long flags;	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);	cmd->maxtxpkt = 1;	cmd->maxrxpkt = 1;	if (lp->phy_type != 0) {		spin_lock_irqsave(&lp->lock, flags);		ret = mii_ethtool_gset(&lp->mii, cmd);		spin_unlock_irqrestore(&lp->lock, flags);	} else {		cmd->supported = SUPPORTED_10baseT_Half |				SUPPORTED_10baseT_Full |				SUPPORTED_TP | SUPPORTED_AUI;		if (lp->ctl_rspeed == 10)			cmd->speed = SPEED_10;		else if (lp->ctl_rspeed == 100)			cmd->speed = SPEED_100;		cmd->autoneg = AUTONEG_DISABLE;		if (lp->mii.phy_id==1)			cmd->transceiver = XCVR_INTERNAL;		else			cmd->transceiver = XCVR_EXTERNAL;		cmd->port = 0;		SMC_GET_PHY_SPECIAL(lp->mii.phy_id, status);		cmd->duplex =			(status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ?				DUPLEX_FULL : DUPLEX_HALF;		ret = 0;	}	return ret;}static intsmc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd){	struct smc911x_local *lp = netdev_priv(dev);	int ret;	unsigned long flags;	if (lp->phy_type != 0) {		spin_lock_irqsave(&lp->lock, flags);		ret = mii_ethtool_sset(&lp->mii, cmd);		spin_unlock_irqrestore(&lp->lock, flags);	} else {		if (cmd->autoneg != AUTONEG_DISABLE ||			cmd->speed != SPEED_10 ||			(cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||			(cmd->port != PORT_TP && cmd->port != PORT_AUI))			return -EINVAL;		lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;		ret = 0;	}	return ret;}static voidsmc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	strncpy(info->driver, CARDNAME, sizeof(info->driver));	strncpy(info->version, version, sizeof(info->version));	strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));}static int smc911x_ethtool_nwayreset(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	int ret = -EINVAL;	unsigned long flags;	if (lp->phy_type != 0) {		spin_lock_irqsave(&lp->lock, flags);		ret = mii_nway_restart(&lp->mii);		spin_unlock_irqrestore(&lp->lock, flags);	}	return ret;}static u32 smc911x_ethtool_getmsglevel(struct net_device *dev){	struct smc911x_local *lp = netdev_priv(dev);	return lp->msg_enable;}static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level){	struct smc911x_local *lp = netdev_priv(dev);	lp->msg_enable = level;}static int smc911x_ethtool_getregslen(struct net_device *dev){	/* System regs + MAC regs + PHY regs */	return (((E2P_CMD - ID_REV)/4 + 1) +			(WUCSR - MAC_CR)+1 + 32) * sizeof(u32);}static void smc911x_ethtool_getregs(struct net_device *dev,										 struct ethtool_regs* regs, void *buf){	unsigned long ioaddr = dev->base_addr;	struct smc911x_local *lp = netdev_priv(dev);	unsigned long flags;	u32 reg,i,j=0;	u32 *data = (u32*)buf;	regs->version = lp->version;	for(i=ID_REV;i<=E2P_CMD;i+=4) {		data[j++] = SMC_inl(ioaddr,i);	}	for(i=MAC_CR;i<=WUCSR;i++) {		spin_lock_irqsave(&lp->lock, flags);		SMC_GET_MAC_CSR(i, reg);		spin_unlock_irqrestore(&lp->lock, flags);		data[j++] = reg;	}	for(i=0;i<=31;i++) {		spin_lock_irqsave(&lp->lock, flags);		SMC_GET_MII(i, lp->mii.phy_id, reg);		spin_unlock_irqrestore(&lp->lock, flags);		data[j++] = reg & 0xFFFF;	}}static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev){	unsigned long ioaddr = dev->base_addr;	unsigned int timeout;	int e2p_cmd;	e2p_cmd = SMC_GET_E2P_CMD();	for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {		if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {			PRINTK("%s: %s timeout waiting for EEPROM to respond\n",				dev->name, __FUNCTION__);			return -EFAULT;		}		mdelay(1);		e2p_cmd = SMC_GET_E2P_CMD();	}	if (timeout == 0) {

⌨️ 快捷键说明

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