diff options
author | np <np@FreeBSD.org> | 2009-10-05 20:21:41 +0000 |
---|---|---|
committer | np <np@FreeBSD.org> | 2009-10-05 20:21:41 +0000 |
commit | 7e261d5659ff5086d3f0055f0d6ba9ede8e15f30 (patch) | |
tree | 802f7eebcdd7790a4ecc31d402dcf0fa269b0ff2 /sys/dev/cxgb/common | |
parent | 3c6c0fbaddc33d4c8303445bbe08717280dce4cc (diff) | |
download | FreeBSD-src-7e261d5659ff5086d3f0055f0d6ba9ede8e15f30.zip FreeBSD-src-7e261d5659ff5086d3f0055f0d6ba9ede8e15f30.tar.gz |
cxgb(4) updates, including:
- support for the new Gen-2, BT, and LP-CR cards.
- T3 firmware 7.7.0
- shared "common code" updates.
Approved by: gnn (mentor)
Obtained from: Chelsio
MFC after: 1 month
Diffstat (limited to 'sys/dev/cxgb/common')
-rw-r--r-- | sys/dev/cxgb/common/cxgb_ael1002.c | 959 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_aq100x.c | 544 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_common.h | 42 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_mv88e1xxx.c | 5 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_regs.h | 28 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_t3_hw.c | 273 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_tn1010.c | 4 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_vsc8211.c | 54 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_xgmac.c | 165 |
9 files changed, 1851 insertions, 223 deletions
diff --git a/sys/dev/cxgb/common/cxgb_ael1002.c b/sys/dev/cxgb/common/cxgb_ael1002.c index c92abda..d7bb386 100644 --- a/sys/dev/cxgb/common/cxgb_ael1002.c +++ b/sys/dev/cxgb/common/cxgb_ael1002.c @@ -45,16 +45,30 @@ enum { enum { AEL100X_TX_DISABLE = 9, AEL100X_TX_CONFIG1 = 0xc002, + AEL1002_PWR_DOWN_HI = 0xc011, AEL1002_PWR_DOWN_LO = 0xc012, AEL1002_XFI_EQL = 0xc015, AEL1002_LB_EN = 0xc017, + AEL_OPT_SETTINGS = 0xc017, AEL_I2C_CTRL = 0xc30a, AEL_I2C_DATA = 0xc30b, AEL_I2C_STAT = 0xc30c, + AEL2005_GPIO_CTRL = 0xc214, AEL2005_GPIO_STAT = 0xc215, + + AEL2020_GPIO_INTR = 0xc103, + AEL2020_GPIO_CTRL = 0xc108, + AEL2020_GPIO_STAT = 0xc10c, + AEL2020_GPIO_CFG = 0xc110, + + AEL2020_GPIO_SDA = 0, + AEL2020_GPIO_MODDET = 1, + AEL2020_GPIO_0 = 3, + AEL2020_GPIO_1 = 2, + AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, }; enum { edc_none, edc_sr, edc_twinax }; @@ -81,7 +95,7 @@ struct reg_val { unsigned short set_bits; }; -static int get_module_type(struct cphy *phy); +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms); static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) { @@ -108,6 +122,9 @@ static void ael100x_txon(struct cphy *phy) msleep(30); } +/* + * Read an 8-bit word from a device attached to the PHY's i2c bus. + */ static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) { int i, err; @@ -131,11 +148,14 @@ static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) return data >> 8; } } - CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n", - phy->addr, word_addr); + CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %x.%x timed out\n", + phy->addr, dev_addr, word_addr); return -ETIMEDOUT; } +/* + * Write an 8-bit word to a device attached to the PHY's i2c bus. + */ static int ael_i2c_wr(struct cphy *phy, int dev_addr, int word_addr, int data) { int i, err; @@ -158,8 +178,8 @@ static int ael_i2c_wr(struct cphy *phy, int dev_addr, int word_addr, int data) if ((stat & 3) == 1) return 0; } - CH_WARN(phy->adapter, "PHY %u I2C Write of addr %u timed out\n", - phy->addr, word_addr); + CH_WARN(phy->adapter, "PHY %u i2c Write of dev.addr %x.%x = %#x timed out\n", + phy->addr, dev_addr, word_addr, data); return -ETIMEDOUT; } @@ -230,9 +250,9 @@ static int ael1002_get_module_type(struct cphy *phy, int delay_ms) if (delay_ms) msleep(delay_ms); - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0); + v = ael2xxx_get_module_type(phy, delay_ms); - return v == -ETIMEDOUT ? phy_modtype_none : get_module_type(phy); + return (v == -ETIMEDOUT ? phy_modtype_none : v); } static int ael1002_reset(struct cphy *phy, int wait) @@ -312,12 +332,13 @@ static struct cphy_ops ael1002_ops = { }; #endif -int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael1002_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { int err; + struct cphy *phy = &pinfo->phy; - cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &ael1002_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, "10GBASE-R"); ael100x_txon(phy); @@ -366,12 +387,6 @@ static int ael1006_reset(struct cphy *phy, int wait) } -static int ael1006_power_down(struct cphy *phy, int enable) -{ - return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); -} - #ifdef C99_NOT_SUPPORTED static struct cphy_ops ael1006_ops = { ael1006_reset, @@ -385,7 +400,7 @@ static struct cphy_ops ael1006_ops = { NULL, NULL, get_link_status_r, - ael1006_power_down, + ael1002_power_down, }; #else static struct cphy_ops ael1006_ops = { @@ -395,20 +410,97 @@ static struct cphy_ops ael1006_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, }; #endif -int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael1006_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, + struct cphy *phy = &pinfo->phy; + + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &ael1006_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, "10GBASE-SR"); + phy->modtype = phy_modtype_sr; ael100x_txon(phy); return 0; } +/* + * Decode our module type. + */ +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + v = get_phytrans_type(phy); + if (v == phy_transtype_sfp) { + /* SFP: see SFF-8472 for below */ + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x1) + return phy_modtype_twinax; + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + return phy_modtype_unknown; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : + phy_modtype_twinax; + } + } else if (v == phy_transtype_xfp) { + /* XFP: See INF-8077i for details. */ + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 127); + if (v < 0) + return v; + + if (v != 1) { + /* XXX: set page select to table 1 yourself */ + return phy_modtype_unknown; + } + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 131); + if (v < 0) + return v; + v &= 0xf0; + if (v == 0x10) + return phy_modtype_lrm; + if (v == 0x40) + return phy_modtype_lr; + if (v == 0x80) + return phy_modtype_sr; + } + + return phy_modtype_unknown; +} + +/* + * Code to support the Aeluros/NetLogic 2005 10Gb PHY. + */ static int ael2005_setup_sr_edc(struct cphy *phy) { static struct reg_val regs[] = { @@ -1103,72 +1195,21 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) return err; } -static int get_module_type(struct cphy *phy) +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) { int v; + unsigned int stat; - v = get_phytrans_type(phy); - if (v == phy_transtype_sfp) { - /* SFP: see SFF-8472 for below */ - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); - if (v < 0) - return v; - - if (v == 0x1) - return phy_modtype_twinax; - if (v == 0x10) - return phy_modtype_sr; - if (v == 0x20) - return phy_modtype_lr; - if (v == 0x40) - return phy_modtype_lrm; - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); - if (v < 0) - return v; - if (v != 4) - return phy_modtype_unknown; - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); - if (v < 0) - return v; - - if (v & 0x80) { - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); - if (v < 0) - return v; - return v > 10 ? phy_modtype_twinax_long : - phy_modtype_twinax; - } - } else if (v == phy_transtype_xfp) { - /* XFP: See INF-8077i for details. */ - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 127); - if (v < 0) - return v; - - if (v != 1) { - /* XXX: set page select to table 1 yourself */ - return phy_modtype_unknown; - } + v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat); + if (v) + return v; - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 131); - if (v < 0) - return v; - v &= 0xf0; - if (v == 0x10) - return phy_modtype_lrm; - if (v == 0x40) - return phy_modtype_lr; - if (v == 0x80) - return phy_modtype_sr; - } + if (stat & (1 << 8)) /* module absent */ + return phy_modtype_none; - return phy_modtype_unknown; + return ael2xxx_get_module_type(phy, delay_ms); } - static int ael2005_intr_enable(struct cphy *phy) { int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200); @@ -1187,24 +1228,6 @@ static int ael2005_intr_clear(struct cphy *phy) return err ? err : t3_phy_lasi_intr_clear(phy); } -static int ael2005_get_module_type(struct cphy *phy, int delay_ms) -{ - int v; - unsigned int stat; - - v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat); - if (v) - return v; - - if (stat & (1 << 8)) /* module absent */ - return phy_modtype_none; - - if (delay_ms) - msleep(delay_ms); - - return get_module_type(phy); -} - static int ael2005_reset(struct cphy *phy, int wait) { static struct reg_val regs0[] = { @@ -1223,7 +1246,8 @@ static int ael2005_reset(struct cphy *phy, int wait) { 0, 0, 0, 0 } }; - int err, lasi_ctrl; + int err; + unsigned int lasi_ctrl; err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); if (err) @@ -1311,8 +1335,8 @@ static int ael2005_intr_handler(struct cphy *phy) return ret; } -#ifdef C99_NOT_SUPPORTED static struct cphy_ops ael2005_ops = { +#ifdef C99_NOT_SUPPORTED ael2005_reset, ael2005_intr_enable, ael2005_intr_disable, @@ -1325,9 +1349,7 @@ static struct cphy_ops ael2005_ops = { NULL, get_link_status_r, ael1002_power_down, -}; #else -static struct cphy_ops ael2005_ops = { .reset = ael2005_reset, .intr_enable = ael2005_intr_enable, .intr_disable = ael2005_intr_disable, @@ -1335,14 +1357,16 @@ static struct cphy_ops ael2005_ops = { .intr_handler = ael2005_intr_handler, .get_link_status = get_link_status_r, .power_down = ael1002_power_down, -}; #endif +}; -int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael2005_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { int err; - cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, + struct cphy *phy = &pinfo->phy; + + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &ael2005_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); @@ -1357,6 +1381,713 @@ int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, } /* + * Setup EDC and other parameters for operation with an optical module. + */ +static int ael2020_setup_sr_edc(struct cphy *phy) +{ + static struct reg_val regs[] = { + { MDIO_DEV_PMA_PMD, 0xcc01, 0xffff, 0x488a }, + + { MDIO_DEV_PMA_PMD, 0xcb1b, 0xffff, 0x0200 }, + { MDIO_DEV_PMA_PMD, 0xcb1c, 0xffff, 0x00f0 }, + { MDIO_DEV_PMA_PMD, 0xcc06, 0xffff, 0x00e0 }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + msleep(50); + if (err) + return err; + + phy->priv = edc_sr; + return 0; +} + +/* + * Setup EDC and other parameters for operation with an TWINAX module. + */ +static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) +{ + static struct reg_val uCclock40MHz[] = { + { MDIO_DEV_PMA_PMD, 0xff28, 0xffff, 0x4001 }, + { MDIO_DEV_PMA_PMD, 0xff2a, 0xffff, 0x0002 }, + { 0, 0, 0, 0 } + }; + + static struct reg_val uCclockActivate[] = { + { MDIO_DEV_PMA_PMD, 0xd000, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + static struct reg_val uCactivate[] = { + { MDIO_DEV_PMA_PMD, 0xd080, 0xffff, 0x0100 }, + { MDIO_DEV_PMA_PMD, 0xd092, 0xffff, 0x0000 }, + { 0, 0, 0, 0 } + }; + + static u16 twinax_edc[] = { + 0xd800, 0x4009, + 0xd801, 0x2fff, + 0xd802, 0x300f, + 0xd803, 0x40aa, + 0xd804, 0x401c, + 0xd805, 0x401e, + 0xd806, 0x2ff4, + 0xd807, 0x3dc4, + 0xd808, 0x2035, + 0xd809, 0x3035, + 0xd80a, 0x6524, + 0xd80b, 0x2cb2, + 0xd80c, 0x3012, + 0xd80d, 0x1002, + 0xd80e, 0x26e2, + 0xd80f, 0x3022, + 0xd810, 0x1002, + 0xd811, 0x27d2, + 0xd812, 0x3022, + 0xd813, 0x1002, + 0xd814, 0x2822, + 0xd815, 0x3012, + 0xd816, 0x1002, + 0xd817, 0x2492, + 0xd818, 0x3022, + 0xd819, 0x1002, + 0xd81a, 0x2772, + 0xd81b, 0x3012, + 0xd81c, 0x1002, + 0xd81d, 0x23d2, + 0xd81e, 0x3022, + 0xd81f, 0x1002, + 0xd820, 0x22cd, + 0xd821, 0x301d, + 0xd822, 0x27f2, + 0xd823, 0x3022, + 0xd824, 0x1002, + 0xd825, 0x5553, + 0xd826, 0x0307, + 0xd827, 0x2522, + 0xd828, 0x3022, + 0xd829, 0x1002, + 0xd82a, 0x2142, + 0xd82b, 0x3012, + 0xd82c, 0x1002, + 0xd82d, 0x4016, + 0xd82e, 0x5e63, + 0xd82f, 0x0344, + 0xd830, 0x2142, + 0xd831, 0x3012, + 0xd832, 0x1002, + 0xd833, 0x400e, + 0xd834, 0x2522, + 0xd835, 0x3022, + 0xd836, 0x1002, + 0xd837, 0x2b52, + 0xd838, 0x3012, + 0xd839, 0x1002, + 0xd83a, 0x2742, + 0xd83b, 0x3022, + 0xd83c, 0x1002, + 0xd83d, 0x25e2, + 0xd83e, 0x3022, + 0xd83f, 0x1002, + 0xd840, 0x2fa4, + 0xd841, 0x3dc4, + 0xd842, 0x6624, + 0xd843, 0x414b, + 0xd844, 0x56b3, + 0xd845, 0x03c6, + 0xd846, 0x866b, + 0xd847, 0x400c, + 0xd848, 0x2712, + 0xd849, 0x3012, + 0xd84a, 0x1002, + 0xd84b, 0x2c4b, + 0xd84c, 0x309b, + 0xd84d, 0x56b3, + 0xd84e, 0x03c3, + 0xd84f, 0x866b, + 0xd850, 0x400c, + 0xd851, 0x2272, + 0xd852, 0x3022, + 0xd853, 0x1002, + 0xd854, 0x2742, + 0xd855, 0x3022, + 0xd856, 0x1002, + 0xd857, 0x25e2, + 0xd858, 0x3022, + 0xd859, 0x1002, + 0xd85a, 0x2fb4, + 0xd85b, 0x3dc4, + 0xd85c, 0x6624, + 0xd85d, 0x56b3, + 0xd85e, 0x03c3, + 0xd85f, 0x866b, + 0xd860, 0x401c, + 0xd861, 0x2c45, + 0xd862, 0x3095, + 0xd863, 0x5b53, + 0xd864, 0x2372, + 0xd865, 0x3012, + 0xd866, 0x13c2, + 0xd867, 0x5cc3, + 0xd868, 0x2712, + 0xd869, 0x3012, + 0xd86a, 0x1312, + 0xd86b, 0x2b52, + 0xd86c, 0x3012, + 0xd86d, 0x1002, + 0xd86e, 0x2742, + 0xd86f, 0x3022, + 0xd870, 0x1002, + 0xd871, 0x2582, + 0xd872, 0x3022, + 0xd873, 0x1002, + 0xd874, 0x2142, + 0xd875, 0x3012, + 0xd876, 0x1002, + 0xd877, 0x628f, + 0xd878, 0x2985, + 0xd879, 0x33a5, + 0xd87a, 0x25e2, + 0xd87b, 0x3022, + 0xd87c, 0x1002, + 0xd87d, 0x5653, + 0xd87e, 0x03d2, + 0xd87f, 0x401e, + 0xd880, 0x6f72, + 0xd881, 0x1002, + 0xd882, 0x628f, + 0xd883, 0x2304, + 0xd884, 0x3c84, + 0xd885, 0x6436, + 0xd886, 0xdff4, + 0xd887, 0x6436, + 0xd888, 0x2ff5, + 0xd889, 0x3005, + 0xd88a, 0x8656, + 0xd88b, 0xdfba, + 0xd88c, 0x56a3, + 0xd88d, 0xd05a, + 0xd88e, 0x2972, + 0xd88f, 0x3012, + 0xd890, 0x1392, + 0xd891, 0xd05a, + 0xd892, 0x56a3, + 0xd893, 0xdfba, + 0xd894, 0x0383, + 0xd895, 0x6f72, + 0xd896, 0x1002, + 0xd897, 0x2b45, + 0xd898, 0x3005, + 0xd899, 0x4178, + 0xd89a, 0x5653, + 0xd89b, 0x0384, + 0xd89c, 0x2a62, + 0xd89d, 0x3012, + 0xd89e, 0x1002, + 0xd89f, 0x2f05, + 0xd8a0, 0x3005, + 0xd8a1, 0x41c8, + 0xd8a2, 0x5653, + 0xd8a3, 0x0382, + 0xd8a4, 0x0002, + 0xd8a5, 0x4218, + 0xd8a6, 0x2474, + 0xd8a7, 0x3c84, + 0xd8a8, 0x6437, + 0xd8a9, 0xdff4, + 0xd8aa, 0x6437, + 0xd8ab, 0x2ff5, + 0xd8ac, 0x3c05, + 0xd8ad, 0x8757, + 0xd8ae, 0xb888, + 0xd8af, 0x9787, + 0xd8b0, 0xdff4, + 0xd8b1, 0x6724, + 0xd8b2, 0x866a, + 0xd8b3, 0x6f72, + 0xd8b4, 0x1002, + 0xd8b5, 0x2641, + 0xd8b6, 0x3021, + 0xd8b7, 0x1001, + 0xd8b8, 0xc620, + 0xd8b9, 0x0000, + 0xd8ba, 0xc621, + 0xd8bb, 0x0000, + 0xd8bc, 0xc622, + 0xd8bd, 0x00ce, + 0xd8be, 0xc623, + 0xd8bf, 0x007f, + 0xd8c0, 0xc624, + 0xd8c1, 0x0032, + 0xd8c2, 0xc625, + 0xd8c3, 0x0000, + 0xd8c4, 0xc627, + 0xd8c5, 0x0000, + 0xd8c6, 0xc628, + 0xd8c7, 0x0000, + 0xd8c8, 0xc62c, + 0xd8c9, 0x0000, + 0xd8ca, 0x0000, + 0xd8cb, 0x2641, + 0xd8cc, 0x3021, + 0xd8cd, 0x1001, + 0xd8ce, 0xc502, + 0xd8cf, 0x53ac, + 0xd8d0, 0xc503, + 0xd8d1, 0x2cd3, + 0xd8d2, 0xc600, + 0xd8d3, 0x2a6e, + 0xd8d4, 0xc601, + 0xd8d5, 0x2a2c, + 0xd8d6, 0xc605, + 0xd8d7, 0x5557, + 0xd8d8, 0xc60c, + 0xd8d9, 0x5400, + 0xd8da, 0xc710, + 0xd8db, 0x0700, + 0xd8dc, 0xc711, + 0xd8dd, 0x0f06, + 0xd8de, 0xc718, + 0xd8df, 0x0700, + 0xd8e0, 0xc719, + 0xd8e1, 0x0f06, + 0xd8e2, 0xc720, + 0xd8e3, 0x4700, + 0xd8e4, 0xc721, + 0xd8e5, 0x0f06, + 0xd8e6, 0xc728, + 0xd8e7, 0x0700, + 0xd8e8, 0xc729, + 0xd8e9, 0x1207, + 0xd8ea, 0xc801, + 0xd8eb, 0x7f50, + 0xd8ec, 0xc802, + 0xd8ed, 0x7760, + 0xd8ee, 0xc803, + 0xd8ef, 0x7fce, + 0xd8f0, 0xc804, + 0xd8f1, 0x520e, + 0xd8f2, 0xc805, + 0xd8f3, 0x5c11, + 0xd8f4, 0xc806, + 0xd8f5, 0x3c51, + 0xd8f6, 0xc807, + 0xd8f7, 0x4061, + 0xd8f8, 0xc808, + 0xd8f9, 0x49c1, + 0xd8fa, 0xc809, + 0xd8fb, 0x3840, + 0xd8fc, 0xc80a, + 0xd8fd, 0x0000, + 0xd8fe, 0xc821, + 0xd8ff, 0x0002, + 0xd900, 0xc822, + 0xd901, 0x0046, + 0xd902, 0xc844, + 0xd903, 0x182f, + 0xd904, 0xc013, + 0xd905, 0xf341, + 0xd906, 0xc084, + 0xd907, 0x0030, + 0xd908, 0xc904, + 0xd909, 0x1401, + 0xd90a, 0xcb0c, + 0xd90b, 0x0004, + 0xd90c, 0xcb0e, + 0xd90d, 0xa00a, + 0xd90e, 0xcb0f, + 0xd90f, 0xc0c0, + 0xd910, 0xcb10, + 0xd911, 0xc0c0, + 0xd912, 0xcb11, + 0xd913, 0x00a0, + 0xd914, 0xcb12, + 0xd915, 0x0007, + 0xd916, 0xc241, + 0xd917, 0xa000, + 0xd918, 0xc243, + 0xd919, 0x7fe0, + 0xd91a, 0xc604, + 0xd91b, 0x000e, + 0xd91c, 0xc609, + 0xd91d, 0x00f5, + 0xd91e, 0xc611, + 0xd91f, 0x000e, + 0xd920, 0xc660, + 0xd921, 0x9600, + 0xd922, 0xc687, + 0xd923, 0x0004, + 0xd924, 0xc60a, + 0xd925, 0x04f5, + 0xd926, 0x0000, + 0xd927, 0x2641, + 0xd928, 0x3021, + 0xd929, 0x1001, + 0xd92a, 0xc620, + 0xd92b, 0x14e5, + 0xd92c, 0xc621, + 0xd92d, 0xc53d, + 0xd92e, 0xc622, + 0xd92f, 0x3cbe, + 0xd930, 0xc623, + 0xd931, 0x4452, + 0xd932, 0xc624, + 0xd933, 0xc5c5, + 0xd934, 0xc625, + 0xd935, 0xe01e, + 0xd936, 0xc627, + 0xd937, 0x0000, + 0xd938, 0xc628, + 0xd939, 0x0000, + 0xd93a, 0xc62c, + 0xd93b, 0x0000, + 0xd93c, 0x0000, + 0xd93d, 0x2b84, + 0xd93e, 0x3c74, + 0xd93f, 0x6435, + 0xd940, 0xdff4, + 0xd941, 0x6435, + 0xd942, 0x2806, + 0xd943, 0x3006, + 0xd944, 0x8565, + 0xd945, 0x2b24, + 0xd946, 0x3c24, + 0xd947, 0x6436, + 0xd948, 0x1002, + 0xd949, 0x2b24, + 0xd94a, 0x3c24, + 0xd94b, 0x6436, + 0xd94c, 0x4045, + 0xd94d, 0x8656, + 0xd94e, 0x5663, + 0xd94f, 0x0302, + 0xd950, 0x401e, + 0xd951, 0x1002, + 0xd952, 0x2807, + 0xd953, 0x31a7, + 0xd954, 0x20c4, + 0xd955, 0x3c24, + 0xd956, 0x6724, + 0xd957, 0x1002, + 0xd958, 0x2807, + 0xd959, 0x3187, + 0xd95a, 0x20c4, + 0xd95b, 0x3c24, + 0xd95c, 0x6724, + 0xd95d, 0x1002, + 0xd95e, 0x24f4, + 0xd95f, 0x3c64, + 0xd960, 0x6436, + 0xd961, 0xdff4, + 0xd962, 0x6436, + 0xd963, 0x1002, + 0xd964, 0x2006, + 0xd965, 0x3d76, + 0xd966, 0xc161, + 0xd967, 0x6134, + 0xd968, 0x6135, + 0xd969, 0x5443, + 0xd96a, 0x0303, + 0xd96b, 0x6524, + 0xd96c, 0x00fb, + 0xd96d, 0x1002, + 0xd96e, 0x20d4, + 0xd96f, 0x3c24, + 0xd970, 0x2025, + 0xd971, 0x3005, + 0xd972, 0x6524, + 0xd973, 0x1002, + 0xd974, 0xd019, + 0xd975, 0x2104, + 0xd976, 0x3c24, + 0xd977, 0x2105, + 0xd978, 0x3805, + 0xd979, 0x6524, + 0xd97a, 0xdff4, + 0xd97b, 0x4005, + 0xd97c, 0x6524, + 0xd97d, 0x2e8d, + 0xd97e, 0x303d, + 0xd97f, 0x2408, + 0xd980, 0x35d8, + 0xd981, 0x5dd3, + 0xd982, 0x0307, + 0xd983, 0x8887, + 0xd984, 0x63a7, + 0xd985, 0x8887, + 0xd986, 0x63a7, + 0xd987, 0xdffd, + 0xd988, 0x00f9, + 0xd989, 0x1002, + 0xd98a, 0x0000, + }; + int i, err; + + /* set uC clock and activate it */ + err = set_phy_regs(phy, uCclock40MHz); + msleep(500); + if (err) + return err; + err = set_phy_regs(phy, uCclockActivate); + msleep(500); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) + err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i], + twinax_edc[i + 1]); + /* activate uC */ + err = set_phy_regs(phy, uCactivate); + if (!err) + phy->priv = edc_twinax; + return err; +} + +/* + * Return Module Type. + */ +static int ael2020_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2020_GPIO_STAT, &stat); + if (v) + return v; + + if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { + /* module absent */ + return phy_modtype_none; + } + + return ael2xxx_get_module_type(phy, delay_ms); +} + +/* + * Enable PHY interrupts. We enable "Module Detection" interrupts (on any + * state transition) and then generic Link Alarm Status Interrupt (LASI). + */ +static int ael2020_intr_enable(struct cphy *phy) +{ + struct reg_val regs[] = { + { MDIO_DEV_PMA_PMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x4 }, + { MDIO_DEV_PMA_PMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + { MDIO_DEV_PMA_PMD, AEL2020_GPIO_CTRL, + 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + if (err) + return err; + + phy->caps |= POLL_LINK_1ST_TIME; + + /* enable standard Link Alarm Status Interrupts */ + err = t3_phy_lasi_intr_enable(phy); + if (err) + return err; + + return 0; +} + +/* + * Disable PHY interrupts. The mirror of the above ... + */ +static int ael2020_intr_disable(struct cphy *phy) +{ + struct reg_val regs[] = { + { MDIO_DEV_PMA_PMD, AEL2020_GPIO_CTRL, + 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, + + { MDIO_DEV_PMA_PMD, AEL2020_GPIO_CTRL, + 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + if (err) + return err; + + /* disable standard Link Alarm Status Interrupts */ + return t3_phy_lasi_intr_disable(phy); +} + +/* + * Clear PHY interrupt state. + */ +static int ael2020_intr_clear(struct cphy *phy) +{ + unsigned int stat; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2020_GPIO_INTR, &stat); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +/* + * Common register settings for the AEL2020 when it comes out of reset. + */ +static struct reg_val ael2020_reset_regs[] = { + { MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x3101 }, + + { MDIO_DEV_PMA_PMD, 0xcd40, 0xffff, 0x0001 }, + + { MDIO_DEV_PMA_PMD, 0xff02, 0xffff, 0x0023 }, + { MDIO_DEV_PMA_PMD, 0xff03, 0xffff, 0x0000 }, + { MDIO_DEV_PMA_PMD, 0xff04, 0xffff, 0x0000 }, + + /* end */ + { 0, 0, 0, 0 } +}; + +/* + * Reset the PHY and put it into a canonical operating state. + */ +static int ael2020_reset(struct cphy *phy, int wait) +{ + int err; + unsigned int lasi_ctrl; + + /* grab current interrupt state */ + err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 125); + if (err) + return err; + msleep(100); + + /* basic initialization for all module types */ + phy->priv = edc_none; + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; + + /* determine module type and perform appropriate initialization */ + err = ael2020_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = (u8)err; + if (err == phy_modtype_none || err == phy_modtype_unknown) + err = 0; + else if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2020_setup_twinax_edc(phy, err); + else + err = ael2020_setup_sr_edc(phy); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2020_intr_enable(phy); + return err; +} + +/* + * Handle a PHY interrupt. + */ +static int ael2020_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2020_GPIO_INTR, &stat); + if (ret) + return ret; + + if (stat & (0x1 << AEL2020_GPIO_MODDET)) { + /* modules have max 300 ms init time after hot plug */ + ret = ael2020_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = (u8)ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2020_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + if (!ret) + ret |= cphy_cause_link_change; + return ret; +} + +static struct cphy_ops ael2020_ops = { +#ifdef C99_NOT_SUPPORTED + ael2020_reset, + ael2020_intr_enable, + ael2020_intr_disable, + ael2020_intr_clear, + ael2020_intr_handler, + NULL, + NULL, + NULL, + NULL, + NULL, + get_link_status_r, + ael1002_power_down, +#else + .reset = ael2020_reset, + .intr_enable = ael2020_intr_enable, + .intr_disable = ael2020_intr_disable, + .intr_clear = ael2020_intr_clear, + .intr_handler = ael2020_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, +#endif +}; + +int t3_ael2020_phy_prep(pinfo_t *pinfo, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + int err; + struct cphy *phy = &pinfo->phy; + + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &ael2020_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; + err = ael2020_get_module_type(phy, 0); + if (err >= 0) + phy->modtype = err; + + ael_laser_down(phy, 0); + return 0; +} + +/* * Get link status for a 10GBASE-X device. */ static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, @@ -1394,7 +2125,7 @@ static struct cphy_ops qt2045_ops = { NULL, NULL, get_link_status_x, - ael1006_power_down, + ael1002_power_down, }; #else static struct cphy_ops qt2045_ops = { @@ -1404,16 +2135,17 @@ static struct cphy_ops qt2045_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, }; #endif -int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_qt2045_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { unsigned int stat; + struct cphy *phy = &pinfo->phy; - cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &qt2045_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, "10GBASE-CX4"); @@ -1437,14 +2169,15 @@ static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, { if (link_ok) { unsigned int status; + adapter_t *adapter = phy->adapter; - status = t3_read_reg(phy->adapter, + status = t3_read_reg(adapter, XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | - t3_read_reg(phy->adapter, + t3_read_reg(adapter, XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | - t3_read_reg(phy->adapter, + t3_read_reg(adapter, XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | - t3_read_reg(phy->adapter, + t3_read_reg(adapter, XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); *link_ok = !(status & F_LOWSIG0); } @@ -1487,10 +2220,10 @@ static struct cphy_ops xaui_direct_ops = { }; #endif -int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_xaui_direct_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, + cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &xaui_direct_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, "10GBASE-CX4"); return 0; diff --git a/sys/dev/cxgb/common/cxgb_aq100x.c b/sys/dev/cxgb/common/cxgb_aq100x.c new file mode 100644 index 0000000..abb93c4 --- /dev/null +++ b/sys/dev/cxgb/common/cxgb_aq100x.c @@ -0,0 +1,544 @@ +/************************************************************************** + +Copyright (c) 2009 Chelsio Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Neither the name of the Chelsio Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <cxgb_include.h> + +#undef msleep +#define msleep t3_os_sleep + +enum { + /* MDIO_DEV_PMA_PMD registers */ + AQ_LINK_STAT = 0xe800, + + /* MDIO_DEV_XGXS registers */ + AQ_XAUI_RX_CFG = 0xc400, + AQ_XAUI_KX_CFG = 0xc440, + AQ_XAUI_TX_CFG = 0xe400, + + /* MDIO_DEV_ANEG registers */ + AQ_100M_CTRL = 0x0010, + AQ_10G_CTRL = 0x0020, + AQ_1G_CTRL = 0xc400, + AQ_ANEG_STAT = 0xc800, + + /* MDIO_DEV_VEND1 registers */ + AQ_FW_VERSION = 0x0020, + AQ_THERMAL_THR = 0xc421, + AQ_THERMAL1 = 0xc820, + AQ_THERMAL2 = 0xc821, + AQ_IFLAG_GLOBAL = 0xfc00, + AQ_IMASK_GLOBAL = 0xff00, +}; + +#define AQBIT(x) (1 << (0x##x)) +#define ADV_1G_FULL AQBIT(f) +#define ADV_1G_HALF AQBIT(e) +#define ADV_10G_FULL AQBIT(c) + +#define AQ_WRITE_REGS(phy, regs) do { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(regs); i++) { \ + (void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \ + } \ +} while (0) +#define AQ_READ_REGS(phy, regs) do { \ + unsigned i, v; \ + for (i = 0; i < ARRAY_SIZE(regs); i++) { \ + (void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \ + } \ +} while (0) + +/* + * Return value is temperature in celcius, 0xffff for error or don't know. + */ +static int +aq100x_temperature(struct cphy *phy) +{ + unsigned int v; + + if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) || + v == 0xffff || (v & 1) != 1) + return (0xffff); + + if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v)) + return (0xffff); + + return ((int)((signed char)(v >> 8))); +} + +static int +aq100x_set_defaults(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00); +} + +static int +aq100x_reset(struct cphy *phy, int wait) +{ + int err; + err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); + if (!err) + err = aq100x_set_defaults(phy); + return (err); +} + +static int +aq100x_intr_enable(struct cphy *phy) +{ + struct { + int mmd; + int reg; + int val; + } imasks[] = { + {MDIO_DEV_VEND1, 0xd400, AQBIT(e)}, + {MDIO_DEV_VEND1, 0xff01, AQBIT(2)}, + {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)} + }; + + AQ_WRITE_REGS(phy, imasks); + + return (0); +} + +static int +aq100x_intr_disable(struct cphy *phy) +{ + struct { + int mmd; + int reg; + int val; + } imasks[] = { + {MDIO_DEV_VEND1, 0xd400, 0}, + {MDIO_DEV_VEND1, 0xff01, 0}, + {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0} + }; + + AQ_WRITE_REGS(phy, imasks); + + return (0); +} + +static int +aq100x_intr_clear(struct cphy *phy) +{ + struct { + int mmd; + int reg; + } iclr[] = { + {MDIO_DEV_VEND1, 0xcc00}, + {MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */ + }; + + AQ_READ_REGS(phy, iclr); + + return (0); +} + +static int +aq100x_vendor_intr(struct cphy *phy, int *rc) +{ + int err; + unsigned int cause, v; + + err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause); + if (err) + return (err); + + if (cause & AQBIT(2)) { + err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v); + if (err) + return (err); + + if (v & AQBIT(e)) { + CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n", + phy->addr, aq100x_temperature(phy)); + + t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, + phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0); + + *rc |= cphy_cause_alarm; + } + + cause &= ~4; + } + + if (cause) + CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt" + " (0x%x)\n", phy->addr, cause); + + return (0); + +} + +static int +aq100x_intr_handler(struct cphy *phy) +{ + int err, rc = 0; + unsigned int cause; + + err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause); + if (err) + return (err); + + if (cause & AQBIT(0)) { + err = aq100x_vendor_intr(phy, &rc); + if (err) + return (err); + cause &= ~AQBIT(0); + } + + if (cause) + CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n", + phy->addr, cause); + + return (rc); +} + +static int +aq100x_power_down(struct cphy *phy, int off) +{ + int err, wait = 500; + unsigned int v; + + err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN, + off ? BMCR_PDOWN : 0); + if (err || off) + return (v); + + msleep(300); + do { + err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v); + if (err) + return (err); + v &= BMCR_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n", + phy->addr, v); + return (ETIMEDOUT); + } + + return (0); +} + +static int +aq100x_autoneg_enable(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, + BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART); + + return (err); +} + +static int +aq100x_autoneg_restart(struct cphy *phy) +{ + return aq100x_autoneg_enable(phy); +} + +static int +aq100x_advertise(struct cphy *phy, unsigned int advertise_map) +{ + unsigned int adv; + int err; + + /* 10G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_10000baseT_Full) + adv |= ADV_10G_FULL; + err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL, + ADV_10G_FULL, adv); + if (err) + return (err); + + /* 1G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_1000baseT_Full) + adv |= ADV_1G_FULL; + if (advertise_map & ADVERTISED_1000baseT_Half) + adv |= ADV_1G_HALF; + err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL, + ADV_1G_FULL | ADV_1G_HALF, adv); + if (err) + return (err); + + /* 100M, pause advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv); + + return (err); +} + +static int +aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) +{ + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0); +} + +static int +aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err, set; + + if (speed == SPEED_100) + set = BMCR_SPEED100; + else if (speed == SPEED_1000) + set = BMCR_SPEED1000; + else if (speed == SPEED_10000) + set = BMCR_SPEED1000 | BMCR_SPEED100; + else + return (EINVAL); + + if (duplex != DUPLEX_FULL) + return (EINVAL); + + err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, + BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0); + if (err) + return (err); + + err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_SPEED1000 | BMCR_SPEED100, set); + if (err) + return (err); + + return (0); +} + +static int +aq100x_get_link_status(struct cphy *phy, int *link_ok, int *speed, int *duplex, + int *fc) +{ + int err; + unsigned int v, link = 0; + + err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v); + if (err) + return (err); + if (v == 0xffff || !(v & 1)) + goto done; + + err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v); + if (err) + return (err); + if (v & 0x8000) + goto done; + if (v & BMCR_ANENABLE) { + + err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v); + if (err) + return (err); + if ((v & 0x20) == 0) + goto done; + + err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v); + if (err) + return (err); + + if (speed) { + switch (v & 0x6) { + case 0x6: *speed = SPEED_10000; + break; + case 0x4: *speed = SPEED_1000; + break; + case 0x2: *speed = SPEED_100; + break; + case 0x0: *speed = SPEED_10; + break; + } + } + + if (duplex) + *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; + + if (fc) { + unsigned int lpa, adv; + err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa); + if (!err) + err = mdio_read(phy, MDIO_DEV_ANEG, + AQ_100M_CTRL, &adv); + if (err) + return err; + + if (lpa & adv & ADVERTISE_PAUSE_CAP) + *fc = PAUSE_RX | PAUSE_TX; + else if (lpa & ADVERTISE_PAUSE_CAP && + lpa & ADVERTISE_PAUSE_ASYM && + adv & ADVERTISE_PAUSE_ASYM) + *fc = PAUSE_TX; + else if (lpa & ADVERTISE_PAUSE_ASYM && + adv & ADVERTISE_PAUSE_CAP) + *fc = PAUSE_RX; + else + *fc = 0; + } + + } else { + err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v); + if (err) + return (err); + + v &= BMCR_SPEED1000 | BMCR_SPEED100; + if (speed) { + if (v == (BMCR_SPEED1000 | BMCR_SPEED100)) + *speed = SPEED_10000; + else if (v == BMCR_SPEED1000) + *speed = SPEED_1000; + else if (v == BMCR_SPEED100) + *speed = SPEED_100; + else + *speed = SPEED_10; + } + + if (duplex) + *duplex = DUPLEX_FULL; + } + + link = 1; +done: + if (link_ok) + *link_ok = link; + return (0); +} + +static struct cphy_ops aq100x_ops = { + .reset = aq100x_reset, + .intr_enable = aq100x_intr_enable, + .intr_disable = aq100x_intr_disable, + .intr_clear = aq100x_intr_clear, + .intr_handler = aq100x_intr_handler, + .autoneg_enable = aq100x_autoneg_enable, + .autoneg_restart = aq100x_autoneg_restart, + .advertise = aq100x_advertise, + .set_loopback = aq100x_set_loopback, + .set_speed_duplex = aq100x_set_speed_duplex, + .get_link_status = aq100x_get_link_status, + .power_down = aq100x_power_down, +}; + +int +t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + struct cphy *phy = &pinfo->phy; + unsigned int v, v2, gpio, wait; + int err; + adapter_t *adapter = pinfo->adapter; + + cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops, + SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | + SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI | + SUPPORTED_MISC_IRQ, "1000/10GBASE-T"); + + /* + * Hard reset the PHY. + */ + gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); + msleep(1); + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); + + /* + * Give it enough time to load the firmware and get ready for mdio. + */ + msleep(1000); + wait = 500; /* in 10ms increments */ + do { + err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v); + if (err || v == 0xffff) { + + /* Allow prep_adapter to succeed when ffff is read */ + + CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", + phy_addr, err, v); + goto done; + } + + v &= BMCR_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", + phy_addr, v); + + goto done; /* let prep_adapter succeed */ + } + + /* Firmware version check. */ + (void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v); + if (v < 0x115) + CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr, + v >> 8, v & 0xff); + +#if 0 + /* The PHY should start in really-low-power mode. */ + (void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v); + if ((v & BMCR_PDOWN) == 0) + CH_WARN(adapter, "PHY%d does not start in low power mode.\n", + phy_addr); +#endif + + /* + * Verify XAUI and 1000-X settings, but let prep succeed no matter what. + */ + v = v2 = 0; + (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v); + (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2); + if (v != 0x1b || v2 != 0x1b) + CH_WARN(adapter, "PHY%d: incorrect XAUI settings " + "(0x%x, 0x%x).\n", phy_addr, v, v2); + v = 0; + (void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v); + if ((v & 0xf) != 0xf) + CH_WARN(adapter, "PHY%d: incorrect 1000-X settings " + "(0x%x).\n", phy_addr, v); + + (void) aq100x_set_defaults(phy); +done: + return (err); +} diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h index 09e7840..1aa3642 100644 --- a/sys/dev/cxgb/common/cxgb_common.h +++ b/sys/dev/cxgb/common/cxgb_common.h @@ -56,7 +56,11 @@ enum { }; enum { - SUPPORTED_IRQ = 1 << 24 + SUPPORTED_LINK_IRQ = 1 << 24, + /* skip 25 */ + SUPPORTED_MISC_IRQ = 1 << 26, + SUPPORTED_IRQ = (SUPPORTED_LINK_IRQ | SUPPORTED_MISC_IRQ), + POLL_LINK_1ST_TIME = 1 << 27 }; enum { /* adapter interrupt-maintained statistics */ @@ -93,7 +97,7 @@ enum { enum { FW_VERSION_MAJOR = 7, - FW_VERSION_MINOR = 1, + FW_VERSION_MINOR = 7, FW_VERSION_MICRO = 0 }; @@ -484,6 +488,7 @@ struct cmac { u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; + unsigned int was_reset; u64 rx_pause; struct mac_stats stats; }; @@ -526,6 +531,7 @@ enum { cphy_cause_link_change = 1, cphy_cause_fifo_error = 2, cphy_cause_module_change = 4, + cphy_cause_alarm = 8, }; /* PHY module types */ @@ -563,9 +569,10 @@ struct cphy_ops { struct cphy { u8 addr; /* PHY address */ u8 modtype; /* PHY module type */ - short priv; /* scratch pad */ + unsigned int priv; /* scratch pad */ unsigned int caps; /* PHY capabilities */ adapter_t *adapter; /* associated adapter */ + pinfo_t *pinfo; /* associated port */ const char *desc; /* PHY description */ unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ @@ -589,7 +596,7 @@ static inline int mdio_write(struct cphy *phy, int mmd, int reg, } /* Convenience initializer */ -static inline void cphy_init(struct cphy *phy, adapter_t *adapter, +static inline void cphy_init(struct cphy *phy, adapter_t *adapter, pinfo_t *pinfo, int phy_addr, struct cphy_ops *phy_ops, const struct mdio_ops *mdio_ops, unsigned int caps, const char *desc) @@ -597,6 +604,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, phy->addr = (u8)phy_addr; phy->caps = caps; phy->adapter = adapter; + phy->pinfo = pinfo; phy->desc = desc; phy->ops = phy_ops; if (mdio_ops) { @@ -742,7 +750,7 @@ int t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n, int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, u64 *buf); -int t3_mac_reset(struct cmac *mac); +int t3_mac_init(struct cmac *mac); void t3b_pcs_reset(struct cmac *mac); void t3_mac_disable_exact_filters(struct cmac *mac); void t3_mac_enable_exact_filters(struct cmac *mac); @@ -827,25 +835,33 @@ int t3_vsc7323_enable(adapter_t *adap, int port, int which); int t3_vsc7323_disable(adapter_t *adap, int port, int which); const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac); +int t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp); +int t3_i2c_write8(adapter_t *adapter, int chained, u8 val); + int t3_mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int *valp); int t3_mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int val); -int t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr, + const struct mdio_ops *mdio_ops); +int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port); +int t3_ael1002_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael1006_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael2005_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_ael2020_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_qt2045_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_tn1010_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); -int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_xaui_direct_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops); +int t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr, + const struct mdio_ops *mdio_ops); #endif /* __CHELSIO_COMMON_H */ diff --git a/sys/dev/cxgb/common/cxgb_mv88e1xxx.c b/sys/dev/cxgb/common/cxgb_mv88e1xxx.c index 7d39def..6281ac8 100644 --- a/sys/dev/cxgb/common/cxgb_mv88e1xxx.c +++ b/sys/dev/cxgb/common/cxgb_mv88e1xxx.c @@ -294,12 +294,13 @@ static struct cphy_ops mv88e1xxx_ops = { }; #endif -int t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { + struct cphy *phy = &pinfo->phy; int err; - cphy_init(phy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops, + cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &mv88e1xxx_ops, mdio_ops, SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); diff --git a/sys/dev/cxgb/common/cxgb_regs.h b/sys/dev/cxgb/common/cxgb_regs.h index dd8db9a..644fa26 100644 --- a/sys/dev/cxgb/common/cxgb_regs.h +++ b/sys/dev/cxgb/common/cxgb_regs.h @@ -280,6 +280,11 @@ $FreeBSD$ #define V_RSPQ7STARVED(x) ((x) << S_RSPQ7STARVED) #define F_RSPQ7STARVED V_RSPQ7STARVED(1U) +#define S_RSPQXSTARVED 0 +#define M_RSPQXSTARVED 0xff +#define V_RSPQXSTARVED(x) ((x) << S_RSPQXSTARVED) +#define G_RSPQXSTARVED(x) (((x) >> S_RSPQXSTARVED) & M_RSPQXSTARVED) + #define S_RSPQ0DISABLED 8 #define V_RSPQ0DISABLED(x) ((x) << S_RSPQ0DISABLED) #define F_RSPQ0DISABLED V_RSPQ0DISABLED(1U) @@ -376,6 +381,11 @@ $FreeBSD$ #define V_FL15EMPTY(x) ((x) << S_FL15EMPTY) #define F_FL15EMPTY V_FL15EMPTY(1U) +#define S_FLXEMPTY 16 +#define M_FLXEMPTY 0xffff +#define V_FLXEMPTY(x) ((x) << S_FLXEMPTY) +#define G_FLXEMPTY(x) (((x) >> S_FLXEMPTY) & M_FLXEMPTY) + #define A_SG_EGR_PRI_CNT 0x50 #define S_EGRERROPCODE 24 @@ -6235,10 +6245,28 @@ $FreeBSD$ #define V_ACK(x) ((x) << S_ACK) #define F_ACK V_ACK(1U) +#define S_I2C_DATA 0 +#define M_I2C_DATA 0xff +#define V_I2C_DATA(x) ((x) << S_I2C_DATA) +#define G_I2C_DATA(x) (((x) >> S_I2C_DATA) & M_I2C_DATA) + +#define S_I2C_BUSY 31 +#define V_I2C_BUSY(x) ((x) << S_I2C_BUSY) +#define F_I2C_BUSY V_I2C_BUSY(1U) + +#define S_I2C_ACK 30 +#define V_I2C_ACK(x) ((x) << S_I2C_ACK) +#define F_I2C_ACK V_I2C_ACK(1U) + #define S_I2C_CONT 1 #define V_I2C_CONT(x) ((x) << S_I2C_CONT) #define F_I2C_CONT V_I2C_CONT(1U) +#define S_I2C_RDWR 0 +#define V_I2C_RDWR(x) ((x) << S_I2C_RDWR) +#define F_I2C_READ V_I2C_RDWR(0U) +#define F_I2C_WRITE V_I2C_RDWR(1U) + /* registers for module MI1 */ #define MI1_BASE_ADDR 0x6b0 diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c index 5d6711e..e340058 100644 --- a/sys/dev/cxgb/common/cxgb_t3_hw.c +++ b/sys/dev/cxgb/common/cxgb_t3_hw.c @@ -189,6 +189,62 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, } /* + * Low-level I2C read and write routines. These simply read and write a + * single byte with the option of indicating a "continue" if another operation + * is to be chained. Generally most code will use higher-level routines to + * read and write to I2C Slave Devices. + */ +#define I2C_ATTEMPTS 100 + +/* + * Read an 8-bit value from the I2C bus. If the "chained" parameter is + * non-zero then a STOP bit will not be written after the read command. On + * error (the read timed out, etc.), a negative errno will be returned (e.g. + * -EAGAIN, etc.). On success, the 8-bit value read from the I2C bus is + * stored into the buffer *valp and the value of the I2C ACK bit is returned + * as a 0/1 value. + */ +int t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp) +{ + int ret; + u32 opval; + MDIO_LOCK(adapter); + t3_write_reg(adapter, A_I2C_OP, + F_I2C_READ | (chained ? F_I2C_CONT : 0)); + ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0, + I2C_ATTEMPTS, 10, &opval); + if (ret >= 0) { + ret = ((opval & F_I2C_ACK) == F_I2C_ACK); + *valp = G_I2C_DATA(t3_read_reg(adapter, A_I2C_DATA)); + } + MDIO_UNLOCK(adapter); + return ret; +} + +/* + * Write an 8-bit value to the I2C bus. If the "chained" parameter is + * non-zero, then a STOP bit will not be written after the write command. On + * error (the write timed out, etc.), a negative errno will be returned (e.g. + * -EAGAIN, etc.). On success, the value of the I2C ACK bit is returned as a + * 0/1 value. + */ +int t3_i2c_write8(adapter_t *adapter, int chained, u8 val) +{ + int ret; + u32 opval; + MDIO_LOCK(adapter); + t3_write_reg(adapter, A_I2C_DATA, V_I2C_DATA(val)); + t3_write_reg(adapter, A_I2C_OP, + F_I2C_WRITE | (chained ? F_I2C_CONT : 0)); + ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0, + I2C_ATTEMPTS, 10, &opval); + if (ret >= 0) + ret = ((opval & F_I2C_ACK) == F_I2C_ACK); + MDIO_UNLOCK(adapter); + return ret; +} + +/* * Initialize MI1. */ static void mi1_init(adapter_t *adap, const struct adapter_info *ai) @@ -515,7 +571,12 @@ static struct adapter_info t3_adap_info[] = { F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, - &mi1_mdio_ext_ops, "Chelsio N310" } + &mi1_mdio_ext_ops, "Chelsio T310" }, + { 1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, }; /* @@ -528,7 +589,7 @@ const struct adapter_info *t3_get_adapter_info(unsigned int id) } struct port_type_info { - int (*phy_prep)(struct cphy *phy, adapter_t *adapter, int phy_addr, + int (*phy_prep)(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *ops); }; @@ -542,6 +603,8 @@ static struct port_type_info port_types[] = { { t3_qt2045_phy_prep }, { t3_ael1006_phy_prep }, { t3_tn1010_phy_prep }, + { t3_aq100x_phy_prep }, + { t3_ael2020_phy_prep }, }; #define VPD_ENTRY(name, len) \ @@ -670,6 +733,125 @@ static unsigned int hex2int(unsigned char c) } /** + * get_desc_len - get the length of a vpd descriptor. + * @adapter: the adapter + * @offset: first byte offset of the vpd descriptor + * + * Retrieves the length of the small/large resource + * data type starting at offset. + */ +static int get_desc_len(adapter_t *adapter, u32 offset) +{ + u32 read_offset, tmp, shift, len = 0; + u8 tag, buf[8]; + int ret; + + read_offset = offset & 0xfffffffc; + shift = offset & 0x03; + + ret = t3_seeprom_read(adapter, read_offset, &tmp); + if (ret < 0) + return ret; + + *((u32 *)buf) = cpu_to_le32(tmp); + + tag = buf[shift]; + if (tag & 0x80) { + ret = t3_seeprom_read(adapter, read_offset + 4, &tmp); + if (ret < 0) + return ret; + + *((u32 *)(&buf[4])) = cpu_to_le32(tmp); + len = (buf[shift + 1] & 0xff) + + ((buf[shift+2] << 8) & 0xff00) + 3; + } else + len = (tag & 0x07) + 1; + + return len; +} + +/** + * is_end_tag - Check if a vpd tag is the end tag. + * @adapter: the adapter + * @offset: first byte offset of the tag + * + * Checks if the tag located at offset is the end tag. + */ +static int is_end_tag(adapter_t * adapter, u32 offset) +{ + u32 read_offset, shift, ret, tmp; + u8 buf[4]; + + read_offset = offset & 0xfffffffc; + shift = offset & 0x03; + + ret = t3_seeprom_read(adapter, read_offset, &tmp); + if (ret) + return ret; + *((u32 *)buf) = cpu_to_le32(tmp); + + if (buf[shift] == 0x78) + return 1; + else + return 0; +} + +/** + * t3_get_vpd_len - computes the length of a vpd structure + * @adapter: the adapter + * @vpd: contains the offset of first byte of vpd + * + * Computes the lentgh of the vpd structure starting at vpd->offset. + */ + +int t3_get_vpd_len(adapter_t * adapter, struct generic_vpd *vpd) +{ + u32 len=0, offset; + int inc, ret; + + offset = vpd->offset; + + while (offset < (vpd->offset + MAX_VPD_BYTES)) { + ret = is_end_tag(adapter, offset); + if (ret < 0) + return ret; + else if (ret == 1) + break; + + inc = get_desc_len(adapter, offset); + if (inc < 0) + return inc; + len += inc; + offset += inc; + } + return (len + 1); +} + +/** + * t3_read_vpd - reads the stream of bytes containing a vpd structure + * @adapter: the adapter + * @vpd: contains a buffer that would hold the stream of bytes + * + * Reads the vpd structure starting at vpd->offset into vpd->data, + * the length of the byte stream to read is vpd->len. + */ + +int t3_read_vpd(adapter_t *adapter, struct generic_vpd *vpd) +{ + u32 i, ret; + + for (i = 0; i < vpd->len; i += 4) { + ret = t3_seeprom_read(adapter, vpd->offset + i, + (u32 *) &(vpd->data[i])); + if (ret) + return ret; + } + + return 0; +} + + +/** * get_vpd_params - read VPD parameters from VPD EEPROM * @adapter: adapter to read * @p: where to store the parameters @@ -1313,11 +1495,6 @@ static void t3_clear_faults(adapter_t *adapter, int port_id) struct port_info *pi = adap2pinfo(adapter, port_id); struct cmac *mac = &pi->mac; - t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, - F_ENDROPPKT, 0); - t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); - t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, F_CLRSTATS, 1); - if (adapter->params.nports <= 2) { t3_xgm_intr_disable(adapter, pi->port_id); t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); @@ -1339,7 +1516,7 @@ static void t3_clear_faults(adapter_t *adapter, int port_id) */ void t3_link_changed(adapter_t *adapter, int port_id) { - int link_ok, speed, duplex, fc, link_fault, link_change; + int link_ok, speed, duplex, fc, link_fault; struct port_info *pi = adap2pinfo(adapter, port_id); struct cphy *phy = &pi->phy; struct cmac *mac = &pi->mac; @@ -1353,6 +1530,16 @@ void t3_link_changed(adapter_t *adapter, int port_id) phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + if (lc->requested_fc & PAUSE_AUTONEG) + fc &= lc->requested_fc; + else + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + /* Update mac speed before checking for link fault. */ + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE && + (speed != lc->speed || duplex != lc->duplex || fc != lc->fc)) + t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); + /* * Check for link faults if any of these is true: * a) A link fault is suspected, and PHY says link ok @@ -1368,11 +1555,8 @@ void t3_link_changed(adapter_t *adapter, int port_id) pi->link_fault = LF_YES; } - /* Don't report link up or any other change */ + /* Don't report link up */ link_ok = 0; - speed = lc->speed; - duplex = lc->duplex; - fc = lc->fc; } else { /* clear faults here if this was a false alarm. */ if (pi->link_fault == LF_MAYBE && @@ -1383,37 +1567,29 @@ void t3_link_changed(adapter_t *adapter, int port_id) } } - if (lc->requested_fc & PAUSE_AUTONEG) - fc &= lc->requested_fc; - else - fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - if (link_ok == lc->link_ok && speed == lc->speed && duplex == lc->duplex && fc == lc->fc) return; /* nothing changed */ - link_change = link_ok != lc->link_ok; lc->link_ok = (unsigned char)link_ok; lc->speed = speed < 0 ? SPEED_INVALID : speed; lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + lc->fc = fc; if (link_ok) { /* down -> up, or up -> up with changed settings */ - if (link_change && adapter->params.rev > 0 && - uses_xaui(adapter)) { - t3b_pcs_reset(mac); + if (adapter->params.rev > 0 && uses_xaui(adapter)) { t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, F_TXACTENABLE | F_RXEN); } - if (speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { - /* Set MAC settings to match PHY. */ - t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); - lc->fc = (unsigned char)fc; - } - + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, + F_ENDROPPKT, 0); + t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, + F_CLRSTATS, 1); t3_clear_faults(adapter, port_id); } else { @@ -1450,7 +1626,9 @@ void t3_link_changed(adapter_t *adapter, int port_id) t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN); } - t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); + t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc, + mac->was_reset); + mac->was_reset = 0; } /** @@ -1478,6 +1656,7 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) if (fc & PAUSE_RX) lc->advertising |= ADVERTISED_Pause; } + phy->ops->advertise(phy, lc->advertising); if (lc->autoneg == AUTONEG_DISABLE) { @@ -1490,7 +1669,7 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); /* PR 5666. Power phy up when doing an ifup */ if (!is_10G(phy->adapter)) - phy->ops->power_down(phy, 0); + phy->ops->power_down(phy, 0); } else phy->ops->autoneg_enable(phy); } else { @@ -2020,6 +2199,10 @@ int t3_phy_intr_handler(adapter_t *adapter) p->phy.fifo_errors++; if (phy_cause & cphy_cause_module_change) t3_os_phymod_changed(adapter, i); + if (phy_cause & cphy_cause_alarm) + CH_WARN(adapter, "Operation affected due to " + "adverse environment. Check the spec " + "sheet for corrective action."); } } @@ -3871,7 +4054,7 @@ static void config_pcie(adapter_t *adap) { 201, 321, 258, 450, 834, 1602 } }; - u16 val; + u16 val, devid; unsigned int log2_width, pldsize; unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; @@ -3880,6 +4063,18 @@ static void config_pcie(adapter_t *adap) &val); pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + /* + * Gen2 adapter pcie bridge compatibility requires minimum + * Max_Read_Request_size + */ + t3_os_pci_read_config_2(adap, 0x2, &devid); + if (devid == 0x37) { + t3_os_pci_write_config_2(adap, + adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, + val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD); + pldsize = 0; + } + t3_os_pci_read_config_2(adap, adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, &val); @@ -3934,7 +4129,7 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) goto out_err; if (adapter->params.nports > 2) - t3_mac_reset(&adap2pinfo(adapter, 0)->mac); + t3_mac_init(&adap2pinfo(adapter, 0)->mac); if (vpd->mclk) { partition_mem(adapter, &adapter->params.tp); @@ -4098,15 +4293,25 @@ static void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, adapter_t *adapter, int index) { + u16 devid; + mac->adapter = adapter; mac->multiport = adapter->params.nports > 2; if (mac->multiport) { mac->ext_port = (unsigned char)index; mac->nucast = 8; - index = 0; } else mac->nucast = 1; + /* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC + is connected to each port, its suppose to be using xgmac0 for both ports + */ + t3_os_pci_read_config_2(adapter, 0x2, &devid); + + if (mac->multiport || + (!adapter->params.vpd.xauicfg[1] && (devid==0x37))) + index = 0; + mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; if (adapter->params.rev == 0 && uses_xaui(adapter)) { @@ -4336,7 +4541,7 @@ int __devinit t3_prep_adapter(adapter_t *adapter, if (j >= ARRAY_SIZE(adapter->params.vpd.port_type)) return -EINVAL; } - ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ret = pti->phy_prep(p, ai->phy_base_addr + j, ai->mdio_ops); if (ret) return ret; @@ -4408,7 +4613,7 @@ int t3_reinit_adapter(adapter_t *adap) if (j >= ARRAY_SIZE(adap->params.vpd.port_type)) return -EINVAL; } - ret = pti->phy_prep(&p->phy, adap, p->phy.addr, NULL); + ret = pti->phy_prep(p, p->phy.addr, NULL); if (ret) return ret; p->phy.ops->power_down(&p->phy, 1); diff --git a/sys/dev/cxgb/common/cxgb_tn1010.c b/sys/dev/cxgb/common/cxgb_tn1010.c index 623f784..4575828 100644 --- a/sys/dev/cxgb/common/cxgb_tn1010.c +++ b/sys/dev/cxgb/common/cxgb_tn1010.c @@ -209,10 +209,10 @@ static struct cphy_ops tn1010_ops = { }; #endif -int t3_tn1010_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +int t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &tn1010_ops, mdio_ops, + cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &tn1010_ops, mdio_ops, SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_AUI | SUPPORTED_TP, "1000/10GBASE-T"); diff --git a/sys/dev/cxgb/common/cxgb_vsc8211.c b/sys/dev/cxgb/common/cxgb_vsc8211.c index 004f2f8..9d83859 100644 --- a/sys/dev/cxgb/common/cxgb_vsc8211.c +++ b/sys/dev/cxgb/common/cxgb_vsc8211.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); enum { VSC8211_SIGDET_CTRL = 19, VSC8211_EXT_CTRL = 23, + VSC8211_PHY_CTRL = 24, VSC8211_INTR_ENABLE = 25, VSC8211_INTR_STATUS = 26, VSC8211_LED_CTRL = 27, @@ -375,13 +376,62 @@ static struct cphy_ops vsc8211_fiber_ops = { }; #endif -int t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, +#define VSC8211_PHY_CTRL 24 + +#define S_VSC8211_TXFIFODEPTH 7 +#define M_VSC8211_TXFIFODEPTH 0x7 +#define V_VSC8211_TXFIFODEPTH(x) ((x) << S_VSC8211_TXFIFODEPTH) +#define G_VSC8211_TXFIFODEPTH(x) (((x) >> S_VSC8211_TXFIFODEPTH) & M_VSC8211_TXFIFODEPTH) + +#define S_VSC8211_RXFIFODEPTH 4 +#define M_VSC8211_RXFIFODEPTH 0x7 +#define V_VSC8211_RXFIFODEPTH(x) ((x) << S_VSC8211_RXFIFODEPTH) +#define G_VSC8211_RXFIFODEPTH(x) (((x) >> S_VSC8211_RXFIFODEPTH) & M_VSC8211_RXFIFODEPTH) + +int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port) +{ + /* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */ + unsigned int val = 4; + unsigned int currentregval; + unsigned int regval; + int err; + + /* Retrieve the port info structure from adater_t */ + struct port_info *portinfo = adap2pinfo(adap, port); + + /* What phy is this */ + struct cphy *phy = &portinfo->phy; + + /* Read the current value of the PHY control Register */ + err = mdio_read(phy, 0, VSC8211_PHY_CTRL, ¤tregval); + + if (err) + return err; + + /* IEEE mode supports up to 1518 bytes */ + /* mtu does not contain the header + FCS (18 bytes) */ + if (mtu > 1500) + /* + * If using a packet size > 1500 set TX FIFO Depth bits + * 9:7 to 011 (Jumbo packet mode) + */ + val = 3; + + regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) | + (currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) & + ~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH)); + + return mdio_write(phy, 0, VSC8211_PHY_CTRL, regval); +} + +int t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr, const struct mdio_ops *mdio_ops) { + struct cphy *phy = &pinfo->phy; int err; unsigned int val; - cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, + cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &vsc8211_ops, mdio_ops, SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c index 677f349..e323c9b 100644 --- a/sys/dev/cxgb/common/cxgb_xgmac.c +++ b/sys/dev/cxgb/common/cxgb_xgmac.c @@ -41,6 +41,28 @@ static inline int macidx(const struct cmac *mac) return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); } +/* + * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified. + */ +static inline int xgm_reset_ctrl(const struct cmac *mac) +{ + adapter_t *adap = mac->adapter; + int val = F_MAC_RESET_ | F_XGMAC_STOP_EN; + + if (is_10G(adap)) { + int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset); + + val |= F_PCS_RESET_; + if (G_PORTSPEED(cfg) != 3) /* not running at 10G */ + val |= F_XG2G_RESET_; + } else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + + return (val); +} + static void xaui_serdes_reset(struct cmac *mac) { static const unsigned int clear[] = { @@ -81,12 +103,12 @@ void t3b_pcs_reset(struct cmac *mac) } /** - * t3_mac_reset - reset a MAC - * @mac: the MAC to reset + * t3_mac_init - initialize a MAC + * @mac: the MAC to initialize * - * Reset the given MAC. + * Initialize the given MAC. */ -int t3_mac_reset(struct cmac *mac) +int t3_mac_init(struct cmac *mac) { static struct addr_val_pair mac_reset_avp[] = { { A_XGM_TX_CTRL, 0 }, @@ -138,7 +160,7 @@ int t3_mac_reset(struct cmac *mac) if (mac->multiport) { t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft, - MAX_FRAME_SIZE - 4); + V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4)); t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_DISPREAMBLE); t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE | @@ -154,13 +176,7 @@ int t3_mac_reset(struct cmac *mac) V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); - val = F_MAC_RESET_ | F_XGMAC_STOP_EN; - if (!mac->multiport) - val |= F_XG2G_RESET_; - if (uses_xaui(adap)) - val |= F_PCS_RESET_; - else - val |= F_RGMII_RESET_; + val = xgm_reset_ctrl(mac); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { @@ -172,16 +188,17 @@ int t3_mac_reset(struct cmac *mac) return 0; } -static int t3b2_mac_reset(struct cmac *mac) +static int t3_mac_reset(struct cmac *mac, int portspeed) { - u32 val; + u32 val, store_mps; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; int idx = macidx(mac); unsigned int store; /* Stop egress traffic to xgm*/ - if (!macidx(mac)) + store_mps = t3_read_reg(adap, A_MPS_CFG); + if (!idx) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); @@ -198,7 +215,7 @@ static int t3b2_mac_reset(struct cmac *mac) /* Store A_TP_TX_DROP_CFG_CH0 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx); + store = t3_read_reg(adap, A_TP_PIO_DATA); msleep(10); @@ -209,44 +226,55 @@ static int t3b2_mac_reset(struct cmac *mac) /* Check for xgm Rx fifo empty */ /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, - 0x80000000, 1, 1000, 2)) { - CH_ERR(adap, "MAC %d Rx fifo drain failed\n", - macidx(mac)); + 0x80000000, 1, 1000, 2) && portspeed < 0) { + CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); return -1; } - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ - (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if (portspeed >= 0) { + u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); - val = F_MAC_RESET_; - if (is_10G(adap)) - val |= F_PCS_RESET_; - else if (uses_xaui(adap)) - val |= F_PCS_RESET_ | F_XG2G_RESET_; - else - val |= F_RGMII_RESET_ | F_XG2G_RESET_; - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); - (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - if ((val & F_PCS_RESET_) && adap->params.rev) { - msleep(1); - t3b_pcs_reset(mac); + /* + * safespeedchange: wipes out pretty much all XGMAC registers. + */ + + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, + portspeed | F_SAFESPEEDCHANGE); + (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + F_SAFESPEEDCHANGE, 0); + (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); + t3_mac_init(mac); + + t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); + } else { + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ + (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + val = xgm_reset_ctrl(mac); + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + msleep(1); + t3b_pcs_reset(mac); + } + t3_write_reg(adap, A_XGM_RX_CFG + oft, + F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); } - t3_write_reg(adap, A_XGM_RX_CFG + oft, - F_DISPAUSEFRAMES | F_EN1536BFRAMES | - F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); /* Restore the DROP_CFG */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, store); /* Resume egress traffic to xgm */ - if (!macidx(mac)) - t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); - else - t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); + t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, + store_mps); /* Set: re-enable NIC traffic */ - t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); + t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); return 0; } @@ -409,6 +437,8 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) int ipg; unsigned int thres, v, reg; adapter_t *adap = mac->adapter; + unsigned port_type = adap->params.vpd.port_type[macidx(mac)]; + unsigned int orig_mtu=mtu; /* * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max @@ -422,6 +452,14 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) if (mac->multiport) return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); + /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */ + if (port_type == 2) { + int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac)); + + if (err) + return err; + } + if (adap->params.rev >= T3_REV_B2 && (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { t3_mac_disable_exact_filters(mac); @@ -507,10 +545,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; if (mac->multiport) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE + oft)) / 8); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, @@ -529,15 +569,27 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) else return -EINVAL; - t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, - V_PORTSPEED(M_PORTSPEED), val); + if (!uses_xaui(adap)) /* T302 */ + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + V_PORTSPEED(M_PORTSPEED), val); + else { + u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); + + if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { + t3_mac_reset(mac, val); + mac->was_reset = 1; + } + } } val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - if (fc & PAUSE_TX) - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE + oft)) / 8); + if (fc & PAUSE_TX) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); + } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, @@ -618,18 +670,12 @@ int t3_mac_disable(struct cmac *mac, int which) mac->txen = 0; } if (which & MAC_DIRECTION_RX) { - int val = F_MAC_RESET_; + int val = xgm_reset_ctrl(mac); t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, F_PCS_RESET_, 0); msleep(100); t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); - if (is_10G(adap)) - val |= F_PCS_RESET_; - else if (uses_xaui(adap)) - val |= F_PCS_RESET_ | F_XG2G_RESET_; - else - val |= F_RGMII_RESET_ | F_XG2G_RESET_; t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); } return 0; @@ -650,10 +696,15 @@ int t3b2_mac_watchdog_task(struct cmac *mac) tx_xcnt = 1; /* By default tx_xcnt is making progress*/ tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/ if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { + u32 cfg, active, enforcepkt; + tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset))); - if (tx_xcnt == 0) { + cfg = t3_read_reg(adap, A_MPS_CFG); + active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE; + enforcepkt = cfg & F_ENFORCEPKT; + if (active && enforcepkt && (tx_xcnt == 0)) { t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + macidx(mac)); tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, @@ -691,7 +742,7 @@ out: t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ mac->toggle_cnt++; } else if (status == 2) { - t3b2_mac_reset(mac); + t3_mac_reset(mac, -1); mac->toggle_cnt = 0; } return status; |