netxen: stop second phy correctly
[safe/jmp/linux-2.6] / drivers / net / r8169.c
index 9deda50..af80309 100644 (file)
@@ -123,15 +123,6 @@ enum mac_version {
        RTL_GIGA_MAC_VER_20 = 0x14  // 8168C
 };
 
-enum phy_version {
-       RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */
-       RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */
-       RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
-};
-
 #define _R(NAME,MAC,MASK) \
        { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
 
@@ -180,6 +171,8 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(0x16ec,                    0x0116), 0, 0, RTL_CFG_0 },
        { PCI_VENDOR_ID_LINKSYS,                0x1032,
                PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+       { 0x0001,                               0x8168,
+               PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
        {0,},
 };
 
@@ -401,12 +394,13 @@ struct rtl8169_private {
        void __iomem *mmio_addr;        /* memory map physical address */
        struct pci_dev *pci_dev;        /* Index of PCI device */
        struct net_device *dev;
+#ifdef CONFIG_R8169_NAPI
        struct napi_struct napi;
+#endif
        spinlock_t lock;                /* spin lock flag */
        u32 msg_enable;
        int chipset;
        int mac_version;
-       int phy_version;
        u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
        u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
        u32 dirty_rx;
@@ -476,7 +470,7 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
 {
        int i;
 
-       RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0xFF) << 16 | value);
+       RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
 
        for (i = 20; i > 0; i--) {
                /*
@@ -493,7 +487,7 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
 {
        int i, value = -1;
 
-       RTL_W32(PHYAR, 0x0 | (reg_addr & 0xFF) << 16);
+       RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
 
        for (i = 20; i > 0; i--) {
                /*
@@ -501,7 +495,7 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
                 * the specified MII register.
                 */
                if (RTL_R32(PHYAR) & 0x80000000) {
-                       value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+                       value = RTL_R32(PHYAR) & 0xffff;
                        break;
                }
                udelay(25);
@@ -1178,54 +1172,21 @@ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
        dprintk("mac_version = 0x%02x\n", tp->mac_version);
 }
 
-static void rtl8169_get_phy_version(struct rtl8169_private *tp,
-                                   void __iomem *ioaddr)
-{
-       const struct {
-               u16 mask;
-               u16 set;
-               int phy_version;
-       } phy_info[] = {
-               { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
-               { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
-               { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
-               { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
-       }, *p = phy_info;
+struct phy_reg {
        u16 reg;
+       u16 val;
+};
 
-       reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
-       while ((reg & p->mask) != p->set)
-               p++;
-       tp->phy_version = p->phy_version;
-}
-
-static void rtl8169_print_phy_version(struct rtl8169_private *tp)
+static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len)
 {
-       struct {
-               int version;
-               char *msg;
-               u32 reg;
-       } phy_print[] = {
-               { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
-               { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
-               { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
-               { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
-               { 0, NULL, 0x0000 }
-       }, *p;
-
-       for (p = phy_print; p->msg; p++) {
-               if (tp->phy_version == p->version) {
-                       dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
-                       return;
-               }
+       while (len-- > 0) {
+               mdio_write(ioaddr, regs->reg, regs->val);
+               regs++;
        }
-       dprintk("phy_version == Unknown\n");
 }
 
-static void rtl8169_hw_phy_config(struct net_device *dev)
+static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
 {
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
        struct {
                u16 regs[5]; /* Beware of bit-sign propagation */
        } phy_magic[5] = { {
@@ -1258,33 +1219,9 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
        }, *p = phy_magic;
        unsigned int i;
 
-       rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
-
-       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
-               return;
-       if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
-               return;
-
-       dprintk("MAC version != 0 && PHY version == 0 or 1\n");
-       dprintk("Do final_reg2.cfg\n");
-
-       /* Shazam ! */
-
-       if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
-               mdio_write(ioaddr, 31, 0x0002);
-               mdio_write(ioaddr,  1, 0x90d0);
-               mdio_write(ioaddr, 31, 0x0000);
-               return;
-       }
-
-       if ((tp->mac_version != RTL_GIGA_MAC_VER_02) &&
-           (tp->mac_version != RTL_GIGA_MAC_VER_03))
-               return;
-
-       mdio_write(ioaddr, 31, 0x0001);                 //w 31 2 0 1
-       mdio_write(ioaddr, 21, 0x1000);                 //w 21 15 0 1000
-       mdio_write(ioaddr, 24, 0x65c7);                 //w 24 15 0 65c7
+       mdio_write(ioaddr, 0x1f, 0x0001);               //w 31 2 0 1
+       mdio_write(ioaddr, 0x15, 0x1000);               //w 21 15 0 1000
+       mdio_write(ioaddr, 0x18, 0x65c7);               //w 24 15 0 65c7
        rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);   //w 4 11 11 0
 
        for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
@@ -1297,7 +1234,100 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
        }
-       mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+       mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0002 },
+               { 0x01, 0x90d0 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x1d, 0x0f00 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x1ec8 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x12, 0x2300 },
+               { 0x1f, 0x0002 },
+               { 0x00, 0x88d4 },
+               { 0x01, 0x82b1 },
+               { 0x03, 0x7002 },
+               { 0x08, 0x9e30 },
+               { 0x09, 0x01f0 },
+               { 0x0a, 0x5500 },
+               { 0x0c, 0x00c8 },
+               { 0x1f, 0x0003 },
+               { 0x12, 0xc096 },
+               { 0x16, 0x000a },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cx_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x12, 0x2300 },
+               { 0x1f, 0x0003 },
+               { 0x16, 0x0f0a },
+               { 0x1f, 0x0000 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x7eb8 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl_hw_phy_config(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       rtl8169_print_mac_version(tp);
+
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_01:
+               break;
+       case RTL_GIGA_MAC_VER_02:
+       case RTL_GIGA_MAC_VER_03:
+               rtl8169s_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_04:
+               rtl8169sb_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_18:
+               rtl8168cp_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_19:
+               rtl8168c_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_20:
+               rtl8168cx_hw_phy_config(ioaddr);
+               break;
+       default:
+               break;
+       }
 }
 
 static void rtl8169_phy_timer(unsigned long __opaque)
@@ -1309,7 +1339,6 @@ static void rtl8169_phy_timer(unsigned long __opaque)
        unsigned long timeout = RTL8169_PHY_TIMEOUT;
 
        assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
-       assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
 
        if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
                return;
@@ -1344,8 +1373,7 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
        del_timer_sync(timer);
@@ -1356,8 +1384,7 @@ static inline void rtl8169_request_timer(struct net_device *dev)
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
        mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
@@ -1409,7 +1436,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       rtl8169_hw_phy_config(dev);
+       rtl_hw_phy_config(dev);
 
        dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
        RTL_W8(0x82, 0x01);
@@ -1675,10 +1702,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
-       rtl8169_get_phy_version(tp, ioaddr);
 
        rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
 
        for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
                if (tp->mac_version == rtl_chip_info[i].mac_version)
@@ -1701,7 +1726,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
-       if (RTL_R8(PHYstatus) & TBI_Enable) {
+       if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+           (RTL_R8(PHYstatus) & TBI_Enable)) {
                tp->set_speed = rtl8169_set_speed_tbi;
                tp->get_settings = rtl8169_gset_tbi;
                tp->phy_reset_enable = rtl8169_tbi_reset_enable;
@@ -2185,7 +2211,7 @@ out:
 
 static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
 {
-       desc->addr = 0x0badbadbadbadbadull;
+       desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
        desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
 }
 
@@ -2372,6 +2398,8 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
        rtl8169_irq_mask_and_ack(ioaddr);
 
 #ifdef CONFIG_R8169_NAPI
+       tp->intr_mask = 0xffff;
+       RTL_W16(IntrMask, tp->intr_event);
        napi_enable(&tp->napi);
 #endif
 }
@@ -2809,7 +2837,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                }
 
                /* Work around for AMD plateform. */
-               if ((desc->opts2 & 0xfffe000) &&
+               if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
                    (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
                        desc->opts2 = 0;
                        cur_rx++;
@@ -2953,13 +2981,16 @@ static void rtl8169_down(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       unsigned int poll_locked = 0;
        unsigned int intrmask;
 
        rtl8169_delete_timer(dev);
 
        netif_stop_queue(dev);
 
+#ifdef CONFIG_R8169_NAPI
+       napi_disable(&tp->napi);
+#endif
+
 core_down:
        spin_lock_irq(&tp->lock);
 
@@ -2973,11 +3004,6 @@ core_down:
 
        synchronize_irq(dev->irq);
 
-       if (!poll_locked) {
-               napi_disable(&tp->napi);
-               poll_locked++;
-       }
-
        /* Give a racing hard_start_xmit a few cycles to complete. */
        synchronize_sched();  /* FIXME: should this be synchronize_irq()? */