qlcnic: 83xx ethtool interface routines

83xx ethtool interface routines

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sony Chacko 2013-01-01 03:20:28 +00:00 committed by David S. Miller
parent 4e60ac4641
commit 7e38d04bcb
6 changed files with 749 additions and 192 deletions

View file

@ -352,6 +352,7 @@ struct qlcnic_rx_buffer {
#define QLCNIC_INTR_DEFAULT 0x04
#define QLCNIC_CONFIG_INTR_COALESCE 3
#define QLCNIC_DEV_INFO_SIZE 1
struct qlcnic_nic_intr_coalesce {
u8 type;
@ -942,6 +943,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_AER 5
#define __QLCNIC_DIAG_RES_ALLOC 6
#define __QLCNIC_LED_ENABLE 7
#define __QLCNIC_ELB_INPROGRESS 8
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2

View file

@ -2383,3 +2383,375 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
return 0;
}
int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
{
int err;
u32 config = 0, state;
struct qlcnic_cmd_args cmd;
struct qlcnic_hardware_context *ahw = adapter->ahw;
state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) {
dev_info(&adapter->pdev->dev, "link state down\n");
return config;
}
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
err = qlcnic_issue_cmd(adapter, &cmd);
if (err) {
dev_info(&adapter->pdev->dev,
"Get Link Status Command failed: 0x%x\n", err);
goto out;
} else {
config = cmd.rsp.arg[1];
switch (QLC_83XX_CURRENT_LINK_SPEED(config)) {
case QLC_83XX_10M_LINK:
ahw->link_speed = SPEED_10;
break;
case QLC_83XX_100M_LINK:
ahw->link_speed = SPEED_100;
break;
case QLC_83XX_1G_LINK:
ahw->link_speed = SPEED_1000;
break;
case QLC_83XX_10G_LINK:
ahw->link_speed = SPEED_10000;
break;
default:
ahw->link_speed = 0;
break;
}
config = cmd.rsp.arg[3];
if (config & 1)
err = 1;
}
out:
qlcnic_free_mbx_args(&cmd);
return config;
}
int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
{
u32 config = 0;
int status = 0;
struct qlcnic_hardware_context *ahw = adapter->ahw;
/* Get port configuration info */
status = qlcnic_83xx_get_port_info(adapter);
/* Get Link Status related info */
config = qlcnic_83xx_test_link(adapter);
ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
/* hard code until there is a way to get it from flash */
ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
return status;
}
int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
struct ethtool_cmd *ecmd)
{
int status = 0;
u32 config = adapter->ahw->port_config;
if (ecmd->autoneg)
adapter->ahw->port_config |= BIT_15;
switch (ethtool_cmd_speed(ecmd)) {
case SPEED_10:
adapter->ahw->port_config |= BIT_8;
break;
case SPEED_100:
adapter->ahw->port_config |= BIT_9;
break;
case SPEED_1000:
adapter->ahw->port_config |= BIT_10;
break;
case SPEED_10000:
adapter->ahw->port_config |= BIT_11;
break;
default:
return -EINVAL;
}
status = qlcnic_83xx_set_port_config(adapter);
if (status) {
dev_info(&adapter->pdev->dev,
"Faild to Set Link Speed and autoneg.\n");
adapter->ahw->port_config = config;
}
return status;
}
static inline u64 *qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd,
u64 *data, int index)
{
u32 low, hi;
u64 val;
low = cmd->rsp.arg[index];
hi = cmd->rsp.arg[index + 1];
val = (((u64) low) | (((u64) hi) << 32));
*data++ = val;
return data;
}
static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *cmd, u64 *data,
int type, int *ret)
{
int err, k, total_regs;
*ret = 0;
err = qlcnic_issue_cmd(adapter, cmd);
if (err != QLCNIC_RCODE_SUCCESS) {
dev_info(&adapter->pdev->dev,
"Error in get statistics mailbox command\n");
*ret = -EIO;
return data;
}
total_regs = cmd->rsp.num;
switch (type) {
case QLC_83XX_STAT_MAC:
/* fill in MAC tx counters */
for (k = 2; k < 28; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
/* skip 24 bytes of reserved area */
/* fill in MAC rx counters */
for (k += 6; k < 60; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
/* skip 24 bytes of reserved area */
/* fill in MAC rx frame stats */
for (k += 6; k < 80; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
break;
case QLC_83XX_STAT_RX:
for (k = 2; k < 8; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
/* skip 8 bytes of reserved data */
for (k += 2; k < 24; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
/* skip 8 bytes containing RE1FBQ error data */
for (k += 2; k < total_regs; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
break;
case QLC_83XX_STAT_TX:
for (k = 2; k < 10; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
/* skip 8 bytes of reserved data */
for (k += 2; k < total_regs; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
break;
default:
dev_warn(&adapter->pdev->dev, "Unknown get statistics mode\n");
*ret = -EIO;
}
return data;
}
void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
{
struct qlcnic_cmd_args cmd;
int ret = 0;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
/* Get Tx stats */
cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);
cmd.rsp.num = QLC_83XX_TX_STAT_REGS;
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_TX, &ret);
if (ret) {
dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
goto out;
}
/* Get MAC stats */
cmd.req.arg[1] = BIT_2 | (adapter->portnum << 16);
cmd.rsp.num = QLC_83XX_MAC_STAT_REGS;
memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_MAC, &ret);
if (ret) {
dev_info(&adapter->pdev->dev,
"Error getting Rx stats\n");
goto out;
}
/* Get Rx stats */
cmd.req.arg[1] = adapter->recv_ctx->context_id << 16;
cmd.rsp.num = QLC_83XX_RX_STAT_REGS;
memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_RX, &ret);
if (ret)
dev_info(&adapter->pdev->dev,
"Error getting Tx stats\n");
out:
qlcnic_free_mbx_args(&cmd);
}
int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)
{
u32 major, minor, sub;
major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
sub = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {
dev_info(&adapter->pdev->dev, "%s: Reg test failed\n",
__func__);
return 1;
}
return 0;
}
int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)
{
return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *
sizeof(adapter->ahw->ext_reg_tbl)) +
(ARRAY_SIZE(qlcnic_83xx_reg_tbl) +
sizeof(adapter->ahw->reg_tbl));
}
int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
{
int i, j = 0;
for (i = QLCNIC_DEV_INFO_SIZE + 1;
j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++, j++)
regs_buff[i] = QLC_SHARED_REG_RD32(adapter, j);
for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)
regs_buff[i++] = QLCRDX(adapter->ahw, j);
return i;
}
int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *cmd)
{
u8 val;
int ret;
u32 data;
u16 intrpt_id, id;
if (adapter->flags & QLCNIC_MSIX_ENABLED)
intrpt_id = adapter->ahw->intr_tbl[0].id;
else
intrpt_id = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_ID);
cmd->req.arg[1] = 1;
cmd->req.arg[2] = intrpt_id;
cmd->req.arg[3] = BIT_0;
ret = qlcnic_issue_cmd(adapter, cmd);
data = cmd->rsp.arg[2];
id = LSW(data);
val = LSB(MSW(data));
if (id != intrpt_id)
dev_info(&adapter->pdev->dev,
"Interrupt generated: 0x%x, requested:0x%x\n",
id, intrpt_id);
if (val)
dev_info(&adapter->pdev->dev,
"Interrupt test error: 0x%x\n", val);
return ret;
}
void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,
struct ethtool_pauseparam *pause)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
int status = 0;
u32 config;
status = qlcnic_83xx_get_port_config(adapter);
if (status) {
dev_err(&adapter->pdev->dev,
"%s: Get Pause Config failed\n", __func__);
return;
}
config = ahw->port_config;
if (config & QLC_83XX_CFG_STD_PAUSE) {
if (config & QLC_83XX_CFG_STD_TX_PAUSE)
pause->tx_pause = 1;
if (config & QLC_83XX_CFG_STD_RX_PAUSE)
pause->rx_pause = 1;
}
if (QLC_83XX_AUTONEG(config))
pause->autoneg = 1;
}
int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
struct ethtool_pauseparam *pause)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
int status = 0;
u32 config;
status = qlcnic_83xx_get_port_config(adapter);
if (status) {
dev_err(&adapter->pdev->dev,
"%s: Get Pause Config failed.\n", __func__);
return status;
}
config = ahw->port_config;
if (ahw->port_type == QLCNIC_GBE) {
if (pause->autoneg)
ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;
if (!pause->autoneg)
ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;
} else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {
return -EOPNOTSUPP;
}
if (!(config & QLC_83XX_CFG_STD_PAUSE))
ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;
if (pause->rx_pause && pause->tx_pause) {
ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;
} else if (pause->rx_pause && !pause->tx_pause) {
ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;
ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;
} else if (pause->tx_pause && !pause->rx_pause) {
ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;
ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;
} else if (!pause->rx_pause && !pause->tx_pause) {
ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE;
}
status = qlcnic_83xx_set_port_config(adapter);
if (status) {
dev_err(&adapter->pdev->dev,
"%s: Set Pause Config failed.\n", __func__);
ahw->port_config = config;
}
return status;
}
static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
{
int ret;
qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
QLC_83XX_FLASH_OEM_READ_SIG);
qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
QLC_83XX_FLASH_READ_CTRL);
ret = qlcnic_83xx_poll_flash_status_reg(adapter);
if (ret)
return -EIO;
ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
return ret & 0xFF;
}
int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
{
int status;
status = qlcnic_83xx_read_flash_status_reg(adapter);
if (status == -EIO) {
dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",
__func__);
return 1;
}
return 0;
}

View file

@ -337,8 +337,6 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
void qlcnic_83xx_get_stats(struct qlcnic_adapter *,
struct ethtool_stats *, u64 *);
int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *, int);
@ -409,4 +407,18 @@ int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data);
int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
struct ethtool_pauseparam *);
int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *,
struct ethtool_pauseparam *);
int qlcnic_83xx_test_link(struct qlcnic_adapter *);
int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *,
struct qlcnic_cmd_args *);
int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
#endif

View file

@ -22,42 +22,37 @@ struct qlcnic_stats {
#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
static const u32 qlcnic_fw_dump_level[] = {
0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
};
static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
{"xmit_called",
QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
{"xmit_finished",
QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
{"rx_dropped",
QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
{"tx_dropped",
QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
{"csummed",
QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
{"rx_pkts",
QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
{"lro_pkts",
QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"rx_bytes",
QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
{"tx_bytes",
QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
{"lrobytes",
QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames",
QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
{"xmit_on",
QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
{"xmit_off",
QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"xmit_called", QLC_SIZEOF(stats.xmitcalled),
QLC_OFF(stats.xmitcalled)},
{"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
QLC_OFF(stats.xmitfinished)},
{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
{"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
{"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)},
{"null rxbuf",
QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
QLC_OFF(stats.skb_alloc_failure)},
{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
QLC_OFF(stats.rx_dma_map_error)},
{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
QLC_OFF(stats.tx_dma_map_error)},
{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
QLC_OFF(stats.mac_filter_limit_overrun)},
{"spurious intr", QLC_SIZEOF(stats.spurious_intr),
QLC_OFF(stats.spurious_intr)},
};
@ -78,7 +73,15 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx numbytes",
};
static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_tx_bytes",
"ctx_tx_pkts",
"ctx_tx_errors",
"ctx_tx_dropped_pkts",
"ctx_tx_num_buffers",
};
static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
"mac_tx_frames",
"mac_tx_bytes",
"mac_tx_mcast_pkts",
@ -110,25 +113,62 @@ static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
"mac_rx_length_large",
"mac_rx_jabber",
"mac_rx_dropped",
"mac_rx_crc_error",
"mac_crc_error",
"mac_align_error",
};
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_rx_bytes",
"ctx_rx_pkts",
"ctx_lro_pkt_cnt",
"ctx_ip_csum_error",
"ctx_rx_pkts_wo_ctx",
"ctx_rx_pkts_dropped_wo_sts",
"ctx_rx_osized_pkts",
"ctx_rx_pkts_dropped_wo_rds",
"ctx_rx_unexpected_mcast_pkts",
"ctx_invalid_mac_address",
"ctx_rx_rds_ring_prim_attemoted",
"ctx_rx_rds_ring_prim_success",
"ctx_num_lro_flows_added",
"ctx_num_lro_flows_removed",
"ctx_num_lro_flows_active",
"ctx_pkts_dropped_unknown",
};
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline",
"Interrupt_Test_offline",
"Internal_Loopback_offline",
"External_Loopback_offline"
"EEPROM_Test_offline"
};
#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
static inline int qlcnic_82xx_statistics(void)
{
return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
}
static inline int qlcnic_83xx_statistics(void)
{
return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
}
static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
{
if (qlcnic_82xx_check(adapter))
return qlcnic_82xx_statistics();
else if (qlcnic_83xx_check(adapter))
return qlcnic_83xx_statistics();
else
return -1;
}
#define QLCNIC_RING_REGS_COUNT 20
#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
#define QLCNIC_MAX_EEPROM_LEN 1024
@ -148,6 +188,12 @@ static const u32 diag_registers[] = {
QLCNIC_PEG_ALIVE_COUNTER,
QLCNIC_PEG_HALT_STATUS1,
QLCNIC_PEG_HALT_STATUS2,
-1
};
static const u32 ext_diag_registers[] = {
CRB_XG_STATE_P3P,
ISR_INT_STATE_REG,
QLCNIC_CRB_PEG_NET_0+0x3c,
QLCNIC_CRB_PEG_NET_1+0x3c,
QLCNIC_CRB_PEG_NET_2+0x3c,
@ -156,12 +202,19 @@ static const u32 diag_registers[] = {
};
#define QLCNIC_MGMT_API_VERSION 2
#define QLCNIC_DEV_INFO_SIZE 1
#define QLCNIC_ETHTOOL_REGS_VER 2
#define QLCNIC_ETHTOOL_REGS_VER 3
static int qlcnic_get_regs_len(struct net_device *dev)
{
return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
QLCNIC_DEV_INFO_SIZE + 1;
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 len;
if (qlcnic_83xx_check(adapter))
len = qlcnic_83xx_get_regs_len(adapter);
else
len = sizeof(ext_diag_registers) + sizeof(diag_registers);
return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
}
static int qlcnic_get_eeprom_len(struct net_device *dev)
@ -174,10 +227,9 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 fw_major, fw_minor, fw_build;
fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%d.%d.%d", fw_major, fw_minor, fw_build);
@ -192,7 +244,10 @@ static int
qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
u32 speed, reg;
int check_sfp_module = 0;
u16 pcifn = ahw->pci_func;
/* read which mode */
if (adapter->ahw->port_type == QLCNIC_GBE) {
@ -213,9 +268,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->autoneg = adapter->ahw->link_autoneg;
} else if (adapter->ahw->port_type == QLCNIC_XGBE) {
u32 val;
u32 val = 0;
if (qlcnic_83xx_check(adapter))
qlcnic_83xx_get_settings(adapter);
else
val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
if (val == QLCNIC_PORT_MODE_802_3_AP) {
ecmd->supported = SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_1000baseT_Full;
@ -225,6 +283,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_running(dev) && adapter->ahw->has_link_events) {
if (qlcnic_82xx_check(adapter)) {
reg = QLCRD32(adapter,
P3P_LINK_SPEED_REG(pcifn));
speed = P3P_LINK_SPEED_VAL(pcifn, reg);
ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
}
ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
ecmd->autoneg = adapter->ahw->link_autoneg;
ecmd->duplex = adapter->ahw->link_duplex;
@ -294,6 +358,13 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
}
break;
case QLCNIC_BRDTYPE_83XX_10G:
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
ecmd->port = PORT_FIBRE;
check_sfp_module = netif_running(dev) && ahw->has_link_events;
break;
default:
dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
adapter->ahw->board_type);
@ -321,16 +392,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return 0;
}
static int
qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
struct ethtool_cmd *ecmd)
{
u32 config = 0;
u32 ret = 0;
struct qlcnic_adapter *adapter = netdev_priv(dev);
if (adapter->ahw->port_type != QLCNIC_GBE)
return -EOPNOTSUPP;
u32 ret = 0, config = 0;
/* read which mode */
if (ecmd->duplex)
config |= 0x1;
@ -358,6 +423,24 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EOPNOTSUPP;
else if (ret)
return -EIO;
return ret;
}
static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u32 ret = 0;
struct qlcnic_adapter *adapter = netdev_priv(dev);
if (adapter->ahw->port_type != QLCNIC_GBE)
return -EOPNOTSUPP;
if (qlcnic_83xx_check(adapter))
ret = qlcnic_83xx_set_settings(adapter, ecmd);
else
ret = qlcnic_set_port_config(adapter, ecmd);
if (!ret)
return ret;
adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
adapter->ahw->link_duplex = ecmd->duplex;
@ -370,6 +453,19 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return dev->netdev_ops->ndo_open(dev);
}
static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
u32 *regs_buff)
{
int i, j = 0;
for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
j = 0;
while (ext_diag_registers[j] != -1)
regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
return i;
}
static void
qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
@ -377,17 +473,20 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring;
u32 *regs_buff = p;
int ring, i = 0, j = 0;
int ring, i = 0;
memset(p, 0, qlcnic_get_regs_len(dev));
regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
(adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
regs_buff[1] = QLCNIC_MGMT_API_VERSION;
for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
if (qlcnic_82xx_check(adapter))
i = qlcnic_82xx_get_registers(adapter, regs_buff);
else
i = qlcnic_83xx_get_registers(adapter, regs_buff);
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return;
@ -415,6 +514,10 @@ static u32 qlcnic_test_link(struct net_device *dev)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 val;
if (qlcnic_83xx_check(adapter)) {
val = qlcnic_83xx_test_link(adapter);
return (val & 1) ? 0 : 1;
}
val = QLCRD32(adapter, CRB_XG_STATE_P3P);
val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
return (val == XG_LINK_UP_P3P) ? 0 : 1;
@ -426,8 +529,10 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int offset;
int ret;
int ret = -1;
if (qlcnic_83xx_check(adapter))
return 0;
if (eeprom->len == 0)
return -EINVAL;
@ -435,8 +540,9 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
((adapter->pdev)->device << 16);
offset = eeprom->offset;
ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
eeprom->len);
if (qlcnic_82xx_check(adapter))
ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
eeprom->len);
if (ret < 0)
return ret;
@ -547,6 +653,10 @@ qlcnic_get_pauseparam(struct net_device *netdev,
int port = adapter->ahw->physical_port;
__u32 val;
if (qlcnic_83xx_check(adapter)) {
qlcnic_83xx_get_pauseparam(adapter, pause);
return;
}
if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return;
@ -592,6 +702,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
int port = adapter->ahw->physical_port;
__u32 val;
if (qlcnic_83xx_check(adapter))
return qlcnic_83xx_set_pauseparam(adapter, pause);
/* read mode */
if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
@ -606,6 +719,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
val);
QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
/* set autoneg */
val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
switch (port) {
@ -668,6 +782,9 @@ static int qlcnic_reg_test(struct net_device *dev)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 data_read;
if (qlcnic_83xx_check(adapter))
return qlcnic_83xx_reg_test(adapter);
data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
if ((data_read & 0xffff) != adapter->pdev->vendor)
return 1;
@ -675,16 +792,30 @@ static int qlcnic_reg_test(struct net_device *dev)
return 0;
}
static int qlcnic_eeprom_test(struct net_device *dev)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
if (qlcnic_82xx_check(adapter))
return 0;
return qlcnic_83xx_flash_test(adapter);
}
static int qlcnic_get_sset_count(struct net_device *dev, int sset)
{
int len;
struct qlcnic_adapter *adapter = netdev_priv(dev);
switch (sset) {
case ETH_SS_TEST:
return QLCNIC_TEST_LEN;
case ETH_SS_STATS:
if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
return QLCNIC_TOTAL_STATS_LEN;
len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
qlcnic_83xx_check(adapter))
return len;
return qlcnic_82xx_statistics();
default:
return -EOPNOTSUPP;
}
@ -707,8 +838,12 @@ static int qlcnic_irq_test(struct net_device *netdev)
adapter->ahw->diag_cnt = 0;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
cmd.req.arg[1] = adapter->ahw->pci_func;
ret = qlcnic_issue_cmd(adapter, &cmd);
if (qlcnic_83xx_check(adapter)) {
ret = qlcnic_83xx_interrupt_test(adapter, &cmd);
} else {
cmd.req.arg[1] = adapter->ahw->pci_func;
ret = qlcnic_issue_cmd(adapter, &cmd);
}
if (ret)
goto done;
@ -760,11 +895,10 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
skb_put(skb, QLCNIC_ILB_PKT_SIZE);
adapter->ahw->diag_cnt = 0;
qlcnic_xmit_frame(skb, adapter->netdev);
loop = 0;
do {
msleep(1);
qlcnic_process_rcv_ring_diag(sds_ring);
@ -775,18 +909,18 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
dev_kfree_skb_any(skb);
if (!adapter->ahw->diag_cnt)
QLCDB(adapter, DRV,
"LB Test: packet #%d was not received\n", i + 1);
dev_warn(&adapter->pdev->dev,
"LB Test: packet #%d was not received\n",
i + 1);
else
cnt++;
}
if (cnt != i) {
dev_warn(&adapter->pdev->dev, "LB Test failed\n");
if (mode != QLCNIC_ILB_MODE) {
dev_err(&adapter->pdev->dev,
"LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
if (mode != QLCNIC_ILB_MODE)
dev_warn(&adapter->pdev->dev,
"WARNING: Please make sure external"
"loopback connector is plugged in\n");
}
"WARNING: Please check loopback cable\n");
return -1;
}
return 0;
@ -797,20 +931,23 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int max_sds_rings = adapter->max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_hardware_context *ahw = adapter->ahw;
int loop = 0;
int ret;
if (!(adapter->ahw->capabilities &
QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
netdev_info(netdev, "Firmware is not loopback test capable\n");
if (qlcnic_83xx_check(adapter))
goto skip_cap;
if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
dev_info(&adapter->pdev->dev,
"Firmware do not support loopback test\n");
return -EOPNOTSUPP;
}
QLCDB(adapter, DRV, "%s loopback test in progress\n",
mode == QLCNIC_ILB_MODE ? "internal" : "external");
if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(netdev, "Loopback test not supported for non "
"privilege function\n");
skip_cap:
dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
mode == QLCNIC_ILB_MODE ? "internal" : "external");
if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
dev_warn(&adapter->pdev->dev,
"Loopback test not supported in nonprivileged mode\n");
return 0;
}
@ -822,12 +959,14 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
goto clear_it;
sds_ring = &adapter->recv_ctx->sds_rings[0];
ret = qlcnic_set_lb_mode(adapter, mode);
if (ret)
goto free_res;
adapter->ahw->diag_cnt = 0;
if (qlcnic_83xx_check(adapter))
goto skip_fw_msg;
ahw->diag_cnt = 0;
do {
msleep(500);
qlcnic_process_rcv_ring_diag(sds_ring);
@ -840,10 +979,22 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
ret = adapter->ahw->diag_cnt;
goto free_res;
}
} while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
} while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
skip_fw_msg:
if (qlcnic_83xx_check(adapter)) {
/* wait until firmware report link up before running traffic */
loop = 0;
do {
msleep(500);
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
dev_info(&adapter->pdev->dev,
"No linkup event after LB req\n");
ret = -QLCNIC_FW_NOT_RESPOND;
goto free_res;
}
} while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
}
ret = qlcnic_do_lb_test(adapter, mode);
qlcnic_clear_lb_mode(adapter, mode);
free_res:
@ -877,20 +1028,18 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
if (data[3])
eth_test->flags |= ETH_TEST_FL_FAILED;
if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
if (data[4])
eth_test->flags |= ETH_TEST_FL_FAILED;
eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
}
data[4] = qlcnic_eeprom_test(dev);
if (data[4])
eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
static void
qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int index, i, j;
int index, i, num_stats;
switch (stringset) {
case ETH_SS_TEST:
@ -903,14 +1052,34 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
qlcnic_gstrings_stats[index].stat_string,
ETH_GSTRING_LEN);
}
for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_mac_stats_strings[j],
ETH_GSTRING_LEN);
if (qlcnic_83xx_check(adapter)) {
num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
for (i = 0; i < num_stats; i++, index++)
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_83xx_tx_stats_strings[i],
ETH_GSTRING_LEN);
num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
for (i = 0; i < num_stats; i++, index++)
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_83xx_mac_stats_strings[i],
ETH_GSTRING_LEN);
num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
for (i = 0; i < num_stats; i++, index++)
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_83xx_rx_stats_strings[i],
ETH_GSTRING_LEN);
return;
} else {
num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
for (i = 0; i < num_stats; i++, index++)
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_83xx_mac_stats_strings[i],
ETH_GSTRING_LEN);
}
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
for (i = 0; i < num_stats; index++, i++) {
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_device_gstrings_stats[i],
ETH_GSTRING_LEN);
@ -919,89 +1088,84 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
static void
qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
qlcnic_fill_stats(u64 *data, void *stats, int type)
{
int ind = *index;
if (type == QLCNIC_MAC_STATS) {
struct qlcnic_mac_statistics *mac_stats =
(struct qlcnic_mac_statistics *)stats;
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
data[ind++] =
QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
*data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
} else if (type == QLCNIC_ESW_STATS) {
struct __qlcnic_esw_statistics *esw_stats =
(struct __qlcnic_esw_statistics *)stats;
data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
*data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->errors);
*data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
}
*index = ind;
}
static void
qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
struct qlcnic_esw_statistics port_stats;
struct qlcnic_mac_statistics mac_stats;
int index, ret;
int index, ret, length, size;
char *p;
for (index = 0; index < QLCNIC_STATS_LEN; index++) {
char *p =
(char *)adapter +
qlcnic_gstrings_stats[index].stat_offset;
data[index] =
(qlcnic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
memset(data, 0, stats->n_stats * sizeof(u64));
length = QLCNIC_STATS_LEN;
for (index = 0; index < length; index++) {
p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
size = qlcnic_gstrings_stats[index].sizeof_stat;
*data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
}
/* Retrieve MAC statistics from firmware */
memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
qlcnic_get_mac_stats(adapter, &mac_stats);
qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
if (qlcnic_83xx_check(adapter)) {
if (adapter->ahw->linkup)
qlcnic_83xx_get_stats(adapter, data);
return;
} else {
/* Retrieve MAC statistics from firmware */
memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
qlcnic_get_mac_stats(adapter, &mac_stats);
qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
}
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
@ -1012,14 +1176,13 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
if (ret)
return;
qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
if (ret)
return;
qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
}
static int qlcnic_set_led(struct net_device *dev,
@ -1029,6 +1192,8 @@ static int qlcnic_set_led(struct net_device *dev,
int max_sds_rings = adapter->max_sds_rings;
int err = -EIO, active = 1;
if (qlcnic_83xx_check(adapter))
return -EOPNOTSUPP;
if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(dev, "LED test not supported for non "
"privilege function\n");
@ -1095,6 +1260,8 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
if (qlcnic_83xx_check(adapter))
return;
wol->supported = 0;
wol->wolopts = 0;
@ -1113,8 +1280,10 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
if (wol->wolopts & ~WAKE_MAGIC)
if (qlcnic_83xx_check(adapter))
return -EOPNOTSUPP;
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
if (!(wol_cfg & (1 << adapter->portnum)))
@ -1306,7 +1475,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
return 0;
}
netdev_info(netdev, "Forcing a FW dump\n");
qlcnic_dev_request_reset(adapter, 0);
qlcnic_dev_request_reset(adapter, val->flag);
break;
case QLCNIC_DISABLE_FW_DUMP:
if (fw_dump->enable && fw_dump->tmpl_hdr) {
@ -1326,7 +1495,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
return 0;
case QLCNIC_FORCE_FW_RESET:
netdev_info(netdev, "Forcing a FW reset\n");
qlcnic_dev_request_reset(adapter, 0);
qlcnic_dev_request_reset(adapter, val->flag);
adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
return 0;
case QLCNIC_SET_QUIESCENT:
@ -1340,8 +1509,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP;
}
for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
if (val->flag == FW_DUMP_LEVELS[i]) {
for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
if (val->flag == qlcnic_fw_dump_level[i]) {
fw_dump->tmpl_hdr->drv_cap_mask =
val->flag;
netdev_info(netdev, "Driver mask changed to: 0x%x\n",
@ -1385,10 +1554,3 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_dump_data = qlcnic_get_dump_data,
.set_dump = qlcnic_set_dump,
};
const struct ethtool_ops qlcnic_ethtool_failed_ops = {
.get_settings = qlcnic_get_settings,
.get_drvinfo = qlcnic_get_drvinfo,
.set_msglevel = qlcnic_set_msglevel,
.get_msglevel = qlcnic_get_msglevel,
};

View file

@ -909,7 +909,7 @@ int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
if (!(changed & NETIF_F_LRO))
return 0;
netdev->features = features ^ NETIF_F_LRO;
netdev->features ^= NETIF_F_LRO;
if (qlcnic_config_hw_lro(adapter, hw_lro))
return -EIO;

View file

@ -878,8 +878,8 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
if (qlcnic_83xx_check(adapter))
return;
features = (NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM | NETIF_F_GRO);
features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_IPV6_CSUM | NETIF_F_GRO);
vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM);
@ -894,12 +894,17 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
if (esw_cfg->offload_flags & BIT_0) {
netdev->features |= features;
adapter->rx_csum = 1;
if (!(esw_cfg->offload_flags & BIT_1))
if (!(esw_cfg->offload_flags & BIT_1)) {
netdev->features &= ~NETIF_F_TSO;
if (!(esw_cfg->offload_flags & BIT_2))
features &= ~NETIF_F_TSO;
}
if (!(esw_cfg->offload_flags & BIT_2)) {
netdev->features &= ~NETIF_F_TSO6;
features &= ~NETIF_F_TSO6;
}
} else {
netdev->features &= ~features;
features &= ~features;
adapter->rx_csum = 0;
}
@ -1518,7 +1523,10 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &adapter->recv_ctx->sds_rings[ring];
qlcnic_enable_int(sds_ring);
if (qlcnic_82xx_check(adapter))
qlcnic_enable_int(sds_ring);
else
qlcnic_83xx_enable_intr(adapter, sds_ring);
}
}
@ -1605,7 +1613,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_IPV6_CSUM | NETIF_F_GRO |
NETIF_F_HW_VLAN_RX);
netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
@ -1627,6 +1635,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
netdev->features |= NETIF_F_LRO;
netdev->hw_features = netdev->features;
netdev->irq = adapter->msix_entries[0].vector;
err = register_netdev(netdev);