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 + -
显示快捷键?