sis900.c

来自「linux 内核源代码」· C语言 代码 · 共 2,188 行 · 第 1/5 页

C
2,188
字号
	sis_priv = net_dev->priv;	net_dev->base_addr = ioaddr;	net_dev->irq = pci_dev->irq;	sis_priv->pci_dev = pci_dev;	spin_lock_init(&sis_priv->lock);	pci_set_drvdata(pci_dev, net_dev);	ring_space = pci_alloc_consistent(pci_dev, TX_TOTAL_SIZE, &ring_dma);	if (!ring_space) {		ret = -ENOMEM;		goto err_out_cleardev;	}	sis_priv->tx_ring = (BufferDesc *)ring_space;	sis_priv->tx_ring_dma = ring_dma;	ring_space = pci_alloc_consistent(pci_dev, RX_TOTAL_SIZE, &ring_dma);	if (!ring_space) {		ret = -ENOMEM;		goto err_unmap_tx;	}	sis_priv->rx_ring = (BufferDesc *)ring_space;	sis_priv->rx_ring_dma = ring_dma;	/* The SiS900-specific entries in the device structure. */	net_dev->open = &sis900_open;	net_dev->hard_start_xmit = &sis900_start_xmit;	net_dev->stop = &sis900_close;	net_dev->set_config = &sis900_set_config;	net_dev->set_multicast_list = &set_rx_mode;	net_dev->do_ioctl = &mii_ioctl;	net_dev->tx_timeout = sis900_tx_timeout;	net_dev->watchdog_timeo = TX_TIMEOUT;	net_dev->ethtool_ops = &sis900_ethtool_ops;#ifdef CONFIG_NET_POLL_CONTROLLER        net_dev->poll_controller = &sis900_poll;#endif	if (sis900_debug > 0)		sis_priv->msg_enable = sis900_debug;	else		sis_priv->msg_enable = SIS900_DEF_MSG;	sis_priv->mii_info.dev = net_dev;	sis_priv->mii_info.mdio_read = mdio_read;	sis_priv->mii_info.mdio_write = mdio_write;	sis_priv->mii_info.phy_id_mask = 0x1f;	sis_priv->mii_info.reg_num_mask = 0x1f;	/* Get Mac address according to the chip revision */	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev));	if(netif_msg_probe(sis_priv))		printk(KERN_DEBUG "%s: detected revision %2.2x, "				"trying to get MAC address...\n",				dev_name, sis_priv->chipset_rev);	ret = 0;	if (sis_priv->chipset_rev == SIS630E_900_REV)		ret = sis630e_get_mac_addr(pci_dev, net_dev);	else if ((sis_priv->chipset_rev > 0x81) && (sis_priv->chipset_rev <= 0x90) )		ret = sis635_get_mac_addr(pci_dev, net_dev);	else if (sis_priv->chipset_rev == SIS96x_900_REV)		ret = sis96x_get_mac_addr(pci_dev, net_dev);	else		ret = sis900_get_mac_addr(pci_dev, net_dev);	if (ret == 0) {		printk(KERN_WARNING "%s: Cannot read MAC address.\n", dev_name);		ret = -ENODEV;		goto err_unmap_rx;	}	/* 630ET : set the mii access mode as software-mode */	if (sis_priv->chipset_rev == SIS630ET_900_REV)		outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);	/* probe for mii transceiver */	if (sis900_mii_probe(net_dev) == 0) {		printk(KERN_WARNING "%s: Error probing MII device.\n",		       dev_name);		ret = -ENODEV;		goto err_unmap_rx;	}	/* save our host bridge revision */	dev = pci_get_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, NULL);	if (dev) {		pci_read_config_byte(dev, PCI_CLASS_REVISION, &sis_priv->host_bridge_rev);		pci_dev_put(dev);	}	ret = register_netdev(net_dev);	if (ret)		goto err_unmap_rx;	/* print some information about our NIC */	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",	       net_dev->name, card_name, ioaddr, net_dev->irq,	       print_mac(mac, net_dev->dev_addr));	/* Detect Wake on Lan support */	ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27;	if (netif_msg_probe(sis_priv) && (ret & PME_D3C) == 0)		printk(KERN_INFO "%s: Wake on LAN only available from suspend to RAM.", net_dev->name);	return 0; err_unmap_rx:	pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring,		sis_priv->rx_ring_dma); err_unmap_tx:	pci_free_consistent(pci_dev, TX_TOTAL_SIZE, sis_priv->tx_ring,		sis_priv->tx_ring_dma); err_out_cleardev: 	pci_set_drvdata(pci_dev, NULL);	pci_release_regions(pci_dev); err_out:	free_netdev(net_dev);	return ret;}/** *	sis900_mii_probe - Probe MII PHY for sis900 *	@net_dev: the net device to probe for * *	Search for total of 32 possible mii phy addresses. *	Identify and set current phy if found one, *	return error if it failed to found. */static int __devinit sis900_mii_probe(struct net_device * net_dev){	struct sis900_private * sis_priv = net_dev->priv;	const char *dev_name = pci_name(sis_priv->pci_dev);	u16 poll_bit = MII_STAT_LINK, status = 0;	unsigned long timeout = jiffies + 5 * HZ;	int phy_addr;	sis_priv->mii = NULL;	/* search for total of 32 possible mii phy addresses */	for (phy_addr = 0; phy_addr < 32; phy_addr++) {		struct mii_phy * mii_phy = NULL;		u16 mii_status;		int i;		mii_phy = NULL;		for(i = 0; i < 2; i++)			mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);		if (mii_status == 0xffff || mii_status == 0x0000) {			if (netif_msg_probe(sis_priv))				printk(KERN_DEBUG "%s: MII at address %d"						" not accessible\n",						dev_name, phy_addr);			continue;		}		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {			printk(KERN_WARNING "Cannot allocate mem for struct mii_phy\n");			mii_phy = sis_priv->first_mii;			while (mii_phy) {				struct mii_phy *phy;				phy = mii_phy;				mii_phy = mii_phy->next;				kfree(phy);			}			return 0;		}		mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);		mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);		mii_phy->phy_addr = phy_addr;		mii_phy->status = mii_status;		mii_phy->next = sis_priv->mii;		sis_priv->mii = mii_phy;		sis_priv->first_mii = mii_phy;		for (i = 0; mii_chip_table[i].phy_id1; i++)			if ((mii_phy->phy_id0 == mii_chip_table[i].phy_id0 ) &&			    ((mii_phy->phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){				mii_phy->phy_types = mii_chip_table[i].phy_types;				if (mii_chip_table[i].phy_types == MIX)					mii_phy->phy_types =					    (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME;				printk(KERN_INFO "%s: %s transceiver found "							"at address %d.\n",							dev_name,							mii_chip_table[i].name,							phy_addr);				break;			}		if( !mii_chip_table[i].phy_id1 ) {			printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",			       dev_name, phy_addr);			mii_phy->phy_types = UNKNOWN;		}	}	if (sis_priv->mii == NULL) {		printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);		return 0;	}	/* select default PHY for mac */	sis_priv->mii = NULL;	sis900_default_phy( net_dev );	/* Reset phy if default phy is internal sis900 */        if ((sis_priv->mii->phy_id0 == 0x001D) &&	    ((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))        	status = sis900_reset_phy(net_dev, sis_priv->cur_phy);        /* workaround for ICS1893 PHY */        if ((sis_priv->mii->phy_id0 == 0x0015) &&            ((sis_priv->mii->phy_id1&0xFFF0) == 0xF440))            	mdio_write(net_dev, sis_priv->cur_phy, 0x0018, 0xD200);	if(status & MII_STAT_LINK){		while (poll_bit) {			yield();			poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);			if (time_after_eq(jiffies, timeout)) {				printk(KERN_WARNING "%s: reset phy and link down now\n",				       dev_name);				return -ETIME;			}		}	}	if (sis_priv->chipset_rev == SIS630E_900_REV) {		/* SiS 630E has some bugs on default value of PHY registers */		mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1);		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00);		mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0);		//mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);	}	if (sis_priv->mii->status & MII_STAT_LINK)		netif_carrier_on(net_dev);	else		netif_carrier_off(net_dev);	return 1;}/** *	sis900_default_phy - Select default PHY for sis900 mac. *	@net_dev: the net device to probe for * *	Select first detected PHY with link as default. *	If no one is link on, select PHY whose types is HOME as default. *	If HOME doesn't exist, select LAN. */static u16 sis900_default_phy(struct net_device * net_dev){	struct sis900_private * sis_priv = net_dev->priv; 	struct mii_phy *phy = NULL, *phy_home = NULL,		*default_phy = NULL, *phy_lan = NULL;	u16 status;        for (phy=sis_priv->first_mii; phy; phy=phy->next) {		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);		/* Link ON & Not select default PHY & not ghost PHY */		 if ((status & MII_STAT_LINK) && !default_phy &&					(phy->phy_types != UNKNOWN))		 	default_phy = phy;		 else {			status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL);			mdio_write(net_dev, phy->phy_addr, MII_CONTROL,				status | MII_CNTL_AUTO | MII_CNTL_ISOLATE);			if (phy->phy_types == HOME)				phy_home = phy;			else if(phy->phy_types == LAN)				phy_lan = phy;		 }	}	if (!default_phy && phy_home)		default_phy = phy_home;	else if (!default_phy && phy_lan)		default_phy = phy_lan;	else if (!default_phy)		default_phy = sis_priv->first_mii;	if (sis_priv->mii != default_phy) {		sis_priv->mii = default_phy;		sis_priv->cur_phy = default_phy->phy_addr;		printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",		       pci_name(sis_priv->pci_dev), sis_priv->cur_phy);	}	sis_priv->mii_info.phy_id = sis_priv->cur_phy;	status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);	status &= (~MII_CNTL_ISOLATE);	mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);	return status;}/** * 	sis900_set_capability - set the media capability of network adapter. *	@net_dev : the net device to probe for *	@phy : default PHY * *	Set the media capability of network adapter according to *	mii status register. It's necessary before auto-negotiate. */static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *phy){	u16 cap;	u16 status;	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);	status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);	cap = MII_NWAY_CSMA_CD |		((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) |		((phy->status & MII_STAT_CAN_TX)    ? MII_NWAY_TX:0) |		((phy->status & MII_STAT_CAN_T_FDX) ? MII_NWAY_T_FDX:0)|		((phy->status & MII_STAT_CAN_T)     ? MII_NWAY_T:0);	mdio_write(net_dev, phy->phy_addr, MII_ANADV, cap);}/* Delay between EEPROM clock transitions. */#define eeprom_delay()  inl(ee_addr)/** *	read_eeprom - Read Serial EEPROM *	@ioaddr: base i/o address *	@location: the EEPROM location to read * *	Read Serial EEPROM through EEPROM Access Register. *	Note that location is in word (16 bits) unit */static u16 __devinit read_eeprom(long ioaddr, int location){	int i;	u16 retval = 0;	long ee_addr = ioaddr + mear;	u32 read_cmd = location | EEread;	outl(0, ee_addr);	eeprom_delay();	outl(EECS, ee_addr);	eeprom_delay();	/* Shift the read command (9) bits out. */	for (i = 8; i >= 0; i--) {		u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;		outl(dataval, ee_addr);		eeprom_delay();		outl(dataval | EECLK, ee_addr);		eeprom_delay();	}	outl(EECS, ee_addr);	eeprom_delay();	/* read the 16-bits data in */	for (i = 16; i > 0; i--) {		outl(EECS, ee_addr);		eeprom_delay();		outl(EECS | EECLK, ee_addr);		eeprom_delay();		retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);		eeprom_delay();	}	/* Terminate the EEPROM access. */	outl(0, ee_addr);	eeprom_delay();	return (retval);}/* Read and write the MII management registers using software-generated   serial MDIO protocol. Note that the command bits and data bits are   send out separately */#define mdio_delay()    inl(mdio_addr)static void mdio_idle(long mdio_addr){	outl(MDIO | MDDIR, mdio_addr);	mdio_delay();	outl(MDIO | MDDIR | MDC, mdio_addr);}/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_reset(long mdio_addr){	int i;	for (i = 31; i >= 0; i--) {		outl(MDDIR | MDIO, mdio_addr);		mdio_delay();		outl(MDDIR | MDIO | MDC, mdio_addr);		mdio_delay();	}	return;}/** *	mdio_read - read MII PHY register *	@net_dev: the net device to read *	@phy_id: the phy address to read *	@location: the phy regiester id to read * *	Read MII registers through MDIO and MDC *	using MDIO management frame structure and protocol(defined by ISO/IEC). *	Please see SiS7014 or ICS spec */static int mdio_read(struct net_device *net_dev, int phy_id, int location){	long mdio_addr = net_dev->base_addr + mear;	int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);	u16 retval = 0;	int i;	mdio_reset(mdio_addr);	mdio_idle(mdio_addr);

⌨️ 快捷键说明

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