|
@@ -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>");
|
|
@@ -1766,6 +1768,29 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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[] = {
|
|
@@ -2139,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));
|
|
|
|
|
@@ -2203,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");
|
|
|
}
|
|
|
|
|
@@ -2257,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));
|
|
|
|
|
@@ -2312,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");
|
|
|
}
|
|
|
|
|
@@ -3200,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))
|