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

📄 sis900.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	sis900_init_tx_ring(net_dev);	sis900_init_rx_ring(net_dev);	set_rx_mode(net_dev);	netif_start_queue(net_dev);	/* Workaround for EDB */	sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);	/* Enable all known interrupts by setting the interrupt mask. */	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);	outl(RxENA | inl(ioaddr + cr), ioaddr + cr);	outl(IE, ioaddr + ier);	sis900_check_mode(net_dev, sis_priv->mii);	/* Set the timer to switch to check for link beat and perhaps switch	   to an alternate media type. */	init_timer(&sis_priv->timer);	sis_priv->timer.expires = jiffies + HZ;	sis_priv->timer.data = (unsigned long)net_dev;	sis_priv->timer.function = &sis900_timer;	add_timer(&sis_priv->timer);	return 0;}/** *	sis900_init_rxfilter: - Initialize the Rx filter *	@net_dev: the net device to initialize for * *	Set receive filter address to our MAC address *	and enable packet filtering. */static voidsis900_init_rxfilter (struct net_device * net_dev){	long ioaddr = net_dev->base_addr;	u32 rfcrSave;	u32 i;	rfcrSave = inl(rfcr + ioaddr);	/* disable packet filtering before setting filter */	outl(rfcrSave & ~RFEN, rfcr + ioaddr);	/* load MAC addr to filter data register */	for (i = 0 ; i < 3 ; i++) {		u32 w;		w = (u32) *((u16 *)(net_dev->dev_addr)+i);		outl((i << RFADDR_shift), ioaddr + rfcr);		outl(w, ioaddr + rfdr);		if (sis900_debug > 2) {			printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n",			       net_dev->name, i, inl(ioaddr + rfdr));		}	}	/* enable packet filitering */	outl(rfcrSave | RFEN, rfcr + ioaddr);}/** *	sis900_init_tx_ring: - Initialize the Tx descriptor ring *	@net_dev: the net device to initialize for * *	Initialize the Tx descriptor ring,  */static voidsis900_init_tx_ring(struct net_device *net_dev){	struct sis900_private *sis_priv = net_dev->priv;	long ioaddr = net_dev->base_addr;	int i;	sis_priv->tx_full = 0;	sis_priv->dirty_tx = sis_priv->cur_tx = 0;	for (i = 0; i < NUM_TX_DESC; i++) {		sis_priv->tx_skbuff[i] = NULL;		sis_priv->tx_ring[i].link = sis_priv->tx_ring_dma +			((i+1)%NUM_TX_DESC)*sizeof(BufferDesc);		sis_priv->tx_ring[i].cmdsts = 0;		sis_priv->tx_ring[i].bufptr = 0;	}	/* load Transmit Descriptor Register */	outl(sis_priv->tx_ring_dma, ioaddr + txdp);	if (sis900_debug > 2)		printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n",		       net_dev->name, inl(ioaddr + txdp));}/** *	sis900_init_rx_ring: - Initialize the Rx descriptor ring *	@net_dev: the net device to initialize for * *	Initialize the Rx descriptor ring,  *	and pre-allocate recevie buffers (socket buffer) */static void sis900_init_rx_ring(struct net_device *net_dev){	struct sis900_private *sis_priv = net_dev->priv;	long ioaddr = net_dev->base_addr;	int i;	sis_priv->cur_rx = 0;	sis_priv->dirty_rx = 0;	/* init RX descriptor */	for (i = 0; i < NUM_RX_DESC; i++) {		sis_priv->rx_skbuff[i] = NULL;		sis_priv->rx_ring[i].link = sis_priv->rx_ring_dma +			((i+1)%NUM_RX_DESC)*sizeof(BufferDesc);		sis_priv->rx_ring[i].cmdsts = 0;		sis_priv->rx_ring[i].bufptr = 0;	}	/* allocate sock buffers */	for (i = 0; i < NUM_RX_DESC; i++) {		struct sk_buff *skb;		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 */			break;		}		skb->dev = net_dev;		sis_priv->rx_skbuff[i] = skb;		sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;                sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,                        skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);	}	sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);	/* load Receive Descriptor Register */	outl(sis_priv->rx_ring_dma, ioaddr + rxdp);	if (sis900_debug > 2)		printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n",		       net_dev->name, inl(ioaddr + rxdp));}/** *	sis630_set_eq: - set phy equalizer value for 630 LAN *	@net_dev: the net device to set equalizer value *	@revision: 630 LAN revision number * *	630E equalizer workaround rule(Cyrus Huang 08/15) *	PHY register 14h(Test) *	Bit 14: 0 -- Automatically dectect (default) *		1 -- Manually set Equalizer filter *	Bit 13: 0 -- (Default) *		1 -- Speed up convergence of equalizer setting *	Bit 9 : 0 -- (Default) *		1 -- Disable Baseline Wander *	Bit 3~7   -- Equalizer filter setting *	Link ON: Set Bit 9, 13 to 1, Bit 14 to 0 *	Then calculate equalizer value *	Then set equalizer value, and set Bit 14 to 1, Bit 9 to 0 *	Link Off:Set Bit 13 to 1, Bit 14 to 0 *	Calculate Equalizer value: *	When Link is ON and Bit 14 is 0, SIS900PHY will auto-dectect proper equalizer value. *	When the equalizer is stable, this value is not a fixed value. It will be within *	a small range(eg. 7~9). Then we get a minimum and a maximum value(eg. min=7, max=9) *	0 <= max <= 4  --> set equalizer to max *	5 <= max <= 14 --> set equalizer to max+1 or set equalizer to max+2 if max == min *	max >= 15      --> set equalizer to max+5 or set equalizer to max+6 if max == min */static void sis630_set_eq(struct net_device *net_dev, u8 revision){	struct sis900_private *sis_priv = net_dev->priv;	u16 reg14h, eq_value=0, max_value=0, min_value=0;	u8 host_bridge_rev;	int i, maxcount=10;	struct pci_dev *dev=NULL;	if ( !(revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||	       revision == SIS630A_900_REV || revision ==  SIS630ET_900_REV) )		return;	dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, dev);	if (dev)		pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev);	if (netif_carrier_ok(net_dev)) {		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF);		for (i=0; i < maxcount; i++) {			eq_value=(0x00F8 & mdio_read(net_dev, sis_priv->cur_phy, MII_RESV)) >> 3;			if (i == 0)				max_value=min_value=eq_value;			max_value=(eq_value > max_value) ? eq_value : max_value;			min_value=(eq_value < min_value) ? eq_value : min_value;		}		/* 630E rule to determine the equalizer value */		if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||		    revision == SIS630ET_900_REV) {			if (max_value < 5)				eq_value=max_value;			else if (max_value >= 5 && max_value < 15)				eq_value=(max_value == min_value) ? max_value+2 : max_value+1;			else if (max_value >= 15)				eq_value=(max_value == min_value) ? max_value+6 : max_value+5;		}		/* 630B0&B1 rule to determine the equalizer value */		if (revision == SIS630A_900_REV && 		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) {			if (max_value == 0)				eq_value=3;			else				eq_value=(max_value+min_value+1)/2;		}		/* write equalizer value and setting */		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);		reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8);		reg14h=(reg14h | 0x6000) & 0xFDFF;		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h);	}	else {		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);		if (revision == SIS630A_900_REV && 		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) 			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF);		else			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF);	}	return;}/** *	sis900_timer: - sis900 timer routine *	@data: pointer to sis900 net device * *	On each timer ticks we check two things,  *	link status (ON/OFF) and link mode (10/100/Full/Half) */static void sis900_timer(unsigned long data){	struct net_device *net_dev = (struct net_device *)data;	struct sis900_private *sis_priv = net_dev->priv;	struct mii_phy *mii_phy = sis_priv->mii;	static int next_tick = 5*HZ;	u16 status;	u8 revision;	if (!sis_priv->autong_complete){		int speed, duplex = 0;		sis900_read_mode(net_dev, &speed, &duplex);		if (duplex){			sis900_set_mode(net_dev->base_addr, speed, duplex);			pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);			sis630_set_eq(net_dev, revision);			netif_start_queue(net_dev);		}		sis_priv->timer.expires = jiffies + HZ;		add_timer(&sis_priv->timer);		return;	}	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);	/* Link OFF -> ON */	if (!netif_carrier_ok(net_dev)) {	LookForLink:		/* Search for new PHY */		status = sis900_default_phy(net_dev);		mii_phy = sis_priv->mii;		if (status & MII_STAT_LINK){			sis900_check_mode(net_dev, mii_phy);			netif_carrier_on(net_dev);		}	}	/* Link ON -> OFF */	else {                if (!(status & MII_STAT_LINK)){                	netif_carrier_off(net_dev);                	printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);                	/* Change mode issue */                	if ((mii_phy->phy_id0 == 0x001D) && 			    ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))               			sis900_reset_phy(net_dev,  sis_priv->cur_phy);                  	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);			sis630_set_eq(net_dev, revision);                  	goto LookForLink;                }	}	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 * *	Older driver gets the media mode from mii status output *	register. Now we set our media capability and auto-negotiate *	to get the upper bound of speed and duplex between two ends. *	If the types of mii phy is HOME, it doesn't need to auto-negotiate *	and autong_complete should be set to 1. */static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy){	struct sis900_private *sis_priv = net_dev->priv;	long ioaddr = net_dev->base_addr;	int speed, duplex;	if( mii_phy->phy_types == LAN  ){		outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg);		sis900_set_capability(net_dev , mii_phy);		sis900_auto_negotiate(net_dev, sis_priv->cur_phy);	}else{		outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg);		speed = HW_SPEED_HOME;		duplex = FDX_CAPABLE_HALF_SELECTED;		sis900_set_mode(ioaddr, speed, duplex);		sis_priv->autong_complete = 1;	}}/** *	sis900_set_mode: - Set the media mode of mac register. *	@ioaddr: the address of the device *	@speed : the transmit speed to be determined *	@duplex: the duplex mode to be determined * *	Set the media mode of mac register txcfg/rxcfg according to *	speed and duplex of phy. Bit EDB_MASTER_EN indicates the EDB *	bus is used instead of PCI bus. When this bit is set 1, the *	Max DMA Burst Size for TX/RX DMA should be no larger than 16 *	double words. */static void sis900_set_mode (long ioaddr, int speed, int duplex){	u32 tx_flags = 0, rx_flags = 0;	if( inl(ioaddr + cfg) & EDB_MASTER_EN ){		tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);		rx_flags = DMA_BURST_64 << RxMXDMA_shift;	}	else{		tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);		rx_flags = DMA_BURST_512 << 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_auto_negotiate:  Set the Auto-Negotiation Enable/Reset bit. *	@net_dev: the net device to read mode for *	@phy_addr: mii phy address * *	If the adapter is link-on, set the auto-negotiate enable/reset bit. *	autong_complete should be set to 0 when starting auto-negotiation. *	autong_complete should be set to 1 if we didn't start auto-negotiation. *	sis900_timer will wait for link on again if autong_complete = 0. */static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr){	struct sis900_private *sis_priv = net_dev->priv;	int i = 0;	u32 status;		while (i++ < 2)		status = mdio_read(net_dev, phy_addr, MII_STATUS);	if (!(status & MII_STAT_LINK)){		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);		sis_priv->autong_complete = 1;		netif_carrier_off(net_dev);		return;	}	/* (Re)start AutoNegotiate */	mdio_write(net_dev, phy_addr, MII_CONTROL,		   MII_CNTL_AUTO | MII_CNTL_RST_AUTO);	sis_priv->autong_complete = 0;}/** *	sis900_read_mode: - read media mode for sis900 internal phy *	@net_dev: the net device to read mode for *	@speed  : the transmit speed to be determined *	@duplex : the duplex mode to be determined * *	The capability of remote end will be put in mii register autorec *	after auto-negotiation. Use AND operation to get the upper bound *	of speed and duplex between two ends. */static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex){	struct sis900_private *sis_priv = net_dev->priv;

⌨️ 快捷键说明

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