atl1c: add PHY link event(up/down) patch
authorHuang, Xiong <xiong@qca.qualcomm.com>
Mon, 30 Apr 2012 15:38:50 +0000 (15:38 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 May 2012 01:44:13 +0000 (21:44 -0400)
On some platforms the PHY settings need to change depending on the
cable link status to get better stability.

Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/atheros/atl1c/atl1c.h
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c

index acc2956df90798143ba3c4bc316e82b0bf3b7b20..b2bf324631dc89f7902f9d7322c549331daa1c78 100644 (file)
@@ -436,6 +436,7 @@ struct atl1c_hw {
        bool phy_configured;
        bool re_autoneg;
        bool emi_ca;
+       bool msi_lnkpatch;      /* link patch for specific platforms */
 };
 
 /*
index 07f017f59b397775066673f1557cb3d8aaad3219..209c1791531c3843d0df6e438f0b87c37a8dd77d 100644 (file)
@@ -848,3 +848,40 @@ int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc)
 
        return 0;
 }
+
+
+/* configure phy after Link change Event */
+void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed)
+{
+       u16 phy_val;
+       bool adj_thresh = false;
+
+       if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 ||
+           hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2)
+               adj_thresh = true;
+
+       if (link_speed != SPEED_0) { /* link up */
+               /* az with brcm, half-amp */
+               if (hw->nic_type == athr_l1d_2) {
+                       atl1c_read_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL6,
+                               &phy_val);
+                       phy_val = FIELD_GETX(phy_val, CLDCTRL6_CAB_LEN);
+                       phy_val = phy_val > CLDCTRL6_CAB_LEN_SHORT ?
+                               AZ_ANADECT_LONG : AZ_ANADECT_DEF;
+                       atl1c_write_phy_dbg(hw, MIIDBG_AZ_ANADECT, phy_val);
+               }
+               /* threshold adjust */
+               if (adj_thresh && link_speed == SPEED_100 && hw->msi_lnkpatch) {
+                       atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, L1D_MSE16DB_UP);
+                       atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
+                               L1D_SYSMODCTRL_IECHOADJ_DEF);
+               }
+       } else { /* link down */
+               if (adj_thresh && hw->msi_lnkpatch) {
+                       atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
+                               SYSMODCTRL_IECHOADJ_DEF);
+                       atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB,
+                               L1D_MSE16DB_DOWN);
+               }
+       }
+}
index 0adb341313326f555e8c99398a39e61e36a94b84..ea3f5201a8ff4d3d7d1f6971bb67bd58fa38779e 100644 (file)
@@ -63,6 +63,7 @@ int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr,
                        u16 reg_addr, u16 phy_data);
 int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data);
 int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data);
+void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
 
 /* hw-ids */
 #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
index 25b7b009849647800fd943abab5ebea42262d20f..6d5b37479ec4083f5696d3ad7f6183cb91390c08 100644 (file)
@@ -258,6 +258,7 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
                        if (netif_msg_hw(adapter))
                                dev_warn(&pdev->dev, "stop mac failed\n");
                atl1c_set_aspm(hw, SPEED_0);
+               atl1c_post_phy_linkchg(hw, SPEED_0);
                netif_carrier_off(netdev);
                netif_stop_queue(netdev);
        } else {
@@ -274,6 +275,7 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
                        adapter->link_speed  = speed;
                        adapter->link_duplex = duplex;
                        atl1c_set_aspm(hw, speed);
+                       atl1c_post_phy_linkchg(hw, speed);
                        atl1c_start_mac(adapter);
                        if (netif_msg_link(adapter))
                                dev_info(&pdev->dev,
@@ -697,6 +699,55 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
                hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
        return 0;
 }
+
+struct atl1c_platform_patch {
+       u16 pci_did;
+       u8  pci_revid;
+       u16 subsystem_vid;
+       u16 subsystem_did;
+       u32 patch_flag;
+#define ATL1C_LINK_PATCH       0x1
+};
+static const struct atl1c_platform_patch plats[] __devinitdata = {
+{0x2060, 0xC1, 0x1019, 0x8152, 0x1},
+{0x2060, 0xC1, 0x1019, 0x2060, 0x1},
+{0x2060, 0xC1, 0x1019, 0xE000, 0x1},
+{0x2062, 0xC0, 0x1019, 0x8152, 0x1},
+{0x2062, 0xC0, 0x1019, 0x2062, 0x1},
+{0x2062, 0xC0, 0x1458, 0xE000, 0x1},
+{0x2062, 0xC1, 0x1019, 0x8152, 0x1},
+{0x2062, 0xC1, 0x1019, 0x2062, 0x1},
+{0x2062, 0xC1, 0x1458, 0xE000, 0x1},
+{0x2062, 0xC1, 0x1565, 0x2802, 0x1},
+{0x2062, 0xC1, 0x1565, 0x2801, 0x1},
+{0x1073, 0xC0, 0x1019, 0x8151, 0x1},
+{0x1073, 0xC0, 0x1019, 0x1073, 0x1},
+{0x1073, 0xC0, 0x1458, 0xE000, 0x1},
+{0x1083, 0xC0, 0x1458, 0xE000, 0x1},
+{0x1083, 0xC0, 0x1019, 0x8151, 0x1},
+{0x1083, 0xC0, 0x1019, 0x1083, 0x1},
+{0x1083, 0xC0, 0x1462, 0x7680, 0x1},
+{0x1083, 0xC0, 0x1565, 0x2803, 0x1},
+{0},
+};
+
+static void __devinit atl1c_patch_assign(struct atl1c_hw *hw)
+{
+       int i = 0;
+
+       hw->msi_lnkpatch = false;
+
+       while (plats[i].pci_did != 0) {
+               if (plats[i].pci_did == hw->device_id &&
+                   plats[i].pci_revid == hw->revision_id &&
+                   plats[i].subsystem_vid == hw->subsystem_vendor_id &&
+                   plats[i].subsystem_did == hw->subsystem_id) {
+                       if (plats[i].patch_flag & ATL1C_LINK_PATCH)
+                               hw->msi_lnkpatch = true;
+               }
+               i++;
+       }
+}
 /*
  * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter)
  * @adapter: board private structure to initialize
@@ -732,6 +783,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
                dev_err(&pdev->dev, "set mac function pointers failed\n");
                return -1;
        }
+       atl1c_patch_assign(hw);
+
        hw->intr_mask = IMR_NORMAL_MASK;
        hw->phy_configured = false;
        hw->preamble_len = 7;