#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 25
-#define QLCNIC_LINUX_VERSIONID "5.0.25.1"
+#define _QLCNIC_LINUX_SUBVERSION 28
+#define QLCNIC_LINUX_VERSIONID "5.0.28.1"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
(((sts_data) >> 52) & 0x1)
#define qlcnic_get_lro_sts_seq_number(sts_data) \
((sts_data) & 0x0FFFFFFFF)
+#define qlcnic_get_lro_sts_mss(sts_data1) \
+ ((sts_data1 >> 32) & 0x0FFFF)
struct status_desc {
struct qlcnic_fw_dump {
u8 clr; /* flag to indicate if dump is cleared */
+ u32 pos; /* position in the dump buffer */
u8 enable; /* enable/disable dump */
u32 size; /* total size of the dump */
void *data; /* dump data area */
#define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E
#define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f
#define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030
+#define QLCNIC_CDRP_CMD_GET_MAC_STATS 0x00000037
#define QLCNIC_RCODE_SUCCESS 0
#define QLCNIC_RCODE_NOT_SUPPORTED 9
#define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7)
#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8)
#define QLCNIC_CAP0_VALIDOFF (1 << 11)
+#define QLCNIC_CAP0_LRO_MSS (1 << 21)
/*
* Context state
#define QLCNIC_FW_CAPABILITY_FVLANTX BIT_9
#define QLCNIC_FW_CAPABILITY_HW_LRO BIT_10
#define QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK BIT_27
+#define QLCNIC_FW_CAPABILITY_MORE_CAPS BIT_31
+
+#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
#define QLCNIC_NEED_FLR 0x1000
#define QLCNIC_FW_RESET_OWNER 0x2000
#define QLCNIC_FW_HANG 0x4000
+#define QLCNIC_FW_LRO_MSS_CAP 0x8000
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
#define QLCNIC_STATS_ESWITCH 2
#define QLCNIC_QUERY_RX_COUNTER 0
#define QLCNIC_QUERY_TX_COUNTER 1
-#define QLCNIC_ESW_STATS_NOT_AVAIL 0xffffffffffffffffULL
+#define QLCNIC_STATS_NOT_AVAIL 0xffffffffffffffffULL
+#define QLCNIC_FILL_STATS(VAL1) \
+ (((VAL1) == QLCNIC_STATS_NOT_AVAIL) ? 0 : VAL1)
+#define QLCNIC_MAC_STATS 1
+#define QLCNIC_ESW_STATS 2
#define QLCNIC_ADD_ESW_STATS(VAL1, VAL2)\
do { \
- if (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) && \
- ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \
+ if (((VAL1) == QLCNIC_STATS_NOT_AVAIL) && \
+ ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \
(VAL1) = (VAL2); \
- else if (((VAL1) != QLCNIC_ESW_STATS_NOT_AVAIL) && \
- ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \
+ else if (((VAL1) != QLCNIC_STATS_NOT_AVAIL) && \
+ ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \
(VAL1) += (VAL2); \
} while (0)
+struct qlcnic_mac_statistics{
+ __le64 mac_tx_frames;
+ __le64 mac_tx_bytes;
+ __le64 mac_tx_mcast_pkts;
+ __le64 mac_tx_bcast_pkts;
+ __le64 mac_tx_pause_cnt;
+ __le64 mac_tx_ctrl_pkt;
+ __le64 mac_tx_lt_64b_pkts;
+ __le64 mac_tx_lt_127b_pkts;
+ __le64 mac_tx_lt_255b_pkts;
+ __le64 mac_tx_lt_511b_pkts;
+ __le64 mac_tx_lt_1023b_pkts;
+ __le64 mac_tx_lt_1518b_pkts;
+ __le64 mac_tx_gt_1518b_pkts;
+ __le64 rsvd1[3];
+
+ __le64 mac_rx_frames;
+ __le64 mac_rx_bytes;
+ __le64 mac_rx_mcast_pkts;
+ __le64 mac_rx_bcast_pkts;
+ __le64 mac_rx_pause_cnt;
+ __le64 mac_rx_ctrl_pkt;
+ __le64 mac_rx_lt_64b_pkts;
+ __le64 mac_rx_lt_127b_pkts;
+ __le64 mac_rx_lt_255b_pkts;
+ __le64 mac_rx_lt_511b_pkts;
+ __le64 mac_rx_lt_1023b_pkts;
+ __le64 mac_rx_lt_1518b_pkts;
+ __le64 mac_rx_gt_1518b_pkts;
+ __le64 rsvd2[3];
+
+ __le64 mac_rx_length_error;
+ __le64 mac_rx_length_small;
+ __le64 mac_rx_length_large;
+ __le64 mac_rx_jabber;
+ __le64 mac_rx_dropped;
+ __le64 mac_rx_crc_error;
+ __le64 mac_align_error;
+} __packed;
+
struct __qlcnic_esw_statistics {
__le16 context_id;
__le16 version;
#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed
#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed
#define QLCNIC_FORCE_FW_RESET 0xdeaddead
+#define QLCNIC_SET_QUIESCENT 0xadd00010
+#define QLCNIC_RESET_QUIESCENT 0xadd00020
+
+#define QLCNIC_INVALID_KEY EINVAL
+
+#ifndef SPEED_UNKNOWN
+#define SPEED_UNKNOWN -1
+#endif
+
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN 0xff
+#endif
struct qlcnic_dump_operations {
enum op_codes opcode;
int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8,
struct __qlcnic_esw_statistics *);
int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
+int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
extern int qlcnic_config_tso;
/*
}
extern const struct ethtool_ops qlcnic_ethtool_ops;
+extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
struct qlcnic_nic_template {
int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
| QLCNIC_CAP0_VALIDOFF);
cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+ cap |= QLCNIC_CAP0_LRO_MSS;
+
prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
msix_handler);
prq->txrx_sds_binding = nsds_rings - 1;
return err;
}
+/* This routine will retrieve the MAC statistics from firmware */
+int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
+ struct qlcnic_mac_statistics *mac_stats)
+{
+ struct qlcnic_mac_statistics *stats;
+ struct qlcnic_cmd_args cmd;
+ size_t stats_size = sizeof(struct qlcnic_mac_statistics);
+ dma_addr_t stats_dma_t;
+ void *stats_addr;
+ int err;
+
+ stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
+ &stats_dma_t, GFP_KERNEL);
+ if (!stats_addr) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Unable to allocate memory.\n", __func__);
+ return -ENOMEM;
+ }
+ memset(stats_addr, 0, stats_size);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS;
+ cmd.req.arg1 = stats_size << 16;
+ cmd.req.arg2 = MSD(stats_dma_t);
+ cmd.req.arg3 = LSD(stats_dma_t);
+
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
+
+ if (!err) {
+ stats = stats_addr;
+ mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
+ mac_stats->mac_tx_bytes = le64_to_cpu(stats->mac_tx_bytes);
+ mac_stats->mac_tx_mcast_pkts =
+ le64_to_cpu(stats->mac_tx_mcast_pkts);
+ mac_stats->mac_tx_bcast_pkts =
+ le64_to_cpu(stats->mac_tx_bcast_pkts);
+ mac_stats->mac_rx_frames = le64_to_cpu(stats->mac_rx_frames);
+ mac_stats->mac_rx_bytes = le64_to_cpu(stats->mac_rx_bytes);
+ mac_stats->mac_rx_mcast_pkts =
+ le64_to_cpu(stats->mac_rx_mcast_pkts);
+ mac_stats->mac_rx_length_error =
+ le64_to_cpu(stats->mac_rx_length_error);
+ mac_stats->mac_rx_length_small =
+ le64_to_cpu(stats->mac_rx_length_small);
+ mac_stats->mac_rx_length_large =
+ le64_to_cpu(stats->mac_rx_length_large);
+ mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
+ mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
+ mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "%s: Get mac stats failed =%d.\n", __func__, err);
+ }
+
+ dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
+ stats_dma_t);
+ return err;
+}
+
int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
return -EIO;
memset(esw_stats, 0, sizeof(u64));
- esw_stats->unicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->multicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->broadcast_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->dropped_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->errors = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->local_frames = QLCNIC_ESW_STATS_NOT_AVAIL;
- esw_stats->numbytes = QLCNIC_ESW_STATS_NOT_AVAIL;
+ esw_stats->unicast_frames = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->multicast_frames = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->broadcast_frames = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->dropped_frames = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->errors = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->local_frames = QLCNIC_STATS_NOT_AVAIL;
+ esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL;
esw_stats->context_id = eswitch;
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
"tx numbytes",
};
-#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+ "mac_tx_frames",
+ "mac_tx_bytes",
+ "mac_tx_mcast_pkts",
+ "mac_tx_bcast_pkts",
+ "mac_tx_pause_cnt",
+ "mac_tx_ctrl_pkt",
+ "mac_tx_lt_64b_pkts",
+ "mac_tx_lt_127b_pkts",
+ "mac_tx_lt_255b_pkts",
+ "mac_tx_lt_511b_pkts",
+ "mac_tx_lt_1023b_pkts",
+ "mac_tx_lt_1518b_pkts",
+ "mac_tx_gt_1518b_pkts",
+ "mac_rx_frames",
+ "mac_rx_bytes",
+ "mac_rx_mcast_pkts",
+ "mac_rx_bcast_pkts",
+ "mac_rx_pause_cnt",
+ "mac_rx_ctrl_pkt",
+ "mac_rx_lt_64b_pkts",
+ "mac_rx_lt_127b_pkts",
+ "mac_rx_lt_255b_pkts",
+ "mac_rx_lt_511b_pkts",
+ "mac_rx_lt_1023b_pkts",
+ "mac_rx_lt_1518b_pkts",
+ "mac_rx_gt_1518b_pkts",
+ "mac_rx_length_error",
+ "mac_rx_length_small",
+ "mac_rx_length_large",
+ "mac_rx_jabber",
+ "mac_rx_dropped",
+ "mac_rx_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
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
- sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
-
- strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
- strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%d.%d.%d", fw_major, fw_minor, fw_build);
+
+ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info));
+ strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
+ sizeof(drvinfo->version));
}
static int
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int check_sfp_module = 0;
- u16 pcifn = adapter->ahw->pci_func;
/* read which mode */
if (adapter->ahw->port_type == QLCNIC_GBE) {
goto skip;
}
- val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
- ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ *
- P3P_LINK_SPEED_VAL(pcifn, val));
- ecmd->duplex = DUPLEX_FULL;
+ ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+ ecmd->duplex = DUPLEX_UNKNOWN;
ecmd->autoneg = AUTONEG_DISABLE;
} else
return -EIO;
ring->rx_max_pending = adapter->max_rxd;
ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
-
- ring->rx_mini_max_pending = 0;
- ring->rx_mini_pending = 0;
}
static u32
return QLCNIC_TEST_LEN;
case ETH_SS_STATS:
if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
- return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
- return QLCNIC_STATS_LEN;
+ return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
+ return QLCNIC_TOTAL_STATS_LEN;
default:
return -EOPNOTSUPP;
}
qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
- int index, i;
+ int index, i, j;
switch (stringset) {
case ETH_SS_TEST:
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 (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
}
}
-#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \
- (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1)
-
static void
-qlcnic_fill_device_stats(int *index, u64 *data,
- struct __qlcnic_esw_statistics *stats)
+qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
{
int ind = *index;
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames);
- data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes);
+ 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);
+ } 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);
+ }
*index = ind;
}
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
struct qlcnic_esw_statistics port_stats;
+ struct qlcnic_mac_statistics mac_stats;
int index, ret;
for (index = 0; index < QLCNIC_STATS_LEN; index++) {
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 (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
if (ret)
return;
- qlcnic_fill_device_stats(&index, data, &port_stats.rx);
+ qlcnic_fill_stats(&index, 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_device_stats(&index, data, &port_stats.tx);
+ qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
}
static int qlcnic_set_led(struct net_device *dev,
if (!fw_dump->clr) {
netdev_info(netdev, "Dump not available\n");
- qlcnic_api_unlock(adapter);
- return -EINVAL;
+ return 0;
}
/* Copy template header first */
copy_sz = fw_dump->tmpl_hdr->size;
vfree(fw_dump->data);
fw_dump->data = NULL;
fw_dump->clr = 0;
-
+ netdev_info(netdev, "extracted the FW dump Successfully\n");
return 0;
}
return ret;
}
if (fw_dump->clr) {
- dev_info(&adapter->pdev->dev,
+ netdev_info(netdev,
"Previous dump not cleared, not forcing dump\n");
return ret;
}
.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,
+};
#define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0))
#define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128))
+#define CRB_FW_CAPABILITIES_2 (QLCNIC_CAM_RAM(0x12c))
#define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0))
/*
#define QLCNIC_DEV_FAILED 0x6
#define QLCNIC_DEV_QUISCENT 0x7
+#define QLCNIC_DEV_BADBAD 0xbad0bad0
+
#define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */
#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
#define FLASH_ROM_WINDOW 0x42110030
#define FLASH_ROM_DATA 0x42150000
+
+static const u32 FW_DUMP_LEVELS[] = {
+ 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
+
static const u32 MIU_TEST_READ_DATA[] = {
0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
fw_dump->clr = 1;
snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
adapter->netdev->name);
- dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
+ netdev_info(adapter->netdev, "Dump data, %d bytes captured\n",
fw_dump->size);
/* Send a udev event to notify availability of FW dump */
kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
adapter->module_type = module;
adapter->link_autoneg = autoneg;
- adapter->link_speed = link_speed;
+
+ if (link_status) {
+ adapter->link_speed = link_speed;
+ } else {
+ adapter->link_speed = SPEED_UNKNOWN;
+ adapter->link_duplex = DUPLEX_UNKNOWN;
+ }
}
static void
length = skb->len;
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+ skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+
if (vid != 0xffff)
__vlan_hwaccel_put_tag(skb, vid);
netif_receive_skb(skb);
#endif
};
+static const struct net_device_ops qlcnic_netdev_failed_ops = {
+ .ndo_open = qlcnic_open,
+};
+
static struct qlcnic_nic_template qlcnic_ops = {
.config_bridged_mode = qlcnic_config_bridged_mode,
.config_led = qlcnic_config_led,
__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
int ring;
+ u32 capab2;
+
struct qlcnic_host_rds_ring *rds_ring;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
if (qlcnic_set_eswitch_port_config(adapter))
return -EIO;
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+ capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+ if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+ adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+ }
+
if (qlcnic_fw_create_ctx(adapter))
return -EIO;
qlcnic_napi_disable(adapter);
qlcnic_fw_destroy_ctx(adapter);
+ adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
qlcnic_reset_rx_buffers_list(adapter);
qlcnic_release_tx_buffers(adapter);
if (netif_running(netdev)) {
err = qlcnic_attach(adapter);
- if (!err)
+ if (!err) {
__qlcnic_up(adapter, netdev);
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
}
netif_device_attach(netdev);
netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
if (!netdev) {
- dev_err(&pdev->dev, "failed to allocate net_device\n");
err = -ENOMEM;
goto err_out_free_res;
}
err = adapter->nic_ops->start_firmware(adapter);
if (err) {
- dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
- goto err_out_decr_ref;
+ dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
+ "\t\tIf reboot doesn't help, try flashing the card\n");
+ goto err_out_maintenance_mode;
}
if (qlcnic_read_mac_addr(adapter))
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return err;
+
+err_out_maintenance_mode:
+ netdev->netdev_ops = &qlcnic_netdev_failed_ops;
+ SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register net device\n");
+ goto err_out_decr_ref;
+ }
+ pci_set_drvdata(pdev, adapter);
+ qlcnic_create_diag_entries(adapter);
+ return 0;
}
static void __devexit qlcnic_remove(struct pci_dev *pdev)
static int qlcnic_open(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
int err;
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
+ netdev_err(netdev, "Device in FAILED state\n");
+ return -EIO;
+ }
+
netif_carrier_off(netdev);
err = qlcnic_attach(adapter);
return;
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
+ netdev_err(adapter->netdev,
+ "Device is in FAILED state, Please Reboot\n");
+ qlcnic_api_unlock(adapter);
+ return;
+ }
if (state == QLCNIC_DEV_READY) {
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
msleep(10);
+ if (!adapter->fw_work.work.func)
+ return;
+
cancel_delayed_work_sync(&adapter->fw_work);
}
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
- if (LSW(MSB(peg_status)) == 0x67)
+ if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
dev_err(&adapter->pdev->dev,
"Firmware aborted with error code 0x00006700. "
"Device is being reset.\n");
return size;
}
+static ssize_t
+qlcnic_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ void *tmp_buf;
+ int i, copy_sz, pos;
+ u32 *buf_ptr, *hdr_ptr;
+ size_t data_sz, ret = 0, tmp_sz = 0;
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(adapter->netdev, "FW Dump not supported\n");
+ return -ENOTSUPP;
+ }
+
+ if (offset >= size || offset < 0)
+ return 0;
+
+ if (!fw_dump->clr) {
+ dev_info(dev, "Dump not available\n");
+ return 0;
+ }
+
+ copy_sz = fw_dump->tmpl_hdr->size - fw_dump->pos;
+ /* Copy template header first */
+ if (copy_sz > 0) {
+ if (copy_sz < size)
+ tmp_sz = copy_sz;
+ else
+ tmp_sz = size;
+ tmp_buf = vmalloc(tmp_sz);
+ if (!tmp_buf)
+ return -EIO;
+ memset(tmp_buf, 0, tmp_sz);
+ buf_ptr = (u32 *) tmp_buf;
+ hdr_ptr = (u32 *) ((void *) fw_dump->tmpl_hdr + fw_dump->pos);
+ for (i = 0; i < tmp_sz/sizeof(u32); i++)
+ *buf_ptr++ = cpu_to_le32(*hdr_ptr++);
+
+ ret = memory_read_from_buffer((void *) buf, tmp_sz, &offset,
+ (void *) tmp_buf, tmp_sz);
+ fw_dump->pos += tmp_sz;
+ data_sz = size - tmp_sz;
+ vfree(tmp_buf);
+ tmp_buf = NULL;
+ } else {
+ copy_sz = fw_dump->tmpl_hdr->size + fw_dump->size -
+ fw_dump->pos;
+ if (copy_sz >= size)
+ data_sz = size;
+ else
+ data_sz = copy_sz;
+ }
+ /* Copy captured dump data */
+ if (data_sz > 0) {
+ pos = fw_dump->pos - fw_dump->tmpl_hdr->size;
+ ret = memory_read_from_buffer((void *) (buf + tmp_sz), data_sz,
+ &offset, (void *) (fw_dump->data + pos), data_sz);
+ fw_dump->pos += data_sz;
+ }
+ /* free dump area once the whoel dump data has been captured */
+ if (fw_dump->pos == fw_dump->size + fw_dump->tmpl_hdr->size) {
+ vfree(fw_dump->data);
+ fw_dump->size = 0;
+ fw_dump->data = NULL;
+ fw_dump->clr = 0;
+ fw_dump->pos = 0;
+ netdev_info(adapter->netdev,
+ "extracted the FW dump Successfully\n");
+ }
+ return ret;
+}
+
+static ssize_t
+qlcnic_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ struct net_device *netdev = adapter->netdev;
+ int err = size;
+ unsigned long data;
+ u32 state;
+
+ data = simple_strtoul(buf, NULL, 16);
+ rtnl_lock();
+ switch (data) {
+ case QLCNIC_FORCE_FW_DUMP_KEY:
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(netdev, "FW dump not supported\n");
+ err = -ENOTSUPP;
+ goto out;
+ }
+
+ if (!fw_dump->enable) {
+ netdev_info(netdev, "FW dump not enabled\n");
+ goto out;
+ }
+ if (fw_dump->clr) {
+ netdev_info(netdev,
+ "Previous dump not cleared, not forcing dump\n");
+ goto out;
+ }
+ netdev_info(netdev, "Forcing a fw dump\n");
+ qlcnic_dev_request_reset(adapter);
+ break;
+ case QLCNIC_DISABLE_FW_DUMP:
+ if (fw_dump->enable && fw_dump->tmpl_hdr) {
+ netdev_info(netdev, "Disabling FW dump\n");
+ fw_dump->enable = 0;
+ }
+ break;
+ case QLCNIC_ENABLE_FW_DUMP:
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(netdev, "FW dump not supported\n");
+ err = -ENOTSUPP;
+ goto out;
+ }
+ if (!fw_dump->enable) {
+ netdev_info(netdev, "Enabling FW dump\n");
+ fw_dump->enable = 1;
+ }
+ break;
+ case QLCNIC_FORCE_FW_RESET:
+ netdev_info(netdev, "Forcing a FW reset\n");
+ qlcnic_dev_request_reset(adapter);
+ adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
+ break;
+ case QLCNIC_SET_QUIESCENT:
+ case QLCNIC_RESET_QUIESCENT:
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ netdev_info(netdev, "Device in FAILED state\n");
+ break;
+ default:
+ netdev_err(netdev, "Invalid dump key, 0x%lx\n", data);
+ err = -QLCNIC_INVALID_KEY;
+ break;
+ }
+out:
+ rtnl_unlock();
+ return err;
+}
+
+static ssize_t
+qlcnic_store_fwdump_level(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int i;
+ unsigned long int val;
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct net_device *netdev = adapter->netdev;
+
+ val = simple_strtoul(buf, NULL, 16);
+
+ for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
+ if (val == FW_DUMP_LEVELS[i]) {
+ rtnl_lock();
+ adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask = val;
+ rtnl_unlock();
+ netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+ adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask);
+ return size;
+ }
+ }
+ netdev_info(netdev, "Invalid Dump Level: 0x%lx\n",
+ (unsigned long int) val);
+ return -EINVAL;
+}
+
+static ssize_t
+qlcnic_show_fwdump_level(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 size = adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask;
+ return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+qlcnic_store_fwdump_size(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ return -EIO;
+}
+
+static ssize_t
+qlcnic_show_fwdump_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 size = 0;
+ if (adapter->ahw->fw_dump.clr)
+ size = adapter->ahw->fw_dump.size +
+ adapter->ahw->fw_dump.tmpl_hdr->size;
+ return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+qlcnic_show_fwdump_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 state = adapter->ahw->fw_dump.enable;
+ return sprintf(buf, "%u\n", state);
+}
+
+static ssize_t
+qlcnic_store_fwdump_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ return -EIO;
+}
+
+static struct device_attribute dev_attr_fwdump_size = {
+ .attr = {.name = "fwdump_size", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_fwdump_size,
+ .store = qlcnic_store_fwdump_size,
+};
+
+static struct device_attribute dev_attr_fwdump_level = {
+ .attr = {.name = "fwdump_level", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_fwdump_level,
+ .store = qlcnic_store_fwdump_level,
+};
+
static struct bin_attribute bin_attr_crb = {
.attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
.size = 0,
.write = qlcnic_sysfs_write_mem,
};
+static struct bin_attribute bin_attr_fw_dump = {
+ .attr = {.name = "fw_dump", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_fw_dump,
+ .write = qlcnic_sysfs_write_fw_dump,
+};
+
+static struct device_attribute dev_attr_fwdump_state = {
+ .attr = {.name = "fwdump_state", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_fwdump_state,
+ .store = qlcnic_store_fwdump_state,
+};
+
static int
validate_pm_config(struct qlcnic_adapter *adapter,
struct qlcnic_pm_func_cfg *pm_cfg, int count)
qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
if (device_create_bin_file(dev, &bin_attr_port_stats))
dev_info(dev, "failed to create port stats sysfs entry");
return;
if (device_create_file(dev, &dev_attr_diag_mode))
dev_info(dev, "failed to create diag_mode sysfs entry\n");
- if (device_create_file(dev, &dev_attr_beacon))
- dev_info(dev, "failed to create beacon sysfs entry");
if (device_create_file(dev, &dev_attr_elb_mode))
dev_info(dev, "failed to create elb_mode sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_crb))
dev_info(dev, "failed to create crb sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_fw_dump))
+ dev_info(dev, "failed to create fw_dump sysfs entry");
+ if (adapter->ahw->fw_dump.tmpl_hdr) {
+ if (device_create_file(dev, &dev_attr_fwdump_size))
+ dev_info(dev,
+ "failed to create fwdump_size sysfs entry");
+ if (device_create_file(dev, &dev_attr_fwdump_level))
+ dev_info(dev,
+ "failed to create fwdump_level sysfs entry");
+ if (device_create_file(dev, &dev_attr_fwdump_state))
+ dev_info(dev, "failed to create fwdump_state sysfs entry");
+ }
+
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
+ if (device_create_file(dev, &dev_attr_beacon))
+ dev_info(dev, "failed to create beacon sysfs entry");
if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry");
+
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
if (device_create_bin_file(dev, &bin_attr_esw_config))
qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
device_remove_bin_file(dev, &bin_attr_port_stats);
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
return;
device_remove_file(dev, &dev_attr_diag_mode);
- device_remove_file(dev, &dev_attr_beacon);
device_remove_file(dev, &dev_attr_elb_mode);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
+ device_remove_bin_file(dev, &bin_attr_fw_dump);
+ if (adapter->ahw->fw_dump.tmpl_hdr) {
+ device_remove_file(dev, &dev_attr_fwdump_size);
+ device_remove_file(dev, &dev_attr_fwdump_level);
+ device_remove_file(dev, &dev_attr_fwdump_state);
+ }
+
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
+
+ device_remove_file(dev, &dev_attr_beacon);
device_remove_bin_file(dev, &bin_attr_pci_config);
+
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
device_remove_bin_file(dev, &bin_attr_esw_config);