diff options
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 107 |
1 files changed, 106 insertions, 1 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index eb338212f5af..7852d98bad75 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -517,7 +517,8 @@ static int from_fw_port_mod_type(enum fw_port_type port_type, else return PORT_OTHER; } else if (port_type == FW_PORT_TYPE_KR4_100G || - port_type == FW_PORT_TYPE_KR_SFP28) { + port_type == FW_PORT_TYPE_KR_SFP28 || + port_type == FW_PORT_TYPE_KR_XLAUI) { return PORT_NONE; } @@ -645,6 +646,13 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full); break; + case FW_PORT_TYPE_KR_XLAUI: + SET_LMM(Backplane); + FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); + FW_CAPS_TO_LMM(SPEED_40G, 40000baseKR4_Full); + break; + case FW_PORT_TYPE_CR2_QSFP: SET_LMM(FIBRE); SET_LMM(50000baseSR2_Full); @@ -1396,6 +1404,101 @@ static int get_dump_data(struct net_device *dev, struct ethtool_dump *eth_dump, return 0; } +static int cxgb4_get_module_info(struct net_device *dev, + struct ethtool_modinfo *modinfo) +{ + struct port_info *pi = netdev_priv(dev); + u8 sff8472_comp, sff_diag_type, sff_rev; + struct adapter *adapter = pi->adapter; + int ret; + + if (!t4_is_inserted_mod_type(pi->mod_type)) + return -EINVAL; + + switch (pi->port_type) { + case FW_PORT_TYPE_SFP: + case FW_PORT_TYPE_QSA: + case FW_PORT_TYPE_SFP28: + ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, + I2C_DEV_ADDR_A0, SFF_8472_COMP_ADDR, + SFF_8472_COMP_LEN, &sff8472_comp); + if (ret) + return ret; + ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, + I2C_DEV_ADDR_A0, SFP_DIAG_TYPE_ADDR, + SFP_DIAG_TYPE_LEN, &sff_diag_type); + if (ret) + return ret; + + if (!sff8472_comp || (sff_diag_type & 4)) { + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + } + break; + + case FW_PORT_TYPE_QSFP: + case FW_PORT_TYPE_QSFP_10G: + case FW_PORT_TYPE_CR_QSFP: + case FW_PORT_TYPE_CR2_QSFP: + case FW_PORT_TYPE_CR4_QSFP: + ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, + I2C_DEV_ADDR_A0, SFF_REV_ADDR, + SFF_REV_LEN, &sff_rev); + /* For QSFP type ports, revision value >= 3 + * means the SFP is 8636 compliant. + */ + if (ret) + return ret; + if (sff_rev >= 0x3) { + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int cxgb4_get_module_eeprom(struct net_device *dev, + struct ethtool_eeprom *eprom, u8 *data) +{ + int ret = 0, offset = eprom->offset, len = eprom->len; + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + memset(data, 0, eprom->len); + if (offset + len <= I2C_PAGE_SIZE) + return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, + I2C_DEV_ADDR_A0, offset, len, data); + + /* offset + len spans 0xa0 and 0xa1 pages */ + if (offset <= I2C_PAGE_SIZE) { + /* read 0xa0 page */ + len = I2C_PAGE_SIZE - offset; + ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, + I2C_DEV_ADDR_A0, offset, len, data); + if (ret) + return ret; + offset = I2C_PAGE_SIZE; + /* Remaining bytes to be read from second page = + * Total length - bytes read from first page + */ + len = eprom->len - len; + } + /* Read additional optical diagnostics from page 0xa2 if supported */ + return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, I2C_DEV_ADDR_A2, + offset, len, &data[eprom->len - len]); +} + static const struct ethtool_ops cxgb_ethtool_ops = { .get_link_ksettings = get_link_ksettings, .set_link_ksettings = set_link_ksettings, @@ -1430,6 +1533,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_dump = set_dump, .get_dump_flag = get_dump_flag, .get_dump_data = get_dump_data, + .get_module_info = cxgb4_get_module_info, + .get_module_eeprom = cxgb4_get_module_eeprom, }; void cxgb4_set_ethtool_ops(struct net_device *netdev) |