Merge branch 'qed-Add-support-for-phy-module-query'

Sudarsana Reddy Kalluru says:

====================
qed*: Add support for phy module query.

The patch series adds driver support for querying the PHY module's
eeprom data.

Please consider applying it to 'net-next'.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-07-19 23:35:38 -07:00
commit a3eed83a18
6 changed files with 207 additions and 0 deletions

View 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 */

View File

@ -2102,6 +2102,28 @@ static int qed_update_mtu(struct qed_dev *cdev, u16 mtu)
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,

View File

@ -2463,6 +2463,55 @@ int qed_mcp_nvm_write(struct qed_dev *cdev,
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;

View File

@ -839,6 +839,22 @@ int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn,
u32 *o_mcp_resp,
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
*

View File

@ -1780,6 +1780,92 @@ static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata)
return 0;
}
static int qede_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo)
{
struct qede_dev *edev = netdev_priv(dev);
u8 buf[4];
int rc;
/* Read first 4 bytes to find the sfp type */
rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
QED_I2C_DEV_ADDR_A0, 0, 4);
if (rc) {
DP_ERR(edev, "Failed reading EEPROM data %d\n", rc);
return rc;
}
switch (buf[0]) {
case 0x3: /* SFP, SFP+, SFP-28 */
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break;
case 0xc: /* QSFP */
case 0xd: /* QSFP+ */
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
break;
case 0x11: /* QSFP-28 */
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
break;
default:
DP_ERR(edev, "Unknown transceiver type 0x%x\n", buf[0]);
return -EINVAL;
}
return 0;
}
static int qede_get_module_eeprom(struct net_device *dev,
struct ethtool_eeprom *ee, u8 *data)
{
struct qede_dev *edev = netdev_priv(dev);
u32 start_addr = ee->offset, size = 0;
u8 *buf = data;
int rc = 0;
/* Read A0 section */
if (ee->offset < ETH_MODULE_SFF_8079_LEN) {
/* Limit transfer size to the A0 section boundary */
if (ee->offset + ee->len > ETH_MODULE_SFF_8079_LEN)
size = ETH_MODULE_SFF_8079_LEN - ee->offset;
else
size = ee->len;
rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
QED_I2C_DEV_ADDR_A0,
start_addr, size);
if (rc) {
DP_ERR(edev, "Failed reading A0 section %d\n", rc);
return rc;
}
buf += size;
start_addr += size;
}
/* Read A2 section */
if (start_addr >= ETH_MODULE_SFF_8079_LEN &&
start_addr < ETH_MODULE_SFF_8472_LEN) {
size = ee->len - size;
/* Limit transfer size to the A2 section boundary */
if (start_addr + size > ETH_MODULE_SFF_8472_LEN)
size = ETH_MODULE_SFF_8472_LEN - start_addr;
start_addr -= ETH_MODULE_SFF_8079_LEN;
rc = edev->ops->common->read_module_eeprom(edev->cdev, buf,
QED_I2C_DEV_ADDR_A2,
start_addr, size);
if (rc) {
DP_VERBOSE(edev, QED_MSG_DEBUG,
"Failed reading A2 section %d\n", rc);
return 0;
}
}
return rc;
}
static const struct ethtool_ops qede_ethtool_ops = {
.get_link_ksettings = qede_get_link_ksettings,
.set_link_ksettings = qede_set_link_ksettings,
@ -1813,6 +1899,8 @@ static const struct ethtool_ops qede_ethtool_ops = {
.get_channels = qede_get_channels,
.set_channels = qede_set_channels,
.self_test = qede_self_test,
.get_module_info = qede_get_module_info,
.get_module_eeprom = qede_get_module_eeprom,
.get_eee = qede_get_eee,
.set_eee = qede_set_eee,

View 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) \