X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fsis190.c;h=31dd3f036fa84cc0f3298efd5f8c9e0fb96897df;hb=6eddb5cb906ac5c9a17a1b76464eadacd88b6c92;hp=1e8e7111c261f2955374dd41a8c3e3fb19cd30bc;hpb=830fb7d23217ae748df0b16d4d419110810036b7;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 1e8e711..31dd3f0 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -43,6 +43,10 @@ #define net_tx_err(p, arg...) if (netif_msg_tx_err(p)) \ printk(arg) +#define PHY_MAX_ADDR 32 +#define PHY_ID_ANY 0x1f +#define MII_REG_ANY 0x1f + #ifdef CONFIG_SIS190_NAPI #define NAPI_SUFFIX "-NAPI" #else @@ -64,11 +68,12 @@ #define MAC_ADDR_LEN 6 -#define NUM_TX_DESC 64 -#define NUM_RX_DESC 64 +#define NUM_TX_DESC 64 /* [8..1024] */ +#define NUM_RX_DESC 64 /* [8..8192] */ #define TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) #define RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RX_BUF_SIZE 1536 +#define RX_BUF_MASK 0xfff8 #define SIS190_REGS_SIZE 0x80 #define SIS190_TX_TIMEOUT (6*HZ) @@ -148,12 +153,6 @@ enum sis190_register_content { RxHalt = 0x00000002, TxHalt = 0x00000001, - /* RxStatusDesc */ - RxRES = 0x00200000, // unused - RxCRC = 0x00080000, - RxRUNT = 0x00100000, // unused - RxRWT = 0x00400000, // unused - /* {Rx/Tx}CmdBits */ CmdReset = 0x10, CmdRxEnb = 0x08, // unused @@ -180,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 @@ -196,30 +187,70 @@ enum sis190_register_content { }; struct TxDesc { - u32 PSize; - u32 status; - u32 addr; - u32 size; + __le32 PSize; + __le32 status; + __le32 addr; + __le32 size; }; struct RxDesc { - u32 PSize; - u32 status; - u32 addr; - u32 size; + __le32 PSize; + __le32 status; + __le32 addr; + __le32 size; }; enum _DescStatusBit { /* _Desc.status */ - OWNbit = 0x80000000, - INTbit = 0x40000000, - DEFbit = 0x00200000, - CRCbit = 0x00020000, - PADbit = 0x00010000, + OWNbit = 0x80000000, // RXOWN/TXOWN + INTbit = 0x40000000, // RXINT/TXINT + CRCbit = 0x00020000, // CRCOFF/CRCEN + PADbit = 0x00010000, // PREADD/PADEN /* _Desc.size */ - RingEnd = (1 << 31), - /* _Desc.PSize */ + RingEnd = 0x80000000, + /* TxDesc.status */ + LSEN = 0x08000000, // TSO ? -- FR + IPCS = 0x04000000, + TCPCS = 0x02000000, + UDPCS = 0x01000000, + BSTEN = 0x00800000, + EXTEN = 0x00400000, + DEFEN = 0x00200000, + BKFEN = 0x00100000, + CRSEN = 0x00080000, + COLEN = 0x00040000, + THOL3 = 0x30000000, + THOL2 = 0x20000000, + THOL1 = 0x10000000, + THOL0 = 0x00000000, + /* RxDesc.status */ + IPON = 0x20000000, + TCPON = 0x10000000, + UDPON = 0x08000000, + Wakup = 0x00400000, + Magic = 0x00200000, + Pause = 0x00100000, + DEFbit = 0x00200000, + BCAST = 0x000c0000, + MCAST = 0x00080000, + UCAST = 0x00040000, + /* RxDesc.PSize */ + TAGON = 0x80000000, + RxDescCountMask = 0x7f000000, // multi-desc pkt when > 1 ? -- FR + ABORT = 0x00800000, + SHORT = 0x00400000, + LIMIT = 0x00200000, + MIIER = 0x00100000, + OVRUN = 0x00080000, + NIBON = 0x00040000, + COLON = 0x00020000, + CRCOK = 0x00010000, RxSizeMask = 0x0000ffff + /* + * The asic could apparently do vlan, TSO, jumbo (sis191 only) and + * provide two (unused with Linux) Tx queues. No publically + * available documentation alas. + */ }; enum sis190_eeprom_access_register_bits { @@ -240,6 +271,12 @@ 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; @@ -260,18 +297,48 @@ struct sis190_private { struct timer_list timer; u32 msg_enable; struct mii_if_info mii_if; + struct list_head first_phy; + u32 features; +}; + +struct sis190_phy { + struct list_head list; + int phy_id; + u16 id[2]; + u16 status; + u8 type; +}; + +enum sis190_phy_type { + UNKNOWN = 0x00, + HOME = 0x01, + LAN = 0x02, + MIX = 0x03 +}; + +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, 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, }, }; @@ -293,13 +360,13 @@ MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); static const u32 sis190_intr_mask = - RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt; + RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange; /* * 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) { @@ -319,21 +386,17 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl) printk(KERN_ERR PFX "PHY command failed !\n"); } -static void mdio_write(void __iomem *ioaddr, int reg, int val) +static void mdio_write(void __iomem *ioaddr, int phy_id, int reg, int val) { - u32 pmd = 1; - __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite | - (((u32) reg) << EhnMIIregShift) | (pmd << EhnMIIpmdShift) | + (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) | (((u32) val) << EhnMIIdataShift)); } -static int mdio_read(void __iomem *ioaddr, int reg) +static int mdio_read(void __iomem *ioaddr, int phy_id, int reg) { - u32 pmd = 1; - __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread | - (((u32) reg) << EhnMIIregShift) | (pmd << EhnMIIpmdShift)); + (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift)); return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift); } @@ -342,14 +405,20 @@ static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val) { struct sis190_private *tp = netdev_priv(dev); - mdio_write(tp->mmio_addr, reg, val); + mdio_write(tp->mmio_addr, phy_id, reg, val); } static int __mdio_read(struct net_device *dev, int phy_id, int reg) { struct sis190_private *tp = netdev_priv(dev); - return mdio_read(tp->mmio_addr, reg); + return mdio_read(tp->mmio_addr, phy_id, reg); +} + +static u16 mdio_read_latched(void __iomem *ioaddr, int phy_id, int reg) +{ + mdio_read(ioaddr, phy_id, reg); + return mdio_read(ioaddr, phy_id, reg); } static u16 __devinit sis190_read_eeprom(void __iomem *ioaddr, u32 reg) @@ -400,7 +469,7 @@ static inline void sis190_give_to_asic(struct RxDesc *desc, u32 rx_buf_sz) u32 eor = le32_to_cpu(desc->size) & RingEnd; desc->PSize = 0x0; - desc->size = cpu_to_le32(rx_buf_sz | eor); + desc->size = cpu_to_le32((rx_buf_sz & RX_BUF_MASK) | eor); wmb(); desc->status = cpu_to_le32(OWNbit | INTbit); } @@ -486,6 +555,26 @@ static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, return ret; } +static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats) +{ +#define ErrMask (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT) + + if ((status & CRCOK) && !(status & ErrMask)) + return 0; + + if (!(status & CRCOK)) + stats->rx_crc_errors++; + else if (status & OVRUN) + stats->rx_over_errors++; + else if (status & (SHORT | LIMIT)) + stats->rx_length_errors++; + else if (status & (MIIER | NIBON | COLON)) + stats->rx_frame_errors++; + + stats->rx_errors++; + return -1; +} + static int sis190_rx_interrupt(struct net_device *dev, struct sis190_private *tp, void __iomem *ioaddr) { @@ -509,19 +598,9 @@ static int sis190_rx_interrupt(struct net_device *dev, // net_intr(tp, KERN_INFO "%s: Rx PSize = %08x.\n", dev->name, // status); - if (status & RxCRC) { - net_intr(tp, KERN_INFO "%s: bad crc. status = %08x.\n", - dev->name, status); - stats->rx_errors++; - stats->rx_crc_errors++; + if (sis190_rx_pkt_err(status, stats) < 0) sis190_give_to_asic(desc, tp->rx_buf_sz); - } else if (!(status & PADbit)) { - net_intr(tp, KERN_INFO "%s: bad pad. status = %08x.\n", - dev->name, status); - stats->rx_errors++; - stats->rx_length_errors++; - sis190_give_to_asic(desc, tp->rx_buf_sz); - } else { + else { struct sk_buff *skb = tp->Rx_skbuff[entry]; int pkt_size = (status & RxSizeMask) - 4; void (*pci_action)(struct pci_dev *, dma_addr_t, @@ -558,8 +637,10 @@ static int sis190_rx_interrupt(struct net_device *dev, sis190_rx_skb(skb); dev->last_rx = jiffies; - stats->rx_bytes += pkt_size; stats->rx_packets++; + stats->rx_bytes += pkt_size; + if ((status & BCAST) == MCAST) + stats->multicast++; } } count = cur_rx - tp->cur_rx; @@ -761,7 +842,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; } @@ -798,11 +879,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); @@ -829,59 +905,78 @@ static void sis190_phy_task(void * data) struct net_device *dev = data; struct sis190_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; + int phy_id = tp->mii_if.phy_id; u16 val; rtnl_lock(); - val = mdio_read(ioaddr, MII_BMCR); + val = mdio_read(ioaddr, phy_id, MII_BMCR); if (val & BMCR_RESET) { // FIXME: needlessly high ? -- FR 02/07/2005 mod_timer(&tp->timer, jiffies + HZ/10); - } else if (!(mdio_read(ioaddr, MII_BMSR) & BMSR_ANEGCOMPLETE)) { + } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & + BMSR_ANEGCOMPLETE)) { net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n", dev->name); - mdio_write(ioaddr, MII_BMCR, val | BMCR_RESET); + netif_carrier_off(dev); + mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET); mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); } else { /* 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; - - val = mdio_read(ioaddr, 0x1f); + { 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); net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val); - val = mdio_read(ioaddr, MII_LPA); - net_link(tp, KERN_INFO "%s: mii lpa = %04x.\n", dev->name, val); + val = mdio_read(ioaddr, phy_id, MII_LPA); + adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); + net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n", + dev->name, val, adv); + + 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); @@ -924,6 +1019,11 @@ static void sis190_set_rxbufsize(struct sis190_private *tp, unsigned int mtu = dev->mtu; tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE; + /* RxDesc->size has a licence to kill the lower bits */ + if (tp->rx_buf_sz & 0x07) { + tp->rx_buf_sz += 8; + tp->rx_buf_sz &= RX_BUF_MASK; + } } static int sis190_open(struct net_device *dev) @@ -1118,6 +1218,199 @@ static struct net_device_stats *sis190_get_stats(struct net_device *dev) return &tp->stats; } +static void sis190_free_phy(struct list_head *first_phy) +{ + struct sis190_phy *cur, *next; + + list_for_each_entry_safe(cur, next, first_phy, list) { + kfree(cur); + } +} + +/** + * sis190_default_phy - Select default PHY for sis190 mac. + * @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 sis190_default_phy(struct net_device *dev) +{ + struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan; + struct sis190_private *tp = netdev_priv(dev); + struct mii_if_info *mii_if = &tp->mii_if; + void __iomem *ioaddr = tp->mmio_addr; + u16 status; + + phy_home = phy_default = phy_lan = NULL; + + list_for_each_entry(phy, &tp->first_phy, list) { + status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR); + + // Link ON & Not select default PHY & not ghost PHY. + if ((status & BMSR_LSTATUS) && + !phy_default && + (phy->type != UNKNOWN)) { + phy_default = phy; + } else { + status = mdio_read(ioaddr, phy->phy_id, MII_BMCR); + mdio_write(ioaddr, phy->phy_id, MII_BMCR, + status | BMCR_ANENABLE | BMCR_ISOLATE); + if (phy->type == HOME) + phy_home = phy; + else if (phy->type == LAN) + phy_lan = phy; + } + } + + if (!phy_default) { + if (phy_home) + phy_default = phy_home; + else if (phy_lan) + phy_default = phy_lan; + else + phy_default = list_entry(&tp->first_phy, + struct sis190_phy, list); + } + + if (mii_if->phy_id != phy_default->phy_id) { + mii_if->phy_id = phy_default->phy_id; + net_probe(tp, KERN_INFO + "%s: Using transceiver at address %d as default.\n", + pci_name(tp->pci_dev), mii_if->phy_id); + } + + status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR); + status &= (~BMCR_ISOLATE); + + mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status); + status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR); + + return status; +} + +static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, + struct sis190_phy *phy, unsigned int phy_id, + u16 mii_status) +{ + void __iomem *ioaddr = tp->mmio_addr; + struct mii_chip_info *p; + + INIT_LIST_HEAD(&phy->list); + phy->status = mii_status; + phy->phy_id = phy_id; + + phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1); + phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2); + + for (p = mii_chip_table; p->type; p++) { + if ((p->id[0] == phy->id[0]) && + (p->id[1] == (phy->id[1] & 0xfff0))) { + break; + } + } + + if (p->id[1]) { + phy->type = (p->type == MIX) ? + ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? + LAN : HOME) : p->type; + tp->features |= p->feature; + } else + phy->type = UNKNOWN; + + net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", + pci_name(tp->pci_dev), + (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 + * + * 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 sis190_mii_probe(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct mii_if_info *mii_if = &tp->mii_if; + void __iomem *ioaddr = tp->mmio_addr; + int phy_id; + int rc = 0; + + INIT_LIST_HEAD(&tp->first_phy); + + for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { + struct sis190_phy *phy; + u16 status; + + status = mdio_read_latched(ioaddr, phy_id, MII_BMSR); + + // Try next mii if the current one is not accessible. + if (status == 0xffff || status == 0x0000) + continue; + + phy = kmalloc(sizeof(*phy), GFP_KERNEL); + if (!phy) { + sis190_free_phy(&tp->first_phy); + rc = -ENOMEM; + goto out; + } + + sis190_init_phy(dev, tp, phy, phy_id, status); + + list_add(&tp->first_phy, &phy->list); + } + + if (list_empty(&tp->first_phy)) { + net_probe(tp, KERN_INFO "%s: No MII transceivers found!\n", + pci_name(tp->pci_dev)); + rc = -EIO; + goto out; + } + + /* 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; + mii_if->phy_id_mask = PHY_ID_ANY; + mii_if->reg_num_mask = MII_REG_ANY; +out: + return rc; +} + +static void __devexit sis190_mii_remove(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + sis190_free_phy(&tp->first_phy); +} + static void sis190_release_board(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -1195,13 +1488,6 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) tp->pci_dev = pdev; tp->mmio_addr = ioaddr; - tp->mii_if.dev = dev; - tp->mii_if.mdio_read = __mdio_read; - tp->mii_if.mdio_write = __mdio_write; - // tp->mii_if.phy_id = XXX; - tp->mii_if.phy_id_mask = 0x1f; - tp->mii_if.reg_num_mask = 0x1f; - sis190_irq_mask_and_ack(ioaddr); sis190_soft_reset(ioaddr); @@ -1248,6 +1534,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) { @@ -1270,11 +1561,13 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, /* Get MAC address from EEPROM */ for (i = 0; i < MAC_ADDR_LEN / 2; i++) { - u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); + __le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); } + sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo)); + return 0; } @@ -1320,6 +1613,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); @@ -1371,23 +1666,24 @@ static void sis190_set_speed_auto(struct net_device *dev) { struct sis190_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; + int phy_id = tp->mii_if.phy_id; int val; net_link(tp, KERN_INFO "%s: Enabling Auto-negotiation.\n", dev->name); - val = mdio_read(ioaddr, MII_ADVERTISE); + val = mdio_read(ioaddr, phy_id, MII_ADVERTISE); // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0 // unchanged. - mdio_write(ioaddr, MII_ADVERTISE, (val & ADVERTISE_SLCT) | + mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) | ADVERTISE_100FULL | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_10HALF); // Enable 1000 Full Mode. - mdio_write(ioaddr, MII_CTRL1000, ADVERTISE_1000FULL); + mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL); // Enable auto-negotiation and restart auto-negotiation. - mdio_write(ioaddr, MII_BMCR, + mdio_write(ioaddr, phy_id, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET); } @@ -1495,6 +1791,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; @@ -1522,11 +1820,14 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, dev->base_addr = (unsigned long) 0xdead; spin_lock_init(&tp->lock); - rc = register_netdev(dev); + + rc = sis190_mii_probe(dev); if (rc < 0) goto err_release_board; - pci_set_drvdata(pdev, dev); + rc = register_netdev(dev); + if (rc < 0) + goto err_remove_mii; net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", @@ -1536,12 +1837,17 @@ 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); out: return rc; +err_remove_mii: + sis190_mii_remove(dev); err_release_board: sis190_release_board(pdev); goto out; @@ -1551,6 +1857,7 @@ static void __devexit sis190_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + sis190_mii_remove(dev); unregister_netdev(dev); sis190_release_board(pdev); pci_set_drvdata(pdev, NULL);