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

📄 smc91x.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	smc_phy_check_media(dev, 1);smc_phy_configure_exit:	// Exit auto-negotiation	spin_unlock_irq(&lp->lock);}/************************************************************************* . smc_phy_interrupt . . Purpose:  Handle interrupts relating to PHY register 18. This is .  called from the "hard" interrupt handler under our private spinlock. . ************************************************************************/static voidsmc_phy_interrupt(struct net_device* dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	int phyaddr = lp->mii.phy_id;	int phy18;	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);	if (lp->phy_type == 0)		return;	for(;;) {		smc_phy_check_media(dev, 0);		// Read PHY Register 18, Status Output		phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG);		if ((phy18 & PHY_INT_INT) == 0)			break;	}}//--- END PHY CONTROL AND CONFIGURATION-------------------------------------static void smc_10bt_check_media(struct net_device *dev, int init){	struct smc_local *lp = (struct smc_local *)dev->priv;	unsigned long ioaddr = dev->base_addr;	unsigned int old_carrier, new_carrier, old_bank;	old_bank = SMC_CURRENT_BANK();	SMC_SELECT_BANK(0);	old_carrier = netif_carrier_ok(dev) ? 1 : 0;	new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0;	if (init || (old_carrier != new_carrier)) {		if (!new_carrier) {			netif_carrier_off(dev);		} else {			netif_carrier_on(dev);		}		if (netif_msg_link(lp))			printk(KERN_INFO "%s: link %s\n", dev->name,			       new_carrier ? "up" : "down");	}	SMC_SELECT_BANK(old_bank);}static void smc_eph_interrupt(struct net_device *dev){	unsigned long ioaddr = dev->base_addr;	unsigned int old_bank, ctl;	smc_10bt_check_media(dev, 0);	old_bank = SMC_CURRENT_BANK();	SMC_SELECT_BANK(1);	ctl = SMC_GET_CTL();	SMC_SET_CTL(ctl & ~CTL_LE_ENABLE);	SMC_SET_CTL(ctl);	SMC_SELECT_BANK(old_bank);}/* * This is the main routine of the driver, to handle the device when * it needs some attention. */static irqreturn_tsmc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	unsigned long ioaddr = dev->base_addr;	struct smc_local *lp = (struct smc_local *)dev->priv;	int status, mask, timeout, card_stats, int_status;	int saved_bank, saved_pointer, handled = 0;	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);	saved_bank = SMC_CURRENT_BANK();	SMC_SELECT_BANK(2);	saved_pointer = SMC_GET_PTR();	mask = SMC_GET_INT_MASK();	SMC_SET_INT_MASK( 0 );	/* set a timeout value, so I don't stay here forever */	timeout = 8;	do {		int_status = status = SMC_GET_INT();		PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",			dev->name, status, mask,			({ int meminfo; SMC_SELECT_BANK(0);			   meminfo = SMC_GET_MIR();			   SMC_SELECT_BANK(2); meminfo; }),			SMC_GET_FIFO());		status &= mask;		if (!status)			break;		spin_lock(&lp->lock);		handled = 1;		if (status & IM_RCV_INT) {			PRINTK3("%s: RX irq\n", dev->name);			smc_rcv(dev);		} else if (status & IM_TX_INT) {			PRINTK3("%s: TX int\n", dev->name);			smc_tx(dev);			SMC_ACK_INT( IM_TX_INT );#if THROTTLE_TX_PKTS			netif_wake_queue(dev);#endif		} else if (status & IM_ALLOC_INT) {			PRINTK3("%s: Allocation irq\n", dev->name);			smc_hardware_send_packet(dev);			mask |= (IM_TX_INT | IM_TX_EMPTY_INT);			mask &= ~IM_ALLOC_INT;#if ! THROTTLE_TX_PKTS			netif_wake_queue(dev);#endif		} else if (status & IM_TX_EMPTY_INT) {			PRINTK3("%s: TX empty\n", dev->name);			mask &= ~IM_TX_EMPTY_INT;			/* update stats */			SMC_SELECT_BANK( 0 );			card_stats = SMC_GET_COUNTER();			SMC_SELECT_BANK( 2 );			/* single collisions */			lp->stats.collisions += card_stats & 0xF;			card_stats >>= 4;			/* multiple collisions */			lp->stats.collisions += card_stats & 0xF;		} else if (status & IM_RX_OVRN_INT) {			PRINTK1( "%s: RX overrun\n", dev->name);			SMC_ACK_INT( IM_RX_OVRN_INT );			lp->stats.rx_errors++;			lp->stats.rx_fifo_errors++;		} else if (status & IM_EPH_INT) {			smc_eph_interrupt(dev);		} else if (status & IM_MDINT) {			SMC_ACK_INT( IM_MDINT );			smc_phy_interrupt(dev);		} else if (status & IM_ERCV_INT ) {			SMC_ACK_INT( IM_ERCV_INT );			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);		}		spin_unlock(&lp->lock);	} while (--timeout);	/* restore register states */	SMC_SET_INT_MASK( mask );	SMC_SET_PTR( saved_pointer );	SMC_SELECT_BANK( saved_bank );	PRINTK3("%s: Interrupt done\n", dev->name);	//return IRQ_RETVAL(handled);	if(!handled)		printk(KERN_DEBUG "Invalid int status 0x%x, mask 0x%x\n", int_status, mask);	return IRQ_HANDLED;}/* Our watchdog timed out. Called by the networking layer */static voidsmc_timeout(struct net_device *dev){	struct smc_local *lp 	= (struct smc_local *)dev->priv;	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);	smc_reset(dev);	smc_enable(dev);#if 0	/* Reconfiguring the PHY doesn't seem like a bad idea here, but	 * it introduced a problem.  Now that this is a timeout routine,	 * we are getting called from within an interrupt context.	 * smc_phy_configure() calls smc_wait_ms() which calls	 * schedule_timeout() which calls schedule().  When schedule()	 * is called from an interrupt context, it prints out	 * "Scheduling in interrupt" and then calls BUG().  This is	 * obviously not desirable.  This was worked around by removing	 * the call to smc_phy_configure() here because it didn't seem	 * absolutely necessary.  Ultimately, if smc_wait_ms() is	 * supposed to be usable from an interrupt context (which it	 * looks like it thinks it should handle), it should be fixed.	 */	/* Reconfigure the PHY */	if (lp->phy_type != 0)		smc_phy_configure(dev);#endif	/* clear anything saved */	if (lp->saved_skb != NULL) {		dev_kfree_skb (lp->saved_skb);		lp->saved_skb = NULL;		lp->stats.tx_errors++;		lp->stats.tx_aborted_errors++;	}	dev->trans_start = jiffies;	netif_wake_queue(dev);}/* .    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 3 bits are the .    number of the 8 bit register, while the low 3 bits are the bit within .    that register. . .    This routine is based very heavily on the one provided by Peter Cammaert.*/static voidsmc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs){	int			i;	unsigned char		multicast_table[ 8 ];	struct dev_mc_list	*cur_addr;	/* table for flipping the order of 3 bits */	static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };	/* start with a table of all zeros: reject all */	memset( multicast_table, 0, sizeof( multicast_table ) );	cur_addr = addrs;	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {		int 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;		/* only use the low order bits */		position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f;		/* do some messy swapping to put the bit in the right spot */		multicast_table[invert3[position&7]] |=					(1<<invert3[(position>>3)&7]);	}	/* now, the table can be loaded into the chipset */	SMC_SELECT_BANK( 3 );	SMC_SET_MCAST( multicast_table );}/* . 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 smc_set_multicast_list(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	unsigned long ioaddr = dev->base_addr;	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);	SMC_SELECT_BANK(0);	if ( dev->flags & IFF_PROMISC ) {		PRINTK2("%s: RCR_PRMS\n", dev->name);		lp->rcr_cur_mode |= RCR_PRMS;		SMC_SET_RCR( lp->rcr_cur_mode );	}/* BUG?  I never disable promiscuous mode if multicasting was turned on.   Now, I turn off promiscuous mode, but I don't do anything to multicasting   when promiscuous mode is turned on.*/	/* 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) {		lp->rcr_cur_mode |= RCR_ALMUL;		SMC_SET_RCR( lp->rcr_cur_mode );		PRINTK2("%s: RCR_ALMUL\n", dev->name);	}	/* We just get all multicast packets even if we only want them	 . from one source.  This will be changed at some future	 . point. */	else if (dev->mc_count )  {		/* support hardware multicasting */		/* be sure I get rid of flags I might have set */		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);		SMC_SET_RCR( lp->rcr_cur_mode );		/* NOTE: this has to set the bank, so make sure it is the		   last thing called.  The bank is set to zero at the top */		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );	} else  {		PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);		SMC_SET_RCR( lp->rcr_cur_mode );		/*		  since I'm disabling all multicast entirely, I need to		  clear the multicast list		*/		SMC_SELECT_BANK( 3 );		SMC_CLEAR_MCAST();	}}/* * Open and Initialize the board * * Set up everything, reset the card, etc .. */static intsmc_open(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	unsigned long ioaddr = dev->base_addr;	PRINTK2("%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)) {		PRINTK2((KERN_DEBUG "smc_open: no valid ethernet hw addr\n"));		return -EINVAL;	}	/* clear out all the junk that was put here before... */	lp->saved_skb = NULL;	// Setup the default Register Modes	lp->tcr_cur_mode = TCR_DEFAULT;	lp->rcr_cur_mode = RCR_DEFAULT;	lp->rpc_cur_mode = RPC_DEFAULT;	/*	 * If we are not using a MII interface, we need to	 * monitor our own carrier signal to detect faults.	 */	if (lp->phy_type == 0)		lp->tcr_cur_mode |= TCR_MON_CSN;	/* reset the hardware */	smc_reset(dev);	smc_enable(dev);	SMC_SELECT_BANK( 1 );	SMC_SET_MAC_ADDR(dev->dev_addr);	/* Configure the PHY */	if (lp->phy_type != 0)		smc_phy_configure(dev);	else {		spin_lock_irq(&lp->lock);		smc_10bt_check_media(dev, 1);		spin_unlock_irq(&lp->lock);	}	netif_start_queue(dev);	return 0;}/*---------------------------------------------------- . smc_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 intsmc_close(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);	netif_stop_queue(dev);	netif_carrier_off(dev);	/* clear everything */	smc_shutdown(dev->base_addr);	spin_lock_irq(&lp->lock);	if (lp->phy_type != 0)		smc_phy_powerdown(dev, lp->mii.phy_id);	spin_unlock_irq(&lp->lock);	return 0;}/*------------------------------------------------------------ . Get the current statistics. . This may be called with the card open or closed. .-------------------------------------------------------------*/static struct net_device_stats *smc_query_statistics(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);	return &lp->stats;}/*------------------------------------------------------------ . Ethtool support .-------------------------------------------------------------*/static intsmc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd){	struct smc_local *lp = (struct smc_local *)dev->priv;	int ret;	cmd->maxtxpkt = 1;	cmd->maxrxpkt = 1;	if (lp->phy_type != 0) {		spin_lock_irq(&lp->lock);		ret = mii_ethtool_gset(&lp->mii, cmd);		spin_unlock_irq(&lp->lock);	} 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;		cmd->transceiver = XCVR_INTERNAL;		cmd->port = 0;		cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF;		ret = 0;	}	return ret;}static intsmc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd){	struct smc_local *lp = (struct smc_local *)dev->priv;	int ret;	if (lp->phy_type != 0) {		spin_lock_irq(&lp->lock);		ret = mii_ethtool_sset(&lp->mii, cmd);		spin_unlock_irq(&lp->lock);	} 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->port = cmd->port;		lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;//		if (netif_running(dev))//			smc_set_port(dev);		ret = 0;	}	return ret;}static voidsmc_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->class_dev.dev->bus_id, sizeof(info->bus_info));}static int smc_ethtool_nwayreset(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	int ret = -EINVAL;	if (lp->phy_type != 0) {		spin_lock_irq(&lp->lock);		ret = mii_nway_restart(&lp->mii);		spin_unlock_irq(&lp->lock);	}	return ret;}static u32 smc_ethtool_getmsglevel(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	return lp->msg_enable;}static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level){	struct smc_local *lp = (struct smc_local *)dev->priv;	lp->msg_enable = level;}static struct ethtool_ops smc_ethtool_ops = {	.get_settings	= smc_ethtool_getsettings,	.set_settings	= smc_ethtool_setsettings,	.get_drvinfo	= smc_ethtool_getdrvinfo,	.get_msglevel	= smc_ethtool_getmsglevel,	.set_msglevel	= smc_ethtool_setmsglevel,	.nway_reset	= smc_ethtool_nwayreset,

⌨️ 快捷键说明

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