]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/r8169.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-post-merge-2.6
[mv-sheeva.git] / drivers / net / r8169.c
index 27a7c20f64cd5eb0041bbcf601ffee380b81ed3c..bde7d61f193063b91ffb7fb02c0a1db787ca7d78 100644 (file)
@@ -554,6 +554,8 @@ struct rtl8169_private {
        struct mii_if_info mii;
        struct rtl8169_counters counters;
        u32 saved_wolopts;
+
+       const struct firmware *fw;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -1632,42 +1634,163 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
 {
        __le32 *phytable = (__le32 *)fw->data;
        struct net_device *dev = tp->dev;
-       size_t i;
+       size_t index, fw_size = fw->size / sizeof(*phytable);
+       u32 predata, count;
 
        if (fw->size % sizeof(*phytable)) {
                netif_err(tp, probe, dev, "odd sized firmware %zd\n", fw->size);
                return;
        }
 
-       for (i = 0; i < fw->size / sizeof(*phytable); i++) {
-               u32 action = le32_to_cpu(phytable[i]);
+       for (index = 0; index < fw_size; index++) {
+               u32 action = le32_to_cpu(phytable[index]);
+               u32 regno = (action & 0x0fff0000) >> 16;
 
-               if (!action)
+               switch(action & 0xf0000000) {
+               case PHY_READ:
+               case PHY_DATA_OR:
+               case PHY_DATA_AND:
+               case PHY_READ_EFUSE:
+               case PHY_CLEAR_READCOUNT:
+               case PHY_WRITE:
+               case PHY_WRITE_PREVIOUS:
+               case PHY_DELAY_MS:
                        break;
 
-               if ((action & 0xf0000000) != PHY_WRITE) {
-                       netif_err(tp, probe, dev,
-                                 "unknown action 0x%08x\n", action);
+               case PHY_BJMPN:
+                       if (regno > index) {
+                               netif_err(tp, probe, tp->dev,
+                                       "Out of range of firmware\n");
+                               return;
+                       }
+                       break;
+               case PHY_READCOUNT_EQ_SKIP:
+                       if (index + 2 >= fw_size) {
+                               netif_err(tp, probe, tp->dev,
+                                       "Out of range of firmware\n");
+                               return;
+                       }
+                       break;
+               case PHY_COMP_EQ_SKIPN:
+               case PHY_COMP_NEQ_SKIPN:
+               case PHY_SKIPN:
+                       if (index + 1 + regno >= fw_size) {
+                               netif_err(tp, probe, tp->dev,
+                                       "Out of range of firmware\n");
+                               return;
+                       }
+                       break;
+
+               case PHY_READ_MAC_BYTE:
+               case PHY_WRITE_MAC_BYTE:
+               case PHY_WRITE_ERI_WORD:
+               default:
+                       netif_err(tp, probe, tp->dev,
+                                 "Invalid action 0x%08x\n", action);
                        return;
                }
        }
 
-       while (i-- != 0) {
-               u32 action = le32_to_cpu(*phytable);
+       predata = 0;
+       count = 0;
+
+       for (index = 0; index < fw_size; ) {
+               u32 action = le32_to_cpu(phytable[index]);
                u32 data = action & 0x0000ffff;
-               u32 reg = (action & 0x0fff0000) >> 16;
+               u32 regno = (action & 0x0fff0000) >> 16;
+
+               if (!action)
+                       break;
 
                switch(action & 0xf0000000) {
+               case PHY_READ:
+                       predata = rtl_readphy(tp, regno);
+                       count++;
+                       index++;
+                       break;
+               case PHY_DATA_OR:
+                       predata |= data;
+                       index++;
+                       break;
+               case PHY_DATA_AND:
+                       predata &= data;
+                       index++;
+                       break;
+               case PHY_BJMPN:
+                       index -= regno;
+                       break;
+               case PHY_READ_EFUSE:
+                       predata = rtl8168d_efuse_read(tp->mmio_addr, regno);
+                       index++;
+                       break;
+               case PHY_CLEAR_READCOUNT:
+                       count = 0;
+                       index++;
+                       break;
                case PHY_WRITE:
-                       rtl_writephy(tp, reg, data);
-                       phytable++;
+                       rtl_writephy(tp, regno, data);
+                       index++;
+                       break;
+               case PHY_READCOUNT_EQ_SKIP:
+                       if (count == data)
+                               index += 2;
+                       else
+                               index += 1;
                        break;
+               case PHY_COMP_EQ_SKIPN:
+                       if (predata == data)
+                               index += regno;
+                       index++;
+                       break;
+               case PHY_COMP_NEQ_SKIPN:
+                       if (predata != data)
+                               index += regno;
+                       index++;
+                       break;
+               case PHY_WRITE_PREVIOUS:
+                       rtl_writephy(tp, regno, predata);
+                       index++;
+                       break;
+               case PHY_SKIPN:
+                       index += regno + 1;
+                       break;
+               case PHY_DELAY_MS:
+                       mdelay(data);
+                       index++;
+                       break;
+
+               case PHY_READ_MAC_BYTE:
+               case PHY_WRITE_MAC_BYTE:
+               case PHY_WRITE_ERI_WORD:
                default:
                        BUG();
                }
        }
 }
 
+static void rtl_release_firmware(struct rtl8169_private *tp)
+{
+       release_firmware(tp->fw);
+       tp->fw = NULL;
+}
+
+static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name)
+{
+       const struct firmware **fw = &tp->fw;
+       int rc = !*fw;
+
+       if (rc) {
+               rc = request_firmware(fw, fw_name, &tp->pci_dev->dev);
+               if (rc < 0)
+                       goto out;
+       }
+
+       /* TODO: release firmware once rtl_phy_write_fw signals failures. */
+       rtl_phy_write_fw(tp, *fw);
+out:
+       return rc;
+}
+
 static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -2041,7 +2164,6 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
                { 0x0d, 0xf880 }
        };
        void __iomem *ioaddr = tp->mmio_addr;
-       const struct firmware *fw;
 
        rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
 
@@ -2105,11 +2227,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if (rtl_readphy(tp, 0x06) == 0xbf00 &&
-           request_firmware(&fw, FIRMWARE_8168D_1, &tp->pci_dev->dev) == 0) {
-               rtl_phy_write_fw(tp, fw);
-               release_firmware(fw);
-       } else {
+       if ((rtl_readphy(tp, 0x06) != 0xbf00) ||
+           (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) {
                netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
        }
 
@@ -2159,7 +2278,6 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
                { 0x0d, 0xf880 }
        };
        void __iomem *ioaddr = tp->mmio_addr;
-       const struct firmware *fw;
 
        rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
 
@@ -2214,11 +2332,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if (rtl_readphy(tp, 0x06) == 0xb300 &&
-           request_firmware(&fw, FIRMWARE_8168D_2, &tp->pci_dev->dev) == 0) {
-               rtl_phy_write_fw(tp, fw);
-               release_firmware(fw);
-       } else {
+       if ((rtl_readphy(tp, 0x06) != 0xb300) ||
+           (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) {
                netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
        }
 
@@ -3069,15 +3184,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                rtl8168_driver_start(tp);
        }
 
-       rtl8169_init_phy(dev, tp);
-
-       /*
-        * Pretend we are using VLANs; This bypasses a nasty bug where
-        * Interrupts stop flowing on high load on 8110SCd controllers.
-        */
-       if (tp->mac_version == RTL_GIGA_MAC_VER_05)
-               RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
-
        device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
 
        if (pci_dev_run_wake(pdev))
@@ -3111,6 +3217,8 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 
        cancel_delayed_work_sync(&tp->task);
 
+       rtl_release_firmware(tp);
+
        unregister_netdev(dev);
 
        if (pci_dev_run_wake(pdev))
@@ -3127,6 +3235,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 static int rtl8169_open(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
        struct pci_dev *pdev = tp->pci_dev;
        int retval = -ENOMEM;
 
@@ -3162,6 +3271,15 @@ static int rtl8169_open(struct net_device *dev)
 
        napi_enable(&tp->napi);
 
+       rtl8169_init_phy(dev, tp);
+
+       /*
+        * Pretend we are using VLANs; This bypasses a nasty bug where
+        * Interrupts stop flowing on high load on 8110SCd controllers.
+        */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+               RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
+
        rtl_pll_power_up(tp);
 
        rtl_hw_start(dev);
@@ -3171,7 +3289,7 @@ static int rtl8169_open(struct net_device *dev)
        tp->saved_wolopts = 0;
        pm_runtime_put_noidle(&pdev->dev);
 
-       rtl8169_check_link_status(dev, tp, tp->mmio_addr);
+       rtl8169_check_link_status(dev, tp, ioaddr);
 out:
        return retval;