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

📄 sis900.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		    revision == SIS630A_900_REV)			sis630_set_eq(net_dev, revision);		/* change what cur_phy means */		if (mii_phy->phy_addr != sis_priv->cur_phy) {			printk(KERN_INFO "%s: Changing transceiver to %s\n",			       net_dev->name, mii_phy->chip_info->name);			/* disable previous PHY */			status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);			mdio_write(net_dev, sis_priv->cur_phy,				   MII_CONTROL, status | MII_CNTL_ISOLATE);			/* enable next PHY */			status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL);			mdio_write(net_dev, mii_phy->phy_addr,				   MII_CONTROL, status & ~MII_CNTL_ISOLATE);			sis_priv->cur_phy = mii_phy->phy_addr;		}		sis900_check_mode(net_dev, mii_phy);	}	sis_priv->timer.expires = jiffies + next_tick;	add_timer(&sis_priv->timer);}/** *	sis900_check_mode: - check the media mode for sis900 *	@net_dev: the net device to be checked *	@mii_phy: the mii phy * *	call mii_phy->chip_info->read_mode function *	to check the speed and duplex mode for sis900 */static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy){	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;	long ioaddr = net_dev->base_addr;	int speed, duplex;	u32 tx_flags = 0, rx_flags = 0;	mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex);	tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);	rx_flags = RX_DMA_BURST << RxMXDMA_shift;	if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) {		rx_flags |= (RxDRNT_10 << RxDRNT_shift);		tx_flags |= (TxDRNT_10 << TxDRNT_shift);	}	else {		rx_flags |= (RxDRNT_100 << RxDRNT_shift);		tx_flags |= (TxDRNT_100 << TxDRNT_shift);	}	if (duplex == FDX_CAPABLE_FULL_SELECTED) {		tx_flags |= (TxCSI | TxHBI);		rx_flags |= RxATX;	}	outl (tx_flags, ioaddr + txcfg);	outl (rx_flags, ioaddr + rxcfg);}/** *	sis900_read_mode: - read media mode for sis900 internal phy *	@net_dev: the net device to read mode for *	@phy_addr: mii phy address *	@speed: the transmit speed to be determined *	@duplex: the duplex mode to be determined * *	read MII_STSOUT register from sis900 internal phy *	to determine the speed and duplex mode for sis900 */static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex){	int i = 0;	u32 status;	/* STSOUT register is Latched on Transition, read operation updates it */	while (i++ < 2)		status = mdio_read(net_dev, phy_addr, MII_STSOUT);	if (status & MII_STSOUT_SPD)		*speed = HW_SPEED_100_MBPS;	else		*speed = HW_SPEED_10_MBPS;	if (status & MII_STSOUT_DPLX)		*duplex = FDX_CAPABLE_FULL_SELECTED;	else		*duplex = FDX_CAPABLE_HALF_SELECTED;	if (status & MII_STSOUT_LINK_FAIL)		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);	else		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",		       net_dev->name,		       *speed == HW_SPEED_100_MBPS ?		       "100mbps" : "10mbps",		       *duplex == FDX_CAPABLE_FULL_SELECTED ?		       "full" : "half");}/** *	amd79c901_read_mode: - read media mode for amd79c901 phy *	@net_dev: the net device to read mode for *	@phy_addr: mii phy address *	@speed: the transmit speed to be determined *	@duplex: the duplex mode to be determined * *	read MII_STATUS register from amd79c901 phy *	to determine the speed and duplex mode for sis900 */static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex){	int i;	u16 status;	for (i = 0; i < 2; i++)		status = mdio_read(net_dev, phy_addr, MII_STATUS);	if (status & MII_STAT_CAN_AUTO) {		/* 10BASE-T PHY */		for (i = 0; i < 2; i++)			status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY);		if (status & MII_STSSUM_SPD)			*speed = HW_SPEED_100_MBPS;		else			*speed = HW_SPEED_10_MBPS;		if (status & MII_STSSUM_DPLX)			*duplex = FDX_CAPABLE_FULL_SELECTED;		else			*duplex = FDX_CAPABLE_HALF_SELECTED;		if (status & MII_STSSUM_LINK)			printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",			       net_dev->name,			       *speed == HW_SPEED_100_MBPS ?			       "100mbps" : "10mbps",			       *duplex == FDX_CAPABLE_FULL_SELECTED ?			       "full" : "half");		else			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);	}	else {		/* HomePNA */		*speed = HW_SPEED_HOME;		*duplex = FDX_CAPABLE_HALF_SELECTED;		if (status & MII_STAT_LINK)			printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n",			       net_dev->name);		else			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);	}}/** *	ics1893_read_mode: - read media mode for ICS1893 PHY *	@net_dev: the net device to read mode for *	@phy_addr: mii phy address *	@speed: the transmit speed to be determined *	@duplex: the duplex mode to be determined * *	ICS1893 PHY use Quick Poll Detailed Status register *	to determine the speed and duplex mode for sis900 */static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex){	int i = 0;	u32 status;	/* MII_QPDSTS is Latched, read twice in succession will reflect the current state */	for (i = 0; i < 2; i++)		status = mdio_read(net_dev, phy_addr, MII_QPDSTS);	if (status & MII_STSICS_SPD)		*speed = HW_SPEED_100_MBPS;	else		*speed = HW_SPEED_10_MBPS;	if (status & MII_STSICS_DPLX)		*duplex = FDX_CAPABLE_FULL_SELECTED;	else		*duplex = FDX_CAPABLE_HALF_SELECTED;	if (status & MII_STSICS_LINKSTS)		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",		       net_dev->name,		       *speed == HW_SPEED_100_MBPS ?		       "100mbps" : "10mbps",		       *duplex == FDX_CAPABLE_FULL_SELECTED ?		       "full" : "half");	else		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);}/** *	sis900_tx_timeout: - sis900 transmit timeout routine *	@net_dev: the net device to transmit * *	print transmit timeout status *	disable interrupts and do some tasks */static void sis900_tx_timeout(struct net_device *net_dev){	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;	long ioaddr = net_dev->base_addr;	unsigned long flags;	int i;	printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",	       net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));	/* Disable interrupts by clearing the interrupt mask. */	outl(0x0000, ioaddr + imr);	/* use spinlock to prevent interrupt handler accessing buffer ring */	spin_lock_irqsave(&sis_priv->lock, flags);	/* discard unsent packets */	sis_priv->dirty_tx = sis_priv->cur_tx = 0;	for (i = 0; i < NUM_TX_DESC; i++) {		if (sis_priv->tx_skbuff[i] != NULL) {			dev_kfree_skb(sis_priv->tx_skbuff[i]);			sis_priv->tx_skbuff[i] = 0;			sis_priv->tx_ring[i].cmdsts = 0;			sis_priv->tx_ring[i].bufptr = 0;			sis_priv->stats.tx_dropped++;		}	}	sis_priv->tx_full = 0;	netif_wake_queue(net_dev);	spin_unlock_irqrestore(&sis_priv->lock, flags);	net_dev->trans_start = jiffies;	/* FIXME: Should we restart the transmission thread here  ?? */	outl(TxENA, ioaddr + cr);	/* Enable all known interrupts by setting the interrupt mask. */	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);	return;}/** *	sis900_start_xmit: - sis900 start transmit routine *	@skb: socket buffer pointer to put the data being transmitted *	@net_dev: the net device to transmit with * *	Set the transmit buffer descriptor,  *	and write TxENA to enable transimt state machine. *	tell upper layer if the buffer is full */static intsis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev){	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;	long ioaddr = net_dev->base_addr;	unsigned int  entry;	unsigned long flags;	spin_lock_irqsave(&sis_priv->lock, flags);	/* Calculate the next Tx descriptor entry. */	entry = sis_priv->cur_tx % NUM_TX_DESC;	sis_priv->tx_skbuff[entry] = skb;	/* set the transmit buffer descriptor and enable Transmit State Machine */	sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data);	sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);	outl(TxENA, ioaddr + cr);	if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {		/* Typical path, tell upper layer that more transmission is possible */		netif_start_queue(net_dev);	} else {		/* buffer full, tell upper layer no more transmission */		sis_priv->tx_full = 1;		netif_stop_queue(net_dev);	}	spin_unlock_irqrestore(&sis_priv->lock, flags);	net_dev->trans_start = jiffies;	if (sis900_debug > 3)		printk(KERN_INFO "%s: Queued Tx packet at %p size %d "		       "to slot %d.\n",		       net_dev->name, skb->data, (int)skb->len, entry);	return 0;}/** *	sis900_interrupt: - sis900 interrupt handler *	@irq: the irq number *	@dev_instance: the client data object *	@regs: snapshot of processor context * *	The interrupt handler does all of the Rx thread work,  *	and cleans up after the Tx thread */static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	struct net_device *net_dev = (struct net_device *)dev_instance;	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;	int boguscnt = max_interrupt_work;	long ioaddr = net_dev->base_addr;	u32 status;	spin_lock (&sis_priv->lock);	do {		status = inl(ioaddr + isr);		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)			/* nothing intresting happened */			break;		/* why dow't we break after Tx/Rx case ?? keyword: full-duplex */		if (status & (RxORN | RxERR | RxOK))			/* Rx interrupt */			sis900_rx(net_dev);		if (status & (TxURN | TxERR | TxIDLE))			/* Tx interrupt */			sis900_finish_xmit(net_dev);		/* something strange happened !!! */		if (status & HIBERR) {			printk(KERN_INFO "%s: Abnormal interrupt,"			       "status %#8.8x.\n", net_dev->name, status);			break;		}		if (--boguscnt < 0) {			printk(KERN_INFO "%s: Too much work at interrupt, "			       "interrupt status = %#8.8x.\n",			       net_dev->name, status);			break;		}	} while (1);	if (sis900_debug > 3)		printk(KERN_INFO "%s: exiting interrupt, "		       "interrupt status = 0x%#8.8x.\n",		       net_dev->name, inl(ioaddr + isr));		spin_unlock (&sis_priv->lock);	return;}/** *	sis900_rx: - sis900 receive routine *	@net_dev: the net device which receives data * *	Process receive interrupt events,  *	put buffer to higher layer and refill buffer pool *	Note: This fucntion is called by interrupt handler,  *	don't do "too much" work here */static int sis900_rx(struct net_device *net_dev){	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;	long ioaddr = net_dev->base_addr;	unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;	u32 rx_status = sis_priv->rx_ring[entry].cmdsts;	if (sis900_debug > 3)		printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "		       "status:0x%8.8x\n",		       sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);	while (rx_status & OWN) {		unsigned int rx_size;		rx_size = (rx_status & DSIZE) - CRC_SIZE;		if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {			/* corrupted packet received */			if (sis900_debug > 3)				printk(KERN_INFO "%s: Corrupted packet "				       "received, buffer status = 0x%8.8x.\n",				       net_dev->name, rx_status);			sis_priv->stats.rx_errors++;			if (rx_status & OVERRUN)				sis_priv->stats.rx_over_errors++;			if (rx_status & (TOOLONG|RUNT))				sis_priv->stats.rx_length_errors++;			if (rx_status & (RXISERR | FAERR))				sis_priv->stats.rx_frame_errors++;			if (rx_status & CRCERR) 				sis_priv->stats.rx_crc_errors++;			/* reset buffer descriptor state */			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;		} else {			struct sk_buff * skb;			/* This situation should never happen, but due to			   some unknow bugs, it is possible that			   we are working on NULL sk_buff :-( */			if (sis_priv->rx_skbuff[entry] == NULL) {				printk(KERN_INFO "%s: NULL pointer " 				       "encountered in Rx ring, skipping\n",				       net_dev->name);				break;			}			/* gvie the socket buffer to upper layers */			skb = sis_priv->rx_skbuff[entry];			skb_put(skb, rx_size);			skb->protocol = eth_type_trans(skb, net_dev);			netif_rx(skb);			/* some network statistics */			if ((rx_status & BCAST) == MCAST)				sis_priv->stats.multicast++;			net_dev->last_rx = jiffies;			sis_priv->stats.rx_bytes += rx_size;			sis_priv->stats.rx_packets++;			/* refill the Rx buffer, what if there is not enought memory for			   new socket buffer ?? */			if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {				/* not enough memory for skbuff, this makes a "hole"				   on the buffer ring, it is not clear how the				   hardware will react to this kind of degenerated				   buffer */				printk(KERN_INFO "%s: Memory squeeze,"				       "deferring packet.\n",				       net_dev->name);				sis_priv->rx_skbuff[entry] = NULL;				/* reset buffer descriptor state */				sis_priv->rx_ring[entry].cmdsts = 0;				sis_priv->rx_ring[entry].bufptr = 0;				sis_priv->stats.rx_dropped++;				break;			}			skb->dev = net_dev;			sis_priv->rx_skbuff[entry] = skb;			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;			sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);			sis_priv->dirty_rx++;		}		sis_priv->cur_rx++;		entry = sis_priv->cur_rx % NUM_RX_DESC;		rx_status = sis_priv->rx_ring[entry].cmdsts;	} // while	/* refill the Rx buffer, what if the rate of refilling is slower than 

⌨️ 快捷键说明

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