diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic')
-rw-r--r-- | drivers/net/ethernet/qlogic/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 121 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 91 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 179 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 85 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 233 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 102 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlge/qlge_main.c | 25 |
15 files changed, 731 insertions, 201 deletions
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index f59e6be4a66e..c14bd3116e45 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -56,6 +56,16 @@ config QLCNIC_DCB mode of DCB is supported. PG and PFC values are related only to Tx. +config QLCNIC_VXLAN + bool "Virtual eXtensible Local Area Network (VXLAN) offload support" + default n + depends on QLCNIC && VXLAN && !(QLCNIC=y && VXLAN=m) + ---help--- + This enables hardware offload support for VXLAN protocol over QLogic's + 84XX series adapters. + Say Y here if you want to enable hardware offload support for + Virtual eXtensible Local Area Network (VXLAN) in the driver. + config QLGE tristate "QLogic QLGE 10Gb Ethernet Driver Support" depends on PCI diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 70849dea32b1..f09c35d669b3 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -643,8 +643,9 @@ static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter, if (adapter->msix_supported) { netxen_init_msix_entries(adapter, num_msix); - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { + err = pci_enable_msix_range(pdev, adapter->msix_entries, + num_msix, num_msix); + if (err > 0) { adapter->flags |= NETXEN_NIC_MSIX_ENABLED; netxen_set_msix_bit(pdev, 1); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index f19f81cde134..f31bb5e9d8a9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -38,8 +38,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 55 -#define QLCNIC_LINUX_VERSIONID "5.3.55" +#define _QLCNIC_LINUX_SUBVERSION 57 +#define QLCNIC_LINUX_VERSIONID "5.3.57" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -169,11 +169,20 @@ struct cmd_desc_type0 { __le64 addr_buffer2; - __le16 reference_handle; + __le16 encap_descr; /* 15:10 offset of outer L3 header, + * 9:6 number of 32bit words in outer L3 header, + * 5 offload outer L4 checksum, + * 4 offload outer L3 checksum, + * 3 Inner L4 type, TCP=0, UDP=1, + * 2 Inner L3 type, IPv4=0, IPv6=1, + * 1 Outer L3 type,IPv4=0, IPv6=1, + * 0 type of encapsulation, GRE=0, VXLAN=1 + */ __le16 mss; u8 port_ctxid; /* 7:4 ctxid 3:0 port */ - u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ - __le16 conn_id; /* IPSec offoad only */ + u8 hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ + u8 outer_hdr_length; /* Encapsulation only */ + u8 rsvd1; __le64 addr_buffer3; __le64 addr_buffer1; @@ -183,7 +192,9 @@ struct cmd_desc_type0 { __le64 addr_buffer4; u8 eth_addr[ETH_ALEN]; - __le16 vlan_TCI; + __le16 vlan_TCI; /* In case of encapsulation, + * this is for outer VLAN + */ } __attribute__ ((aligned(64))); @@ -394,7 +405,7 @@ struct qlcnic_nic_intr_coalesce { u32 timer_out; }; -struct qlcnic_dump_template_hdr { +struct qlcnic_83xx_dump_template_hdr { u32 type; u32 offset; u32 size; @@ -411,15 +422,42 @@ struct qlcnic_dump_template_hdr { u32 rsvd[0]; }; +struct qlcnic_82xx_dump_template_hdr { + u32 type; + u32 offset; + u32 size; + u32 cap_mask; + u32 num_entries; + u32 version; + u32 timestamp; + u32 checksum; + u32 drv_cap_mask; + u32 sys_info[3]; + u32 saved_state[16]; + u32 cap_sizes[8]; + u32 rsvd[7]; + u32 capabilities; + u32 rsvd1[0]; +}; + struct qlcnic_fw_dump { u8 clr; /* flag to indicate if dump is cleared */ bool enable; /* enable/disable dump */ u32 size; /* total size of the dump */ + u32 cap_mask; /* Current capture mask */ void *data; /* dump data area */ - struct qlcnic_dump_template_hdr *tmpl_hdr; + void *tmpl_hdr; dma_addr_t phys_addr; void *dma_buffer; bool use_pex_dma; + /* Read only elements which are common between 82xx and 83xx + * template header. Update these values immediately after we read + * template header from Firmware + */ + u32 tmpl_hdr_size; + u32 version; + u32 num_entries; + u32 offset; }; /* @@ -497,6 +535,7 @@ struct qlcnic_hardware_context { u8 extend_lb_time; u8 phys_port_id[ETH_ALEN]; u8 lb_mode; + u16 vxlan_port; }; struct qlcnic_adapter_stats { @@ -511,6 +550,9 @@ struct qlcnic_adapter_stats { u64 txbytes; u64 lrobytes; u64 lso_frames; + u64 encap_lso_frames; + u64 encap_tx_csummed; + u64 encap_rx_csummed; u64 xmit_on; u64 xmit_off; u64 skb_alloc_failure; @@ -872,6 +914,10 @@ struct qlcnic_mac_vlan_list { #define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7 #define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9 +#define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD BIT_0 +#define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD BIT_1 +#define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD BIT_4 + /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 #define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2 @@ -966,6 +1012,11 @@ struct qlcnic_ipaddr { #define QLCNIC_HAS_PHYS_PORT_ID 0x40000 #define QLCNIC_TSS_RSS 0x80000 +#ifdef CONFIG_QLCNIC_VXLAN +#define QLCNIC_ADD_VXLAN_PORT 0x100000 +#define QLCNIC_DEL_VXLAN_PORT 0x200000 +#endif + #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) #define QLCNIC_IS_TSO_CAPABLE(adapter) \ @@ -1769,10 +1820,28 @@ struct qlcnic_hardware_ops { struct qlcnic_host_tx_ring *); void (*disable_tx_intr) (struct qlcnic_adapter *, struct qlcnic_host_tx_ring *); + u32 (*get_saved_state)(void *, u32); + void (*set_saved_state)(void *, u32, u32); + void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *); + u32 (*get_cap_size)(void *, int); + void (*set_sys_info)(void *, int, u32); + void (*store_cap_mask)(void *, u32); }; extern struct qlcnic_nic_template qlcnic_vf_ops; +static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter) +{ + return adapter->ahw->extra_capability[0] & + QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD; +} + +static inline bool qlcnic_encap_rx_offload(struct qlcnic_adapter *adapter) +{ + return adapter->ahw->extra_capability[0] & + QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD; +} + static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter) { return adapter->nic_ops->start_firmware(adapter); @@ -2007,6 +2076,42 @@ static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->read_phys_port_id(adapter); } +static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter, + void *t_hdr, u32 index) +{ + return adapter->ahw->hw_ops->get_saved_state(t_hdr, index); +} + +static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter, + void *t_hdr, u32 index, u32 value) +{ + adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value); +} + +static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter, + struct qlcnic_fw_dump *fw_dump) +{ + adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump); +} + +static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter, + void *tmpl_hdr, int index) +{ + return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index); +} + +static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter, + void *tmpl_hdr, int idx, u32 value) +{ + adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value); +} + +static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter, + void *tmpl_hdr, u32 mask) +{ + adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask); +} + static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, u32 key) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 27c4f131863b..b7cffb46a75d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -77,7 +77,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_GET_PORT_CONFIG, 2, 2}, {QLCNIC_CMD_GET_LINK_STATUS, 2, 4}, {QLCNIC_CMD_IDC_ACK, 5, 1}, - {QLCNIC_CMD_INIT_NIC_FUNC, 2, 1}, + {QLCNIC_CMD_INIT_NIC_FUNC, 3, 1}, {QLCNIC_CMD_STOP_NIC_FUNC, 2, 1}, {QLCNIC_CMD_SET_LED_CONFIG, 5, 1}, {QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, @@ -87,6 +87,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, {QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50}, + {QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1}, }; const u32 qlcnic_83xx_ext_reg_tbl[] = { @@ -203,7 +204,12 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .disable_sds_intr = qlcnic_83xx_disable_sds_intr, .enable_tx_intr = qlcnic_83xx_enable_tx_intr, .disable_tx_intr = qlcnic_83xx_disable_tx_intr, - + .get_saved_state = qlcnic_83xx_get_saved_state, + .set_saved_state = qlcnic_83xx_set_saved_state, + .cache_tmpl_hdr_values = qlcnic_83xx_cache_tmpl_hdr_values, + .get_cap_size = qlcnic_83xx_get_cap_size, + .set_sys_info = qlcnic_83xx_set_sys_info, + .store_cap_mask = qlcnic_83xx_store_cap_mask, }; static struct qlcnic_nic_template qlcnic_83xx_ops = { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index f92485ca21d1..88d809c35633 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -308,6 +308,8 @@ struct qlc_83xx_reset { #define QLC_83XX_IDC_FLASH_PARAM_ADDR 0x3e8020 struct qlcnic_adapter; +struct qlcnic_fw_dump; + struct qlc_83xx_idc { int (*state_entry) (struct qlcnic_adapter *); u64 sec_counter; @@ -526,8 +528,9 @@ enum qlc_83xx_ext_regs { }; /* Initialize/Stop NIC command bit definitions */ -#define QLC_REGISTER_DCB_AEN BIT_1 #define QLC_REGISTER_LB_IDC BIT_0 +#define QLC_REGISTER_DCB_AEN BIT_1 +#define QLC_83XX_MULTI_TENANCY_INFO BIT_29 #define QLC_INIT_FW_RESOURCES BIT_31 /* 83xx funcitons */ @@ -650,4 +653,10 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *); void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *); int qlcnic_83xx_aer_reset(struct qlcnic_adapter *); void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *); +u32 qlcnic_83xx_get_saved_state(void *, u32); +void qlcnic_83xx_set_saved_state(void *, u32, u32); +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_83xx_get_cap_size(void *, int); +void qlcnic_83xx_set_sys_info(void *, int, u32); +void qlcnic_83xx_store_cap_mask(void *, u32); #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 90a2dda351ec..b48737dcd3c5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1020,10 +1020,99 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter, return 0; } +#ifdef CONFIG_QLCNIC_VXLAN +#define QLC_83XX_ENCAP_TYPE_VXLAN BIT_1 +#define QLC_83XX_MATCH_ENCAP_ID BIT_2 +#define QLC_83XX_SET_VXLAN_UDP_DPORT BIT_3 +#define QLC_83XX_VXLAN_UDP_DPORT(PORT) ((PORT & 0xffff) << 16) + +#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1 +#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0 + +static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter) +{ + u16 port = adapter->ahw->vxlan_port; + struct qlcnic_cmd_args cmd; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + + ret = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_INIT_NIC_FUNC); + if (ret) + return ret; + + cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO; + cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN | + QLC_83XX_SET_VXLAN_UDP_DPORT | + QLC_83XX_VXLAN_UDP_DPORT(port); + + ret = qlcnic_issue_cmd(adapter, &cmd); + if (ret) + netdev_err(adapter->netdev, + "Failed to set VXLAN port %d in adapter\n", + port); + + qlcnic_free_mbx_args(&cmd); + + return ret; +} + +static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter, + bool state) +{ + u16 vxlan_port = adapter->ahw->vxlan_port; + struct qlcnic_cmd_args cmd; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + + ret = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_SET_INGRESS_ENCAP); + if (ret) + return ret; + + cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING : + QLCNIC_DISABLE_INGRESS_ENCAP_PARSING; + + ret = qlcnic_issue_cmd(adapter, &cmd); + if (ret) + netdev_err(adapter->netdev, + "Failed to %s VXLAN parsing for port %d\n", + state ? "enable" : "disable", vxlan_port); + else + netdev_info(adapter->netdev, + "%s VXLAN parsing for port %d\n", + state ? "Enabled" : "Disabled", vxlan_port); + + qlcnic_free_mbx_args(&cmd); + + return ret; +} +#endif + static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter) { if (adapter->fhash.fnum) qlcnic_prune_lb_filters(adapter); + +#ifdef CONFIG_QLCNIC_VXLAN + if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) { + if (qlcnic_set_vxlan_port(adapter)) + return; + + if (qlcnic_set_vxlan_parsing(adapter, true)) + return; + + adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT; + } else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) { + if (qlcnic_set_vxlan_parsing(adapter, false)) + return; + + adapter->ahw->vxlan_port = 0; + adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT; + } +#endif } /** @@ -1301,7 +1390,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) addr = (u64)dest; ret = qlcnic_83xx_ms_mem_write128(adapter, addr, - (u32 *)p_cache, size / 16); + p_cache, size / 16); if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); release_firmware(fw); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index acee1a5d80c6..5bacf5210aed 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -47,6 +47,12 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)}, {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)}, {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)}, + {"encap_lso_frames", QLC_SIZEOF(stats.encap_lso_frames), + QLC_OFF(stats.encap_lso_frames)}, + {"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed), + QLC_OFF(stats.encap_tx_csummed)}, + {"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed), + QLC_OFF(stats.encap_rx_csummed)}, {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), QLC_OFF(stats.skb_alloc_failure)}, {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun), @@ -1639,14 +1645,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) } if (fw_dump->clr) - dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; + dump->len = fw_dump->tmpl_hdr_size + fw_dump->size; else dump->len = 0; if (!qlcnic_check_fw_dump_state(adapter)) dump->flag = ETH_FW_DUMP_DISABLE; else - dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->flag = fw_dump->cap_mask; dump->version = adapter->fw_version; return 0; @@ -1671,9 +1677,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, netdev_info(netdev, "Dump not available\n"); return -EINVAL; } + /* Copy template header first */ - copy_sz = fw_dump->tmpl_hdr->size; - hdr_ptr = (u32 *) fw_dump->tmpl_hdr; + copy_sz = fw_dump->tmpl_hdr_size; + hdr_ptr = (u32 *)fw_dump->tmpl_hdr; data = buffer; for (i = 0; i < copy_sz/sizeof(u32); i++) *data++ = cpu_to_le32(*hdr_ptr++); @@ -1681,7 +1688,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, /* Copy captured dump data */ memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size); dump->len = copy_sz + fw_dump->size; - dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->flag = fw_dump->cap_mask; /* Free dump area once data has been captured */ vfree(fw_dump->data); @@ -1703,7 +1710,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask) return -EOPNOTSUPP; } - fw_dump->tmpl_hdr->drv_cap_mask = mask; + fw_dump->cap_mask = mask; + + /* Store new capture mask in template header as well*/ + qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask); + netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask); return 0; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 03d18a0be6ce..9f3adf4e70b5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -317,9 +317,7 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data) int qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) { - int timeout = 0; - int err = 0; - u32 done = 0; + int timeout = 0, err = 0, done = 0; while (!done) { done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), @@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) if (done == 1) break; if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { - dev_err(&adapter->pdev->dev, - "Failed to acquire sem=%d lock; holdby=%d\n", - sem, - id_reg ? QLCRD32(adapter, id_reg, &err) : -1); + if (id_reg) { + done = QLCRD32(adapter, id_reg, &err); + if (done != -1) + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock held by=%d\n", + sem, done); + else + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock", + sem); + } else { + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock", sem); + } return -EIO; } msleep(1); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 63d75617d445..cbe2399c30a0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -98,6 +98,7 @@ enum qlcnic_regs { #define QLCNIC_CMD_GET_LINK_EVENT 0x48 #define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE 0x49 #define QLCNIC_CMD_CONFIGURE_HW_LRO 0x4A +#define QLCNIC_CMD_SET_INGRESS_ENCAP 0x4E #define QLCNIC_CMD_INIT_NIC_FUNC 0x60 #define QLCNIC_CMD_STOP_NIC_FUNC 0x61 #define QLCNIC_CMD_IDC_ACK 0x63 @@ -161,6 +162,7 @@ struct qlcnic_host_sds_ring; struct qlcnic_host_tx_ring; struct qlcnic_hardware_context; struct qlcnic_adapter; +struct qlcnic_fw_dump; int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *); int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32); @@ -213,4 +215,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *); int qlcnic_82xx_resume(struct qlcnic_adapter *); void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed); void qlcnic_fw_poll_work(struct work_struct *work); + +u32 qlcnic_82xx_get_saved_state(void *, u32); +void qlcnic_82xx_set_saved_state(void *, u32, u32); +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_82xx_get_cap_size(void *, int); +void qlcnic_82xx_set_sys_info(void *, int, u32); +void qlcnic_82xx_store_cap_mask(void *, u32); #endif /* __QLCNIC_HW_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 54ebf300332a..173b3d12991f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -13,16 +13,19 @@ #include "qlcnic.h" -#define TX_ETHER_PKT 0x01 -#define TX_TCP_PKT 0x02 -#define TX_UDP_PKT 0x03 -#define TX_IP_PKT 0x04 -#define TX_TCP_LSO 0x05 -#define TX_TCP_LSO6 0x06 -#define TX_TCPV6_PKT 0x0b -#define TX_UDPV6_PKT 0x0c -#define FLAGS_VLAN_TAGGED 0x10 -#define FLAGS_VLAN_OOB 0x40 +#define QLCNIC_TX_ETHER_PKT 0x01 +#define QLCNIC_TX_TCP_PKT 0x02 +#define QLCNIC_TX_UDP_PKT 0x03 +#define QLCNIC_TX_IP_PKT 0x04 +#define QLCNIC_TX_TCP_LSO 0x05 +#define QLCNIC_TX_TCP_LSO6 0x06 +#define QLCNIC_TX_ENCAP_PKT 0x07 +#define QLCNIC_TX_ENCAP_LSO 0x08 +#define QLCNIC_TX_TCPV6_PKT 0x0b +#define QLCNIC_TX_UDPV6_PKT 0x0c + +#define QLCNIC_FLAGS_VLAN_TAGGED 0x10 +#define QLCNIC_FLAGS_VLAN_OOB 0x40 #define qlcnic_set_tx_vlan_tci(cmd_desc, v) \ (cmd_desc)->vlan_TCI = cpu_to_le16(v); @@ -364,6 +367,101 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, spin_unlock(&adapter->mac_learn_lock); } +#define QLCNIC_ENCAP_VXLAN_PKT BIT_0 +#define QLCNIC_ENCAP_OUTER_L3_IP6 BIT_1 +#define QLCNIC_ENCAP_INNER_L3_IP6 BIT_2 +#define QLCNIC_ENCAP_INNER_L4_UDP BIT_3 +#define QLCNIC_ENCAP_DO_L3_CSUM BIT_4 +#define QLCNIC_ENCAP_DO_L4_CSUM BIT_5 + +static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter, + struct cmd_desc_type0 *first_desc, + struct sk_buff *skb, + struct qlcnic_host_tx_ring *tx_ring) +{ + u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0; + int copied, copy_len, descr_size; + u32 producer = tx_ring->producer; + struct cmd_desc_type0 *hwdesc; + u16 flags = 0, encap_descr = 0; + + opcode = QLCNIC_TX_ETHER_PKT; + encap_descr = QLCNIC_ENCAP_VXLAN_PKT; + + if (skb_is_gso(skb)) { + inner_hdr_len = skb_inner_transport_header(skb) + + inner_tcp_hdrlen(skb) - + skb_inner_mac_header(skb); + + /* VXLAN header size = 8 */ + outer_hdr_len = skb_transport_offset(skb) + 8 + + sizeof(struct udphdr); + first_desc->outer_hdr_length = outer_hdr_len; + total_hdr_len = inner_hdr_len + outer_hdr_len; + encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM | + QLCNIC_ENCAP_DO_L4_CSUM; + first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + first_desc->hdr_length = inner_hdr_len; + + /* Copy inner and outer headers in Tx descriptor(s) + * If total_hdr_len > cmd_desc_type0, use multiple + * descriptors + */ + copied = 0; + descr_size = (int)sizeof(struct cmd_desc_type0); + while (copied < total_hdr_len) { + copy_len = min(descr_size, (total_hdr_len - copied)); + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + skb_copy_from_linear_data_offset(skb, copied, + (char *)hwdesc, + copy_len); + copied += copy_len; + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + + /* Make sure updated tx_ring->producer is visible + * for qlcnic_tx_avail() + */ + smp_mb(); + adapter->stats.encap_lso_frames++; + + opcode = QLCNIC_TX_ENCAP_LSO; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (inner_ip_hdr(skb)->version == 6) { + if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) + encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; + } else { + if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP) + encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; + } + + adapter->stats.encap_tx_csummed++; + opcode = QLCNIC_TX_ENCAP_PKT; + } + + /* Prepare first 16 bits of byte offset 16 of Tx descriptor */ + if (ip_hdr(skb)->version == 6) + encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6; + + /* outer IP header's size in 32bit words size*/ + encap_descr |= (skb_network_header_len(skb) >> 2) << 6; + + /* outer IP header offset */ + encap_descr |= skb_network_offset(skb) << 10; + first_desc->encap_descr = cpu_to_le16(encap_descr); + + first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) - + skb->data; + first_desc->ip_hdr_offset = skb_inner_network_offset(skb); + + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); + + return 0; +} + static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb, struct qlcnic_host_tx_ring *tx_ring) @@ -378,11 +476,11 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, if (protocol == ETH_P_8021Q) { vh = (struct vlan_ethhdr *)skb->data; - flags = FLAGS_VLAN_TAGGED; + flags = QLCNIC_FLAGS_VLAN_TAGGED; vlan_tci = ntohs(vh->h_vlan_TCI); protocol = ntohs(vh->h_vlan_encapsulated_proto); } else if (vlan_tx_tag_present(skb)) { - flags = FLAGS_VLAN_OOB; + flags = QLCNIC_FLAGS_VLAN_OOB; vlan_tci = vlan_tx_tag_get(skb); } if (unlikely(adapter->tx_pvid)) { @@ -391,7 +489,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) goto set_flags; - flags = FLAGS_VLAN_OOB; + flags = QLCNIC_FLAGS_VLAN_OOB; vlan_tci = adapter->tx_pvid; } set_flags: @@ -402,25 +500,26 @@ set_flags: flags |= BIT_0; memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN); } - opcode = TX_ETHER_PKT; + opcode = QLCNIC_TX_ETHER_PKT; if (skb_is_gso(skb)) { hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); - first_desc->total_hdr_length = hdr_len; - opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; + first_desc->hdr_length = hdr_len; + opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 : + QLCNIC_TX_TCP_LSO; /* For LSO, we need to copy the MAC/IP/TCP headers into * the descriptor ring */ copied = 0; offset = 2; - if (flags & FLAGS_VLAN_OOB) { - first_desc->total_hdr_length += VLAN_HLEN; + if (flags & QLCNIC_FLAGS_VLAN_OOB) { + first_desc->hdr_length += VLAN_HLEN; first_desc->tcp_hdr_offset = VLAN_HLEN; first_desc->ip_hdr_offset = VLAN_HLEN; /* Only in case of TSO on vlan device */ - flags |= FLAGS_VLAN_TAGGED; + flags |= QLCNIC_FLAGS_VLAN_TAGGED; /* Create a TSO vlan header template for firmware */ hwdesc = &tx_ring->desc_head[producer]; @@ -464,16 +563,16 @@ set_flags: l4proto = ip_hdr(skb)->protocol; if (l4proto == IPPROTO_TCP) - opcode = TX_TCP_PKT; + opcode = QLCNIC_TX_TCP_PKT; else if (l4proto == IPPROTO_UDP) - opcode = TX_UDP_PKT; + opcode = QLCNIC_TX_UDP_PKT; } else if (protocol == ETH_P_IPV6) { l4proto = ipv6_hdr(skb)->nexthdr; if (l4proto == IPPROTO_TCP) - opcode = TX_TCPV6_PKT; + opcode = QLCNIC_TX_TCPV6_PKT; else if (l4proto == IPPROTO_UDP) - opcode = TX_UDPV6_PKT; + opcode = QLCNIC_TX_UDPV6_PKT; } } first_desc->tcp_hdr_offset += skb_transport_offset(skb); @@ -563,6 +662,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct ethhdr *phdr; int i, k, frag_count, delta = 0; u32 producer, num_txd; + u16 protocol; + bool l4_is_udp = false; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { netif_tx_stop_all_queues(netdev); @@ -653,8 +754,23 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_ring->producer = get_next_index(producer, num_txd); smp_mb(); - if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring))) - goto unwind_buff; + protocol = ntohs(skb->protocol); + if (protocol == ETH_P_IP) + l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP; + else if (protocol == ETH_P_IPV6) + l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP; + + /* Check if it is a VXLAN packet */ + if (!skb->encapsulation || !l4_is_udp || + !qlcnic_encap_tx_offload(adapter)) { + if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, + tx_ring))) + goto unwind_buff; + } else { + if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc, + skb, tx_ring))) + goto unwind_buff; + } if (adapter->drv_mac_learn) qlcnic_send_filter(adapter, first_desc, skb); @@ -1587,6 +1703,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt) return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0; } +#define QLCNIC_ENCAP_LENGTH_MASK 0x7f + +static inline u8 qlcnic_encap_length(u64 sts_data) +{ + return sts_data & QLCNIC_ENCAP_LENGTH_MASK; +} + static struct qlcnic_rx_buffer * qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, struct qlcnic_host_sds_ring *sds_ring, @@ -1637,6 +1760,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); + if (qlcnic_encap_length(sts_data[1]) && + skb->ip_summed == CHECKSUM_UNNECESSARY) { + skb->encapsulation = 1; + adapter->stats.encap_rx_csummed++; + } + if (vid != 0xffff) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1222865cfb73..309d05640883 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -21,6 +21,9 @@ #include <linux/aer.h> #include <linux/log2.h> #include <linux/pci.h> +#ifdef CONFIG_QLCNIC_VXLAN +#include <net/vxlan.h> +#endif MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -90,7 +93,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *); static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, pci_channel_state_t); - static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -462,6 +464,37 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev, return 0; } +#ifdef CONFIG_QLCNIC_VXLAN +static void qlcnic_add_vxlan_port(struct net_device *netdev, + sa_family_t sa_family, __be16 port) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_hardware_context *ahw = adapter->ahw; + + /* Adapter supports only one VXLAN port. Use very first port + * for enabling offload + */ + if (!qlcnic_encap_rx_offload(adapter) || ahw->vxlan_port) + return; + + ahw->vxlan_port = ntohs(port); + adapter->flags |= QLCNIC_ADD_VXLAN_PORT; +} + +static void qlcnic_del_vxlan_port(struct net_device *netdev, + sa_family_t sa_family, __be16 port) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_hardware_context *ahw = adapter->ahw; + + if (!qlcnic_encap_rx_offload(adapter) || !ahw->vxlan_port || + (ahw->vxlan_port != ntohs(port))) + return; + + adapter->flags |= QLCNIC_DEL_VXLAN_PORT; +} +#endif + static const struct net_device_ops qlcnic_netdev_ops = { .ndo_open = qlcnic_open, .ndo_stop = qlcnic_close, @@ -480,6 +513,10 @@ static const struct net_device_ops qlcnic_netdev_ops = { .ndo_fdb_del = qlcnic_fdb_del, .ndo_fdb_dump = qlcnic_fdb_dump, .ndo_get_phys_port_id = qlcnic_get_phys_port_id, +#ifdef CONFIG_QLCNIC_VXLAN + .ndo_add_vxlan_port = qlcnic_add_vxlan_port, + .ndo_del_vxlan_port = qlcnic_del_vxlan_port, +#endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, #endif @@ -561,6 +598,12 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .disable_sds_intr = qlcnic_82xx_disable_sds_intr, .enable_tx_intr = qlcnic_82xx_enable_tx_intr, .disable_tx_intr = qlcnic_82xx_disable_tx_intr, + .get_saved_state = qlcnic_82xx_get_saved_state, + .set_saved_state = qlcnic_82xx_set_saved_state, + .cache_tmpl_hdr_values = qlcnic_82xx_cache_tmpl_hdr_values, + .get_cap_size = qlcnic_82xx_get_cap_size, + .set_sys_info = qlcnic_82xx_set_sys_info, + .store_cap_mask = qlcnic_82xx_store_cap_mask, }; static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) @@ -684,7 +727,7 @@ restore: int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) { struct pci_dev *pdev = adapter->pdev; - int err = -1, vector; + int err, vector; if (!adapter->msix_entries) { adapter->msix_entries = kcalloc(num_msix, @@ -701,13 +744,17 @@ enable_msix: for (vector = 0; vector < num_msix; vector++) adapter->msix_entries[vector].entry = vector; - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { + err = pci_enable_msix_range(pdev, + adapter->msix_entries, 1, num_msix); + + if (err == num_msix) { adapter->flags |= QLCNIC_MSIX_ENABLED; adapter->ahw->num_msix = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); - return err; + return 0; } else if (err > 0) { + pci_disable_msix(pdev); + dev_info(&pdev->dev, "Unable to allocate %d MSI-X vectors, Available vectors %d\n", num_msix, err); @@ -715,12 +762,12 @@ enable_msix: if (qlcnic_82xx_check(adapter)) { num_msix = rounddown_pow_of_two(err); if (err < QLCNIC_82XX_MINIMUM_VECTOR) - return -EIO; + return -ENOSPC; } else { num_msix = rounddown_pow_of_two(err - 1); num_msix += 1; if (err < QLCNIC_83XX_MINIMUM_VECTOR) - return -EIO; + return -ENOSPC; } if (qlcnic_82xx_check(adapter) && @@ -747,7 +794,7 @@ enable_msix: } } - return err; + return -EIO; } static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) @@ -1934,6 +1981,11 @@ qlcnic_attach(struct qlcnic_adapter *adapter) qlcnic_create_sysfs_entries(adapter); +#ifdef CONFIG_QLCNIC_VXLAN + if (qlcnic_encap_rx_offload(adapter)) + vxlan_get_rx_port(netdev); +#endif + adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; return 0; @@ -2196,6 +2248,19 @@ 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; + if (qlcnic_encap_tx_offload(adapter)) { + netdev->features |= NETIF_F_GSO_UDP_TUNNEL; + + /* encapsulation Tx offload supported by Adapter */ + netdev->hw_enc_features = NETIF_F_IP_CSUM | + NETIF_F_GSO_UDP_TUNNEL | + NETIF_F_TSO | + NETIF_F_TSO6; + } + + if (qlcnic_encap_rx_offload(adapter)) + netdev->hw_enc_features |= NETIF_F_RXCSUM; + netdev->hw_features = netdev->features; netdev->priv_flags |= IFF_UNICAST_FLT; netdev->irq = adapter->msix_entries[0].vector; @@ -2442,8 +2507,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) { switch (err) { case -ENOTRECOVERABLE: - dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n"); - dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n"); + dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n"); + dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n"); goto err_out_free_hw; case -ENOMEM: dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n"); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index 7763962e2ec4..37b979b1266b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode { QLCNIC_DUMP_RDEND = 255 }; +inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + return hdr->saved_state[index]; +} + +inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index, + u32 value) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + hdr->saved_state[index] = value; +} + +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ + struct qlcnic_82xx_dump_template_hdr *hdr; + + hdr = fw_dump->tmpl_hdr; + fw_dump->tmpl_hdr_size = hdr->size; + fw_dump->version = hdr->version; + fw_dump->num_entries = hdr->num_entries; + fw_dump->offset = hdr->offset; + + hdr->drv_cap_mask = hdr->cap_mask; + fw_dump->cap_mask = hdr->cap_mask; +} + +inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + return hdr->cap_sizes[index]; +} + +void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + hdr->sys_info[idx] = value; +} + +void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr; + + hdr->drv_cap_mask = mask; +} + +inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + return hdr->saved_state[index]; +} + +inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index, + u32 value) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + hdr->saved_state[index] = value; +} + +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ + struct qlcnic_83xx_dump_template_hdr *hdr; + + hdr = fw_dump->tmpl_hdr; + fw_dump->tmpl_hdr_size = hdr->size; + fw_dump->version = hdr->version; + fw_dump->num_entries = hdr->num_entries; + fw_dump->offset = hdr->offset; + + hdr->drv_cap_mask = hdr->cap_mask; + fw_dump->cap_mask = hdr->cap_mask; +} + +inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + return hdr->cap_sizes[index]; +} + +void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + hdr->sys_info[idx] = value; +} + +void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ + struct qlcnic_83xx_dump_template_hdr *hdr; + + hdr = tmpl_hdr; + hdr->drv_cap_mask = mask; +} + struct qlcnic_dump_operations { enum qlcnic_minidump_opcode opcode; u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *, @@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter, static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, __le32 *buffer) { + void *hdr = adapter->ahw->fw_dump.tmpl_hdr; + struct __ctrl *ctr = &entry->region.ctrl; int i, k, timeout = 0; - u32 addr, data; + u32 addr, data, temp; u8 no_ops; - struct __ctrl *ctr = &entry->region.ctrl; - struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr; addr = ctr->addr; no_ops = ctr->no_ops; @@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, } break; case QLCNIC_DUMP_RD_SAVE: - if (ctr->index_a) - addr = t_hdr->saved_state[ctr->index_a]; + temp = ctr->index_a; + if (temp) + addr = qlcnic_get_saved_state(adapter, + hdr, + temp); data = qlcnic_ind_rd(adapter, addr); - t_hdr->saved_state[ctr->index_v] = data; + qlcnic_set_saved_state(adapter, hdr, + ctr->index_v, data); break; case QLCNIC_DUMP_WRT_SAVED: - if (ctr->index_v) - data = t_hdr->saved_state[ctr->index_v]; + temp = ctr->index_v; + if (temp) + data = qlcnic_get_saved_state(adapter, + hdr, + temp); else data = ctr->val1; - if (ctr->index_a) - addr = t_hdr->saved_state[ctr->index_a]; + + temp = ctr->index_a; + if (temp) + addr = qlcnic_get_saved_state(adapter, + hdr, + temp); qlcnic_ind_wr(adapter, addr, data); break; case QLCNIC_DUMP_MOD_SAVE_ST: - data = t_hdr->saved_state[ctr->index_v]; + data = qlcnic_get_saved_state(adapter, hdr, + ctr->index_v); data <<= ctr->shl_val; data >>= ctr->shr_val; if (ctr->val2) data &= ctr->val2; data |= ctr->val3; data += ctr->val1; - t_hdr->saved_state[ctr->index_v] = data; + qlcnic_set_saved_state(adapter, hdr, + ctr->index_v, data); break; default: dev_info(&adapter->pdev->dev, @@ -544,7 +658,7 @@ out: static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter, struct __mem *mem) { - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_83xx_dump_template_hdr *tmpl_hdr; struct device *dev = &adapter->pdev->dev; u32 dma_no, dma_base_addr, temp_addr; int i, ret, dma_sts; @@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter, struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; u32 temp, dma_base_addr, size = 0, read_size = 0; struct qlcnic_pex_dma_descriptor *dma_descr; - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_83xx_dump_template_hdr *tmpl_hdr; struct device *dev = &adapter->pdev->dev; dma_addr_t dma_phys_addr; void *dma_buffer; @@ -938,8 +1052,8 @@ static int qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd) { - struct qlcnic_dump_template_hdr tmp_hdr; - u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32); + struct qlcnic_83xx_dump_template_hdr tmp_hdr; + u32 size = sizeof(tmp_hdr) / sizeof(u32); int ret = 0; if (qlcnic_82xx_check(adapter)) @@ -1027,17 +1141,19 @@ free_mem: return err; } +#define QLCNIC_TEMPLATE_VERSION (0x20001) + int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) { - int err; - u32 temp_size = 0; - u32 version, csum, *tmp_buf; struct qlcnic_hardware_context *ahw; - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_fw_dump *fw_dump; + u32 version, csum, *tmp_buf; u8 use_flash_temp = 0; + u32 temp_size = 0; + int err; ahw = adapter->ahw; - + fw_dump = &ahw->fw_dump; err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size, &use_flash_temp); if (err) { @@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) return -EIO; } - ahw->fw_dump.tmpl_hdr = vzalloc(temp_size); - if (!ahw->fw_dump.tmpl_hdr) + fw_dump->tmpl_hdr = vzalloc(temp_size); + if (!fw_dump->tmpl_hdr) return -ENOMEM; - tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr; + tmp_buf = (u32 *)fw_dump->tmpl_hdr; if (use_flash_temp) goto flash_temp; @@ -1065,8 +1181,8 @@ flash_temp: dev_err(&adapter->pdev->dev, "Failed to get minidump template header %d\n", err); - vfree(ahw->fw_dump.tmpl_hdr); - ahw->fw_dump.tmpl_hdr = NULL; + vfree(fw_dump->tmpl_hdr); + fw_dump->tmpl_hdr = NULL; return -EIO; } } @@ -1076,21 +1192,22 @@ flash_temp: if (csum) { dev_err(&adapter->pdev->dev, "Template header checksum validation failed\n"); - vfree(ahw->fw_dump.tmpl_hdr); - ahw->fw_dump.tmpl_hdr = NULL; + vfree(fw_dump->tmpl_hdr); + fw_dump->tmpl_hdr = NULL; return -EIO; } - tmpl_hdr = ahw->fw_dump.tmpl_hdr; - tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask; + qlcnic_cache_tmpl_hdr_values(adapter, fw_dump); + dev_info(&adapter->pdev->dev, "Default minidump capture mask 0x%x\n", - tmpl_hdr->cap_mask); + fw_dump->cap_mask); - if ((tmpl_hdr->version & 0xfffff) >= 0x20001) - ahw->fw_dump.use_pex_dma = true; + if (qlcnic_83xx_check(adapter) && + (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION) + fw_dump->use_pex_dma = true; else - ahw->fw_dump.use_pex_dma = false; + fw_dump->use_pex_dma = false; qlcnic_enable_fw_dump_state(adapter); @@ -1099,21 +1216,22 @@ flash_temp: int qlcnic_dump_fw(struct qlcnic_adapter *adapter) { - __le32 *buffer; - u32 ocm_window; - char mesg[64]; - char *msg[] = {mesg, NULL}; - int i, k, ops_cnt, ops_index, dump_size = 0; - u32 entry_offset, dump, no_entries, buf_offset = 0; - struct qlcnic_dump_entry *entry; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; - struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr; static const struct qlcnic_dump_operations *fw_dump_ops; + struct qlcnic_83xx_dump_template_hdr *hdr_83xx; + u32 entry_offset, dump, no_entries, buf_offset = 0; + int i, k, ops_cnt, ops_index, dump_size = 0; struct device *dev = &adapter->pdev->dev; struct qlcnic_hardware_context *ahw; - void *temp_buffer; + struct qlcnic_dump_entry *entry; + void *temp_buffer, *tmpl_hdr; + u32 ocm_window; + __le32 *buffer; + char mesg[64]; + char *msg[] = {mesg, NULL}; ahw = adapter->ahw; + tmpl_hdr = fw_dump->tmpl_hdr; /* Return if we don't have firmware dump template header */ if (!tmpl_hdr) @@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n"); /* Calculate the size for dump data area only */ for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) - if (i & tmpl_hdr->drv_cap_mask) - dump_size += tmpl_hdr->cap_sizes[k]; + if (i & fw_dump->cap_mask) + dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k); + if (!dump_size) return -EIO; @@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) buffer = fw_dump->data; fw_dump->size = dump_size; - no_entries = tmpl_hdr->num_entries; - entry_offset = tmpl_hdr->offset; - tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; - tmpl_hdr->sys_info[1] = adapter->fw_version; + no_entries = fw_dump->num_entries; + entry_offset = fw_dump->offset; + qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION); + qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version); if (fw_dump->use_pex_dma) { temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE, @@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops); fw_dump_ops = qlcnic_fw_dump_ops; } else { + hdr_83xx = tmpl_hdr; ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops); fw_dump_ops = qlcnic_83xx_fw_dump_ops; - ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func]; - tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; - tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func; + ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func]; + hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; + hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func; } for (i = 0; i < no_entries; i++) { - entry = (void *)tmpl_hdr + entry_offset; - if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { + entry = tmpl_hdr + entry_offset; + if (!(entry->hdr.mask & fw_dump->cap_mask)) { entry->hdr.flags |= QLCNIC_DUMP_SKIP; entry_offset += entry->hdr.offset; continue; @@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) fw_dump->clr = 1; snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name); - dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n", - adapter->netdev->name, fw_dump->size, tmpl_hdr->size); + netdev_info(adapter->netdev, + "Dump data %d bytes captured, template header size %d bytes\n", + fw_dump->size, fw_dump->tmpl_hdr_size); /* Send a udev event to notify availability of FW dump */ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index e5277a632671..14f748cbf0de 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -15,6 +15,7 @@ #define QLC_MAC_OPCODE_MASK 0x7 #define QLC_VF_FLOOD_BIT BIT_16 #define QLC_FLOOD_MODE 0x5 +#define QLC_SRIOV_ALLOW_VLAN0 BIT_19 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -335,8 +336,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, return err; cmd.req.arg[1] = 0x4; - if (enable) + if (enable) { cmd.req.arg[1] |= BIT_16; + if (qlcnic_84xx_check(adapter)) + cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0; + } err = qlcnic_issue_cmd(adapter, &cmd); if (err) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 3d64113a35af..448d156c3d08 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -350,33 +350,15 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } -static u32 qlcnic_get_pci_func_count(struct qlcnic_adapter *adapter) -{ - struct qlcnic_hardware_context *ahw = adapter->ahw; - u32 count = 0; - - if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return ahw->total_nic_func; - - if (ahw->total_pci_func <= QLC_DEFAULT_VNIC_COUNT) - count = QLC_DEFAULT_VNIC_COUNT; - else - count = ahw->max_vnic_func; - - return count; -} - int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) { - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); int i; - for (i = 0; i < pci_func_count; i++) { + for (i = 0; i < adapter->ahw->max_vnic_func; i++) { if (adapter->npars[i].pci_func == pci_func) return i; } - - return -1; + return -EINVAL; } static int validate_pm_config(struct qlcnic_adapter *adapter, @@ -464,23 +446,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_pm_func_cfg *pm_cfg; - int i, pm_cfg_size; u8 pci_func; + u32 count; + int i; - pm_cfg_size = pci_func_count * sizeof(*pm_cfg); - if (size != pm_cfg_size) - return QL_STATUS_INVALID_PARAM; - - memset(buf, 0, pm_cfg_size); + memset(buf, 0, size); pm_cfg = (struct qlcnic_pm_func_cfg *)buf; - - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_pm_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { pci_func = adapter->npars[i].pci_func; - if (!adapter->npars[i].active) + if (pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); continue; - + } if (!adapter->npars[i].eswitch_status) continue; @@ -494,7 +474,6 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, static int validate_esw_config(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg, int count) { - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_hardware_context *ahw = adapter->ahw; int i, ret; u32 op_mode; @@ -507,7 +486,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter, for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; - if (pci_func >= pci_func_count) + if (pci_func >= ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) @@ -642,23 +621,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_esw_func_cfg *esw_cfg; - size_t esw_cfg_size; - u8 i, pci_func; - - esw_cfg_size = pci_func_count * sizeof(*esw_cfg); - if (size != esw_cfg_size) - return QL_STATUS_INVALID_PARAM; + u8 pci_func; + u32 count; + int i; - memset(buf, 0, esw_cfg_size); + memset(buf, 0, size); esw_cfg = (struct qlcnic_esw_func_cfg *)buf; - - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_esw_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { pci_func = adapter->npars[i].pci_func; - if (!adapter->npars[i].active) + if (pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); continue; - + } if (!adapter->npars[i].eswitch_status) continue; @@ -741,23 +718,24 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_npar_func_cfg *np_cfg; struct qlcnic_info nic_info; - size_t np_cfg_size; int i, ret; - - np_cfg_size = pci_func_count * sizeof(*np_cfg); - if (size != np_cfg_size) - return QL_STATUS_INVALID_PARAM; + u32 count; memset(&nic_info, 0, sizeof(struct qlcnic_info)); - memset(buf, 0, np_cfg_size); + memset(buf, 0, size); np_cfg = (struct qlcnic_npar_func_cfg *)buf; - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_npar_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { if (qlcnic_is_valid_nic_func(adapter, i) < 0) continue; + if (adapter->npars[i].pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); + continue; + } ret = qlcnic_get_nic_info(adapter, &nic_info, i); if (ret) return ret; @@ -783,7 +761,6 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_esw_statistics port_stats; int ret; @@ -793,7 +770,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file, if (size != sizeof(struct qlcnic_esw_statistics)) return QL_STATUS_INVALID_PARAM; - if (offset >= pci_func_count) + if (offset >= adapter->ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; memset(&port_stats, 0, size); @@ -884,13 +861,12 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file, struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); int ret; if (qlcnic_83xx_check(adapter)) return QLC_STATUS_UNSUPPORTED_CMD; - if (offset >= pci_func_count) + if (offset >= adapter->ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, @@ -914,17 +890,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_pci_func_cfg *pci_cfg; struct qlcnic_pci_info *pci_info; - size_t pci_cfg_sz; int i, ret; + u32 count; - pci_cfg_sz = pci_func_count * sizeof(*pci_cfg); - if (size != pci_cfg_sz) - return QL_STATUS_INVALID_PARAM; - - pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL); + pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; @@ -935,7 +906,8 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, } pci_cfg = (struct qlcnic_pci_func_cfg *)buf; - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_pci_func_cfg); + for (i = 0; i < count; i++) { pci_cfg[i].pci_func = pci_info[i].id; pci_cfg[i].func_type = pci_info[i].type; pci_cfg[i].func_state = 0; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 656c65ddadb4..0a1d76acab81 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2556,11 +2556,10 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr) if (skb_is_gso(skb)) { int err; - if (skb_header_cloned(skb)) { - err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (err) - return err; - } + + err = skb_cow_head(skb, 0); + if (err < 0) + return err; mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB; mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC; @@ -3331,24 +3330,16 @@ static void ql_enable_msix(struct ql_adapter *qdev) for (i = 0; i < qdev->intr_count; i++) qdev->msi_x_entry[i].entry = i; - /* Loop to get our vectors. We start with - * what we want and settle for what we get. - */ - do { - err = pci_enable_msix(qdev->pdev, - qdev->msi_x_entry, qdev->intr_count); - if (err > 0) - qdev->intr_count = err; - } while (err > 0); - + err = pci_enable_msix_range(qdev->pdev, qdev->msi_x_entry, + 1, qdev->intr_count); if (err < 0) { kfree(qdev->msi_x_entry); qdev->msi_x_entry = NULL; netif_warn(qdev, ifup, qdev->ndev, "MSI-X Enable failed, trying MSI.\n"); - qdev->intr_count = 1; qlge_irq_type = MSI_IRQ; - } else if (err == 0) { + } else { + qdev->intr_count = err; set_bit(QL_MSIX_ENABLED, &qdev->flags); netif_info(qdev, ifup, qdev->ndev, "MSI-X Enabled, got %d vectors.\n", |