Commit bf14e9ec authored by David S. Miller's avatar David S. Miller

Merge branch 'bnxt_en-next'

Michael Chan says:

====================
bnxt_en: updates for net-next.

Non-critical bug fixes, improvements, a new ethtool feature, and a new
device ID.

v2: Fixed a bug in bnxt_get_module_eeprom() found by Ben Hutchings.

Ajit Khaparde (2):
  bnxt_en: Add Support for ETHTOOL_GMODULEINFO and ETHTOOL_GMODULEEEPRO
  bnxt_en: Report PCIe link speed and width during driver load

Michael Chan (6):
  bnxt_en: Reduce maximum ring pages if page size is 64K.
  bnxt_en: Improve the delay logic for firmware response.
  bnxt_en: Fix length value in dmesg log firmware error message.
  bnxt_en: Simplify and improve unsupported SFP+ module reporting.
  bnxt_en: Add BCM57314 device ID.
  bnxt_en: Use dma_rmb() instead of rmb().

Satish Baddipadige (1):
  bnxt_en: Fix invalid max channel parameter in ethtool -l.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 909b27f7 b67daab0
...@@ -78,6 +78,7 @@ enum board_idx { ...@@ -78,6 +78,7 @@ enum board_idx {
BCM57402, BCM57402,
BCM57404, BCM57404,
BCM57406, BCM57406,
BCM57314,
BCM57304_VF, BCM57304_VF,
BCM57404_VF, BCM57404_VF,
}; };
...@@ -92,6 +93,7 @@ static const struct { ...@@ -92,6 +93,7 @@ static const struct {
{ "Broadcom BCM57402 NetXtreme-E Dual-port 10Gb Ethernet" }, { "Broadcom BCM57402 NetXtreme-E Dual-port 10Gb Ethernet" },
{ "Broadcom BCM57404 NetXtreme-E Dual-port 10Gb/25Gb Ethernet" }, { "Broadcom BCM57404 NetXtreme-E Dual-port 10Gb/25Gb Ethernet" },
{ "Broadcom BCM57406 NetXtreme-E Dual-port 10GBase-T Ethernet" }, { "Broadcom BCM57406 NetXtreme-E Dual-port 10GBase-T Ethernet" },
{ "Broadcom BCM57314 NetXtreme-C Dual-port 10Gb/25Gb/40Gb/50Gb Ethernet" },
{ "Broadcom BCM57304 NetXtreme-C Ethernet Virtual Function" }, { "Broadcom BCM57304 NetXtreme-C Ethernet Virtual Function" },
{ "Broadcom BCM57404 NetXtreme-E Ethernet Virtual Function" }, { "Broadcom BCM57404 NetXtreme-E Ethernet Virtual Function" },
}; };
...@@ -103,6 +105,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = { ...@@ -103,6 +105,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
{ PCI_VDEVICE(BROADCOM, 0x16d0), .driver_data = BCM57402 }, { PCI_VDEVICE(BROADCOM, 0x16d0), .driver_data = BCM57402 },
{ PCI_VDEVICE(BROADCOM, 0x16d1), .driver_data = BCM57404 }, { PCI_VDEVICE(BROADCOM, 0x16d1), .driver_data = BCM57404 },
{ PCI_VDEVICE(BROADCOM, 0x16d2), .driver_data = BCM57406 }, { PCI_VDEVICE(BROADCOM, 0x16d2), .driver_data = BCM57406 },
{ PCI_VDEVICE(BROADCOM, 0x16df), .driver_data = BCM57314 },
#ifdef CONFIG_BNXT_SRIOV #ifdef CONFIG_BNXT_SRIOV
{ PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = BCM57304_VF }, { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = BCM57304_VF },
{ PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = BCM57404_VF }, { PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = BCM57404_VF },
...@@ -1324,15 +1327,6 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, ...@@ -1324,15 +1327,6 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
((data) & \ ((data) & \
HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK) HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK)
#define BNXT_EVENT_POLICY_MASK \
HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_ENFORCEMENT_POLICY_MASK
#define BNXT_EVENT_POLICY_SFT \
HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_ENFORCEMENT_POLICY_SFT
#define BNXT_GET_EVENT_POLICY(data) \
(((data) & BNXT_EVENT_POLICY_MASK) >> BNXT_EVENT_POLICY_SFT)
static int bnxt_async_event_process(struct bnxt *bp, static int bnxt_async_event_process(struct bnxt *bp,
struct hwrm_async_event_cmpl *cmpl) struct hwrm_async_event_cmpl *cmpl)
{ {
...@@ -1371,9 +1365,6 @@ static int bnxt_async_event_process(struct bnxt *bp, ...@@ -1371,9 +1365,6 @@ static int bnxt_async_event_process(struct bnxt *bp,
if (bp->pf.port_id != port_id) if (bp->pf.port_id != port_id)
break; break;
bp->link_info.last_port_module_event =
BNXT_GET_EVENT_POLICY(data1);
set_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event); set_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event);
break; break;
} }
...@@ -1503,7 +1494,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) ...@@ -1503,7 +1494,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
/* The valid test of the entry must be done first before /* The valid test of the entry must be done first before
* reading any further. * reading any further.
*/ */
rmb(); dma_rmb();
if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) { if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) {
tx_pkts++; tx_pkts++;
/* return full budget so NAPI will complete. */ /* return full budget so NAPI will complete. */
...@@ -2780,7 +2771,7 @@ void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type, ...@@ -2780,7 +2771,7 @@ void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type,
static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
int timeout, bool silent) int timeout, bool silent)
{ {
int i, intr_process, rc; int i, intr_process, rc, tmo_count;
struct input *req = msg; struct input *req = msg;
u32 *data = msg; u32 *data = msg;
__le32 *resp_len, *valid; __le32 *resp_len, *valid;
...@@ -2809,11 +2800,12 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, ...@@ -2809,11 +2800,12 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
timeout = DFLT_HWRM_CMD_TIMEOUT; timeout = DFLT_HWRM_CMD_TIMEOUT;
i = 0; i = 0;
tmo_count = timeout * 40;
if (intr_process) { if (intr_process) {
/* Wait until hwrm response cmpl interrupt is processed */ /* Wait until hwrm response cmpl interrupt is processed */
while (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID && while (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID &&
i++ < timeout) { i++ < tmo_count) {
usleep_range(600, 800); usleep_range(25, 40);
} }
if (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID) { if (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID) {
...@@ -2824,30 +2816,30 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, ...@@ -2824,30 +2816,30 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
} else { } else {
/* Check if response len is updated */ /* Check if response len is updated */
resp_len = bp->hwrm_cmd_resp_addr + HWRM_RESP_LEN_OFFSET; resp_len = bp->hwrm_cmd_resp_addr + HWRM_RESP_LEN_OFFSET;
for (i = 0; i < timeout; i++) { for (i = 0; i < tmo_count; i++) {
len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >> len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >>
HWRM_RESP_LEN_SFT; HWRM_RESP_LEN_SFT;
if (len) if (len)
break; break;
usleep_range(600, 800); usleep_range(25, 40);
} }
if (i >= timeout) { if (i >= tmo_count) {
netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n", netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n",
timeout, le16_to_cpu(req->req_type), timeout, le16_to_cpu(req->req_type),
le16_to_cpu(req->seq_id), *resp_len); le16_to_cpu(req->seq_id), len);
return -1; return -1;
} }
/* Last word of resp contains valid bit */ /* Last word of resp contains valid bit */
valid = bp->hwrm_cmd_resp_addr + len - 4; valid = bp->hwrm_cmd_resp_addr + len - 4;
for (i = 0; i < timeout; i++) { for (i = 0; i < 5; i++) {
if (le32_to_cpu(*valid) & HWRM_RESP_VALID_MASK) if (le32_to_cpu(*valid) & HWRM_RESP_VALID_MASK)
break; break;
usleep_range(600, 800); udelay(1);
} }
if (i >= timeout) { if (i >= 5) {
netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d v:%d\n", netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d v:%d\n",
timeout, le16_to_cpu(req->req_type), timeout, le16_to_cpu(req->req_type),
le16_to_cpu(req->seq_id), len, *valid); le16_to_cpu(req->seq_id), len, *valid);
...@@ -4734,6 +4726,7 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) ...@@ -4734,6 +4726,7 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
link_info->transceiver = resp->xcvr_pkg_type; link_info->transceiver = resp->xcvr_pkg_type;
link_info->phy_addr = resp->eee_config_phy_addr & link_info->phy_addr = resp->eee_config_phy_addr &
PORT_PHY_QCFG_RESP_PHY_ADDR_MASK; PORT_PHY_QCFG_RESP_PHY_ADDR_MASK;
link_info->module_status = resp->module_status;
if (bp->flags & BNXT_FLAG_EEE_CAP) { if (bp->flags & BNXT_FLAG_EEE_CAP) {
struct ethtool_eee *eee = &bp->eee; struct ethtool_eee *eee = &bp->eee;
...@@ -4786,6 +4779,33 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) ...@@ -4786,6 +4779,33 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
return 0; return 0;
} }
static void bnxt_get_port_module_status(struct bnxt *bp)
{
struct bnxt_link_info *link_info = &bp->link_info;
struct hwrm_port_phy_qcfg_output *resp = &link_info->phy_qcfg_resp;
u8 module_status;
if (bnxt_update_link(bp, true))
return;
module_status = link_info->module_status;
switch (module_status) {
case PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX:
case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN:
case PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG:
netdev_warn(bp->dev, "Unqualified SFP+ module detected on port %d\n",
bp->pf.port_id);
if (bp->hwrm_spec_code >= 0x10201) {
netdev_warn(bp->dev, "Module part number %s\n",
resp->phy_vendor_partnumber);
}
if (module_status == PORT_PHY_QCFG_RESP_MODULE_STATUS_DISABLETX)
netdev_warn(bp->dev, "TX is disabled\n");
if (module_status == PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN)
netdev_warn(bp->dev, "SFP+ module is shutdown\n");
}
}
static void static void
bnxt_hwrm_set_pause_common(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req) bnxt_hwrm_set_pause_common(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req)
{ {
...@@ -5078,7 +5098,8 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) ...@@ -5078,7 +5098,8 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
/* Enable TX queues */ /* Enable TX queues */
bnxt_tx_enable(bp); bnxt_tx_enable(bp);
mod_timer(&bp->timer, jiffies + bp->current_interval); mod_timer(&bp->timer, jiffies + bp->current_interval);
bnxt_update_link(bp, true); /* Poll link status and check for SFP+ module status */
bnxt_get_port_module_status(bp);
return 0; return 0;
...@@ -5613,28 +5634,6 @@ static void bnxt_timer(unsigned long data) ...@@ -5613,28 +5634,6 @@ static void bnxt_timer(unsigned long data)
mod_timer(&bp->timer, jiffies + bp->current_interval); mod_timer(&bp->timer, jiffies + bp->current_interval);
} }
static void bnxt_port_module_event(struct bnxt *bp)
{
struct bnxt_link_info *link_info = &bp->link_info;
struct hwrm_port_phy_qcfg_output *resp = &link_info->phy_qcfg_resp;
if (bnxt_update_link(bp, true))
return;
if (link_info->last_port_module_event != 0) {
netdev_warn(bp->dev, "Unqualified SFP+ module detected on port %d\n",
bp->pf.port_id);
if (bp->hwrm_spec_code >= 0x10201) {
netdev_warn(bp->dev, "Module part number %s\n",
resp->phy_vendor_partnumber);
}
}
if (link_info->last_port_module_event == 1)
netdev_warn(bp->dev, "TX is disabled\n");
if (link_info->last_port_module_event == 3)
netdev_warn(bp->dev, "Shutdown SFP+ module\n");
}
static void bnxt_cfg_ntp_filters(struct bnxt *); static void bnxt_cfg_ntp_filters(struct bnxt *);
static void bnxt_sp_task(struct work_struct *work) static void bnxt_sp_task(struct work_struct *work)
...@@ -5683,7 +5682,7 @@ static void bnxt_sp_task(struct work_struct *work) ...@@ -5683,7 +5682,7 @@ static void bnxt_sp_task(struct work_struct *work)
} }
if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event))
bnxt_port_module_event(bp); bnxt_get_port_module_status(bp);
if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event))
bnxt_hwrm_port_qstats(bp); bnxt_hwrm_port_qstats(bp);
...@@ -6260,6 +6259,22 @@ static int bnxt_set_dflt_rings(struct bnxt *bp) ...@@ -6260,6 +6259,22 @@ static int bnxt_set_dflt_rings(struct bnxt *bp)
return rc; return rc;
} }
static void bnxt_parse_log_pcie_link(struct bnxt *bp)
{
enum pcie_link_width width = PCIE_LNK_WIDTH_UNKNOWN;
enum pci_bus_speed speed = PCI_SPEED_UNKNOWN;
if (pcie_get_minimum_link(bp->pdev, &speed, &width) ||
speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN)
netdev_info(bp->dev, "Failed to determine PCIe Link Info\n");
else
netdev_info(bp->dev, "PCIe: Speed %s Width x%d\n",
speed == PCIE_SPEED_2_5GT ? "2.5GT/s" :
speed == PCIE_SPEED_5_0GT ? "5.0GT/s" :
speed == PCIE_SPEED_8_0GT ? "8.0GT/s" :
"Unknown", width);
}
static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
static int version_printed; static int version_printed;
...@@ -6380,6 +6395,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -6380,6 +6395,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
board_info[ent->driver_data].name, board_info[ent->driver_data].name,
(long)pci_resource_start(pdev, 0), dev->dev_addr); (long)pci_resource_start(pdev, 0), dev->dev_addr);
bnxt_parse_log_pcie_link(bp);
return 0; return 0;
init_err: init_err:
......
...@@ -425,10 +425,17 @@ struct rx_tpa_end_cmp_ext { ...@@ -425,10 +425,17 @@ struct rx_tpa_end_cmp_ext {
#define MAX_TPA 64 #define MAX_TPA 64
#if (BNXT_PAGE_SHIFT == 16)
#define MAX_RX_PAGES 1
#define MAX_RX_AGG_PAGES 4
#define MAX_TX_PAGES 1
#define MAX_CP_PAGES 8
#else
#define MAX_RX_PAGES 8 #define MAX_RX_PAGES 8
#define MAX_RX_AGG_PAGES 32 #define MAX_RX_AGG_PAGES 32
#define MAX_TX_PAGES 8 #define MAX_TX_PAGES 8
#define MAX_CP_PAGES 64 #define MAX_CP_PAGES 64
#endif
#define RX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct rx_bd)) #define RX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct rx_bd))
#define TX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_bd)) #define TX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_bd))
...@@ -831,6 +838,7 @@ struct bnxt_link_info { ...@@ -831,6 +838,7 @@ struct bnxt_link_info {
u16 lp_auto_link_speeds; u16 lp_auto_link_speeds;
u16 force_link_speed; u16 force_link_speed;
u32 preemphasis; u32 preemphasis;
u8 module_status;
/* copy of requested setting from ethtool cmd */ /* copy of requested setting from ethtool cmd */
u8 autoneg; u8 autoneg;
...@@ -842,7 +850,6 @@ struct bnxt_link_info { ...@@ -842,7 +850,6 @@ struct bnxt_link_info {
u32 advertising; u32 advertising;
bool force_link_chng; bool force_link_chng;
u8 last_port_module_event;
/* a copy of phy_qcfg output used to report link /* a copy of phy_qcfg output used to report link
* info to VF * info to VF
*/ */
...@@ -1123,6 +1130,16 @@ static inline void bnxt_disable_poll(struct bnxt_napi *bnapi) ...@@ -1123,6 +1130,16 @@ static inline void bnxt_disable_poll(struct bnxt_napi *bnapi)
#endif #endif
#define I2C_DEV_ADDR_A0 0xa0
#define I2C_DEV_ADDR_A2 0xa2
#define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e
#define SFP_EEPROM_SFF_8472_COMP_SIZE 1
#define SFF_MODULE_ID_SFP 0x3
#define SFF_MODULE_ID_QSFP 0xc
#define SFF_MODULE_ID_QSFP_PLUS 0xd
#define SFF_MODULE_ID_QSFP28 0x11
#define BNXT_MAX_PHY_I2C_RESP_SIZE 64
void bnxt_set_ring_params(struct bnxt *); void bnxt_set_ring_params(struct bnxt *);
void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16); void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
int _hwrm_send_message(struct bnxt *, void *, u32, int); int _hwrm_send_message(struct bnxt *, void *, u32, int);
......
...@@ -327,7 +327,11 @@ static void bnxt_get_channels(struct net_device *dev, ...@@ -327,7 +327,11 @@ static void bnxt_get_channels(struct net_device *dev,
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true);
channel->max_combined = max_rx_rings; channel->max_combined = max_rx_rings;
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false); if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) {
max_rx_rings = 0;
max_tx_rings = 0;
}
tcs = netdev_get_num_tc(dev); tcs = netdev_get_num_tc(dev);
if (tcs > 1) if (tcs > 1)
max_tx_rings /= tcs; max_tx_rings /= tcs;
...@@ -1494,6 +1498,125 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) ...@@ -1494,6 +1498,125 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)
return 0; return 0;
} }
static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr,
u16 page_number, u16 start_addr,
u16 data_length, u8 *buf)
{
struct hwrm_port_phy_i2c_read_input req = {0};
struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr;
int rc, byte_offset = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1);
req.i2c_slave_addr = i2c_addr;
req.page_number = cpu_to_le16(page_number);
req.port_id = cpu_to_le16(bp->pf.port_id);
do {
u16 xfer_size;
xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE);
data_length -= xfer_size;
req.page_offset = cpu_to_le16(start_addr + byte_offset);
req.data_length = xfer_size;
req.enables = cpu_to_le32(start_addr + byte_offset ?
PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (!rc)
memcpy(buf + byte_offset, output->data, xfer_size);
mutex_unlock(&bp->hwrm_cmd_lock);
byte_offset += xfer_size;
} while (!rc && data_length > 0);
return rc;
}
static int bnxt_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_port_phy_i2c_read_input req = {0};
struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr;
int rc;
/* No point in going further if phy status indicates
* module is not inserted or if it is powered down or
* if it is of type 10GBase-T
*/
if (bp->link_info.module_status >
PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG)
return -EOPNOTSUPP;
/* This feature is not supported in older firmware versions */
if (bp->hwrm_spec_code < 0x10202)
return -EOPNOTSUPP;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1);
req.i2c_slave_addr = I2C_DEV_ADDR_A0;
req.page_number = 0;
req.page_offset = cpu_to_le16(SFP_EEPROM_SFF_8472_COMP_ADDR);
req.data_length = SFP_EEPROM_SFF_8472_COMP_SIZE;
req.port_id = cpu_to_le16(bp->pf.port_id);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
u32 module_id = le32_to_cpu(output->data[0]);
switch (module_id) {
case SFF_MODULE_ID_SFP:
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break;
case SFF_MODULE_ID_QSFP:
case SFF_MODULE_ID_QSFP_PLUS:
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
break;
case SFF_MODULE_ID_QSFP28:
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
break;
default:
rc = -EOPNOTSUPP;
break;
}
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_get_module_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
u16 start = eeprom->offset, length = eeprom->len;
int rc;
memset(data, 0, eeprom->len);
/* Read A0 portion of the EEPROM */
if (start < ETH_MODULE_SFF_8436_LEN) {
if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN)
length = ETH_MODULE_SFF_8436_LEN - start;
rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0,
start, length, data);
if (rc)
return rc;
start += length;
data += length;
length = eeprom->len - length;
}
/* Read A2 portion of the EEPROM */
if (length) {
start -= ETH_MODULE_SFF_8436_LEN;
bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1, start,
length, data);
}
return rc;
}
const struct ethtool_ops bnxt_ethtool_ops = { const struct ethtool_ops bnxt_ethtool_ops = {
.get_settings = bnxt_get_settings, .get_settings = bnxt_get_settings,
.set_settings = bnxt_set_settings, .set_settings = bnxt_set_settings,
...@@ -1524,4 +1647,6 @@ const struct ethtool_ops bnxt_ethtool_ops = { ...@@ -1524,4 +1647,6 @@ const struct ethtool_ops bnxt_ethtool_ops = {
.get_link = bnxt_get_link, .get_link = bnxt_get_link,
.get_eee = bnxt_get_eee, .get_eee = bnxt_get_eee,
.set_eee = bnxt_set_eee, .set_eee = bnxt_set_eee,
.get_module_info = bnxt_get_module_info,
.get_module_eeprom = bnxt_get_module_eeprom,
}; };
...@@ -2093,6 +2093,40 @@ struct hwrm_port_phy_qcaps_output { ...@@ -2093,6 +2093,40 @@ struct hwrm_port_phy_qcaps_output {
#define PORT_PHY_QCAPS_RESP_VALID_SFT 24 #define PORT_PHY_QCAPS_RESP_VALID_SFT 24
}; };
/* hwrm_port_phy_i2c_read */
/* Input (40 bytes) */
struct hwrm_port_phy_i2c_read_input {
__le16 req_type;
__le16 cmpl_ring;
__le16 seq_id;
__le16 target_id;
__le64 resp_addr;
__le32 flags;
__le32 enables;
#define PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET 0x1UL
__le16 port_id;
u8 i2c_slave_addr;
u8 unused_0;
__le16 page_number;
__le16 page_offset;
u8 data_length;
u8 unused_1[7];
};
/* Output (80 bytes) */
struct hwrm_port_phy_i2c_read_output {
__le16 error_code;
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
__le32 data[16];
__le32 unused_0;
u8 unused_1;
u8 unused_2;
u8 unused_3;
u8 valid;
};
/* Input (24 bytes) */ /* Input (24 bytes) */
struct hwrm_queue_qportcfg_input { struct hwrm_queue_qportcfg_input {
__le16 req_type; __le16 req_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment