diff options
author | Robert Mustacchi <rm@joyent.com> | 2018-02-06 22:58:28 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2018-09-13 22:12:11 +0000 |
commit | 286d309c80aad9eac1fdbcb0388ed194d995d837 (patch) | |
tree | 6ac14ccec669b3ef7b524bc01db09ede4d80822f /usr/src | |
parent | be4355ddcfa407e2d3e4a06973af5cbef6ccdbae (diff) | |
download | illumos-gate-286d309c80aad9eac1fdbcb0388ed194d995d837.tar.gz |
9805 i40e should read SFP data when firmware supports it
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Dale Ghent <dale.ghent@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/i40e/core/i40e_adminq_cmd.h | 20 | ||||
-rw-r--r-- | usr/src/uts/common/io/i40e/core/i40e_common.c | 70 | ||||
-rw-r--r-- | usr/src/uts/common/io/i40e/core/i40e_prototype.h | 9 | ||||
-rw-r--r-- | usr/src/uts/common/io/i40e/i40e_gld.c | 76 |
4 files changed, 173 insertions, 2 deletions
diff --git a/usr/src/uts/common/io/i40e/core/i40e_adminq_cmd.h b/usr/src/uts/common/io/i40e/core/i40e_adminq_cmd.h index fc70dc5891..49eb7caf4b 100644 --- a/usr/src/uts/common/io/i40e/core/i40e_adminq_cmd.h +++ b/usr/src/uts/common/io/i40e/core/i40e_adminq_cmd.h @@ -242,6 +242,8 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_set_phy_debug = 0x0622, i40e_aqc_opc_upload_ext_phy_fm = 0x0625, i40e_aqc_opc_run_phy_activity = 0x0626, + i40e_aqc_opc_set_phy_register = 0x0628, + i40e_aqc_opc_get_phy_register = 0x0629, /* NVM commands */ i40e_aqc_opc_nvm_read = 0x0701, @@ -1992,6 +1994,24 @@ struct i40e_aqc_run_phy_activity { I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity); + +/* Set PHY Register command (0x0628) */ +/* Get PHY Register command (0x0629) */ +struct i40e_aqc_phy_register_access { + u8 phy_interface; +#define I40E_AQ_PHY_REG_ACCESS_INTERNAL 0 +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL 1 +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE 2 + u8 dev_addres; + u8 reserved1[2]; + u32 reg_address; + u32 reg_value; + u8 reserved2[4]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access); + + /* NVM Read command (indirect 0x0701) * NVM Erase commands (direct 0x0702) * NVM Update commands (indirect 0x0703) diff --git a/usr/src/uts/common/io/i40e/core/i40e_common.c b/usr/src/uts/common/io/i40e/core/i40e_common.c index df50677faa..f4dd8da819 100644 --- a/usr/src/uts/common/io/i40e/core/i40e_common.c +++ b/usr/src/uts/common/io/i40e/core/i40e_common.c @@ -6563,6 +6563,76 @@ do_retry: wr32(hw, reg_addr, reg_val); } + +/** + * i40e_aq_set_phy_register + * @hw: pointer to the hw struct + * @phy_select: select which phy should be accessed + * @dev_addr: PHY device address + * @reg_addr: PHY register address + * @reg_val: new register value + * @cmd_details: pointer to command details structure or NULL + * + * Write the external PHY register. + **/ +enum i40e_status_code i40e_aq_set_phy_register(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, + u32 reg_addr, u32 reg_val, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_phy_register_access *cmd = + (struct i40e_aqc_phy_register_access *)&desc.params.raw; + enum i40e_status_code status; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_phy_register); + + cmd->phy_interface = phy_select; + cmd->dev_addres = dev_addr; + cmd->reg_address = reg_addr; + cmd->reg_value = reg_val; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + +/** + * i40e_aq_get_phy_register + * @hw: pointer to the hw struct + * @phy_select: select which phy should be accessed + * @dev_addr: PHY device address + * @reg_addr: PHY register address + * @reg_val: read register value + * @cmd_details: pointer to command details structure or NULL + * + * Read the external PHY register. + **/ +enum i40e_status_code i40e_aq_get_phy_register(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, + u32 reg_addr, u32 *reg_val, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_phy_register_access *cmd = + (struct i40e_aqc_phy_register_access *)&desc.params.raw; + enum i40e_status_code status; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_phy_register); + + cmd->phy_interface = phy_select; + cmd->dev_addres = dev_addr; + cmd->reg_address = reg_addr; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + if (!status) + *reg_val = cmd->reg_value; + + return status; +} + /** * i40e_aq_set_arp_proxy_config * @hw: pointer to the HW structure diff --git a/usr/src/uts/common/io/i40e/core/i40e_prototype.h b/usr/src/uts/common/io/i40e/core/i40e_prototype.h index c90a03c259..08433ebd11 100644 --- a/usr/src/uts/common/io/i40e/core/i40e_prototype.h +++ b/usr/src/uts/common/io/i40e/core/i40e_prototype.h @@ -502,6 +502,15 @@ enum i40e_status_code i40e_aq_rx_ctl_write_register(struct i40e_hw *hw, u32 reg_addr, u32 reg_val, struct i40e_asq_cmd_details *cmd_details); void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val); +enum i40e_status_code i40e_aq_set_phy_register(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, + u32 reg_addr, u32 reg_val, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_aq_get_phy_register(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, + u32 reg_addr, u32 *reg_val, + struct i40e_asq_cmd_details *cmd_details); + enum i40e_status_code i40e_aq_set_arp_proxy_config(struct i40e_hw *hw, struct i40e_aqc_arp_proxy_data *proxy_config, struct i40e_asq_cmd_details *cmd_details); diff --git a/usr/src/uts/common/io/i40e/i40e_gld.c b/usr/src/uts/common/io/i40e/i40e_gld.c index 9c7f860081..d34057d64f 100644 --- a/usr/src/uts/common/io/i40e/i40e_gld.c +++ b/usr/src/uts/common/io/i40e/i40e_gld.c @@ -11,7 +11,7 @@ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. - * Copyright (c) 2017, Joyent, Inc. + * Copyright (c) 2018, Joyent, Inc. * Copyright 2017 Tegile Systems, Inc. All rights reserved. */ @@ -582,6 +582,15 @@ i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) return (EINVAL); mutex_enter(&i40e->i40e_general_lock); + switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { + case I40E_MODULE_TYPE_SFP: + case I40E_MODULE_TYPE_QSFP: + break; + default: + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + present = !!(i40e->i40e_hw_space.phy.link_info.link_info & I40E_AQ_MEDIA_AVAILABLE); if (present) { @@ -599,6 +608,69 @@ i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) } static int +i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf, + size_t nbytes, off_t offset, size_t *nread) +{ + i40e_t *i40e = arg; + struct i40e_hw *hw = &i40e->i40e_hw_space; + uint8_t *buf8 = buf; + size_t i; + + if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL || + (page != 0xa0 && page != 0xa2) || offset < 0) + return (EINVAL); + + /* + * Both supported pages have a length of 256 bytes, ensure nothing asks + * us to go beyond that. + */ + if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) { + return (EINVAL); + } + + mutex_enter(&i40e->i40e_general_lock); + switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { + case I40E_MODULE_TYPE_SFP: + case I40E_MODULE_TYPE_QSFP: + break; + default: + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + + /* + * Make sure we have a sufficiently new firmware version to run this + * command. This was introduced in firmware API 1.7. This is apparently + * only supported on the XL710 MAC, not the XL722. + */ + if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 || + hw->aq.api_min_ver < 7) { + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + + for (i = 0; i < nbytes; i++, offset++) { + enum i40e_status_code status; + uint32_t val; + + status = i40e_aq_get_phy_register(hw, + I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, offset, + &val, NULL); + if (status != I40E_SUCCESS) { + mutex_exit(&i40e->i40e_general_lock); + return (EIO); + } + + buf8[i] = (uint8_t)val; + } + + mutex_exit(&i40e->i40e_general_lock); + *nread = nbytes; + + return (0); +} + +static int i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags) { i40e_t *i40e = arg; @@ -702,7 +774,7 @@ i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) mct->mct_flags = 0; mct->mct_ntransceivers = 1; mct->mct_info = i40e_transceiver_info; - mct->mct_read = NULL; + mct->mct_read = i40e_transceiver_read; return (B_TRUE); case MAC_CAPAB_LED: |