Commit 1b949324 authored by Chien Tung's avatar Chien Tung Committed by Roland Dreier

RDMA/nes: Fix SFP+ PHY initialization

SFP+ PHY initialization has very long delays, incorrect settings for
direct attach copper cables, and inconsistent link detection.

Adjust delays to the minimum required by the PHY.  Worst case is now
less than 4 seconds.  Add new register settings for direct attach
cables.  Change link detection logic to use two new registers for more
consistent link state detection.  Reorganize code to shorten line
length.
Signed-off-by: default avatarChien Tung <chien.tin.tung@intel.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 5962c2c8
...@@ -757,6 +757,10 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, ...@@ -757,6 +757,10 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
((port_count > 2) && ((port_count > 2) &&
(nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G))) { (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G))) {
/* init serdes 1 */ /* init serdes 1 */
if (nesadapter->phy_type[0] == NES_PHY_TYPE_ARGUS) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
}
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF); nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) { if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
serdes_common_control = nes_read_indexed(nesdev, serdes_common_control = nes_read_indexed(nesdev,
...@@ -1259,203 +1263,155 @@ int nes_init_phy(struct nes_device *nesdev) ...@@ -1259,203 +1263,155 @@ int nes_init_phy(struct nes_device *nesdev)
{ {
struct nes_adapter *nesadapter = nesdev->nesadapter; struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0; u32 counter = 0;
u32 sds_common_control0; u32 sds;
u32 mac_index = nesdev->mac_index; u32 mac_index = nesdev->mac_index;
u32 tx_config = 0; u32 tx_config = 0;
u16 phy_data; u16 phy_data;
u32 temp_phy_data = 0; u32 temp_phy_data = 0;
u32 temp_phy_data2 = 0; u32 temp_phy_data2 = 0;
u32 i = 0; u8 phy_type = nesadapter->phy_type[mac_index];
u8 phy_index = nesadapter->phy_index[mac_index];
if ((nesadapter->OneG_Mode) && if ((nesadapter->OneG_Mode) &&
(nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { (phy_type != NES_PHY_TYPE_PUMA_1G)) {
nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index); nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) { if (phy_type == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__);
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config &= 0xFFFFFFE3; tx_config &= 0xFFFFFFE3;
tx_config |= 0x04; tx_config |= 0x04;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
} }
nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data); nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n", nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000);
nesadapter->phy_index[mac_index], phy_data);
nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
/* Reset the PHY */ /* Reset the PHY */
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000); nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000);
udelay(100); udelay(100);
counter = 0; counter = 0;
do { do {
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data); if (counter++ > 100)
if (counter++ > 100) break; break;
} while (phy_data & 0x8000); } while (phy_data & 0x8000);
/* Setting no phy loopback */ /* Setting no phy loopback */
phy_data &= 0xbfff; phy_data &= 0xbfff;
phy_data |= 0x1140; phy_data |= 0x1140;
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data); nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data);
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data); nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data);
nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data);
nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x17 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x1e = 0x%X.\n", phy_data);
/* Setting the interrupt mask */ /* Setting the interrupt mask */
nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data); nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data); nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee);
nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee); nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
/* turning on flow control */ /* turning on flow control */
nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data); nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data); nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00);
nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
(phy_data & ~(0x03E0)) | 0xc00);
/* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
phy_data | 0xc00); */
nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
/* Clear Half duplex */
nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
phy_data & ~(0x0100));
nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); /* Clear Half duplex */
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300); nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
} else { nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100));
if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) || nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
(nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
/* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config &= 0xFFFFFFE3;
tx_config |= 0x15;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
mdelay(10); nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
/* return 0;
* if firmware is already running (like from a }
* driver un-load/load, don't do anything.
*/
if (temp_phy_data == temp_phy_data2) {
/* configure QT2505 AMCC PHY */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0001);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
/* if ((phy_type == NES_PHY_TYPE_IRIS) ||
* remove micro from reset; chip boots from ROM, (phy_type == NES_PHY_TYPE_ARGUS)) {
* uploads EEPROM f/w image, uC executes f/w /* setup 10G MDIO operation */
*/ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002); tx_config &= 0xFFFFFFE3;
tx_config |= 0x15;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
if ((phy_type == NES_PHY_TYPE_ARGUS)) {
/* Check firmware heartbeat */
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
udelay(1500);
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
/* if (temp_phy_data != temp_phy_data2)
* wait for heart beat to start to return 0;
* know loading is done
*/
counter = 0;
do {
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
if (counter++ > 1000) {
nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n");
break;
}
mdelay(100);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
} while ((temp_phy_data2 == temp_phy_data));
/* /* no heartbeat, configure the PHY */
* wait for tracking to start to know nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000);
* f/w is good to go nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000);
*/ nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
counter = 0; nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
do { nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
if (counter++ > 1000) { nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n"); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
break;
}
mdelay(1000);
/*
* nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n",
* temp_phy_data);
*/
} while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70));
/* set LOS Control invert RXLOSB_I_PADINV */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000);
/* set LOS Control to mask of RXLOSB_I */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042);
/* set LED1 to input mode (LED1 and LED2 share same LED) */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007);
/* set LED2 to RX link_status and activity */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A);
/* set LED3 to RX link_status */
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009);
/* /* setup LEDs */
* reset the res-calibration on t2 nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
* serdes; ensures it is stable after nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
* the amcc phy is stable nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
*/
sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528);
sds_common_control0 |= 0x1;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
/* release the res-calibration reset */ /* Bring PHY out of reset */
sds_common_control0 &= 0xfffffffe; nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
i = 0; /* Check for heartbeat */
while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) counter = 0;
&& (i++ < 5000)) { mdelay(690);
/* mdelay(1); */ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
} temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
do {
if (counter++ > 150) {
nes_debug(NES_DBG_PHY, "No PHY heartbeat\n");
break;
}
mdelay(1);
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
} while ((temp_phy_data2 == temp_phy_data));
/* /* wait for tracking */
* wait for link train done before moving on, counter = 0;
* or will get an interupt storm do {
*/ nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
counter = 0; temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
do { if (counter++ > 300) {
temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + nes_debug(NES_DBG_PHY, "PHY did not track\n");
(0x200 * (nesdev->mac_index & 1))); break;
if (counter++ > 1000) {
nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n");
break;
}
mdelay(1);
} while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000));
} }
} mdelay(10);
} while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70));
/* setup signal integrity */
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063);
/* reset serdes */
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
mac_index * 0x200);
sds |= 0x1;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
mac_index * 0x200, sds);
sds &= 0xfffffffe;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 +
mac_index * 0x200, sds);
counter = 0;
while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
&& (counter++ < 5000))
;
} }
return 0; return 0;
} }
...@@ -2483,19 +2439,18 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) ...@@ -2483,19 +2439,18 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004);
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005);
/* check link status */ /* check link status */
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
u32temp = 100;
do {
nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
if ((phy_data == temp_phy_data) || (!(--u32temp))) nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
break; nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
temp_phy_data = phy_data; phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
} while (1);
phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
__func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
break; break;
case NES_PHY_TYPE_PUMA_1G: case NES_PHY_TYPE_PUMA_1G:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment