qed: Add qed APIs for PHY module query.
authorSudarsana Reddy Kalluru <sudarsana.kalluru@cavium.com>
Wed, 18 Jul 2018 13:27:22 +0000 (06:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 20 Jul 2018 06:35:37 +0000 (23:35 -0700)
This patch adds qed APIs for reading the PHY module.

Signed-off-by: Sudarsana Reddy Kalluru <Sudarsana.Kalluru@cavium.com>
Signed-off-by: Ariel Elior <ariel.elior@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h
include/linux/qed/qed_if.h

index bee10c1..8faceb6 100644 (file)
@@ -12444,6 +12444,8 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_STATS_TYPE_ISCSI           3
 #define DRV_MSG_CODE_STATS_TYPE_RDMA            4
 
+#define DRV_MSG_CODE_TRANSCEIVER_READ           0x00160000
+
 #define DRV_MSG_CODE_MASK_PARITIES              0x001a0000
 
 #define DRV_MSG_CODE_BIST_TEST                 0x001e0000
@@ -12543,6 +12545,15 @@ struct public_drv_mb {
 #define DRV_MB_PARAM_SET_LED_MODE_ON           0x1
 #define DRV_MB_PARAM_SET_LED_MODE_OFF          0x2
 
+#define DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET           0
+#define DRV_MB_PARAM_TRANSCEIVER_PORT_MASK             0x00000003
+#define DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET           2
+#define DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK             0x000000FC
+#define DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET    8
+#define DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK      0x0000FF00
+#define DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET         16
+#define DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK           0xFFFF0000
+
        /* Resource Allocation params - Driver version support */
 #define DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_MASK 0xFFFF0000
 #define DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT        16
@@ -12596,6 +12607,9 @@ struct public_drv_mb {
 #define FW_MSG_CODE_PHY_OK                     0x00110000
 #define FW_MSG_CODE_OK                         0x00160000
 #define FW_MSG_CODE_ERROR                      0x00170000
+#define FW_MSG_CODE_TRANSCEIVER_DIAG_OK                0x00160000
+#define FW_MSG_CODE_TRANSCEIVER_DIAG_ERROR     0x00170000
+#define FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT    0x00020000
 
 #define FW_MSG_CODE_OS_WOL_SUPPORTED            0x00800000
 #define FW_MSG_CODE_OS_WOL_NOT_SUPPORTED        0x00810000
@@ -12687,6 +12701,8 @@ struct mcp_public_data {
        struct public_func func[MCP_GLOB_FUNC_MAX];
 };
 
+#define MAX_I2C_TRANSACTION_SIZE       16
+
 /* OCBB definitions */
 enum tlvs {
        /* Category 1: Device Properties */
index 0cbc74d..158944a 100644 (file)
@@ -2102,6 +2102,28 @@ out:
        return status;
 }
 
+static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf,
+                                 u8 dev_addr, u32 offset, u32 len)
+{
+       struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+       struct qed_ptt *ptt;
+       int rc = 0;
+
+       if (IS_VF(cdev))
+               return 0;
+
+       ptt = qed_ptt_acquire(hwfn);
+       if (!ptt)
+               return -EAGAIN;
+
+       rc = qed_mcp_phy_sfp_read(hwfn, ptt, MFW_PORT(hwfn), dev_addr,
+                                 offset, len, buf);
+
+       qed_ptt_release(hwfn, ptt);
+
+       return rc;
+}
+
 static struct qed_selftest_ops qed_selftest_ops_pass = {
        .selftest_memory = &qed_selftest_memory,
        .selftest_interrupt = &qed_selftest_interrupt,
@@ -2144,6 +2166,7 @@ const struct qed_common_ops qed_common_ops_pass = {
        .update_mac = &qed_update_mac,
        .update_mtu = &qed_update_mtu,
        .update_wol = &qed_update_wol,
+       .read_module_eeprom = &qed_read_module_eeprom,
 };
 
 void qed_get_protocol_stats(struct qed_dev *cdev,
index 4e0b443..62a220f 100644 (file)
@@ -2463,6 +2463,55 @@ out:
        return rc;
 }
 
+int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                        u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf)
+{
+       u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0;
+       u32 resp, param;
+       int rc;
+
+       nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) &
+                      DRV_MB_PARAM_TRANSCEIVER_PORT_MASK;
+       nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) &
+                      DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK;
+
+       addr = offset;
+       offset = 0;
+       bytes_left = len;
+       while (bytes_left > 0) {
+               bytes_to_copy = min_t(u32, bytes_left,
+                                     MAX_I2C_TRANSACTION_SIZE);
+               nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK |
+                              DRV_MB_PARAM_TRANSCEIVER_PORT_MASK);
+               nvm_offset |= ((addr + offset) <<
+                              DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) &
+                              DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK;
+               nvm_offset |= (bytes_to_copy <<
+                              DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) &
+                              DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK;
+               rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt,
+                                       DRV_MSG_CODE_TRANSCEIVER_READ,
+                                       nvm_offset, &resp, &param, &buf_size,
+                                       (u32 *)(p_buf + offset));
+               if (rc) {
+                       DP_NOTICE(p_hwfn,
+                                 "Failed to send a transceiver read command to the MFW. rc = %d.\n",
+                                 rc);
+                       return rc;
+               }
+
+               if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT)
+                       return -ENODEV;
+               else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK)
+                       return -EINVAL;
+
+               offset += buf_size;
+               bytes_left -= buf_size;
+       }
+
+       return 0;
+}
+
 int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 {
        u32 drv_mb_param = 0, rsp, param;
index 632a838..047976d 100644 (file)
@@ -840,6 +840,22 @@ int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn,
                       u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf);
 
 /**
+ * @brief Read from sfp
+ *
+ *  @param p_hwfn - hw function
+ *  @param p_ptt  - PTT required for register access
+ *  @param port   - transceiver port
+ *  @param addr   - I2C address
+ *  @param offset - offset in sfp
+ *  @param len    - buffer length
+ *  @param p_buf  - buffer to read into
+ *
+ * @return int - 0 - operation was successful.
+ */
+int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                        u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf);
+
+/**
  * @brief indicates whether the MFW objects [under mcp_info] are accessible
  *
  * @param p_hwfn
index b404002..8cd3464 100644 (file)
@@ -759,6 +759,9 @@ struct qed_generic_tlvs {
        u8 mac[QED_TLV_MAC_COUNT][ETH_ALEN];
 };
 
+#define QED_I2C_DEV_ADDR_A0 0xA0
+#define QED_I2C_DEV_ADDR_A2 0xA2
+
 #define QED_NVM_SIGNATURE 0x12435687
 
 enum qed_nvm_flash_cmd {
@@ -1026,6 +1029,18 @@ struct qed_common_ops {
  * @param enabled - true iff WoL should be enabled.
  */
        int (*update_wol) (struct qed_dev *cdev, bool enabled);
+
+/**
+ * @brief read_module_eeprom
+ *
+ * @param cdev
+ * @param buf - buffer
+ * @param dev_addr - PHY device memory region
+ * @param offset - offset into eeprom contents to be read
+ * @param len - buffer length, i.e., max bytes to be read
+ */
+       int (*read_module_eeprom)(struct qed_dev *cdev,
+                                 char *buf, u8 dev_addr, u32 offset, u32 len);
 };
 
 #define MASK_FIELD(_name, _value) \