summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2018-02-06 22:58:28 +0000
committerRobert Mustacchi <rm@joyent.com>2018-09-13 22:12:11 +0000
commit286d309c80aad9eac1fdbcb0388ed194d995d837 (patch)
tree6ac14ccec669b3ef7b524bc01db09ede4d80822f /usr/src
parentbe4355ddcfa407e2d3e4a06973af5cbef6ccdbae (diff)
downloadillumos-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.h20
-rw-r--r--usr/src/uts/common/io/i40e/core/i40e_common.c70
-rw-r--r--usr/src/uts/common/io/i40e/core/i40e_prototype.h9
-rw-r--r--usr/src/uts/common/io/i40e/i40e_gld.c76
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: