X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fsis190.c;h=b08508b358339131da79709561cd2a339746482e;hb=a31e40f614788bbc07b3eb4fcf47a16299a4fe01;hp=5f1d0ad549693af9e253ad3f8d44216782992361;hpb=21461380d30fb52b0bbf96dbcccd0b5096a7b346;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 5f1d0ad..b08508b 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -179,14 +179,6 @@ enum sis190_register_content { TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ - /* StationControl */ - _1000bpsF = 0x1c00, - _1000bpsH = 0x0c00, - _100bpsF = 0x1800, - _100bpsH = 0x0800, - _10bpsF = 0x1400, - _10bpsH = 0x0400, - LinkStatus = 0x02, // unused FullDup = 0x01, // unused @@ -279,9 +271,16 @@ enum sis190_eeprom_address { EEPROMMACAddr = 0x03 }; +enum sis190_feature { + F_HAS_RGMII = 1, + F_PHY_88E1111 = 2, + F_PHY_BCM5461 = 4 +}; + struct sis190_private { void __iomem *mmio_addr; struct pci_dev *pci_dev; + struct net_device *dev; struct net_device_stats stats; spinlock_t lock; u32 rx_buf_sz; @@ -300,6 +299,7 @@ struct sis190_private { u32 msg_enable; struct mii_if_info mii_if; struct list_head first_phy; + u32 features; }; struct sis190_phy { @@ -321,24 +321,25 @@ static struct mii_chip_info { const char *name; u16 id[2]; unsigned int type; + u32 feature; } mii_chip_table[] = { - { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN }, - { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN }, - { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN }, - { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN }, + { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, + { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 }, + { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 }, + { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN, 0 }, { NULL, } }; -const static struct { +static const struct { const char *name; - u8 version; /* depend on docs */ - u32 RxConfigMask; /* clear the bits supported by this chip */ } sis_chip_info[] = { - { DRV_NAME, 0x00, 0xff7e1880, }, + { "SiS 190 PCI Fast Ethernet adapter" }, + { "SiS 191 PCI Gigabit Ethernet adapter" }, }; static struct pci_device_id sis190_pci_tbl[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 }, { 0, }, }; @@ -366,7 +367,7 @@ static const u32 sis190_intr_mask = * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). * The chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; +static const int multicast_filter_limit = 32; static void __mdio_cmd(void __iomem *ioaddr, u32 ctl) { @@ -713,7 +714,7 @@ static void sis190_tx_interrupt(struct net_device *dev, * The interrupt handler does all of the Rx thread work and cleans up after * the Tx thread. */ -static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs) +static irqreturn_t sis190_interrupt(int irq, void *__dev) { struct net_device *dev = __dev; struct sis190_private *tp = netdev_priv(dev); @@ -758,7 +759,7 @@ static void sis190_netpoll(struct net_device *dev) struct pci_dev *pdev = tp->pci_dev; disable_irq(pdev->irq); - sis190_interrupt(pdev->irq, dev, NULL); + sis190_interrupt(pdev->irq, dev); enable_irq(pdev->irq); } #endif @@ -821,9 +822,6 @@ static void sis190_set_rx_mode(struct net_device *dev) u16 rx_mode; if (dev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - net_drv(tp, KERN_NOTICE "%s: Promiscuous mode enabled.\n", - dev->name); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; @@ -842,7 +840,7 @@ static void sis190_set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = - ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; } @@ -879,11 +877,6 @@ static void sis190_hw_start(struct net_device *dev) SIS_W32(IntrStatus, 0xffffffff); SIS_W32(IntrMask, 0x0); - /* - * Default is 100Mbps. - * A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09 - */ - SIS_W16(StationControl, 0x1901); SIS_W32(GMIIControl, 0x0); SIS_W32(TxMacControl, 0x60); SIS_W16(RxMacControl, 0x02); @@ -905,16 +898,20 @@ static void sis190_hw_start(struct net_device *dev) netif_start_queue(dev); } -static void sis190_phy_task(void * data) +static void sis190_phy_task(struct work_struct *work) { - struct net_device *dev = data; - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = + container_of(work, struct sis190_private, phy_task); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; int phy_id = tp->mii_if.phy_id; u16 val; rtnl_lock(); + if (!netif_running(dev)) + goto out_unlock; + val = mdio_read(ioaddr, phy_id, MII_BMCR); if (val & BMCR_RESET) { // FIXME: needlessly high ? -- FR 02/07/2005 @@ -930,29 +927,23 @@ static void sis190_phy_task(void * data) /* Rejoice ! */ struct { int val; + u32 ctl; const char *msg; - u16 ctl; } reg31[] = { - { LPA_1000XFULL | LPA_SLCT, - "1000 Mbps Full Duplex", - 0x01 | _1000bpsF }, - { LPA_1000XHALF | LPA_SLCT, - "1000 Mbps Half Duplex", - 0x01 | _1000bpsH }, - { LPA_100FULL, - "100 Mbps Full Duplex", - 0x01 | _100bpsF }, - { LPA_100HALF, - "100 Mbps Half Duplex", - 0x01 | _100bpsH }, - { LPA_10FULL, - "10 Mbps Full Duplex", - 0x01 | _10bpsF }, - { LPA_10HALF, - "10 Mbps Half Duplex", - 0x01 | _10bpsH }, - { 0, "unknown", 0x0000 } - }, *p; + { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000, + "1000 Mbps Full Duplex" }, + { LPA_1000XHALF | LPA_SLCT, 0x07000c00, + "1000 Mbps Half Duplex" }, + { LPA_100FULL, 0x04000800 | 0x00001000, + "100 Mbps Full Duplex" }, + { LPA_100HALF, 0x04000800, + "100 Mbps Half Duplex" }, + { LPA_10FULL, 0x04000400 | 0x00001000, + "10 Mbps Full Duplex" }, + { LPA_10HALF, 0x04000400, + "10 Mbps Half Duplex" }, + { 0, 0x04000400, "unknown" } + }, *p; u16 adv; val = mdio_read(ioaddr, phy_id, 0x1f); @@ -965,17 +956,35 @@ static void sis190_phy_task(void * data) val &= adv; - for (p = reg31; p->ctl; p++) { + for (p = reg31; p->val; p++) { if ((val & p->val) == p->val) break; } - if (p->ctl) - SIS_W16(StationControl, p->ctl); + + p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; + + if ((tp->features & F_HAS_RGMII) && + (tp->features & F_PHY_BCM5461)) { + // Set Tx Delay in RGMII mode. + mdio_write(ioaddr, phy_id, 0x18, 0xf1c7); + udelay(200); + mdio_write(ioaddr, phy_id, 0x1c, 0x8c00); + p->ctl |= 0x03000000; + } + + SIS_W32(StationControl, p->ctl); + + if (tp->features & F_HAS_RGMII) { + SIS_W32(RGDelay, 0x0441); + SIS_W32(RGDelay, 0x0440); + } + net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name, p->msg); netif_carrier_on(dev); } +out_unlock: rtnl_unlock(); } @@ -1044,11 +1053,11 @@ static int sis190_open(struct net_device *dev) if (rc < 0) goto err_free_rx_1; - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); sis190_request_timer(dev); - rc = request_irq(dev->irq, sis190_interrupt, SA_SHIRQ, dev->name, dev); + rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev); if (rc < 0) goto err_release_timer_2; @@ -1097,8 +1106,6 @@ static void sis190_down(struct net_device *dev) netif_stop_queue(dev); - flush_scheduled_work(); - do { spin_lock_irq(&tp->lock); @@ -1150,8 +1157,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; if (unlikely(skb->len < ETH_ZLEN)) { - skb = skb_padto(skb, ETH_ZLEN); - if (!skb) { + if (skb_padto(skb, ETH_ZLEN)) { tp->stats.tx_dropped++; goto out; } @@ -1309,6 +1315,7 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, phy->type = (p->type == MIX) ? ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? LAN : HOME) : p->type; + tp->features |= p->feature; } else phy->type = UNKNOWN; @@ -1317,6 +1324,25 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); } +static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) +{ + if (tp->features & F_PHY_88E1111) { + void __iomem *ioaddr = tp->mmio_addr; + int phy_id = tp->mii_if.phy_id; + u16 reg[2][2] = { + { 0x808b, 0x0ce1 }, + { 0x808f, 0x0c60 } + }, *p; + + p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1]; + + mdio_write(ioaddr, phy_id, 0x1b, p[0]); + udelay(200); + mdio_write(ioaddr, phy_id, 0x14, p[1]); + udelay(200); + } +} + /** * sis190_mii_probe - Probe MII PHY for sis190 * @dev: the net device to probe for @@ -1367,6 +1393,8 @@ static int __devinit sis190_mii_probe(struct net_device *dev) /* Select default PHY for mac */ sis190_default_phy(dev); + sis190_mii_probe_88e1111_fixup(tp); + mii_if->dev = dev; mii_if->mdio_read = __mdio_read; mii_if->mdio_write = __mdio_write; @@ -1412,6 +1440,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); + tp->dev = dev; tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT); rc = pci_enable_device(pdev); @@ -1506,6 +1535,11 @@ static void sis190_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } +static void sis190_set_rgmii(struct sis190_private *tp, u8 reg) +{ + tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0; +} + static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, struct net_device *dev) { @@ -1530,9 +1564,11 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, for (i = 0; i < MAC_ADDR_LEN / 2; i++) { __le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); - ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); + ((u16 *)dev->dev_addr)[i] = le16_to_cpu(w); } + sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo)); + return 0; } @@ -1578,6 +1614,8 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, outb(0x12, 0x78); reg = inb(0x79); + sis190_set_rgmii(tp, reg); + /* Restore the value to ISA Bridge */ pci_write_config_byte(isa_bridge, 0x48, tmp8); pci_dev_put(isa_bridge); @@ -1714,7 +1752,7 @@ static void sis190_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } -static struct ethtool_ops sis190_ethtool_ops = { +static const struct ethtool_ops sis190_ethtool_ops = { .get_settings = sis190_get_settings, .set_settings = sis190_set_settings, .get_drvinfo = sis190_get_drvinfo, @@ -1754,6 +1792,8 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, goto out; } + pci_set_drvdata(pdev, dev); + tp = netdev_priv(dev); ioaddr = tp->mmio_addr; @@ -1763,7 +1803,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, sis190_init_rxfilter(dev); - INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + INIT_WORK(&tp->phy_task, sis190_phy_task); dev->open = sis190_open; dev->stop = sis190_close; @@ -1790,8 +1830,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, if (rc < 0) goto err_remove_mii; - pci_set_drvdata(pdev, dev); - net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", pci_name(pdev), sis_chip_info[ent->driver_data].name, @@ -1800,6 +1838,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, + (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); + netif_carrier_off(dev); sis190_set_speed_auto(dev); @@ -1818,6 +1859,7 @@ static void __devexit sis190_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); sis190_mii_remove(dev); + flush_scheduled_work(); unregister_netdev(dev); sis190_release_board(pdev); pci_set_drvdata(pdev, NULL); @@ -1832,7 +1874,7 @@ static struct pci_driver sis190_pci_driver = { static int __init sis190_init_module(void) { - return pci_module_init(&sis190_pci_driver); + return pci_register_driver(&sis190_pci_driver); } static void __exit sis190_cleanup_module(void)