aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/qlogic')
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h20
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c5
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c18
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h26
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c7
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c140
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h63
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c73
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c208
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c56
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c2
13 files changed, 549 insertions, 78 deletions
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index b5de8a7b90f1..37ccbe54e62d 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 78
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.78"
+#define _NETXEN_NIC_LINUX_SUBVERSION 79
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.79"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -419,6 +419,8 @@ struct rcv_desc {
(((sts_data) >> 52) & 0x1)
#define netxen_get_lro_sts_seq_number(sts_data) \
((sts_data) & 0x0FFFFFFFF)
+#define netxen_get_lro_sts_mss(sts_data1) \
+ ((sts_data1 >> 32) & 0x0FFFF)
struct status_desc {
@@ -794,6 +796,7 @@ struct netxen_cmd_args {
#define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7)
#define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8)
#define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10)
+#define NX_CAP0_HW_LRO_MSS NX_CAP_BIT(0, 21)
/*
* Context state
@@ -1073,6 +1076,8 @@ typedef struct {
#define NX_FW_CAPABILITY_FVLANTX (1 << 9)
#define NX_FW_CAPABILITY_HW_LRO (1 << 10)
#define NX_FW_CAPABILITY_GBE_LINK_CFG (1 << 11)
+#define NX_FW_CAPABILITY_MORE_CAPS (1 << 31)
+#define NX_FW_CAPABILITY_2_LRO_MAX_TCP_SEG (1 << 2)
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -1155,6 +1160,7 @@ typedef struct {
#define NETXEN_NIC_BRIDGE_ENABLED 0X10
#define NETXEN_NIC_DIAG_ENABLED 0x20
#define NETXEN_FW_RESET_OWNER 0x40
+#define NETXEN_FW_MSS_CAP 0x80
#define NETXEN_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
@@ -1201,6 +1207,9 @@ typedef struct {
#define NX_FORCE_FW_RESET 0xdeaddead
+/* Fw dump levels */
+static const u32 FW_DUMP_LEVELS[] = { 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
+
/* Flash read/write address */
#define NX_FW_DUMP_REG1 0x00130060
#define NX_FW_DUMP_REG2 0x001e0000
@@ -1814,6 +1823,13 @@ struct netxen_brdinfo {
char short_name[NETXEN_MAX_SHORT_NAME];
};
+struct netxen_dimm_cfg {
+ u8 presence;
+ u8 mem_type;
+ u8 dimm_type;
+ u32 size;
+};
+
static const struct netxen_brdinfo netxen_boards[] = {
{NETXEN_BRDTYPE_P2_SB31_10G_CX4, 1, "XGb CX4"},
{NETXEN_BRDTYPE_P2_SB31_10G_HMEZ, 1, "XGb HMEZ"},
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index f3c0057a802b..7f556a84925d 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -229,7 +229,7 @@ netxen_setup_minidump(struct netxen_adapter *adapter)
adapter->mdump.md_template;
adapter->mdump.md_capture_buff = NULL;
adapter->mdump.fw_supports_md = 1;
- adapter->mdump.md_enabled = 1;
+ adapter->mdump.md_enabled = 0;
return err;
@@ -328,6 +328,9 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN);
cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS);
+ if (adapter->flags & NETXEN_FW_MSS_CAP)
+ cap |= NX_CAP0_HW_LRO_MSS;
+
prq->capabilities[0] = cpu_to_le32(cap);
prq->host_int_crb_mode =
cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED);
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
index 8c39299331a2..39730403782f 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
@@ -834,7 +834,7 @@ netxen_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
static int
netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
- int ret = 0;
+ int i;
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_minidump *mdump = &adapter->mdump;
@@ -844,7 +844,7 @@ netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val)
mdump->md_enabled = 1;
if (adapter->fw_mdump_rdy) {
netdev_info(netdev, "Previous dump not cleared, not forcing dump\n");
- return ret;
+ return 0;
}
netdev_info(netdev, "Forcing a fw dump\n");
nx_dev_request_reset(adapter);
@@ -867,19 +867,21 @@ netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val)
adapter->flags &= ~NETXEN_FW_RESET_OWNER;
break;
default:
- if (val->flag <= NX_DUMP_MASK_MAX &&
- val->flag >= NX_DUMP_MASK_MIN) {
- mdump->md_capture_mask = val->flag & 0xff;
- netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+ for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
+ if (val->flag == FW_DUMP_LEVELS[i]) {
+ mdump->md_capture_mask = val->flag;
+ netdev_info(netdev,
+ "Driver mask changed to: 0x%x\n",
mdump->md_capture_mask);
- break;
+ return 0;
+ }
}
netdev_info(netdev,
"Invalid dump level: 0x%x\n", val->flag);
return -EINVAL;
}
- return ret;
+ return 0;
}
static int
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
index b1a897cd9a8d..28e076960bcb 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
@@ -776,6 +776,7 @@ enum {
#define CRB_SW_INT_MASK_3 (NETXEN_NIC_REG(0x1e8))
#define CRB_FW_CAPABILITIES_1 (NETXEN_CAM_RAM(0x128))
+#define CRB_FW_CAPABILITIES_2 (NETXEN_CAM_RAM(0x12c))
#define CRB_MAC_BLOCK_START (NETXEN_CAM_RAM(0x1c0))
/*
@@ -955,6 +956,31 @@ enum {
#define NX_CRB_DEV_REF_COUNT (NETXEN_CAM_RAM(0x138))
#define NX_CRB_DEV_STATE (NETXEN_CAM_RAM(0x140))
+/* MiniDIMM related macros */
+#define NETXEN_DIMM_CAPABILITY (NETXEN_CAM_RAM(0x258))
+#define NETXEN_DIMM_PRESENT 0x1
+#define NETXEN_DIMM_MEMTYPE_DDR2_SDRAM 0x2
+#define NETXEN_DIMM_SIZE 0x4
+#define NETXEN_DIMM_MEMTYPE(VAL) ((VAL >> 3) & 0xf)
+#define NETXEN_DIMM_NUMROWS(VAL) ((VAL >> 7) & 0xf)
+#define NETXEN_DIMM_NUMCOLS(VAL) ((VAL >> 11) & 0xf)
+#define NETXEN_DIMM_NUMRANKS(VAL) ((VAL >> 15) & 0x3)
+#define NETXEN_DIMM_DATAWIDTH(VAL) ((VAL >> 18) & 0x3)
+#define NETXEN_DIMM_NUMBANKS(VAL) ((VAL >> 21) & 0xf)
+#define NETXEN_DIMM_TYPE(VAL) ((VAL >> 25) & 0x3f)
+#define NETXEN_DIMM_VALID_FLAG 0x80000000
+
+#define NETXEN_DIMM_MEM_DDR2_SDRAM 0x8
+
+#define NETXEN_DIMM_STD_MEM_SIZE 512
+
+#define NETXEN_DIMM_TYPE_RDIMM 0x1
+#define NETXEN_DIMM_TYPE_UDIMM 0x2
+#define NETXEN_DIMM_TYPE_SO_DIMM 0x4
+#define NETXEN_DIMM_TYPE_Micro_DIMM 0x8
+#define NETXEN_DIMM_TYPE_Mini_RDIMM 0x10
+#define NETXEN_DIMM_TYPE_Mini_UDIMM 0x20
+
/* Device State */
#define NX_DEV_COLD 1
#define NX_DEV_INITALIZING 2
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 718b27440351..8694124ef77d 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -1131,7 +1131,6 @@ netxen_validate_firmware(struct netxen_adapter *adapter)
_build(file_fw_ver));
return -EINVAL;
}
-
val = nx_get_bios_version(adapter);
netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
if ((__force u32)val != bios) {
@@ -1261,8 +1260,7 @@ next:
void
netxen_release_firmware(struct netxen_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
@@ -1661,6 +1659,9 @@ netxen_process_lro(struct netxen_adapter *adapter,
length = skb->len;
+ if (adapter->flags & NETXEN_FW_MSS_CAP)
+ skb_shinfo(skb)->gso_size = netxen_get_lro_sts_mss(sts_data1);
+
netif_receive_skb(skb);
adapter->stats.lro_pkts++;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 65a718f9ccd3..342b3a79bd0f 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -1184,6 +1184,7 @@ netxen_nic_attach(struct netxen_adapter *adapter)
int err, ring;
struct nx_host_rds_ring *rds_ring;
struct nx_host_tx_ring *tx_ring;
+ u32 capab2;
if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
return 0;
@@ -1192,6 +1193,13 @@ netxen_nic_attach(struct netxen_adapter *adapter)
if (err)
return err;
+ adapter->flags &= ~NETXEN_FW_MSS_CAP;
+ if (adapter->capabilities & NX_FW_CAPABILITY_MORE_CAPS) {
+ capab2 = NXRD32(adapter, CRB_FW_CAPABILITIES_2);
+ if (capab2 & NX_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+ adapter->flags |= NETXEN_FW_MSS_CAP;
+ }
+
err = netxen_napi_add(adapter, netdev);
if (err)
return err;
@@ -1810,7 +1818,6 @@ netxen_tso_check(struct net_device *netdev,
flags = FLAGS_VLAN_TAGGED;
} else if (vlan_tx_tag_present(skb)) {
-
flags = FLAGS_VLAN_OOB;
vid = vlan_tx_tag_get(skb);
netxen_set_tx_vlan_tci(first_desc, vid);
@@ -2926,6 +2933,134 @@ static struct bin_attribute bin_attr_mem = {
.write = netxen_sysfs_write_mem,
};
+static ssize_t
+netxen_sysfs_read_dimm(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 netxen_adapter *adapter = dev_get_drvdata(dev);
+ struct net_device *netdev = adapter->netdev;
+ struct netxen_dimm_cfg dimm;
+ u8 dw, rows, cols, banks, ranks;
+ u32 val;
+
+ if (size != sizeof(struct netxen_dimm_cfg)) {
+ netdev_err(netdev, "Invalid size\n");
+ return -1;
+ }
+
+ memset(&dimm, 0, sizeof(struct netxen_dimm_cfg));
+ val = NXRD32(adapter, NETXEN_DIMM_CAPABILITY);
+
+ /* Checks if DIMM info is valid. */
+ if (val & NETXEN_DIMM_VALID_FLAG) {
+ netdev_err(netdev, "Invalid DIMM flag\n");
+ dimm.presence = 0xff;
+ goto out;
+ }
+
+ rows = NETXEN_DIMM_NUMROWS(val);
+ cols = NETXEN_DIMM_NUMCOLS(val);
+ ranks = NETXEN_DIMM_NUMRANKS(val);
+ banks = NETXEN_DIMM_NUMBANKS(val);
+ dw = NETXEN_DIMM_DATAWIDTH(val);
+
+ dimm.presence = (val & NETXEN_DIMM_PRESENT);
+
+ /* Checks if DIMM info is present. */
+ if (!dimm.presence) {
+ netdev_err(netdev, "DIMM not present\n");
+ goto out;
+ }
+
+ dimm.dimm_type = NETXEN_DIMM_TYPE(val);
+
+ switch (dimm.dimm_type) {
+ case NETXEN_DIMM_TYPE_RDIMM:
+ case NETXEN_DIMM_TYPE_UDIMM:
+ case NETXEN_DIMM_TYPE_SO_DIMM:
+ case NETXEN_DIMM_TYPE_Micro_DIMM:
+ case NETXEN_DIMM_TYPE_Mini_RDIMM:
+ case NETXEN_DIMM_TYPE_Mini_UDIMM:
+ break;
+ default:
+ netdev_err(netdev, "Invalid DIMM type %x\n", dimm.dimm_type);
+ goto out;
+ }
+
+ if (val & NETXEN_DIMM_MEMTYPE_DDR2_SDRAM)
+ dimm.mem_type = NETXEN_DIMM_MEM_DDR2_SDRAM;
+ else
+ dimm.mem_type = NETXEN_DIMM_MEMTYPE(val);
+
+ if (val & NETXEN_DIMM_SIZE) {
+ dimm.size = NETXEN_DIMM_STD_MEM_SIZE;
+ goto out;
+ }
+
+ if (!rows) {
+ netdev_err(netdev, "Invalid no of rows %x\n", rows);
+ goto out;
+ }
+
+ if (!cols) {
+ netdev_err(netdev, "Invalid no of columns %x\n", cols);
+ goto out;
+ }
+
+ if (!banks) {
+ netdev_err(netdev, "Invalid no of banks %x\n", banks);
+ goto out;
+ }
+
+ ranks += 1;
+
+ switch (dw) {
+ case 0x0:
+ dw = 32;
+ break;
+ case 0x1:
+ dw = 33;
+ break;
+ case 0x2:
+ dw = 36;
+ break;
+ case 0x3:
+ dw = 64;
+ break;
+ case 0x4:
+ dw = 72;
+ break;
+ case 0x5:
+ dw = 80;
+ break;
+ case 0x6:
+ dw = 128;
+ break;
+ case 0x7:
+ dw = 144;
+ break;
+ default:
+ netdev_err(netdev, "Invalid data-width %x\n", dw);
+ goto out;
+ }
+
+ dimm.size = ((1 << rows) * (1 << cols) * dw * banks * ranks) / 8;
+ /* Size returned in MB. */
+ dimm.size = (dimm.size) / 0x100000;
+out:
+ memcpy(buf, &dimm, sizeof(struct netxen_dimm_cfg));
+ return sizeof(struct netxen_dimm_cfg);
+
+}
+
+static struct bin_attribute bin_attr_dimm = {
+ .attr = { .name = "dimm", .mode = (S_IRUGO | S_IWUSR) },
+ .size = 0,
+ .read = netxen_sysfs_read_dimm,
+};
+
static void
netxen_create_sysfs_entries(struct netxen_adapter *adapter)
@@ -2963,6 +3098,8 @@ netxen_create_diag_entries(struct netxen_adapter *adapter)
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_dimm))
+ dev_info(dev, "failed to create dimm sysfs entry\n");
}
@@ -2975,6 +3112,7 @@ netxen_remove_diag_entries(struct netxen_adapter *adapter)
device_remove_file(dev, &dev_attr_diag_mode);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
+ device_remove_bin_file(dev, &bin_attr_dimm);
}
#ifdef CONFIG_INET
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 385a4d5c7c25..8680a5dae4a2 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -36,8 +36,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 27
-#define QLCNIC_LINUX_VERSIONID "5.0.27"
+#define _QLCNIC_LINUX_SUBVERSION 28
+#define QLCNIC_LINUX_VERSIONID "5.0.28"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -607,6 +607,7 @@ struct qlcnic_recv_context {
#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
@@ -1180,18 +1181,62 @@ struct qlcnic_esw_func_cfg {
#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;
@@ -1352,6 +1397,8 @@ enum op_codes {
#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
struct qlcnic_dump_operations {
enum op_codes opcode;
@@ -1510,6 +1557,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8,
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;
/*
@@ -1559,6 +1607,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
}
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);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 569a837d2ac4..8db85244e8ad 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -905,6 +905,65 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
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) {
@@ -920,13 +979,13 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
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++) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 89ddf7f7d7df..9e9e78a5c4d7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -78,8 +78,46 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"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",
@@ -644,8 +682,8 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
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;
}
@@ -851,7 +889,7 @@ static void
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:
@@ -864,6 +902,11 @@ 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 (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
@@ -874,22 +917,64 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-#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;
}
@@ -900,6 +985,7 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
{
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++) {
@@ -911,6 +997,11 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
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;
@@ -920,14 +1011,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
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,
@@ -1132,11 +1223,21 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
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 (fw_dump->clr)
dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
else
dump->len = 0;
- dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+
+ if (!fw_dump->enable)
+ dump->flag = ETH_FW_DUMP_DISABLE;
+ else
+ dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+
dump->version = adapter->fw_version;
return 0;
}
@@ -1150,6 +1251,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(netdev, "FW Dump not supported\n");
+ return -ENOTSUPP;
+ }
+
if (!fw_dump->clr) {
netdev_info(netdev, "Dump not available\n");
return -EINVAL;
@@ -1177,55 +1283,74 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
static int
qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
- int ret = 0;
+ int i;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ u32 state;
switch (val->flag) {
case QLCNIC_FORCE_FW_DUMP_KEY:
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(netdev, "FW dump not supported\n");
+ return -ENOTSUPP;
+ }
if (!fw_dump->enable) {
netdev_info(netdev, "FW dump not enabled\n");
- return ret;
+ return 0;
}
if (fw_dump->clr) {
netdev_info(netdev,
"Previous dump not cleared, not forcing dump\n");
- return ret;
+ return 0;
}
netdev_info(netdev, "Forcing a FW dump\n");
qlcnic_dev_request_reset(adapter);
break;
case QLCNIC_DISABLE_FW_DUMP:
- if (fw_dump->enable) {
+ if (fw_dump->enable && fw_dump->tmpl_hdr) {
netdev_info(netdev, "Disabling FW dump\n");
fw_dump->enable = 0;
}
- break;
+ return 0;
case QLCNIC_ENABLE_FW_DUMP:
- if (!fw_dump->enable && fw_dump->tmpl_hdr) {
+ if (!fw_dump->tmpl_hdr) {
+ netdev_err(netdev, "FW dump not supported\n");
+ return -ENOTSUPP;
+ }
+ if (!fw_dump->enable) {
netdev_info(netdev, "Enabling FW dump\n");
fw_dump->enable = 1;
}
- break;
+ return 0;
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;
+ return 0;
+ 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");
+ return 0;
default:
- if (val->flag > QLCNIC_DUMP_MASK_MAX ||
- val->flag < QLCNIC_DUMP_MASK_MIN) {
- netdev_info(netdev,
- "Invalid dump level: 0x%x\n", val->flag);
- ret = -EINVAL;
- goto out;
+ if (!fw_dump->tmpl_hdr) {
+ 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]) {
+ fw_dump->tmpl_hdr->drv_cap_mask =
+ val->flag;
+ netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+ fw_dump->tmpl_hdr->drv_cap_mask);
+ return 0;
+ }
}
- fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
- netdev_info(netdev, "Driver mask changed to: 0x%x\n",
- fw_dump->tmpl_hdr->drv_cap_mask);
+ netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
+ return -EINVAL;
}
-out:
- return ret;
+ return 0;
}
const struct ethtool_ops qlcnic_ethtool_ops = {
@@ -1258,3 +1383,10 @@ 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,
+};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index a52819303d1b..6ced3195aad3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -704,6 +704,8 @@ enum {
#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 */
@@ -776,6 +778,10 @@ struct qlcnic_legacy_intr_set {
#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, };
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index d32cf0ddf1b9..799fd40ed03a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1321,8 +1321,7 @@ next:
void
qlcnic_release_firmware(struct qlcnic_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 75c32e875fef..46e77a2c5121 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = {
#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,
@@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
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))
@@ -1695,6 +1700,18 @@ err_out_disable_pdev:
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)
@@ -1831,8 +1848,14 @@ done:
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);
@@ -1942,7 +1965,7 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter,
__le16 vlan_id = 0;
u8 hindex;
- if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
+ if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
return;
if (adapter->fhash.fnum >= adapter->fhash.fmax)
@@ -2212,8 +2235,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->flags & QLCNIC_MACSPOOF) {
phdr = (struct ethhdr *)skb->data;
- if (compare_ether_addr(phdr->h_source,
- adapter->mac_addr))
+ if (!ether_addr_equal(phdr->h_source, adapter->mac_addr))
goto drop_packet;
}
@@ -3018,6 +3040,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *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);
@@ -3061,6 +3089,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
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);
}
@@ -4280,6 +4311,7 @@ static void
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");
@@ -4288,14 +4320,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
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_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 (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
+
if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry");
+ if (device_create_file(dev, &dev_attr_beacon))
+ dev_info(dev, "failed to create beacon sysfs entry");
+
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
if (device_create_bin_file(dev, &bin_attr_esw_config))
@@ -4314,16 +4351,19 @@ static void
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_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
device_remove_bin_file(dev, &bin_attr_pci_config);
+ device_remove_file(dev, &dev_attr_beacon);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
device_remove_bin_file(dev, &bin_attr_esw_config);
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 49343ec21c82..09d8d33171df 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -3845,7 +3845,7 @@ static int ql_wol(struct ql_adapter *qdev)
if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST |
WAKE_MCAST | WAKE_BCAST)) {
netif_err(qdev, ifdown, qdev->ndev,
- "Unsupported WOL paramter. qdev->wol = 0x%x.\n",
+ "Unsupported WOL parameter. qdev->wol = 0x%x.\n",
qdev->wol);
return -EINVAL;
}