atl1c: add PHY link event(up/down) patch

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>
This commit is contained in:
Huang, Xiong 2012-04-30 15:38:50 +00:00 committed by David S. Miller
parent 7cb6a291ef
commit 903d7ce0cc
4 changed files with 92 additions and 0 deletions

View 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 */
};
/*

View 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);
}
}
}

View 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

View 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;