📄 sis900.c
字号:
err_out_unregister: unregister_netdev(net_dev); 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: kfree(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 __init sis900_mii_probe (struct net_device * net_dev){ struct sis900_private * sis_priv = net_dev->priv; u16 poll_bit = MII_STAT_LINK, status = 0; unsigned int timeout = jiffies + 5 * HZ; int phy_addr; u8 revision; 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) /* the mii is not accessable, try next one */ continue; if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) { printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n"); 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", net_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", net_dev->name, phy_addr); } if (sis_priv->mii == NULL) { printk(KERN_INFO "%s: No MII transceivers found!\n", net_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) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(0); poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); if (jiffies >= timeout) { printk(KERN_WARNING "%s: reset phy and link down now\n", net_dev->name); return -ETIME; } } } pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); if (revision == 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; 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 deafalut PHY */ if ( (status & MII_STAT_LINK) && !(default_phy) ) 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; } } if( (!default_phy) && phy_home ) default_phy = phy_home; 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", net_dev->name,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 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(EECLK, 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(); } outb(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(); outl(EECLK, ee_addr); 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 seperately */#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 u16 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); for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; outl(dataval, mdio_addr); mdio_delay(); outl(dataval | MDC, mdio_addr); mdio_delay(); } /* Read the 16 data bits. */ for (i = 16; i > 0; i--) { outl(0, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); outl(MDC, mdio_addr); mdio_delay(); } outl(0x00, mdio_addr); return retval;}/** * mdio_write: - write MII PHY register * @net_dev: the net device to write * @phy_id: the phy address to write * @location: the phy regiester id to write * @value: the register value to write with * * Write MII registers with @value through MDIO and MDC * using MDIO management frame structure and protocol(defined by ISO/IEC) * please see SiS7014 or ICS spec */static void mdio_write(struct net_device *net_dev, int phy_id, int location, int value){ long mdio_addr = net_dev->base_addr + mear; int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift); int i; mdio_reset(mdio_addr); mdio_idle(mdio_addr); /* Shift the command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; outb(dataval, mdio_addr); mdio_delay(); outb(dataval | MDC, mdio_addr); mdio_delay(); } mdio_delay(); /* Shift the value bits out. */ for (i = 15; i >= 0; i--) { int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR; outl(dataval, mdio_addr); mdio_delay(); outl(dataval | MDC, mdio_addr); mdio_delay(); } mdio_delay(); /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outb(0, mdio_addr); mdio_delay(); outb(MDC, mdio_addr); mdio_delay(); } outl(0x00, mdio_addr); return;}/** * sis900_reset_phy: - reset sis900 mii phy. * @net_dev: the net device to write * @phy_addr: default phy address * * Some specific phy can't work properly without reset. * This function will be called during initialization and * link status change from ON to DOWN. */static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr){ int i = 0; u16 status; while (i++ < 2) status = mdio_read(net_dev, phy_addr, MII_STATUS); mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET ); return status;}/** * sis900_open: - open sis900 device * @net_dev: the net device to open * * Do some initialization and start net interface. * enable interrupts and set sis900 timer. */static intsis900_open(struct net_device *net_dev){ struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; u8 revision; int ret; /* Soft reset the chip. */ sis900_reset(net_dev); /* Equalizer workaround Rule */ pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); sis630_set_eq(net_dev, revision); ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev); if (ret) return ret; sis900_init_rxfilter(net_dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -