diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
18 files changed, 1513 insertions, 814 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index f2a7c7166e24..f19f81cde134 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 52 -#define QLCNIC_LINUX_VERSIONID "5.3.52" +#define _QLCNIC_LINUX_SUBVERSION 55 +#define QLCNIC_LINUX_VERSIONID "5.3.55" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -105,6 +105,8 @@ #define QLCNIC_DEF_TX_RINGS 4 #define QLCNIC_MAX_VNIC_TX_RINGS 4 #define QLCNIC_MAX_VNIC_SDS_RINGS 4 +#define QLCNIC_83XX_MINIMUM_VECTOR 3 +#define QLCNIC_82XX_MINIMUM_VECTOR 2 enum qlcnic_queue_type { QLCNIC_TX_QUEUE = 1, @@ -115,6 +117,10 @@ enum qlcnic_queue_type { #define QLCNIC_VNIC_MODE 0xFF #define QLCNIC_DEFAULT_MODE 0x0 +/* Virtual NIC function count */ +#define QLC_DEFAULT_VNIC_COUNT 8 +#define QLC_84XX_VNIC_COUNT 16 + /* * Following are the states of the Phantom. Phantom will set them and * Host will read to check if the fields are correct. @@ -365,6 +371,7 @@ struct qlcnic_rx_buffer { */ #define QLCNIC_INTR_COAL_TYPE_RX 1 #define QLCNIC_INTR_COAL_TYPE_TX 2 +#define QLCNIC_INTR_COAL_TYPE_RX_TX 3 #define QLCNIC_DEF_INTR_COALESCE_RX_TIME_US 3 #define QLCNIC_DEF_INTR_COALESCE_RX_PACKETS 256 @@ -374,7 +381,7 @@ struct qlcnic_rx_buffer { #define QLCNIC_INTR_DEFAULT 0x04 #define QLCNIC_CONFIG_INTR_COALESCE 3 -#define QLCNIC_DEV_INFO_SIZE 1 +#define QLCNIC_DEV_INFO_SIZE 2 struct qlcnic_nic_intr_coalesce { u8 type; @@ -462,8 +469,10 @@ struct qlcnic_hardware_context { u16 max_rx_ques; u16 max_mtu; u32 msg_enable; - u16 act_pci_func; + u16 total_nic_func; u16 max_pci_func; + u32 max_vnic_func; + u32 total_pci_func; u32 capabilities; u32 extra_capability[3]; @@ -791,9 +800,10 @@ struct qlcnic_cardrsp_tx_ctx { #define QLCNIC_MAC_VLAN_ADD 3 #define QLCNIC_MAC_VLAN_DEL 4 -struct qlcnic_mac_list_s { +struct qlcnic_mac_vlan_list { struct list_head list; uint8_t mac_addr[ETH_ALEN+2]; + u16 vlan_id; }; /* MAC Learn */ @@ -860,7 +870,7 @@ struct qlcnic_mac_list_s { #define QLCNIC_FW_CAP2_HW_LRO_IPV6 BIT_3 #define QLCNIC_FW_CAPABILITY_SET_DRV_VER BIT_5 #define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7 -#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_8 +#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9 /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 @@ -954,6 +964,7 @@ struct qlcnic_ipaddr { #define QLCNIC_TX_INTR_SHARED 0x10000 #define QLCNIC_APP_CHANGED_FLAGS 0x20000 #define QLCNIC_HAS_PHYS_PORT_ID 0x40000 +#define QLCNIC_TSS_RSS 0x80000 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) @@ -963,6 +974,9 @@ struct qlcnic_ipaddr { #define QLCNIC_BEACON_EANBLE 0xC #define QLCNIC_BEACON_DISABLE 0xD +#define QLCNIC_BEACON_ON 2 +#define QLCNIC_BEACON_OFF 0 + #define QLCNIC_MSIX_TBL_SPACE 8192 #define QLCNIC_PCI_REG_MSIX_TBL 0x44 #define QLCNIC_MSIX_TBL_PGSIZE 4096 @@ -1047,6 +1061,9 @@ struct qlcnic_adapter { u8 drv_tx_rings; /* max tx rings supported by driver */ u8 drv_sds_rings; /* max sds rings supported by driver */ + u8 drv_tss_rings; /* tss ring input */ + u8 drv_rss_rings; /* rss ring input */ + u8 rx_csum; u8 portnum; @@ -1072,6 +1089,7 @@ struct qlcnic_adapter { u64 dev_rst_time; bool drv_mac_learn; bool fdb_mac_learn; + bool rx_mac_learn; unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; u8 flash_mfg_id; struct qlcnic_npar_info *npars; @@ -1260,7 +1278,7 @@ struct qlcnic_pci_func_cfg { u16 port_num; u8 pci_func; u8 func_state; - u8 def_mac_addr[6]; + u8 def_mac_addr[ETH_ALEN]; }; struct qlcnic_npar_func_cfg { @@ -1462,8 +1480,6 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config); int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data); int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data); -void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *); -void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64); #define ADDR_IN_RANGE(addr, low, high) \ (((addr) < (high)) && ((addr) >= (low))) @@ -1499,16 +1515,11 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int); #define MAX_CTL_CHECK 1000 -int qlcnic_wol_supported(struct qlcnic_adapter *adapter); void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); int qlcnic_dump_fw(struct qlcnic_adapter *); int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *); bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *); -pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, - pci_channel_state_t); -pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *); -void qlcnic_82xx_io_resume(struct pci_dev *); /* Functions from qlcnic_init.c */ void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int); @@ -1543,9 +1554,7 @@ int qlcnic_check_fw_status(struct qlcnic_adapter *adapter); void qlcnic_watchdog_task(struct work_struct *work); void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); -int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); void qlcnic_set_multi(struct net_device *netdev); -void __qlcnic_set_multi(struct net_device *, u16); int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16); int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *); void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter); @@ -1558,13 +1567,11 @@ netdev_features_t qlcnic_fix_features(struct net_device *netdev, netdev_features_t features); int qlcnic_set_features(struct net_device *netdev, netdev_features_t features); int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable); -int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *); /* Functions from qlcnic_ethtool.c */ int qlcnic_check_loopback_buff(unsigned char *, u8 []); int qlcnic_do_lb_test(struct qlcnic_adapter *, u8); -int qlcnic_loopback_test(struct net_device *, u8); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); @@ -1573,10 +1580,9 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, struct net_device *); void qlcnic_set_tx_ring_count(struct qlcnic_adapter *, u8); void qlcnic_set_sds_ring_count(struct qlcnic_adapter *, u8); -int qlcnic_setup_rings(struct qlcnic_adapter *, u8, u8); +int qlcnic_setup_rings(struct qlcnic_adapter *); int qlcnic_validate_rings(struct qlcnic_adapter *, __u32, int); void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter); -void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); int qlcnic_enable_msix(struct qlcnic_adapter *, u32); void qlcnic_set_drv_version(struct qlcnic_adapter *); @@ -1605,11 +1611,8 @@ void qlcnic_dump_mbx(struct qlcnic_adapter *, struct qlcnic_cmd_args *); void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter); void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter); -void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter); -void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter); void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter); void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter); -int qlcnic_82xx_get_settings(struct qlcnic_adapter *, struct ethtool_cmd *); int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); @@ -1617,7 +1620,7 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); - +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *); void qlcnic_down(struct qlcnic_adapter *, struct net_device *); int qlcnic_up(struct qlcnic_adapter *, struct net_device *); void __qlcnic_down(struct qlcnic_adapter *, struct net_device *); @@ -1632,15 +1635,15 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *); int qlcnic_set_default_offload_settings(struct qlcnic_adapter *); int qlcnic_reset_npar_config(struct qlcnic_adapter *); int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); -void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16); -int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *); int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); int qlcnic_read_mac_addr(struct qlcnic_adapter *); int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); void qlcnic_set_netdev_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); void qlcnic_sriov_vf_schedule_multi(struct net_device *); -void qlcnic_vf_add_mc_list(struct net_device *, u16); +int qlcnic_is_valid_nic_func(struct qlcnic_adapter *, u8); +int qlcnic_get_pci_func_type(struct qlcnic_adapter *, u16, u16 *, u16 *, + u16 *); /* * QLOGIC Board information @@ -1674,11 +1677,8 @@ static inline int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, err = netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); if (err) - dev_err(&adapter->pdev->dev, "failed to set %d Tx queues\n", - adapter->drv_tx_rings); - else - dev_info(&adapter->pdev->dev, "Set %d Tx queues\n", - adapter->drv_tx_rings); + netdev_err(netdev, "failed to set %d Tx queues\n", + adapter->drv_tx_rings); return err; } @@ -1744,7 +1744,8 @@ struct qlcnic_hardware_ops { int (*change_macvlan) (struct qlcnic_adapter *, u8*, u16, u8); void (*napi_enable) (struct qlcnic_adapter *); void (*napi_disable) (struct qlcnic_adapter *); - void (*config_intr_coal) (struct qlcnic_adapter *); + int (*config_intr_coal) (struct qlcnic_adapter *, + struct ethtool_coalesce *); int (*config_rss) (struct qlcnic_adapter *, int); int (*config_hw_lro) (struct qlcnic_adapter *, int); int (*config_loopback) (struct qlcnic_adapter *, u8); @@ -1759,6 +1760,15 @@ struct qlcnic_hardware_ops { pci_channel_state_t); pci_ers_result_t (*io_slot_reset) (struct pci_dev *); void (*io_resume) (struct pci_dev *); + void (*get_beacon_state)(struct qlcnic_adapter *); + void (*enable_sds_intr) (struct qlcnic_adapter *, + struct qlcnic_host_sds_ring *); + void (*disable_sds_intr) (struct qlcnic_adapter *, + struct qlcnic_host_sds_ring *); + void (*enable_tx_intr) (struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); + void (*disable_tx_intr) (struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); }; extern struct qlcnic_nic_template qlcnic_vf_ops; @@ -1931,9 +1941,10 @@ static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->napi_disable(adapter); } -static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) +static inline int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) { - adapter->ahw->hw_ops->config_intr_coal(adapter); + return adapter->ahw->hw_ops->config_intr_coal(adapter, ethcoal); } static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) @@ -1985,6 +1996,11 @@ static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->set_mac_filter_count(adapter); } +static inline void qlcnic_get_beacon_state(struct qlcnic_adapter *adapter) +{ + adapter->ahw->hw_ops->get_beacon_state(adapter); +} + static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter) { if (adapter->ahw->hw_ops->read_phys_port_id) @@ -2027,6 +2043,54 @@ static inline bool qlcnic_check_multi_tx(struct qlcnic_adapter *adapter) return test_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); } +static inline void +qlcnic_82xx_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (qlcnic_check_multi_tx(adapter) && + !adapter->ahw->diag_test) + writel(0x0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_82xx_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (qlcnic_check_multi_tx(adapter) && + !adapter->ahw->diag_test) + writel(1, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(1, tx_ring->crb_intr_mask); +} + +/* Enable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + writel(0, sds_ring->crb_intr_mask); +} + +/* Disable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + writel(1, sds_ring->crb_intr_mask); +} + static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter) { test_and_clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); @@ -2036,10 +2100,10 @@ static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter) /* When operating in a muti tx mode, driver needs to write 0x1 * to src register, instead of 0x0 to disable receiving interrupt. */ -static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) { - struct qlcnic_adapter *adapter = sds_ring->adapter; - if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test && (adapter->flags & QLCNIC_MSIX_ENABLED)) @@ -2048,13 +2112,42 @@ static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) writel(0, sds_ring->crb_intr_mask); } +static inline void qlcnic_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + if (adapter->ahw->hw_ops->enable_sds_intr) + adapter->ahw->hw_ops->enable_sds_intr(adapter, sds_ring); +} + +static inline void +qlcnic_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + if (adapter->ahw->hw_ops->disable_sds_intr) + adapter->ahw->hw_ops->disable_sds_intr(adapter, sds_ring); +} + +static inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (adapter->ahw->hw_ops->enable_tx_intr) + adapter->ahw->hw_ops->enable_tx_intr(adapter, tx_ring); +} + +static inline void qlcnic_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (adapter->ahw->hw_ops->disable_tx_intr) + adapter->ahw->hw_ops->disable_tx_intr(adapter, tx_ring); +} + /* When operating in a muti tx mode, driver needs to write 0x0 * to src register, instead of 0x1 to enable receiving interrupts. */ -static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) { - struct qlcnic_adapter *adapter = sds_ring->adapter; - if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test && (adapter->flags & QLCNIC_MSIX_ENABLED)) @@ -2140,4 +2233,26 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter) return status; } + +static inline bool qlcnic_83xx_pf_check(struct qlcnic_adapter *adapter) +{ + unsigned short device = adapter->pdev->device; + + return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false; +} + +static inline bool qlcnic_83xx_vf_check(struct qlcnic_adapter *adapter) +{ + unsigned short device = adapter->pdev->device; + + return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false; +} + +static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter) +{ + if (qlcnic_84xx_check(adapter)) + return QLC_84XX_VNIC_COUNT; + else + return QLC_DEFAULT_VNIC_COUNT; +} #endif /* __QLCNIC_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index f776f99f7915..4146664d4d6a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -13,8 +13,26 @@ #include <linux/interrupt.h> #include <linux/aer.h> +static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *); +static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8); +static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, + struct qlcnic_cmd_args *); +static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *); +static irqreturn_t qlcnic_83xx_handle_aen(int, void *); +static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, + pci_channel_state_t); +static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *); +static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); +static void qlcnic_83xx_io_resume(struct pci_dev *); +static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8); +static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *); +static int qlcnic_83xx_resume(struct qlcnic_adapter *); +static int qlcnic_83xx_shutdown(struct pci_dev *); +static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *); + #define RSS_HASHTYPE_IP_TCP 0x3 #define QLC_83XX_FW_MBX_CMD 0 +#define QLC_SKIP_INACTIVE_PCI_REGS 7 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1}, @@ -34,7 +52,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_READ_MAX_MTU, 4, 2}, {QLCNIC_CMD_READ_MAX_LRO, 4, 2}, {QLCNIC_CMD_MAC_ADDRESS, 4, 3}, - {QLCNIC_CMD_GET_PCI_INFO, 1, 66}, + {QLCNIC_CMD_GET_PCI_INFO, 1, 129}, {QLCNIC_CMD_GET_NIC_INFO, 2, 19}, {QLCNIC_CMD_SET_NIC_INFO, 32, 1}, {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3}, @@ -68,7 +86,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, - {QLCNIC_CMD_DCB_QUERY_PARAM, 2, 50}, + {QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50}, }; const u32 qlcnic_83xx_ext_reg_tbl[] = { @@ -180,6 +198,11 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .io_error_detected = qlcnic_83xx_io_error_detected, .io_slot_reset = qlcnic_83xx_io_slot_reset, .io_resume = qlcnic_83xx_io_resume, + .get_beacon_state = qlcnic_83xx_get_beacon_state, + .enable_sds_intr = qlcnic_83xx_enable_sds_intr, + .disable_sds_intr = qlcnic_83xx_disable_sds_intr, + .enable_tx_intr = qlcnic_83xx_enable_tx_intr, + .disable_tx_intr = qlcnic_83xx_disable_tx_intr, }; @@ -267,11 +290,22 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, } } -int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_enable_legacy(struct qlcnic_adapter *adapter) { - int err, i, num_msix; struct qlcnic_hardware_context *ahw = adapter->ahw; + /* MSI-X enablement failed, use legacy interrupt */ + adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; + adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; + adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; + adapter->msix_entries[0].vector = adapter->pdev->irq; + dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); +} + +static int qlcnic_83xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ + int num_msix; + num_msix = adapter->drv_sds_rings; /* account for AEN interrupt MSI-X based interrupts */ @@ -280,29 +314,44 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) num_msix += adapter->drv_tx_rings; - err = qlcnic_enable_msix(adapter, num_msix); - if (err == -ENOMEM) - return err; - if (adapter->flags & QLCNIC_MSIX_ENABLED) - num_msix = adapter->ahw->num_msix; - else { - if (qlcnic_sriov_vf_check(adapter)) - return -EINVAL; - num_msix = 1; + return num_msix; +} + +int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + int err, i, num_msix; + + if (adapter->flags & QLCNIC_TSS_RSS) { + err = qlcnic_setup_tss_rss_intr(adapter); + if (err < 0) + return err; + num_msix = ahw->num_msix; + } else { + num_msix = qlcnic_83xx_calculate_msix_vector(adapter); + + err = qlcnic_enable_msix(adapter, num_msix); + if (err == -ENOMEM) + return err; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) { + num_msix = ahw->num_msix; + } else { + if (qlcnic_sriov_vf_check(adapter)) + return -EINVAL; + num_msix = 1; + adapter->drv_tx_rings = QLCNIC_SINGLE_RING; + } } + /* setup interrupt mapping table for fw */ ahw->intr_tbl = vzalloc(num_msix * sizeof(struct qlcnic_intrpt_config)); if (!ahw->intr_tbl) return -ENOMEM; - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - /* MSI-X enablement failed, use legacy interrupt */ - adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; - adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; - adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; - adapter->msix_entries[0].vector = adapter->pdev->irq; - dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); - } + + if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) + qlcnic_83xx_enable_legacy(adapter); for (i = 0; i < num_msix; i++) { if (adapter->flags & QLCNIC_MSIX_ENABLED) @@ -312,35 +361,22 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) ahw->intr_tbl[i].id = i; ahw->intr_tbl[i].src = 0; } + return 0; } -inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter) +static inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter) { writel(0, adapter->tgt_mask_reg); } -inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter) +static inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter) { if (adapter->tgt_mask_reg) writel(1, adapter->tgt_mask_reg); } -/* Enable MSI-x and INT-x interrupts */ -void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_sds_ring *sds_ring) -{ - writel(0, sds_ring->crb_intr_mask); -} - -/* Disable MSI-x and INT-x interrupts */ -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_sds_ring *sds_ring) -{ - writel(1, sds_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter +static inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter *adapter) { u32 mask; @@ -477,7 +513,7 @@ irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data) done: adapter->ahw->diag_cnt++; - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); return IRQ_HANDLED; } @@ -634,10 +670,10 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter) return status; } -void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; - u16 act_pci_fn = ahw->act_pci_func; + u16 act_pci_fn = ahw->total_nic_func; u16 count; ahw->max_mc_count = QLC_83XX_MAX_MC_COUNT; @@ -869,7 +905,7 @@ static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, return; } -void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) +static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; u32 event[QLC_83XX_MBX_AEN_CNT]; @@ -1276,8 +1312,8 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, /* send the mailbox command*/ err = qlcnic_issue_cmd(adapter, &cmd); if (err) { - dev_err(&adapter->pdev->dev, - "Failed to create Tx ctx in firmware 0x%x\n", err); + netdev_err(adapter->netdev, + "Failed to create Tx ctx in firmware 0x%x\n", err); goto out; } mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2]; @@ -1288,8 +1324,9 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, intr_mask = ahw->intr_tbl[adapter->drv_sds_rings + ring].src; tx->crb_intr_mask = ahw->pci_base0 + intr_mask; } - dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n", - tx->ctx_id, mbx_out->state); + netdev_info(adapter->netdev, + "Tx Context[0x%x] Created, state:0x%x\n", + tx->ctx_id, mbx_out->state); out: qlcnic_free_mbx_args(&cmd); return err; @@ -1341,7 +1378,7 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test, if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } } @@ -1366,7 +1403,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_disable_intr(adapter, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); } } @@ -1386,6 +1423,33 @@ out: netif_device_attach(netdev); } +static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlcnic_cmd_args cmd; + u8 beacon_state; + int err = 0; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_CONFIG); + if (!err) { + err = qlcnic_issue_cmd(adapter, &cmd); + if (!err) { + beacon_state = cmd.rsp.arg[4]; + if (beacon_state == QLCNIC_BEACON_DISABLE) + ahw->beacon_state = QLC_83XX_BEACON_OFF; + else if (beacon_state == QLC_83XX_ENABLE_BEACON) + ahw->beacon_state = QLC_83XX_BEACON_ON; + } + } else { + netdev_err(adapter->netdev, "Get beacon state failed, err=%d\n", + err); + } + + qlcnic_free_mbx_args(&cmd); + + return; +} + int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 beacon) { @@ -1498,8 +1562,7 @@ int qlcnic_83xx_set_led(struct net_device *netdev, return err; } -void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter, - int enable) +void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *adapter, int enable) { struct qlcnic_cmd_args cmd; int status; @@ -1507,21 +1570,21 @@ void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter, if (qlcnic_sriov_vf_check(adapter)) return; - if (enable) { + if (enable) status = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC); - if (status) - return; - - cmd.req.arg[1] = BIT_0 | BIT_31; - } else { + else status = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC); - if (status) - return; - cmd.req.arg[1] = BIT_0 | BIT_31; - } + if (status) + return; + + cmd.req.arg[1] = QLC_REGISTER_LB_IDC | QLC_INIT_FW_RESOURCES; + + if (adapter->dcb) + cmd.req.arg[1] |= QLC_REGISTER_DCB_AEN; + status = qlcnic_issue_cmd(adapter, &cmd); if (status) dev_err(&adapter->pdev->dev, @@ -1531,7 +1594,7 @@ void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter, qlcnic_free_mbx_args(&cmd); } -int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter) { struct qlcnic_cmd_args cmd; int err; @@ -1548,7 +1611,7 @@ int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter) return err; } -int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter) { struct qlcnic_cmd_args cmd; int err; @@ -1590,7 +1653,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *interface_id) { if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_alloc_lb_filters_mem(adapter); qlcnic_pf_set_interface_id_promisc(adapter, interface_id); + adapter->rx_mac_learn = true; } else { if (!qlcnic_sriov_vf_check(adapter)) *interface_id = adapter->recv_ctx->context_id << 16; @@ -1617,7 +1682,11 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; qlcnic_83xx_set_interface_id_promisc(adapter, &temp); - cmd->req.arg[1] = (mode ? 1 : 0) | temp; + + if (qlcnic_84xx_check(adapter) && qlcnic_sriov_pf_check(adapter)) + mode = VPORT_MISS_MODE_ACCEPT_ALL; + + cmd->req.arg[1] = mode | temp; err = qlcnic_issue_cmd(adapter, cmd); if (!err) return err; @@ -1711,7 +1780,7 @@ static void qlcnic_extend_lb_idc_cmpltn_wait(struct qlcnic_adapter *adapter, ahw->extend_lb_time = 0; } -int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) +static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) { struct qlcnic_hardware_context *ahw = adapter->ahw; struct net_device *netdev = adapter->netdev; @@ -1780,7 +1849,7 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) return status; } -int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) +static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) { struct qlcnic_hardware_context *ahw = adapter->ahw; u32 config = ahw->port_config, max_wait_count; @@ -2015,8 +2084,8 @@ void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr, qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD); } -void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac, - u8 type, struct qlcnic_cmd_args *cmd) +static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac, + u8 type, struct qlcnic_cmd_args *cmd) { switch (type) { case QLCNIC_SET_STATION_MAC: @@ -2060,37 +2129,130 @@ int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac, return err; } -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_set_rx_intr_coal(struct qlcnic_adapter *adapter) { - int err; - u16 temp; - struct qlcnic_cmd_args cmd; struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + struct qlcnic_cmd_args cmd; + u16 temp; + int err; - if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) - return; + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL); + if (err) + return err; + + temp = adapter->recv_ctx->context_id; + cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16; + temp = coal->rx_time_us; + cmd.req.arg[2] = coal->rx_packets | temp << 16; + cmd.req.arg[3] = coal->flag; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err != QLCNIC_RCODE_SUCCESS) + netdev_err(adapter->netdev, + "failed to set interrupt coalescing parameters\n"); + + qlcnic_free_mbx_args(&cmd); + + return err; +} + +static int qlcnic_83xx_set_tx_intr_coal(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + struct qlcnic_cmd_args cmd; + u16 temp; + int err; err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL); if (err) - return; + return err; - if (coal->type == QLCNIC_INTR_COAL_TYPE_RX) { - temp = adapter->recv_ctx->context_id; - cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16; - temp = coal->rx_time_us; - cmd.req.arg[2] = coal->rx_packets | temp << 16; - } else if (coal->type == QLCNIC_INTR_COAL_TYPE_TX) { - temp = adapter->tx_ring->ctx_id; - cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; - temp = coal->tx_time_us; - cmd.req.arg[2] = coal->tx_packets | temp << 16; - } + temp = adapter->tx_ring->ctx_id; + cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; + temp = coal->tx_time_us; + cmd.req.arg[2] = coal->tx_packets | temp << 16; cmd.req.arg[3] = coal->flag; + err = qlcnic_issue_cmd(adapter, &cmd); if (err != QLCNIC_RCODE_SUCCESS) - dev_info(&adapter->pdev->dev, - "Failed to send interrupt coalescence parameters\n"); + netdev_err(adapter->netdev, + "failed to set interrupt coalescing parameters\n"); + qlcnic_free_mbx_args(&cmd); + + return err; +} + +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *adapter) +{ + int err = 0; + + err = qlcnic_83xx_set_rx_intr_coal(adapter); + if (err) + netdev_err(adapter->netdev, + "failed to set Rx coalescing parameters\n"); + + err = qlcnic_83xx_set_tx_intr_coal(adapter); + if (err) + netdev_err(adapter->netdev, + "failed to set Tx coalescing parameters\n"); + + return err; +} + +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + u32 rx_coalesce_usecs, rx_max_frames; + u32 tx_coalesce_usecs, tx_max_frames; + int err; + + if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) + return -EIO; + + tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; + tx_max_frames = ethcoal->tx_max_coalesced_frames; + rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; + rx_max_frames = ethcoal->rx_max_coalesced_frames; + coal->flag = QLCNIC_INTR_DEFAULT; + + if ((coal->rx_time_us == rx_coalesce_usecs) && + (coal->rx_packets == rx_max_frames)) { + coal->type = QLCNIC_INTR_COAL_TYPE_TX; + coal->tx_time_us = tx_coalesce_usecs; + coal->tx_packets = tx_max_frames; + } else if ((coal->tx_time_us == tx_coalesce_usecs) && + (coal->tx_packets == tx_max_frames)) { + coal->type = QLCNIC_INTR_COAL_TYPE_RX; + coal->rx_time_us = rx_coalesce_usecs; + coal->rx_packets = rx_max_frames; + } else { + coal->type = QLCNIC_INTR_COAL_TYPE_RX_TX; + coal->rx_time_us = rx_coalesce_usecs; + coal->rx_packets = rx_max_frames; + coal->tx_time_us = tx_coalesce_usecs; + coal->tx_packets = tx_max_frames; + } + + switch (coal->type) { + case QLCNIC_INTR_COAL_TYPE_RX: + err = qlcnic_83xx_set_rx_intr_coal(adapter); + break; + case QLCNIC_INTR_COAL_TYPE_TX: + err = qlcnic_83xx_set_tx_intr_coal(adapter); + break; + case QLCNIC_INTR_COAL_TYPE_RX_TX: + err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); + break; + default: + err = -EINVAL; + netdev_err(adapter->netdev, + "Invalid Interrupt coalescing type\n"); + break; + } + + return err; } static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, @@ -2119,7 +2281,7 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, qlcnic_advert_link_change(adapter, link_status); } -irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) +static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data) { struct qlcnic_adapter *adapter = data; struct qlcnic_mailbox *mbx; @@ -2145,36 +2307,6 @@ out: return IRQ_HANDLED; } -int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable) -{ - int err = -EIO; - struct qlcnic_cmd_args cmd; - - if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { - dev_err(&adapter->pdev->dev, - "%s: Error, invoked by non management func\n", - __func__); - return err; - } - - err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH); - if (err) - return err; - - cmd.req.arg[1] = (port & 0xf) | BIT_4; - err = qlcnic_issue_cmd(adapter, &cmd); - - if (err != QLCNIC_RCODE_SUCCESS) { - dev_err(&adapter->pdev->dev, "Failed to enable eswitch%d\n", - err); - err = -EIO; - } - qlcnic_free_mbx_args(&cmd); - - return err; - -} - int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) { @@ -2268,11 +2400,37 @@ out: return err; } +int qlcnic_get_pci_func_type(struct qlcnic_adapter *adapter, u16 type, + u16 *nic, u16 *fcoe, u16 *iscsi) +{ + struct device *dev = &adapter->pdev->dev; + int err = 0; + + switch (type) { + case QLCNIC_TYPE_NIC: + (*nic)++; + break; + case QLCNIC_TYPE_FCOE: + (*fcoe)++; + break; + case QLCNIC_TYPE_ISCSI: + (*iscsi)++; + break; + default: + dev_err(dev, "%s: Unknown PCI type[%x]\n", + __func__, type); + err = -EIO; + } + + return err; +} + int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter, struct qlcnic_pci_info *pci_info) { struct qlcnic_hardware_context *ahw = adapter->ahw; struct device *dev = &adapter->pdev->dev; + u16 nic = 0, fcoe = 0, iscsi = 0; struct qlcnic_cmd_args cmd; int i, err = 0, j = 0; u32 temp; @@ -2283,16 +2441,20 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter, err = qlcnic_issue_cmd(adapter, &cmd); - ahw->act_pci_func = 0; + ahw->total_nic_func = 0; if (err == QLCNIC_RCODE_SUCCESS) { ahw->max_pci_func = cmd.rsp.arg[1] & 0xFF; - for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) { + for (i = 2, j = 0; j < ahw->max_vnic_func; j++, pci_info++) { pci_info->id = cmd.rsp.arg[i] & 0xFFFF; pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16; i++; + if (!pci_info->active) { + i += QLC_SKIP_INACTIVE_PCI_REGS; + continue; + } pci_info->type = cmd.rsp.arg[i] & 0xFFFF; - if (pci_info->type == QLCNIC_TYPE_NIC) - ahw->act_pci_func++; + err = qlcnic_get_pci_func_type(adapter, pci_info->type, + &nic, &fcoe, &iscsi); temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16; pci_info->default_port = temp; i++; @@ -2310,6 +2472,13 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter, err = -EIO; } + ahw->total_nic_func = nic; + ahw->total_pci_func = nic + fcoe + iscsi; + if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) { + dev_err(dev, "%s: Invalid function count: total nic func[%x], total pci func[%x]\n", + __func__, ahw->total_nic_func, ahw->total_pci_func); + err = -EIO; + } qlcnic_free_mbx_args(&cmd); return err; @@ -3459,7 +3628,7 @@ int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter) return 0; } -int qlcnic_83xx_shutdown(struct pci_dev *pdev) +static int qlcnic_83xx_shutdown(struct pci_dev *pdev) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; @@ -3481,7 +3650,7 @@ int qlcnic_83xx_shutdown(struct pci_dev *pdev) return 0; } -int qlcnic_83xx_resume(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_resume(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlc_83xx_idc *idc = &ahw->idc; @@ -3834,8 +4003,8 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter) return 0; } -pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) +static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); @@ -3856,7 +4025,7 @@ pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_NEED_RESET; } -pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) +static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); int err = 0; @@ -3879,7 +4048,7 @@ disconnect: return PCI_ERS_RESULT_DISCONNECT; } -void qlcnic_83xx_io_resume(struct pci_dev *pdev) +static void qlcnic_83xx_io_resume(struct pci_dev *pdev) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index a6a33508e401..f92485ca21d1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -324,6 +324,11 @@ struct qlc_83xx_idc { char **name; }; +enum qlcnic_vlan_operations { + QLC_VLAN_ADD = 0, + QLC_VLAN_DELETE +}; + /* Device States */ enum qlcnic_83xx_states { QLC_83XX_IDC_DEV_UNKNOWN, @@ -376,6 +381,8 @@ enum qlcnic_83xx_states { /* LED configuration settings */ #define QLC_83XX_ENABLE_BEACON 0xe +#define QLC_83XX_BEACON_ON 1 +#define QLC_83XX_BEACON_OFF 0 #define QLC_83XX_LED_RATE 0xff #define QLC_83XX_LED_ACT (1 << 10) #define QLC_83XX_LED_MOD (0 << 13) @@ -518,6 +525,11 @@ enum qlc_83xx_ext_regs { QLC_83XX_ASIC_TEMP, }; +/* Initialize/Stop NIC command bit definitions */ +#define QLC_REGISTER_DCB_AEN BIT_1 +#define QLC_REGISTER_LB_IDC BIT_0 +#define QLC_INIT_FW_RESOURCES BIT_31 + /* 83xx funcitons */ int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *); int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *); @@ -532,17 +544,13 @@ void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *); int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32); -void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []); int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); -int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8); -int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8); int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int); int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int); -int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *); void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16); int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *); int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); -void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int); +void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *, int); int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *); void qlcnic_83xx_napi_del(struct qlcnic_adapter *); @@ -563,32 +571,22 @@ void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *); int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool); int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8); int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *, u8); -void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, - struct qlcnic_cmd_args *); int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *, struct qlcnic_adapter *, u32); void qlcnic_free_mbx_args(struct qlcnic_cmd_args *); void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *, struct qlcnic_info *); -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *); -irqreturn_t qlcnic_83xx_handle_aen(int, void *); +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *, + struct ethtool_coalesce *); +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *); int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *); void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *); irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); irqreturn_t qlcnic_83xx_intr(int, void *); irqreturn_t qlcnic_83xx_tmp_intr(int, void *); -void qlcnic_83xx_enable_intr(struct qlcnic_adapter *, - struct qlcnic_host_sds_ring *); -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *, - struct qlcnic_host_sds_ring *); void qlcnic_83xx_check_vf(struct qlcnic_adapter *, const struct pci_device_id *); -void __qlcnic_83xx_process_aen(struct qlcnic_adapter *); -int qlcnic_83xx_get_port_config(struct qlcnic_adapter *); -int qlcnic_83xx_set_port_config(struct qlcnic_adapter *); -int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8); -int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *); int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *); int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *); void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *); @@ -610,9 +608,7 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *, u32, u8 *, int); int qlcnic_83xx_init(struct qlcnic_adapter *, int); int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *); -int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev); void qlcnic_83xx_idc_poll_dev_state(struct work_struct *); -int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *); void qlcnic_83xx_idc_exit(struct qlcnic_adapter *); void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32); int qlcnic_83xx_lock_driver(struct qlcnic_adapter *); @@ -620,7 +616,6 @@ void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *); int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *); int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32); int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *); -int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int); int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int); int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *); int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *, @@ -648,9 +643,6 @@ int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *); int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *); void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *); void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *); -void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *); -int qlcnic_83xx_shutdown(struct pci_dev *); -int qlcnic_83xx_resume(struct qlcnic_adapter *); int qlcnic_83xx_idc_init(struct qlcnic_adapter *); int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *); int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *); @@ -658,9 +650,4 @@ 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 *); -pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, - pci_channel_state_t); -pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); -void qlcnic_83xx_io_resume(struct pci_dev *); -void qlcnic_83xx_stop_hw(struct qlcnic_adapter *); #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 918e18ddf038..90a2dda351ec 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -39,6 +39,9 @@ static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev); +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *); +static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *); /* Template header */ struct qlc_83xx_reset_hdr { @@ -380,7 +383,7 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter) qlcnic_up(adapter, netdev); netif_device_attach(netdev); clear_bit(__QLCNIC_RESETTING, &adapter->state); - dev_err(&adapter->pdev->dev, "%s:\n", __func__); + netdev_info(adapter->netdev, "%s: soft reset complete.\n", __func__); return 0; } @@ -614,8 +617,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox); qlcnic_83xx_enable_mbx_interrupt(adapter); - /* register for NIC IDC AEN Events */ - qlcnic_83xx_register_nic_idc_func(adapter, 1); + qlcnic_83xx_initialize_nic(adapter, 1); err = qlcnic_sriov_pf_reinit(adapter); if (err) @@ -1529,7 +1531,7 @@ static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev) return -EIO; } -int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) { int err; @@ -1602,7 +1604,7 @@ static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev) } } -int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) { struct qlcnic_hardware_context *ahw = p_dev->ahw; u32 addr, count, prev_ver, curr_ver; @@ -1946,7 +1948,7 @@ static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev, p_dev->ahw->reset.seq_index = index; } -void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev) +static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev) { p_dev->ahw->reset.seq_index = 0; @@ -2029,7 +2031,7 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter) return 0; } -int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) { int err; struct qlcnic_info nic_info; @@ -2213,9 +2215,9 @@ static void qlcnic_83xx_init_rings(struct qlcnic_adapter *adapter) int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) { struct qlcnic_hardware_context *ahw = adapter->ahw; - struct qlcnic_dcb *dcb; int err = 0; + adapter->rx_mac_learn = false; ahw->msix_supported = !!qlcnic_use_msi_x; qlcnic_83xx_init_rings(adapter); @@ -2265,8 +2267,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - /* register for NIC IDC AEN Events */ - qlcnic_83xx_register_nic_idc_func(adapter, 1); + qlcnic_83xx_initialize_nic(adapter, 1); /* Configure default, SR-IOV or Virtual NIC mode of operation */ err = qlcnic_83xx_configure_opmode(adapter); @@ -2279,11 +2280,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) if (err) goto disable_mbx_intr; - dcb = adapter->dcb; - - if (dcb && qlcnic_dcb_attach(dcb)) - qlcnic_clear_dcb_ops(dcb); - /* Periodically monitor device status */ qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work); return 0; @@ -2314,7 +2310,7 @@ void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter) qlcnic_83xx_disable_vnic_mode(adapter, 1); qlcnic_83xx_idc_detach_driver(adapter); - qlcnic_83xx_register_nic_idc_func(adapter, 0); + qlcnic_83xx_initialize_nic(adapter, 0); cancel_delayed_work_sync(&adapter->idc_aen_work); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index 734d28602ac3..be7d7a62cc0d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -8,7 +8,7 @@ #include "qlcnic.h" #include "qlcnic_hw.h" -int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock) +static int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock) { if (lock) { if (qlcnic_83xx_lock_driver(adapter)) @@ -107,7 +107,7 @@ static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter) npar = adapter->npars; - for (i = 0; i < ahw->act_pci_func; i++, npar++) { + for (i = 0; i < ahw->total_nic_func; i++, npar++) { dev_info(dev, "id:%d active:%d type:%d port:%d min_bw:%d max_bw:%d mac_addr:%pM\n", npar->pci_func, npar->active, npar->type, npar->phy_port, npar->min_bw, npar->max_bw, @@ -115,7 +115,7 @@ static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter) } dev_info(dev, "Max functions = %d, active functions = %d\n", - ahw->max_pci_func, ahw->act_pci_func); + ahw->max_pci_func, ahw->total_nic_func); if (qlcnic_83xx_set_vnic_opmode(adapter)) return err; @@ -224,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) return -EIO; } - if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) + if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) { adapter->flags |= QLCNIC_ESWITCH_ENABLED; - else + if (adapter->drv_mac_learn) + adapter->rx_mac_learn = true; + } else { adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; + adapter->rx_mac_learn = false; + } ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 859cb161fc63..64dcbf33d8f0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -91,18 +91,6 @@ void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd) cmd->rsp.arg = NULL; } -static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) -{ - int i; - - for (i = 0; i < adapter->ahw->act_pci_func; i++) { - if (adapter->npars[i].pci_func == pci_func) - return i; - } - - return -1; -} - static u32 qlcnic_poll_rsp(struct qlcnic_adapter *adapter) { @@ -966,13 +954,15 @@ out_free_dma: int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, struct qlcnic_pci_info *pci_info) { - int err = 0, i; + struct qlcnic_hardware_context *ahw = adapter->ahw; + size_t npar_size = sizeof(struct qlcnic_pci_info_le); + size_t pci_size = npar_size * ahw->max_vnic_func; + u16 nic = 0, fcoe = 0, iscsi = 0; + struct qlcnic_pci_info_le *npar; struct qlcnic_cmd_args cmd; dma_addr_t pci_info_dma_t; - struct qlcnic_pci_info_le *npar; void *pci_info_addr; - size_t npar_size = sizeof(struct qlcnic_pci_info_le); - size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; + int err = 0, i; pci_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, pci_size, &pci_info_dma_t, GFP_KERNEL); @@ -989,14 +979,16 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, cmd.req.arg[3] = pci_size; err = qlcnic_issue_cmd(adapter, &cmd); - adapter->ahw->act_pci_func = 0; + ahw->total_nic_func = 0; if (err == QLCNIC_RCODE_SUCCESS) { - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) { + for (i = 0; i < ahw->max_vnic_func; i++, npar++, pci_info++) { pci_info->id = le16_to_cpu(npar->id); pci_info->active = le16_to_cpu(npar->active); + if (!pci_info->active) + continue; pci_info->type = le16_to_cpu(npar->type); - if (pci_info->type == QLCNIC_TYPE_NIC) - adapter->ahw->act_pci_func++; + err = qlcnic_get_pci_func_type(adapter, pci_info->type, + &nic, &fcoe, &iscsi); pci_info->default_port = le16_to_cpu(npar->default_port); pci_info->tx_min_bw = @@ -1011,6 +1003,14 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, err = -EIO; } + ahw->total_nic_func = nic; + ahw->total_pci_func = nic + fcoe + iscsi; + if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) { + dev_err(&adapter->pdev->dev, + "%s: Invalid function count: total nic func[%x], total pci func[%x]\n", + __func__, ahw->total_nic_func, ahw->total_pci_func); + err = -EIO; + } qlcnic_free_mbx_args(&cmd); out_free_dma: dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr, @@ -1203,7 +1203,7 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL; esw_stats->context_id = eswitch; - for (i = 0; i < adapter->ahw->act_pci_func; i++) { + for (i = 0; i < adapter->ahw->total_nic_func; i++) { if (adapter->npars[i].phy_port != eswitch) continue; @@ -1236,15 +1236,16 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, const u8 port, const u8 rx_tx) { + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlcnic_cmd_args cmd; int err; u32 arg1; - struct qlcnic_cmd_args cmd; - if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) + if (ahw->op_mode != QLCNIC_MGMT_FUNC) return -EIO; if (func_esw == QLCNIC_STATS_PORT) { - if (port >= QLCNIC_MAX_PCI_FUNC) + if (port >= ahw->max_vnic_func) goto err_ret; } else if (func_esw == QLCNIC_STATS_ESWITCH) { if (port >= QLCNIC_NIU_MAX_XG_PORTS) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index 86bca7c14f99..77f1bce432d2 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -15,7 +15,6 @@ #define QLC_DCB_GET_MAP(V) (1 << V) -#define QLC_DCB_AEN_BIT 0x2 #define QLC_DCB_FW_VER 0x2 #define QLC_DCB_MAX_TC 0x8 #define QLC_DCB_MAX_APP 0x8 @@ -71,7 +70,6 @@ static void qlcnic_82xx_dcb_aen_handler(struct qlcnic_dcb *, void *); static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_dcb *); static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_dcb *, char *, u8); static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_dcb *); -static int qlcnic_83xx_dcb_register_aen(struct qlcnic_dcb *, bool); static void qlcnic_83xx_dcb_aen_handler(struct qlcnic_dcb *, void *); struct qlcnic_dcb_capability { @@ -179,7 +177,6 @@ static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = { .get_hw_capability = qlcnic_83xx_dcb_get_hw_capability, .query_cee_param = qlcnic_83xx_dcb_query_cee_param, .get_cee_cfg = qlcnic_83xx_dcb_get_cee_cfg, - .register_aen = qlcnic_83xx_dcb_register_aen, .aen_handler = qlcnic_83xx_dcb_aen_handler, }; @@ -260,6 +257,9 @@ int qlcnic_register_dcb(struct qlcnic_adapter *adapter) { struct qlcnic_dcb *dcb; + if (qlcnic_sriov_vf_check(adapter)) + return 0; + dcb = kzalloc(sizeof(struct qlcnic_dcb), GFP_ATOMIC); if (!dcb) return -ENOMEM; @@ -280,7 +280,6 @@ static void __qlcnic_dcb_free(struct qlcnic_dcb *dcb) return; adapter = dcb->adapter; - qlcnic_dcb_register_aen(dcb, 0); while (test_bit(QLCNIC_DCB_AEN_MODE, &dcb->state)) usleep_range(10000, 11000); @@ -304,7 +303,6 @@ static void __qlcnic_dcb_get_info(struct qlcnic_dcb *dcb) { qlcnic_dcb_get_hw_capability(dcb); qlcnic_dcb_get_cee_cfg(dcb); - qlcnic_dcb_register_aen(dcb, 1); } static int __qlcnic_dcb_attach(struct qlcnic_dcb *dcb) @@ -642,29 +640,6 @@ static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) return err; } -static int qlcnic_83xx_dcb_register_aen(struct qlcnic_dcb *dcb, bool flag) -{ - u8 val = (flag ? QLCNIC_CMD_INIT_NIC_FUNC : QLCNIC_CMD_STOP_NIC_FUNC); - struct qlcnic_adapter *adapter = dcb->adapter; - struct qlcnic_cmd_args cmd; - int err; - - err = qlcnic_alloc_mbx_args(&cmd, adapter, val); - if (err) - return err; - - cmd.req.arg[1] = QLC_DCB_AEN_BIT; - - err = qlcnic_issue_cmd(adapter, &cmd); - if (err) - dev_err(&adapter->pdev->dev, "Failed to %s DCBX AEN, err %d\n", - (flag ? "register" : "unregister"), err); - - qlcnic_free_mbx_args(&cmd); - - return err; -} - static void qlcnic_83xx_dcb_aen_handler(struct qlcnic_dcb *dcb, void *data) { u32 *val = data; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h index c04ae0cdc108..3cf4a10fbe1e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -25,7 +25,6 @@ struct qlcnic_dcb_ops { int (*get_hw_capability) (struct qlcnic_dcb *); int (*query_cee_param) (struct qlcnic_dcb *, char *, u8); void (*init_dcbnl_ops) (struct qlcnic_dcb *); - int (*register_aen) (struct qlcnic_dcb *, bool); void (*aen_handler) (struct qlcnic_dcb *, void *); int (*get_cee_cfg) (struct qlcnic_dcb *); void (*get_info) (struct qlcnic_dcb *); @@ -103,13 +102,6 @@ static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) return 0; } -static inline void -qlcnic_dcb_register_aen(struct qlcnic_dcb *dcb, u8 flag) -{ - if (dcb && dcb->ops->register_aen) - dcb->ops->register_aen(dcb, flag); -} - static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *msg) { if (dcb && dcb->ops->aen_handler) @@ -121,4 +113,10 @@ static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->init_dcbnl_ops) dcb->ops->init_dcbnl_ops(dcb); } + +static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb) +{ + if (dcb && qlcnic_dcb_attach(dcb)) + qlcnic_clear_dcb_ops(dcb); +} #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 6b08194aa0d4..acee1a5d80c6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -229,7 +229,7 @@ static const u32 ext_diag_registers[] = { -1 }; -#define QLCNIC_MGMT_API_VERSION 2 +#define QLCNIC_MGMT_API_VERSION 3 #define QLCNIC_ETHTOOL_REGS_VER 4 static inline int qlcnic_get_ring_regs_len(struct qlcnic_adapter *adapter) @@ -278,21 +278,8 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) sizeof(drvinfo->version)); } -static int -qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - - if (qlcnic_82xx_check(adapter)) - return qlcnic_82xx_get_settings(adapter, ecmd); - else if (qlcnic_83xx_check(adapter)) - return qlcnic_83xx_get_settings(adapter, ecmd); - - return -EIO; -} - -int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, - struct ethtool_cmd *ecmd) +static int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, + struct ethtool_cmd *ecmd) { struct qlcnic_hardware_context *ahw = adapter->ahw; u32 speed, reg; @@ -433,6 +420,20 @@ skip: return 0; } +static int qlcnic_get_settings(struct net_device *dev, + struct ethtool_cmd *ecmd) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + if (qlcnic_82xx_check(adapter)) + return qlcnic_82xx_get_settings(adapter, ecmd); + else if (qlcnic_83xx_check(adapter)) + return qlcnic_83xx_get_settings(adapter, ecmd); + + return -EIO; +} + + static int qlcnic_set_port_config(struct qlcnic_adapter *adapter, struct ethtool_cmd *ecmd) { @@ -527,6 +528,9 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff)); regs_buff[1] = QLCNIC_MGMT_API_VERSION; + if (adapter->ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) + regs_buff[2] = adapter->ahw->max_vnic_func; + if (qlcnic_82xx_check(adapter)) i = qlcnic_82xx_get_registers(adapter, regs_buff); else @@ -732,6 +736,7 @@ static int qlcnic_set_channels(struct net_device *dev, channel->rx_count); return err; } + adapter->drv_rss_rings = channel->rx_count; } if (channel->tx_count) { @@ -742,10 +747,12 @@ static int qlcnic_set_channels(struct net_device *dev, channel->tx_count); return err; } + adapter->drv_tss_rings = channel->tx_count; } - err = qlcnic_setup_rings(adapter, channel->rx_count, - channel->tx_count); + adapter->flags |= QLCNIC_TSS_RSS; + + err = qlcnic_setup_rings(adapter); netdev_info(dev, "Allocated %d SDS rings and %d Tx rings\n", adapter->drv_sds_rings, adapter->drv_tx_rings); @@ -1052,7 +1059,7 @@ int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) return 0; } -int qlcnic_loopback_test(struct net_device *netdev, u8 mode) +static int qlcnic_loopback_test(struct net_device *netdev, u8 mode) { struct qlcnic_adapter *adapter = netdev_priv(netdev); int drv_tx_rings = adapter->drv_tx_rings; @@ -1491,9 +1498,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, struct ethtool_coalesce *ethcoal) { struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_nic_intr_coalesce *coal; - u32 rx_coalesce_usecs, rx_max_frames; - u32 tx_coalesce_usecs, tx_max_frames; + int err; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return -EINVAL; @@ -1503,82 +1508,31 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, * unsupported parameters are set. */ if (ethcoal->rx_coalesce_usecs > 0xffff || - ethcoal->rx_max_coalesced_frames > 0xffff || - ethcoal->tx_coalesce_usecs > 0xffff || - ethcoal->tx_max_coalesced_frames > 0xffff || - ethcoal->rx_coalesce_usecs_irq || - ethcoal->rx_max_coalesced_frames_irq || - ethcoal->tx_coalesce_usecs_irq || - ethcoal->tx_max_coalesced_frames_irq || - ethcoal->stats_block_coalesce_usecs || - ethcoal->use_adaptive_rx_coalesce || - ethcoal->use_adaptive_tx_coalesce || - ethcoal->pkt_rate_low || - ethcoal->rx_coalesce_usecs_low || - ethcoal->rx_max_coalesced_frames_low || - ethcoal->tx_coalesce_usecs_low || - ethcoal->tx_max_coalesced_frames_low || - ethcoal->pkt_rate_high || - ethcoal->rx_coalesce_usecs_high || - ethcoal->rx_max_coalesced_frames_high || - ethcoal->tx_coalesce_usecs_high || - ethcoal->tx_max_coalesced_frames_high) + ethcoal->rx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs > 0xffff || + ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->rx_coalesce_usecs_irq || + ethcoal->rx_max_coalesced_frames_irq || + ethcoal->tx_coalesce_usecs_irq || + ethcoal->tx_max_coalesced_frames_irq || + ethcoal->stats_block_coalesce_usecs || + ethcoal->use_adaptive_rx_coalesce || + ethcoal->use_adaptive_tx_coalesce || + ethcoal->pkt_rate_low || + ethcoal->rx_coalesce_usecs_low || + ethcoal->rx_max_coalesced_frames_low || + ethcoal->tx_coalesce_usecs_low || + ethcoal->tx_max_coalesced_frames_low || + ethcoal->pkt_rate_high || + ethcoal->rx_coalesce_usecs_high || + ethcoal->rx_max_coalesced_frames_high || + ethcoal->tx_coalesce_usecs_high || + ethcoal->tx_max_coalesced_frames_high) return -EINVAL; - coal = &adapter->ahw->coal; + err = qlcnic_config_intr_coalesce(adapter, ethcoal); - if (qlcnic_83xx_check(adapter)) { - if (!ethcoal->tx_coalesce_usecs || - !ethcoal->tx_max_coalesced_frames || - !ethcoal->rx_coalesce_usecs || - !ethcoal->rx_max_coalesced_frames) { - coal->flag = QLCNIC_INTR_DEFAULT; - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; - coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; - } else { - tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; - tx_max_frames = ethcoal->tx_max_coalesced_frames; - rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; - rx_max_frames = ethcoal->rx_max_coalesced_frames; - coal->flag = 0; - - if ((coal->rx_time_us == rx_coalesce_usecs) && - (coal->rx_packets == rx_max_frames)) { - coal->type = QLCNIC_INTR_COAL_TYPE_TX; - coal->tx_time_us = tx_coalesce_usecs; - coal->tx_packets = tx_max_frames; - } else if ((coal->tx_time_us == tx_coalesce_usecs) && - (coal->tx_packets == tx_max_frames)) { - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = rx_coalesce_usecs; - coal->rx_packets = rx_max_frames; - } else { - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = rx_coalesce_usecs; - coal->rx_packets = rx_max_frames; - coal->tx_time_us = tx_coalesce_usecs; - coal->tx_packets = tx_max_frames; - } - } - } else { - if (!ethcoal->rx_coalesce_usecs || - !ethcoal->rx_max_coalesced_frames) { - coal->flag = QLCNIC_INTR_DEFAULT; - coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - } else { - coal->flag = 0; - coal->rx_time_us = ethcoal->rx_coalesce_usecs; - coal->rx_packets = ethcoal->rx_max_coalesced_frames; - } - } - - qlcnic_config_intr_coalesce(adapter); - - return 0; + return err; } static int qlcnic_get_intr_coalesce(struct net_device *netdev, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h index d262211b03b3..34e467b239a1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h @@ -698,7 +698,6 @@ struct qlcnic_legacy_intr_set { }; #define QLCNIC_MSIX_BASE 0x132110 -#define QLCNIC_MAX_PCI_FUNC 8 #define QLCNIC_MAX_VLAN_FILTERS 64 #define FLASH_ROM_WINDOW 0x42110030 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 6f7f60c09f07..03d18a0be6ce 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -455,14 +455,14 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) { + struct qlcnic_mac_vlan_list *cur; struct list_head *head; - struct qlcnic_mac_list_s *cur; int err = -EINVAL; /* Delete MAC from the existing list */ list_for_each(head, &adapter->mac_list) { - cur = list_entry(head, struct qlcnic_mac_list_s, list); - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { + cur = list_entry(head, struct qlcnic_mac_vlan_list, list); + if (ether_addr_equal(addr, cur->mac_addr)) { err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr, 0, QLCNIC_MAC_DEL); if (err) @@ -477,17 +477,18 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) { + struct qlcnic_mac_vlan_list *cur; struct list_head *head; - struct qlcnic_mac_list_s *cur; /* look up if already exists */ list_for_each(head, &adapter->mac_list) { - cur = list_entry(head, struct qlcnic_mac_list_s, list); - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) + cur = list_entry(head, struct qlcnic_mac_vlan_list, list); + if (ether_addr_equal(addr, cur->mac_addr) && + cur->vlan_id == vlan) return 0; } - cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); + cur = kzalloc(sizeof(*cur), GFP_ATOMIC); if (cur == NULL) return -ENOMEM; @@ -499,11 +500,12 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) return -EIO; } + cur->vlan_id = vlan; list_add_tail(&cur->list, &adapter->mac_list); return 0; } -void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) +static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -516,8 +518,7 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; - if (!qlcnic_sriov_vf_check(adapter)) - qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); + qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); qlcnic_nic_add_mac(adapter, bcast_addr, vlan); if (netdev->flags & IFF_PROMISC) { @@ -526,15 +527,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) } else if ((netdev->flags & IFF_ALLMULTI) || (netdev_mc_count(netdev) > ahw->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; - } else if (!netdev_mc_empty(netdev) && - !qlcnic_sriov_vf_check(adapter)) { + } else if (!netdev_mc_empty(netdev)) { netdev_for_each_mc_addr(ha, netdev) qlcnic_nic_add_mac(adapter, ha->addr, vlan); } - if (qlcnic_sriov_vf_check(adapter)) - qlcnic_vf_add_mc_list(netdev, vlan); - /* configure unicast MAC address, if there is not sufficient space * to store all the unicast addresses then enable promiscuous mode */ @@ -545,14 +542,15 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) qlcnic_nic_add_mac(adapter, ha->addr, vlan); } - if (!qlcnic_sriov_vf_check(adapter)) { - if (mode == VPORT_MISS_MODE_ACCEPT_ALL && - !adapter->fdb_mac_learn) { - qlcnic_alloc_lb_filters_mem(adapter); - adapter->drv_mac_learn = true; - } else { - adapter->drv_mac_learn = false; - } + if (mode == VPORT_MISS_MODE_ACCEPT_ALL && + !adapter->fdb_mac_learn) { + qlcnic_alloc_lb_filters_mem(adapter); + adapter->drv_mac_learn = 1; + if (adapter->flags & QLCNIC_ESWITCH_ENABLED) + adapter->rx_mac_learn = true; + } else { + adapter->drv_mac_learn = 0; + adapter->rx_mac_learn = false; } qlcnic_nic_set_promisc(adapter, mode); @@ -561,16 +559,17 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) void qlcnic_set_multi(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_mac_vlan_list *cur; struct netdev_hw_addr *ha; - struct qlcnic_mac_list_s *cur; + size_t temp; if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; if (qlcnic_sriov_vf_check(adapter)) { if (!netdev_mc_empty(netdev)) { netdev_for_each_mc_addr(ha, netdev) { - cur = kzalloc(sizeof(struct qlcnic_mac_list_s), - GFP_ATOMIC); + temp = sizeof(struct qlcnic_mac_vlan_list); + cur = kzalloc(temp, GFP_ATOMIC); if (cur == NULL) break; memcpy(cur->mac_addr, @@ -605,11 +604,11 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter) { - struct qlcnic_mac_list_s *cur; struct list_head *head = &adapter->mac_list; + struct qlcnic_mac_vlan_list *cur; while (!list_empty(head)) { - cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list); qlcnic_sre_macaddr_change(adapter, cur->mac_addr, 0, QLCNIC_MAC_DEL); list_del(&cur->list); @@ -756,10 +755,7 @@ int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter) return 0; } -/* - * Send the interrupt coalescing parameter set by ethtool to the card. - */ -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; int rv; @@ -781,10 +777,32 @@ void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) if (rv != 0) dev_err(&adapter->netdev->dev, "Could not send interrupt coalescing parameters\n"); + + return rv; +} + +/* Send the interrupt coalescing parameter set by ethtool to the card. */ +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + int rv; + + coal->flag = QLCNIC_INTR_DEFAULT; + coal->rx_time_us = ethcoal->rx_coalesce_usecs; + coal->rx_packets = ethcoal->rx_max_coalesced_frames; + + rv = qlcnic_82xx_set_rx_coalesce(adapter); + + if (rv) + netdev_err(adapter->netdev, + "Failed to set Rx coalescing parametrs\n"); + + return rv; } -#define QLCNIC_ENABLE_IPV4_LRO 1 -#define QLCNIC_ENABLE_IPV6_LRO 2 +#define QLCNIC_ENABLE_IPV4_LRO BIT_0 +#define QLCNIC_ENABLE_IPV6_LRO (BIT_1 | BIT_9) int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable) { @@ -948,7 +966,7 @@ int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable) return rv; } -int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) +static int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; u64 word; @@ -1247,7 +1265,7 @@ static int qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, return 0; } -void +static void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) { void __iomem *addr = adapter->ahw->pci_base0 + @@ -1258,7 +1276,7 @@ qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) mutex_unlock(&adapter->ahw->mem_lock); } -void +static void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) { void __iomem *addr = adapter->ahw->pci_base0 + @@ -1494,7 +1512,7 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) return 0; } -int +static int qlcnic_wol_supported(struct qlcnic_adapter *adapter) { u32 wol_cfg; @@ -1534,19 +1552,34 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } -int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state) +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_cmd_args cmd; - int err; + u8 beacon_state; + int err = 0; - err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS); - if (!err) { - err = qlcnic_issue_cmd(adapter, &cmd); - if (!err) - *h_state = cmd.rsp.arg[1]; + if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { + err = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_GET_LED_STATUS); + if (!err) { + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) { + netdev_err(adapter->netdev, + "Failed to get current beacon state, err=%d\n", + err); + } else { + beacon_state = cmd.rsp.arg[1]; + if (beacon_state == QLCNIC_BEACON_DISABLE) + ahw->beacon_state = QLCNIC_BEACON_OFF; + else if (beacon_state == QLCNIC_BEACON_EANBLE) + ahw->beacon_state = QLCNIC_BEACON_ON; + } + } + qlcnic_free_mbx_args(&cmd); } - qlcnic_free_mbx_args(&cmd); - return err; + + return; } void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 13303e7d1ed7..63d75617d445 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -162,16 +162,18 @@ struct qlcnic_host_tx_ring; struct qlcnic_hardware_context; struct qlcnic_adapter; -int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); 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); int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int); int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32); int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev); +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *); void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, u16 vlan_id); -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter); +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *, + struct ethtool_coalesce *); +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *); int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int); void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32, int); @@ -181,9 +183,6 @@ int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8); int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8); void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); -void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); -int qlcnic_82xx_setup_intr(struct qlcnic_adapter *); -irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *); int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *, int); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index ad1531ae3aa8..30874cda8476 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -124,41 +124,16 @@ #define qlcnic_83xx_is_ip_align(sts) (((sts) >> 46) & 1) #define qlcnic_83xx_has_vlan_tag(sts) (((sts) >> 47) & 1) -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, - struct qlcnic_host_rds_ring *, u16, u16); +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, + int max); -inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test) - writel(0x0, tx_ring->crb_intr_mask); -} - - -static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test) - writel(1, tx_ring->crb_intr_mask); -} +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, + struct qlcnic_host_rds_ring *, + u16, u16); -inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) +static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan) { - writel(0, tx_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - writel(1, tx_ring->crb_intr_mask); -} - -static inline u8 qlcnic_mac_hash(u64 mac) -{ - return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff)); + return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff)); } static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, @@ -202,7 +177,7 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head, struct hlist_node *n; hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) && + if (ether_addr_equal(tmp_fil->faddr, addr) && tmp_fil->vlan_id == vlan_id) return tmp_fil; } @@ -210,8 +185,8 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head, return NULL; } -void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, - int loopback_pkt, u16 vlan_id) +static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, + struct sk_buff *skb, int loopback_pkt, u16 vlan_id) { struct ethhdr *phdr = (struct ethhdr *)(skb->data); struct qlcnic_filter *fil, *tmp_fil; @@ -221,8 +196,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, u8 hindex, op; int ret; + if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) + vlan_id = 0; + memcpy(&src_addr, phdr->h_source, ETH_ALEN); - hindex = qlcnic_mac_hash(src_addr) & + hindex = qlcnic_mac_hash(src_addr, vlan_id) & (adapter->fhash.fbucket_size - 1); if (loopback_pkt) { @@ -322,31 +300,47 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb) { + struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); + struct ethhdr *phdr = (struct ethhdr *)(skb->data); + struct net_device *netdev = adapter->netdev; + u16 protocol = ntohs(skb->protocol); struct qlcnic_filter *fil, *tmp_fil; - struct hlist_node *n; struct hlist_head *head; - struct net_device *netdev = adapter->netdev; - struct ethhdr *phdr = (struct ethhdr *)(skb->data); + struct hlist_node *n; u64 src_addr = 0; u16 vlan_id = 0; - u8 hindex; + u8 hindex, hval; - if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) - return; + if (!qlcnic_sriov_pf_check(adapter)) { + if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) + return; + } else { + if (protocol == ETH_P_8021Q) { + vh = (struct vlan_ethhdr *)skb->data; + vlan_id = ntohs(vh->h_vlan_TCI); + } else if (vlan_tx_tag_present(skb)) { + vlan_id = vlan_tx_tag_get(skb); + } + + if (ether_addr_equal(phdr->h_source, adapter->mac_addr) && + !vlan_id) + return; + } if (adapter->fhash.fnum >= adapter->fhash.fmax) { adapter->stats.mac_filter_limit_overrun++; - netdev_info(netdev, "Can not add more than %d mac addresses\n", - adapter->fhash.fmax); + netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n", + adapter->fhash.fmax, adapter->fhash.fnum); return; } memcpy(&src_addr, phdr->h_source, ETH_ALEN); - hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); + hval = qlcnic_mac_hash(src_addr, vlan_id); + hindex = hval & (adapter->fhash.fbucket_size - 1); head = &(adapter->fhash.fhead[hindex]); hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && + if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) && tmp_fil->vlan_id == vlan_id) { if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime)) qlcnic_change_filter(adapter, &src_addr, @@ -862,7 +856,7 @@ static int qlcnic_poll(struct napi_struct *napi, int budget) if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); qlcnic_enable_tx_intr(adapter, tx_ring); } } @@ -903,7 +897,7 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1015,9 +1009,9 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index, } } -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, - struct qlcnic_host_rds_ring *ring, - u16 index, u16 cksum) +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, + struct qlcnic_host_rds_ring *ring, + u16 index, u16 cksum) { struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; @@ -1236,7 +1230,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, return buffer; } -int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) { struct qlcnic_host_rds_ring *rds_ring; struct qlcnic_adapter *adapter = sds_ring->adapter; @@ -1466,8 +1460,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test && - (adapter->drv_tx_rings > QLCNIC_SINGLE_RING)) { + !adapter->ahw->diag_test) { netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll, NAPI_POLL_WEIGHT); } else { @@ -1535,13 +1528,12 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; napi_enable(&sds_ring->napi); - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } if (qlcnic_check_multi_tx(adapter) && (adapter->flags & QLCNIC_MSIX_ENABLED) && - !adapter->ahw->diag_test && - (adapter->drv_tx_rings > QLCNIC_SINGLE_RING)) { + !adapter->ahw->diag_test) { for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; napi_enable(&tx_ring->napi); @@ -1562,7 +1554,7 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - qlcnic_disable_int(sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); napi_synchronize(&sds_ring->napi); napi_disable(&sds_ring->napi); } @@ -1572,7 +1564,7 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter) qlcnic_check_multi_tx(adapter)) { for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - qlcnic_disable_tx_int(adapter, tx_ring); + qlcnic_disable_tx_intr(adapter, tx_ring); napi_synchronize(&tx_ring->napi); napi_disable(&tx_ring->napi); } @@ -1601,7 +1593,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; int index, length, cksum, is_lb_pkt; - u16 vid = 0xffff, t_vid; + u16 vid = 0xffff; + int err; if (unlikely(ring >= adapter->max_rds_rings)) return NULL; @@ -1619,19 +1612,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - t_vid = 0; - is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); - } - if (length > rds_ring->skb_size) skb_put(skb, rds_ring->skb_size); else skb_put(skb, length); - if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { + err = qlcnic_check_rx_tagging(adapter, skb, &vid); + + if (adapter->rx_mac_learn) { + is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); + } + + if (unlikely(err)) { adapter->stats.rxdropped++; dev_kfree_skb(skb); return buffer; @@ -1666,7 +1659,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, int l2_hdr_offset, l4_hdr_offset; int index, is_lb_pkt; u16 lro_length, length, data_offset, gso_size; - u16 vid = 0xffff, t_vid; + u16 vid = 0xffff; + int err; if (unlikely(ring > adapter->max_rds_rings)) return NULL; @@ -1688,12 +1682,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - t_vid = 0; - is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); - } if (qlcnic_83xx_is_tstamp(sts_data[1])) data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; else @@ -1702,7 +1690,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, skb_put(skb, lro_length + data_offset); skb_pull(skb, l2_hdr_offset); - if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { + err = qlcnic_check_rx_tagging(adapter, skb, &vid); + + if (adapter->rx_mac_learn) { + is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); + } + + if (unlikely(err)) { adapter->stats.rxdropped++; dev_kfree_skb(skb); return buffer; @@ -1832,7 +1827,7 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget) work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1855,7 +1850,7 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget) work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1874,7 +1869,7 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget) if (work_done) { napi_complete(&tx_ring->napi); if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) - qlcnic_83xx_enable_tx_intr(adapter, tx_ring); + qlcnic_enable_tx_intr(adapter, tx_ring); } return work_done; @@ -1892,7 +1887,7 @@ static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1912,7 +1907,7 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter) sds_ring = &recv_ctx->sds_rings[ring]; napi_enable(&sds_ring->napi); if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } if ((adapter->flags & QLCNIC_MSIX_ENABLED) && @@ -1920,7 +1915,7 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; napi_enable(&tx_ring->napi); - qlcnic_83xx_enable_tx_intr(adapter, tx_ring); + qlcnic_enable_tx_intr(adapter, tx_ring); } } } @@ -1938,7 +1933,7 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_disable_intr(adapter, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); napi_synchronize(&sds_ring->napi); napi_disable(&sds_ring->napi); } @@ -1947,7 +1942,7 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter) !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - qlcnic_83xx_disable_tx_intr(adapter, tx_ring); + qlcnic_disable_tx_intr(adapter, tx_ring); napi_synchronize(&tx_ring->napi); napi_disable(&tx_ring->napi); } @@ -2027,8 +2022,8 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter) qlcnic_free_tx_rings(adapter); } -void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, - int ring, u64 sts_data[]) +static void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, + int ring, u64 sts_data[]) { struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct sk_buff *skb; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 550791b8fbae..1f79d47c45fa 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -81,6 +81,16 @@ static int qlcnicvf_start_firmware(struct qlcnic_adapter *); static int qlcnic_vlan_rx_add(struct net_device *, __be16, u16); static int qlcnic_vlan_rx_del(struct net_device *, __be16, u16); +static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *); +static void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); +static irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); +static pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *); +static int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); +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; @@ -308,12 +318,12 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter) static void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter) { - struct qlcnic_mac_list_s *cur; + struct qlcnic_mac_vlan_list *cur; struct list_head *head; list_for_each(head, &adapter->mac_list) { - cur = list_entry(head, struct qlcnic_mac_list_s, list); - if (!memcmp(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) { + cur = list_entry(head, struct qlcnic_mac_vlan_list, list); + if (ether_addr_equal_unaligned(adapter->mac_addr, cur->mac_addr)) { qlcnic_sre_macaddr_change(adapter, cur->mac_addr, 0, QLCNIC_MAC_DEL); list_del(&cur->list); @@ -337,7 +347,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EINVAL; - if (!memcmp(adapter->mac_addr, addr->sa_data, ETH_ALEN)) + if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data)) return 0; if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { @@ -546,6 +556,11 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .io_error_detected = qlcnic_82xx_io_error_detected, .io_slot_reset = qlcnic_82xx_io_slot_reset, .io_resume = qlcnic_82xx_io_resume, + .get_beacon_state = qlcnic_82xx_get_beacon_state, + .enable_sds_intr = qlcnic_82xx_enable_sds_intr, + .disable_sds_intr = qlcnic_82xx_disable_sds_intr, + .enable_tx_intr = qlcnic_82xx_enable_tx_intr, + .disable_tx_intr = qlcnic_82xx_disable_tx_intr, }; static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) @@ -588,9 +603,6 @@ void qlcnic_set_tx_ring_count(struct qlcnic_adapter *adapter, u8 tx_cnt) QLCNIC_TX_QUEUE); else adapter->drv_tx_rings = tx_cnt; - - dev_info(&adapter->pdev->dev, "Set %d Tx rings\n", - adapter->drv_tx_rings); } void qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) @@ -601,25 +613,79 @@ void qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) QLCNIC_RX_QUEUE); else adapter->drv_sds_rings = rx_cnt; - - dev_info(&adapter->pdev->dev, "Set %d SDS rings\n", - adapter->drv_sds_rings); } -int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; - int drv_tx_rings, drv_sds_rings, tx_vector; - int err = -1, i; + int num_msix = 0, err = 0, vector; + + adapter->flags &= ~QLCNIC_TSS_RSS; + + if (adapter->drv_tss_rings > 0) + num_msix += adapter->drv_tss_rings; + else + num_msix += adapter->drv_tx_rings; + + if (adapter->drv_rss_rings > 0) + num_msix += adapter->drv_rss_rings; + else + num_msix += adapter->drv_sds_rings; + + if (qlcnic_83xx_check(adapter)) + num_msix += 1; + + if (!adapter->msix_entries) { + adapter->msix_entries = kcalloc(num_msix, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!adapter->msix_entries) + return -ENOMEM; + } + +restore: + 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) { + adapter->ahw->num_msix = num_msix; + if (adapter->drv_tss_rings > 0) + adapter->drv_tx_rings = adapter->drv_tss_rings; - if (adapter->flags & QLCNIC_TX_INTR_SHARED) { - drv_tx_rings = 0; - tx_vector = 0; + if (adapter->drv_rss_rings > 0) + adapter->drv_sds_rings = adapter->drv_rss_rings; } else { - drv_tx_rings = adapter->drv_tx_rings; - tx_vector = 1; + netdev_info(adapter->netdev, + "Unable to allocate %d MSI-X vectors, Available vectors %d\n", + num_msix, err); + + num_msix = adapter->drv_tx_rings + adapter->drv_sds_rings; + + /* Set rings to 0 so we can restore original TSS/RSS count */ + adapter->drv_tss_rings = 0; + adapter->drv_rss_rings = 0; + + if (qlcnic_83xx_check(adapter)) + num_msix += 1; + + netdev_info(adapter->netdev, + "Restoring %d Tx, %d SDS rings for total %d vectors.\n", + adapter->drv_tx_rings, adapter->drv_sds_rings, + num_msix); + goto restore; + + err = -EIO; } + return err; +} + +int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +{ + struct pci_dev *pdev = adapter->pdev; + int err = -1, vector; + if (!adapter->msix_entries) { adapter->msix_entries = kcalloc(num_msix, sizeof(struct msix_entry), @@ -628,48 +694,43 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) return -ENOMEM; } - adapter->drv_sds_rings = QLCNIC_SINGLE_RING; adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); if (adapter->ahw->msix_supported) { - enable_msix: - for (i = 0; i < num_msix; i++) - adapter->msix_entries[i].entry = i; +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) { adapter->flags |= QLCNIC_MSIX_ENABLED; - if (qlcnic_83xx_check(adapter)) { - adapter->ahw->num_msix = num_msix; - /* subtract mail box and tx ring vectors */ - adapter->drv_sds_rings = num_msix - - drv_tx_rings - 1; - } else { - adapter->ahw->num_msix = num_msix; - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test && - (adapter->drv_tx_rings > 1)) - drv_sds_rings = num_msix - drv_tx_rings; - else - drv_sds_rings = num_msix; - - adapter->drv_sds_rings = drv_sds_rings; - } + adapter->ahw->num_msix = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); return err; } else if (err > 0) { dev_info(&pdev->dev, - "Unable to allocate %d MSI-X interrupt vectors\n", - num_msix); - if (qlcnic_83xx_check(adapter)) { - if (err < (QLC_83XX_MINIMUM_VECTOR - tx_vector)) - return err; - err -= drv_tx_rings + 1; + "Unable to allocate %d MSI-X vectors, Available vectors %d\n", + num_msix, err); + + if (qlcnic_82xx_check(adapter)) { num_msix = rounddown_pow_of_two(err); - num_msix += drv_tx_rings + 1; + if (err < QLCNIC_82XX_MINIMUM_VECTOR) + return -EIO; } else { - num_msix = rounddown_pow_of_two(err); - if (qlcnic_check_multi_tx(adapter)) - num_msix += drv_tx_rings; + num_msix = rounddown_pow_of_two(err - 1); + num_msix += 1; + if (err < QLCNIC_83XX_MINIMUM_VECTOR) + return -EIO; + } + + if (qlcnic_82xx_check(adapter) && + !qlcnic_check_multi_tx(adapter)) { + adapter->drv_sds_rings = num_msix; + adapter->drv_tx_rings = QLCNIC_SINGLE_RING; + } else { + /* Distribute vectors equally */ + adapter->drv_tx_rings = num_msix / 2; + adapter->drv_sds_rings = adapter->drv_tx_rings; } if (num_msix) { @@ -680,14 +741,29 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) } } else { dev_info(&pdev->dev, - "Unable to allocate %d MSI-X interrupt vectors\n", - num_msix); + "Unable to allocate %d MSI-X vectors, err=%d\n", + num_msix, err); + return err; } } return err; } +static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ + int num_msix; + + num_msix = adapter->drv_sds_rings; + + if (qlcnic_check_multi_tx(adapter)) + num_msix += adapter->drv_tx_rings; + else + num_msix += QLCNIC_SINGLE_RING; + + return num_msix; +} + static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) { int err = 0; @@ -722,25 +798,29 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) return err; } -int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter) +static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter) { int num_msix, err = 0; - num_msix = adapter->drv_sds_rings; - - if (qlcnic_check_multi_tx(adapter)) - num_msix += adapter->drv_tx_rings; + if (adapter->flags & QLCNIC_TSS_RSS) { + err = qlcnic_setup_tss_rss_intr(adapter); + if (err < 0) + return err; + num_msix = adapter->ahw->num_msix; + } else { + num_msix = qlcnic_82xx_calculate_msix_vector(adapter); - err = qlcnic_enable_msix(adapter, num_msix); - if (err == -ENOMEM) - return err; + err = qlcnic_enable_msix(adapter, num_msix); + if (err == -ENOMEM) + return err; - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - qlcnic_disable_multi_tx(adapter); + if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { + qlcnic_disable_multi_tx(adapter); - err = qlcnic_enable_msi_legacy(adapter); - if (!err) - return err; + err = qlcnic_enable_msi_legacy(adapter); + if (!err) + return err; + } } return 0; @@ -800,25 +880,26 @@ static void qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw) static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_pci_info *pci_info; int ret; if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - switch (adapter->ahw->port_type) { + switch (ahw->port_type) { case QLCNIC_GBE: - adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS; + ahw->total_nic_func = QLCNIC_NIU_MAX_GBE_PORTS; break; case QLCNIC_XGBE: - adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS; + ahw->total_nic_func = QLCNIC_NIU_MAX_XG_PORTS; break; } return 0; } - if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) + if (ahw->op_mode == QLCNIC_MGMT_FUNC) return 0; - pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); + pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; @@ -846,12 +927,13 @@ static bool qlcnic_port_eswitch_cfg_capability(struct qlcnic_adapter *adapter) int qlcnic_init_pci_info(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_pci_info *pci_info; int i, id = 0, ret = 0, j = 0; u16 act_pci_func; u8 pfn; - pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); + pci_info = kcalloc(ahw->max_vnic_func, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; @@ -859,7 +941,7 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter) if (ret) goto err_pci_info; - act_pci_func = adapter->ahw->act_pci_func; + act_pci_func = ahw->total_nic_func; adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) * act_pci_func, GFP_KERNEL); @@ -875,10 +957,10 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter) goto err_npars; } - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + for (i = 0; i < ahw->max_vnic_func; i++) { pfn = pci_info[i].id; - if (pfn >= QLCNIC_MAX_PCI_FUNC) { + if (pfn >= ahw->max_vnic_func) { ret = QL_STATUS_INVALID_PARAM; goto err_eswitch; } @@ -1346,7 +1428,7 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter) if (adapter->need_fw_reset) return 0; - for (i = 0; i < adapter->ahw->act_pci_func; i++) { + for (i = 0; i < adapter->ahw->total_nic_func; i++) { if (!adapter->npars[i].eswitch_status) continue; @@ -1409,7 +1491,7 @@ int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter) return 0; /* Set the NPAR config data after FW reset */ - for (i = 0; i < adapter->ahw->act_pci_func; i++) { + for (i = 0; i < adapter->ahw->total_nic_func; i++) { npar = &adapter->npars[i]; pci_func = npar->pci_func; if (!adapter->npars[i].eswitch_status) @@ -1484,7 +1566,7 @@ qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter) return err; } -int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter) +static int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter) { int err; @@ -1685,6 +1767,33 @@ static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter) } } +static int qlcnic_config_def_intr_coalesce(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + int err; + + /* Initialize interrupt coalesce parameters */ + ahw->coal.flag = QLCNIC_INTR_DEFAULT; + + if (qlcnic_83xx_check(adapter)) { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; + ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; + ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + + err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); + } else { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + + err = qlcnic_82xx_set_rx_coalesce(adapter); + } + + return err; +} + int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; @@ -1717,7 +1826,7 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) if (adapter->drv_sds_rings > 1) qlcnic_config_rss(adapter, 1); - qlcnic_config_intr_coalesce(adapter); + qlcnic_config_def_intr_coalesce(adapter); if (netdev->features & NETIF_F_LRO) qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); @@ -1862,7 +1971,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_disable_int(sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); } } @@ -1885,7 +1994,6 @@ out: static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) { - struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), @@ -1894,15 +2002,7 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) err = -ENOMEM; goto err_out; } - /* Initialize interrupt coalesce parameters */ - ahw->coal.flag = QLCNIC_INTR_DEFAULT; - ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; - ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - if (qlcnic_83xx_check(adapter)) { - ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; - ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; - } + /* clear stats */ memset(&adapter->stats, 0, sizeof(adapter->stats)); err_out: @@ -1963,7 +2063,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } } @@ -1995,7 +2095,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter) netif_device_attach(netdev); clear_bit(__QLCNIC_RESETTING, &adapter->state); - dev_err(&adapter->pdev->dev, "%s:\n", __func__); + netdev_info(adapter->netdev, "%s: soft reset complete\n", __func__); return 0; } @@ -2032,10 +2132,10 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter) return err; } -void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter) +static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; - u16 act_pci_fn = ahw->act_pci_func; + u16 act_pci_fn = ahw->total_nic_func; u16 count; ahw->max_mc_count = QLCNIC_MAX_MC_COUNT; @@ -2211,7 +2311,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct qlcnic_hardware_context *ahw; int err, pci_using_dac = -1; char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */ - struct qlcnic_dcb *dcb; if (pdev->is_virtfn) return -ENODEV; @@ -2289,7 +2388,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_wq; adapter->dev_rst_time = jiffies; - adapter->ahw->revision_id = pdev->revision; + ahw->revision_id = pdev->revision; + ahw->max_vnic_func = qlcnic_get_vnic_func_count(adapter); if (qlcnic_mac_learn == FDB_MAC_LEARN) adapter->fdb_mac_learn = true; else if (qlcnic_mac_learn == DRV_MAC_LEARN) @@ -2333,10 +2433,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->flags |= QLCNIC_NEED_FLR; - dcb = adapter->dcb; - - if (dcb && qlcnic_dcb_attach(dcb)) - qlcnic_clear_dcb_ops(dcb); } else if (qlcnic_83xx_check(adapter)) { qlcnic_83xx_check_vf(adapter, ent); adapter->portnum = adapter->ahw->pci_func; @@ -2365,6 +2461,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_hw; } + qlcnic_dcb_enable(adapter->dcb); + if (qlcnic_read_mac_addr(adapter)) dev_warn(&pdev->dev, "failed to read mac addr\n"); @@ -2498,13 +2596,11 @@ static void qlcnic_remove(struct pci_dev *pdev) qlcnic_cancel_idc_work(adapter); ahw = adapter->ahw; - qlcnic_dcb_free(adapter->dcb); - unregister_netdev(netdev); qlcnic_sriov_cleanup(adapter); if (qlcnic_83xx_check(adapter)) { - qlcnic_83xx_register_nic_idc_func(adapter, 0); + qlcnic_83xx_initialize_nic(adapter, 0); cancel_delayed_work_sync(&adapter->idc_aen_work); qlcnic_83xx_free_mbx_intr(adapter); qlcnic_83xx_detach_mailbox_work(adapter); @@ -2512,6 +2608,8 @@ static void qlcnic_remove(struct pci_dev *pdev) kfree(ahw->fw_info); } + qlcnic_dcb_free(adapter->dcb); + qlcnic_detach(adapter); if (adapter->npars != NULL) @@ -2640,7 +2738,7 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) if (adapter->fhash.fmax && adapter->fhash.fhead) return; - act_pci_func = adapter->ahw->act_pci_func; + act_pci_func = adapter->ahw->total_nic_func; spin_lock_init(&adapter->mac_learn_lock); spin_lock_init(&adapter->rx_mac_learn_lock); @@ -2737,12 +2835,58 @@ int qlcnic_check_temp(struct qlcnic_adapter *adapter) return rv; } -static void qlcnic_tx_timeout(struct net_device *netdev) +static inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring) { - struct qlcnic_adapter *adapter = netdev_priv(netdev); + int i; + struct cmd_desc_type0 *tx_desc_info; + + for (i = 0; i < tx_ring->num_desc; i++) { + tx_desc_info = &tx_ring->desc_head[i]; + pr_info("TX Desc: %d\n", i); + print_hex_dump(KERN_INFO, "TX: ", DUMP_PREFIX_OFFSET, 16, 1, + &tx_ring->desc_head[i], + sizeof(struct cmd_desc_type0), true); + } +} + +static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; struct qlcnic_host_tx_ring *tx_ring; int ring; + if (!netdev || !netif_running(netdev)) + return; + + for (ring = 0; ring < adapter->drv_tx_rings; ring++) { + tx_ring = &adapter->tx_ring[ring]; + netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n", + ring, tx_ring->ctx_id); + netdev_info(netdev, + "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", + tx_ring->tx_stats.xmit_finished, + tx_ring->tx_stats.xmit_called, + tx_ring->tx_stats.xmit_on, + tx_ring->tx_stats.xmit_off); + netdev_info(netdev, + "crb_intr_mask=%d, hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", + readl(tx_ring->crb_intr_mask), + readl(tx_ring->crb_cmd_producer), + tx_ring->producer, tx_ring->sw_consumer, + le32_to_cpu(*(tx_ring->hw_consumer))); + + netdev_info(netdev, "Total desc=%d, Available desc=%d\n", + tx_ring->num_desc, qlcnic_tx_avail(tx_ring)); + + if (netif_msg_tx_done(adapter->ahw)) + dump_tx_ring_desc(tx_ring); + } +} + +static void qlcnic_tx_timeout(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) return; @@ -2755,22 +2899,7 @@ static void qlcnic_tx_timeout(struct net_device *netdev) QLCNIC_FORCE_FW_DUMP_KEY); } else { netdev_info(netdev, "Tx timeout, reset adapter context.\n"); - for (ring = 0; ring < adapter->drv_tx_rings; ring++) { - tx_ring = &adapter->tx_ring[ring]; - netdev_info(netdev, "Tx ring=%d\n", ring); - netdev_info(netdev, - "crb_intr_mask=%d, producer=%d, sw_consumer=%d, hw_consumer=%d\n", - readl(tx_ring->crb_intr_mask), - readl(tx_ring->crb_cmd_producer), - tx_ring->sw_consumer, - le32_to_cpu(*(tx_ring->hw_consumer))); - netdev_info(netdev, - "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", - tx_ring->tx_stats.xmit_finished, - tx_ring->tx_stats.xmit_called, - tx_ring->tx_stats.xmit_on, - tx_ring->tx_stats.xmit_off); - } + qlcnic_dump_tx_rings(adapter); adapter->ahw->reset_context = 1; } } @@ -2793,7 +2922,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) return stats; } -irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter) +static irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter) { u32 status; @@ -2832,7 +2961,7 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data) done: adapter->ahw->diag_cnt++; - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); return IRQ_HANDLED; } @@ -2880,17 +3009,39 @@ static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data) #ifdef CONFIG_NET_POLL_CONTROLLER static void qlcnic_poll_controller(struct net_device *netdev) { - int ring; - struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) + return; + + recv_ctx = adapter->recv_ctx; - disable_irq(adapter->irq); for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - qlcnic_intr(adapter->irq, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); + napi_schedule(&sds_ring->napi); + } + + if (adapter->flags & QLCNIC_MSIX_ENABLED) { + /* Only Multi-Tx queue capable devices need to + * schedule NAPI for TX rings + */ + if ((qlcnic_83xx_check(adapter) && + (adapter->flags & QLCNIC_TX_INTR_SHARED)) || + (qlcnic_82xx_check(adapter) && + !qlcnic_check_multi_tx(adapter))) + return; + + for (ring = 0; ring < adapter->drv_tx_rings; ring++) { + tx_ring = &adapter->tx_ring[ring]; + qlcnic_disable_tx_intr(adapter, tx_ring); + napi_schedule(&tx_ring->napi); + } } - enable_irq(adapter->irq); } #endif @@ -3286,7 +3437,8 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter) qlcnic_api_unlock(adapter); } -void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key) +static void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, + u32 key) { u32 state, xg_val = 0, gb_val = 0; @@ -3581,8 +3733,8 @@ static int qlcnic_attach_func(struct pci_dev *pdev) return err; } -pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) +static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; @@ -3612,13 +3764,13 @@ pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_NEED_RESET; } -pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev) +static pci_ers_result_t qlcnic_82xx_io_slot_reset(struct pci_dev *pdev) { return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } -void qlcnic_82xx_io_resume(struct pci_dev *pdev) +static void qlcnic_82xx_io_resume(struct pci_dev *pdev) { u32 state; struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); @@ -3726,12 +3878,6 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, return -EINVAL; } - if (ring_cnt < 2) { - netdev_err(netdev, - "%s rings value should not be lower than 2\n", buf); - return -EINVAL; - } - if (!is_power_of_2(ring_cnt)) { netdev_err(netdev, "%s rings value should be a power of 2\n", buf); @@ -3754,7 +3900,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, return 0; } -int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) +int qlcnic_setup_rings(struct qlcnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; @@ -3775,12 +3921,6 @@ int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) qlcnic_teardown_intr(adapter); - /* compute and set default and max tx/sds rings */ - qlcnic_set_tx_ring_count(adapter, tx_cnt); - qlcnic_set_sds_ring_count(adapter, rx_cnt); - - netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); - err = qlcnic_setup_intr(adapter); if (err) { kfree(adapter->msix_entries); @@ -3788,9 +3928,10 @@ int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) return err; } + netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); + if (qlcnic_83xx_check(adapter)) { - /* register for NIC IDC AEN Events */ - qlcnic_83xx_register_nic_idc_func(adapter, 1); + qlcnic_83xx_initialize_nic(adapter, 1); err = qlcnic_83xx_setup_mbx_intr(adapter); qlcnic_83xx_disable_mbx_poll(adapter); if (err) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 0daf660e12a1..396bd1fd1d27 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h @@ -126,8 +126,8 @@ struct qlcnic_vport { u16 handle; u16 max_tx_bw; u16 min_tx_bw; + u16 pvid; u8 vlan_mode; - u16 vlan; u8 qos; bool spoofchk; u8 mac[6]; @@ -137,6 +137,8 @@ struct qlcnic_vf_info { u8 pci_func; u16 rx_ctx_id; u16 tx_ctx_id; + u16 *sriov_vlans; + int num_vlan; unsigned long state; struct completion ch_free_cmpl; struct work_struct trans_work; @@ -149,6 +151,7 @@ struct qlcnic_vf_info { struct qlcnic_trans_list rcv_pend; struct qlcnic_adapter *adapter; struct qlcnic_vport *vp; + struct mutex vlan_list_lock; /* Lock for VLAN list */ }; struct qlcnic_async_work_list { @@ -185,7 +188,6 @@ void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *); int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int); void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *); int qlcnic_sriov_func_to_index(struct qlcnic_adapter *, u8); -int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8); void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32); int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8); void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *); @@ -195,8 +197,13 @@ int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *, int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *, struct qlcnic_info *, u16); int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8); -int qlcnic_sriov_vf_shutdown(struct pci_dev *); -int qlcnic_sriov_vf_resume(struct qlcnic_adapter *); +void qlcnic_sriov_free_vlans(struct qlcnic_adapter *); +void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *); +bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *); +void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *, + struct qlcnic_vf_info *, u16); +void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *, + struct qlcnic_vf_info *, u16); static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 21a4b274d2e4..17a1ca2050f4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -35,7 +35,10 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *); +static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8); static void qlcnic_sriov_process_bc_cmd(struct work_struct *); +static int qlcnic_sriov_vf_shutdown(struct pci_dev *); +static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *); static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .read_crb = qlcnic_83xx_read_crb, @@ -68,6 +71,8 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .change_l2_filter = qlcnic_83xx_change_l2_filter, .get_board_info = qlcnic_83xx_get_port_info, .free_mac_list = qlcnic_sriov_vf_free_mac_list, + .enable_sds_intr = qlcnic_83xx_enable_sds_intr, + .disable_sds_intr = qlcnic_83xx_disable_sds_intr, }; static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { @@ -176,6 +181,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) vf->adapter = adapter; vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i); mutex_init(&vf->send_cmd_lock); + mutex_init(&vf->vlan_list_lock); INIT_LIST_HEAD(&vf->rcv_act.wait_list); INIT_LIST_HEAD(&vf->rcv_pend.wait_list); spin_lock_init(&vf->rcv_act.lock); @@ -276,6 +282,11 @@ static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) { + if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) + return; + + qlcnic_sriov_free_vlans(adapter); + if (qlcnic_sriov_pf_check(adapter)) qlcnic_sriov_pf_cleanup(adapter); @@ -416,10 +427,15 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter, return 0; sriov->any_vlan = cmd->rsp.arg[2] & 0xf; + sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16; + dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n", + sriov->num_allowed_vlans); + + qlcnic_sriov_alloc_vlans(adapter); + if (!sriov->any_vlan) return 0; - sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16; num_vlans = sriov->num_allowed_vlans; sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL); if (!sriov->allowed_vlans) @@ -473,6 +489,8 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) if (err) return err; + ahw->max_mc_count = nic_info.max_rx_mcast_mac_filters; + err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func); if (err) return -EIO; @@ -500,7 +518,6 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, int pci_using_dac) { - struct qlcnic_dcb *dcb; int err; INIT_LIST_HEAD(&adapter->vf_mc_list); @@ -538,11 +555,6 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, if (err) goto err_out_send_channel_term; - dcb = adapter->dcb; - - if (dcb && qlcnic_dcb_attach(dcb)) - qlcnic_clear_dcb_ops(dcb); - err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); if (err) goto err_out_send_channel_term; @@ -1417,7 +1429,7 @@ cleanup_transaction: return rsp; } -int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) +static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) { struct qlcnic_cmd_args cmd; struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0]; @@ -1447,18 +1459,27 @@ out: return ret; } -void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan) +static void qlcnic_vf_add_mc_list(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_mac_list_s *cur; + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_mac_vlan_list *cur; struct list_head *head, tmp_list; + struct qlcnic_vf_info *vf; + u16 vlan_id; + int i; + static const u8 bcast_addr[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + vf = &adapter->ahw->sriov->vf_info[0]; INIT_LIST_HEAD(&tmp_list); head = &adapter->vf_mc_list; netif_addr_lock_bh(netdev); while (!list_empty(head)) { - cur = list_entry(head->next, struct qlcnic_mac_list_s, list); + cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list); list_move(&cur->list, &tmp_list); } @@ -1466,8 +1487,28 @@ void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan) while (!list_empty(&tmp_list)) { cur = list_entry((&tmp_list)->next, - struct qlcnic_mac_list_s, list); - qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan); + struct qlcnic_mac_vlan_list, list); + if (!qlcnic_sriov_check_any_vlan(vf)) { + qlcnic_nic_add_mac(adapter, bcast_addr, 0); + qlcnic_nic_add_mac(adapter, cur->mac_addr, 0); + } else { + mutex_lock(&vf->vlan_list_lock); + for (i = 0; i < sriov->num_allowed_vlans; i++) { + vlan_id = vf->sriov_vlans[i]; + if (vlan_id) { + qlcnic_nic_add_mac(adapter, bcast_addr, + vlan_id); + qlcnic_nic_add_mac(adapter, + cur->mac_addr, + vlan_id); + } + } + mutex_unlock(&vf->vlan_list_lock); + if (qlcnic_84xx_check(adapter)) { + qlcnic_nic_add_mac(adapter, bcast_addr, 0); + qlcnic_nic_add_mac(adapter, cur->mac_addr, 0); + } + } list_del(&cur->list); kfree(cur); } @@ -1490,13 +1531,24 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc) static void qlcnic_sriov_vf_set_multi(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); - u16 vlan; + struct qlcnic_hardware_context *ahw = adapter->ahw; + u32 mode = VPORT_MISS_MODE_DROP; if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; - vlan = adapter->ahw->sriov->vlan; - __qlcnic_set_multi(netdev, vlan); + if (netdev->flags & IFF_PROMISC) { + if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) + mode = VPORT_MISS_MODE_ACCEPT_ALL; + } else if ((netdev->flags & IFF_ALLMULTI) || + (netdev_mc_count(netdev) > ahw->max_mc_count)) { + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + } + + if (qlcnic_sriov_vf_check(adapter)) + qlcnic_vf_add_mc_list(netdev); + + qlcnic_nic_set_promisc(adapter, mode); } static void qlcnic_sriov_handle_async_multi(struct work_struct *work) @@ -1584,8 +1636,6 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter) if (err) goto err_out_term_channel; - qlcnic_dcb_get_info(adapter->dcb); - return 0; err_out_term_channel: @@ -1833,18 +1883,60 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter) cancel_delayed_work_sync(&adapter->fw_work); } -static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov, +static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, u16 vlan_id) +{ + int i, err = -EINVAL; + + if (!vf->sriov_vlans) + return err; + + mutex_lock(&vf->vlan_list_lock); + + for (i = 0; i < sriov->num_allowed_vlans; i++) { + if (vf->sriov_vlans[i] == vlan_id) { + err = 0; + break; + } + } + + mutex_unlock(&vf->vlan_list_lock); + return err; +} + +static int qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf) +{ + int err = 0; + + mutex_lock(&vf->vlan_list_lock); + + if (vf->num_vlan >= sriov->num_allowed_vlans) + err = -EINVAL; + + mutex_unlock(&vf->vlan_list_lock); + return err; +} + +static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_adapter *adapter, u16 vid, u8 enable) { - u16 vlan = sriov->vlan; + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_vf_info *vf; + bool vlan_exist; u8 allowed = 0; int i; + vf = &adapter->ahw->sriov->vf_info[0]; + vlan_exist = qlcnic_sriov_check_any_vlan(vf); if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE) return -EINVAL; if (enable) { - if (vlan) + if (qlcnic_83xx_vf_check(adapter) && vlan_exist) + return -EINVAL; + + if (qlcnic_sriov_validate_num_vlans(sriov, vf)) return -EINVAL; if (sriov->any_vlan) { @@ -1857,24 +1949,54 @@ static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov, return -EINVAL; } } else { - if (!vlan || vlan != vid) + if (!vlan_exist || qlcnic_sriov_check_vlan_id(sriov, vf, vid)) return -EINVAL; } return 0; } +static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id, + enum qlcnic_vlan_operations opcode) +{ + struct qlcnic_adapter *adapter = vf->adapter; + struct qlcnic_sriov *sriov; + + sriov = adapter->ahw->sriov; + + if (!vf->sriov_vlans) + return; + + mutex_lock(&vf->vlan_list_lock); + + switch (opcode) { + case QLC_VLAN_ADD: + qlcnic_sriov_add_vlan_id(sriov, vf, vlan_id); + break; + case QLC_VLAN_DELETE: + qlcnic_sriov_del_vlan_id(sriov, vf, vlan_id); + break; + default: + netdev_err(adapter->netdev, "Invalid VLAN operation\n"); + } + + mutex_unlock(&vf->vlan_list_lock); + return; +} + int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter, u16 vid, u8 enable) { struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_vf_info *vf; struct qlcnic_cmd_args cmd; int ret; if (vid == 0) return 0; - ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable); + vf = &adapter->ahw->sriov->vf_info[0]; + ret = qlcnic_sriov_validate_vlan_cfg(adapter, vid, enable); if (ret) return ret; @@ -1894,11 +2016,11 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter, qlcnic_free_mac_list(adapter); if (enable) - sriov->vlan = vid; + qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD); else - sriov->vlan = 0; + qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_DELETE); - qlcnic_sriov_vf_set_multi(adapter->netdev); + qlcnic_set_multi(adapter->netdev); } qlcnic_free_mbx_args(&cmd); @@ -1908,21 +2030,19 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter, static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter) { struct list_head *head = &adapter->mac_list; - struct qlcnic_mac_list_s *cur; - u16 vlan; - - vlan = adapter->ahw->sriov->vlan; + struct qlcnic_mac_vlan_list *cur; while (!list_empty(head)) { - cur = list_entry(head->next, struct qlcnic_mac_list_s, list); - qlcnic_sre_macaddr_change(adapter, cur->mac_addr, - vlan, QLCNIC_MAC_DEL); + cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list); + qlcnic_sre_macaddr_change(adapter, cur->mac_addr, cur->vlan_id, + QLCNIC_MAC_DEL); list_del(&cur->list); kfree(cur); } } -int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev) + +static int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; @@ -1946,7 +2066,7 @@ int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev) return 0; } -int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter) +static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter) { struct qlc_83xx_idc *idc = &adapter->ahw->idc; struct net_device *netdev = adapter->netdev; @@ -1972,3 +2092,70 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter) idc->delay); return err; } + +void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter) +{ + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_vf_info *vf; + int i; + + for (i = 0; i < sriov->num_vfs; i++) { + vf = &sriov->vf_info[i]; + vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans, + sizeof(*vf->sriov_vlans), GFP_KERNEL); + } +} + +void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter) +{ + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_vf_info *vf; + int i; + + for (i = 0; i < sriov->num_vfs; i++) { + vf = &sriov->vf_info[i]; + kfree(vf->sriov_vlans); + vf->sriov_vlans = NULL; + } +} + +void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, u16 vlan_id) +{ + int i; + + for (i = 0; i < sriov->num_allowed_vlans; i++) { + if (!vf->sriov_vlans[i]) { + vf->sriov_vlans[i] = vlan_id; + vf->num_vlan++; + return; + } + } +} + +void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, u16 vlan_id) +{ + int i; + + for (i = 0; i < sriov->num_allowed_vlans; i++) { + if (vf->sriov_vlans[i] == vlan_id) { + vf->sriov_vlans[i] = 0; + vf->num_vlan--; + return; + } + } +} + +bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *vf) +{ + bool err = false; + + mutex_lock(&vf->vlan_list_lock); + + if (vf->num_vlan) + err = true; + + mutex_unlock(&vf->vlan_list_lock); + return err; +} diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 024f8161d2fe..09acf15c3a56 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -9,9 +9,14 @@ #include "qlcnic.h" #include <linux/types.h> -#define QLCNIC_SRIOV_VF_MAX_MAC 1 +#define QLCNIC_SRIOV_VF_MAX_MAC 7 #define QLC_VF_MIN_TX_RATE 100 #define QLC_VF_MAX_TX_RATE 9999 +#define QLC_MAC_OPCODE_MASK 0x7 +#define QLC_MAC_STAR_ADD 6 +#define QLC_MAC_STAR_DEL 7 +#define QLC_VF_FLOOD_BIT BIT_16 +#define QLC_FLOOD_MODE 0x5 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -64,9 +69,10 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter, { struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_resources *res = &sriov->ff_max; - u32 temp, num_vf_macs, num_vfs, max; + u16 num_macs = sriov->num_allowed_vlans + 1; int ret = -EIO, vpid, id; struct qlcnic_vport *vp; + u32 num_vfs, max, temp; vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); if (vpid < 0) @@ -75,16 +81,25 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter, num_vfs = sriov->num_vfs; max = num_vfs + 1; info->bit_offsets = 0xffff; + info->max_tx_ques = res->num_tx_queues / max; + + if (qlcnic_83xx_pf_check(adapter)) + num_macs = 1; + info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; - num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC; if (adapter->ahw->pci_func == func) { - temp = res->num_rx_mcast_mac_filters - (num_vfs * num_vf_macs); - info->max_rx_ucast_mac_filters = temp; - temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs); - info->max_tx_mac_filters = temp; info->min_tx_bw = 0; info->max_tx_bw = MAX_BW; + + temp = res->num_rx_ucast_mac_filters - num_macs * num_vfs; + info->max_rx_ucast_mac_filters = temp; + temp = res->num_tx_mac_filters - num_macs * num_vfs; + info->max_tx_mac_filters = temp; + temp = num_macs * num_vfs * QLCNIC_SRIOV_VF_MAX_MAC; + temp = res->num_rx_mcast_mac_filters - temp; + info->max_rx_mcast_mac_filters = temp; + info->max_tx_ques = res->num_tx_queues - sriov->num_vfs; } else { id = qlcnic_sriov_func_to_index(adapter, func); @@ -93,8 +108,12 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter, vp = sriov->vf_info[id].vp; info->min_tx_bw = vp->min_tx_bw; info->max_tx_bw = vp->max_tx_bw; - info->max_rx_ucast_mac_filters = num_vf_macs; - info->max_tx_mac_filters = num_vf_macs; + + info->max_rx_ucast_mac_filters = num_macs; + info->max_tx_mac_filters = num_macs; + temp = num_macs * QLCNIC_SRIOV_VF_MAX_MAC; + info->max_rx_mcast_mac_filters = temp; + info->max_tx_ques = QLCNIC_SINGLE_RING; } @@ -133,6 +152,25 @@ static void qlcnic_sriov_pf_set_ff_max_res(struct qlcnic_adapter *adapter, ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs; } +static void qlcnic_sriov_set_vf_max_vlan(struct qlcnic_adapter *adapter, + struct qlcnic_info *npar_info) +{ + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + int temp, total_fn; + + temp = npar_info->max_rx_mcast_mac_filters; + total_fn = sriov->num_vfs + 1; + + temp = temp / (QLCNIC_SRIOV_VF_MAX_MAC * total_fn); + sriov->num_allowed_vlans = temp - 1; + + if (qlcnic_83xx_pf_check(adapter)) + sriov->num_allowed_vlans = 1; + + netdev_info(adapter->netdev, "Max Guest VLANs supported per VF = %d\n", + sriov->num_allowed_vlans); +} + static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter, struct qlcnic_info *npar_info) { @@ -166,6 +204,7 @@ static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter, npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]); npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]); + qlcnic_sriov_set_vf_max_vlan(adapter, npar_info); qlcnic_sriov_pf_set_ff_max_res(adapter, npar_info); dev_info(&adapter->pdev->dev, "\n\ttotal_pf: %d,\n" @@ -310,6 +349,28 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, return err; } +/* On configuring VF flood bit, PFD will receive traffic from all VFs */ +static int qlcnic_sriov_pf_cfg_flood(struct qlcnic_adapter *adapter) +{ + struct qlcnic_cmd_args cmd; + int err; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); + if (err) + return err; + + cmd.req.arg[1] = QLC_FLOOD_MODE | QLC_VF_FLOOD_BIT; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) + dev_err(&adapter->pdev->dev, + "Failed to configure VF Flood bit on PF, err=%d\n", + err); + + qlcnic_free_mbx_args(&cmd); + return err; +} + static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter, u8 func, u8 enable) { @@ -404,6 +465,8 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter) qlcnic_sriov_pf_disable(adapter); + qlcnic_sriov_free_vlans(adapter); + qlcnic_sriov_pf_cleanup(adapter); /* After disabling SRIOV re-init the driver in default mode @@ -435,6 +498,12 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) if (err) return err; + if (qlcnic_84xx_check(adapter)) { + err = qlcnic_sriov_pf_cfg_flood(adapter); + if (err) + goto disable_vlan_filtering; + } + err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); if (err) goto disable_vlan_filtering; @@ -512,6 +581,8 @@ static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, if (err) goto del_flr_queue; + qlcnic_sriov_alloc_vlans(adapter); + err = qlcnic_sriov_pf_enable(adapter, num_vfs); return err; @@ -609,7 +680,7 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func) if (vp->vlan_mode == QLC_PVID_MODE) { cmd.req.arg[2] |= BIT_6; - cmd.req.arg[3] |= vp->vlan << 8; + cmd.req.arg[3] |= vp->pvid << 8; } err = qlcnic_issue_cmd(adapter, &cmd); @@ -644,10 +715,13 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, struct qlcnic_vf_info *vf = trans->vf; struct qlcnic_vport *vp = vf->vp; struct qlcnic_adapter *adapter; + struct qlcnic_sriov *sriov; u16 func = vf->pci_func; + size_t size; int err; adapter = vf->adapter; + sriov = adapter->ahw->sriov; if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) { err = qlcnic_sriov_pf_config_vport(adapter, 1, func); @@ -657,8 +731,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, qlcnic_sriov_pf_config_vport(adapter, 0, func); } } else { - if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) - vp->vlan = 0; + if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) { + size = sizeof(*vf->sriov_vlans); + size = size * sriov->num_allowed_vlans; + memset(vf->sriov_vlans, 0, size); + } + err = qlcnic_sriov_pf_config_vport(adapter, 0, func); } @@ -680,20 +758,23 @@ err_out: } static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, - struct qlcnic_vport *vp, - u16 func, u16 vlan, u8 op) + struct qlcnic_vf_info *vf, + u16 vlan, u8 op) { struct qlcnic_cmd_args cmd; struct qlcnic_macvlan_mbx mv; + struct qlcnic_vport *vp; u8 *addr; int err; u32 *buf; int vpid; + vp = vf->vp; + if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN)) return -ENOMEM; - vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func); if (vpid < 0) { err = -EINVAL; goto out; @@ -737,6 +818,35 @@ static int qlcnic_sriov_validate_create_rx_ctx(struct qlcnic_cmd_args *cmd) return 0; } +static void qlcnic_83xx_cfg_default_mac_vlan(struct qlcnic_adapter *adapter, + struct qlcnic_vf_info *vf, + int opcode) +{ + struct qlcnic_sriov *sriov; + u16 vlan; + int i; + + sriov = adapter->ahw->sriov; + + mutex_lock(&vf->vlan_list_lock); + if (vf->num_vlan) { + for (i = 0; i < sriov->num_allowed_vlans; i++) { + vlan = vf->sriov_vlans[i]; + if (vlan) + qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, + opcode); + } + } + mutex_unlock(&vf->vlan_list_lock); + + if (vf->vp->vlan_mode != QLC_PVID_MODE) { + if (qlcnic_83xx_pf_check(adapter) && + qlcnic_sriov_check_any_vlan(vf)) + return; + qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, opcode); + } +} + static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, struct qlcnic_cmd_args *cmd) { @@ -744,7 +854,6 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, struct qlcnic_adapter *adapter = vf->adapter; struct qlcnic_rcv_mbx_out *mbx_out; int err; - u16 vlan; err = qlcnic_sriov_validate_create_rx_ctx(cmd); if (err) { @@ -755,12 +864,10 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, cmd->req.arg[6] = vf->vp->handle; err = qlcnic_issue_cmd(adapter, cmd); - vlan = vf->vp->vlan; if (!err) { mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1]; vf->rx_ctx_id = mbx_out->ctx_id; - qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, - vlan, QLCNIC_MAC_ADD); + qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_ADD); } else { vf->rx_ctx_id = 0; } @@ -844,7 +951,6 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans, struct qlcnic_vf_info *vf = trans->vf; struct qlcnic_adapter *adapter = vf->adapter; int err; - u16 vlan; err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd); if (err) { @@ -852,9 +958,7 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans, return err; } - vlan = vf->vp->vlan; - qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, - vlan, QLCNIC_MAC_DEL); + qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_DEL); cmd->req.arg[1] |= vf->vp->handle << 16; err = qlcnic_issue_cmd(adapter, cmd); @@ -1102,6 +1206,13 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, struct qlcnic_vport *vp = vf->vp; u8 op, new_op; + if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) || + ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) { + netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n", + vf->pci_func); + return -EINVAL; + } + if (!(cmd->req.arg[1] & BIT_8)) return -EINVAL; @@ -1121,7 +1232,7 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, cmd->req.arg[1] &= ~0x7; new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; - cmd->req.arg[3] |= vp->vlan << 16; + cmd->req.arg[3] |= vp->pvid << 16; cmd->req.arg[1] |= new_op; } @@ -1191,8 +1302,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, struct qlcnic_vport *vp = vf->vp; u8 cmd_op, mode = vp->vlan_mode; struct qlcnic_adapter *adapter; + struct qlcnic_sriov *sriov; adapter = vf->adapter; + sriov = adapter->ahw->sriov; cmd_op = trans->req_hdr->cmd_op; cmd->rsp.arg[0] |= 1 << 25; @@ -1206,10 +1319,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, switch (mode) { case QLC_GUEST_VLAN_MODE: cmd->rsp.arg[1] = mode | 1 << 8; - cmd->rsp.arg[2] = 1 << 16; + cmd->rsp.arg[2] = sriov->num_allowed_vlans << 16; break; case QLC_PVID_MODE: - cmd->rsp.arg[1] = mode | 1 << 8 | vp->vlan << 16; + cmd->rsp.arg[1] = mode | 1 << 8 | vp->pvid << 16; break; } @@ -1217,24 +1330,27 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, } static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter, - struct qlcnic_vf_info *vf) - + struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) { - struct qlcnic_vport *vp = vf->vp; + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + u16 vlan; - if (!vp->vlan) + if (!qlcnic_sriov_check_any_vlan(vf)) return -EINVAL; + vlan = cmd->req.arg[1] >> 16; if (!vf->rx_ctx_id) { - vp->vlan = 0; + qlcnic_sriov_del_vlan_id(sriov, vf, vlan); return 0; } - qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, - vp->vlan, QLCNIC_MAC_DEL); - vp->vlan = 0; - qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, - 0, QLCNIC_MAC_ADD); + qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_DEL); + qlcnic_sriov_del_vlan_id(sriov, vf, vlan); + + if (qlcnic_83xx_pf_check(adapter)) + qlcnic_sriov_cfg_vf_def_mac(adapter, vf, + 0, QLCNIC_MAC_ADD); return 0; } @@ -1242,32 +1358,37 @@ static int qlcnic_sriov_pf_add_guest_vlan(struct qlcnic_adapter *adapter, struct qlcnic_vf_info *vf, struct qlcnic_cmd_args *cmd) { - struct qlcnic_vport *vp = vf->vp; + struct qlcnic_sriov *sriov = adapter->ahw->sriov; int err = -EIO; + u16 vlan; - if (vp->vlan) + if (qlcnic_83xx_pf_check(adapter) && qlcnic_sriov_check_any_vlan(vf)) return err; + vlan = cmd->req.arg[1] >> 16; + if (!vf->rx_ctx_id) { - vp->vlan = cmd->req.arg[1] >> 16; + qlcnic_sriov_add_vlan_id(sriov, vf, vlan); return 0; } - err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, - 0, QLCNIC_MAC_DEL); - if (err) - return err; + if (qlcnic_83xx_pf_check(adapter)) { + err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, + QLCNIC_MAC_DEL); + if (err) + return err; + } - vp->vlan = cmd->req.arg[1] >> 16; - err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, - vp->vlan, QLCNIC_MAC_ADD); + err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_ADD); if (err) { - qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, - 0, QLCNIC_MAC_ADD); - vp->vlan = 0; + if (qlcnic_83xx_pf_check(adapter)) + qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, + QLCNIC_MAC_ADD); + return err; } + qlcnic_sriov_add_vlan_id(sriov, vf, vlan); return err; } @@ -1290,7 +1411,7 @@ static int qlcnic_sriov_pf_cfg_guest_vlan_cmd(struct qlcnic_bc_trans *tran, if (op) err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd); else - err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf); + err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf, cmd); cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25; return err; @@ -1300,8 +1421,6 @@ static const int qlcnic_pf_passthru_supp_cmds[] = { QLCNIC_CMD_GET_STATISTICS, QLCNIC_CMD_GET_PORT_CONFIG, QLCNIC_CMD_GET_LINK_STATUS, - QLCNIC_CMD_DCB_QUERY_CAP, - QLCNIC_CMD_DCB_QUERY_PARAM, QLCNIC_CMD_INIT_NIC_FUNC, QLCNIC_CMD_STOP_NIC_FUNC, }; @@ -1597,7 +1716,8 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, } if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) - vp->vlan = 0; + memset(vf->sriov_vlans, 0, + sizeof(*vf->sriov_vlans) * sriov->num_allowed_vlans); qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); @@ -1767,20 +1887,22 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, return -EOPNOTSUPP; } + memset(vf_info->sriov_vlans, 0, + sizeof(*vf_info->sriov_vlans) * sriov->num_allowed_vlans); + switch (vlan) { case 4095: - vp->vlan = 0; vp->vlan_mode = QLC_GUEST_VLAN_MODE; break; case 0: vp->vlan_mode = QLC_NO_VLAN_MODE; - vp->vlan = 0; vp->qos = 0; break; default: vp->vlan_mode = QLC_PVID_MODE; - vp->vlan = vlan; + qlcnic_sriov_add_vlan_id(sriov, vf_info, vlan); vp->qos = qos; + vp->pvid = vlan; } netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n", @@ -1795,7 +1917,7 @@ static __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter, switch (vp->vlan_mode) { case QLC_PVID_MODE: - vlan = vp->vlan; + vlan = vp->pvid; break; case QLC_GUEST_VLAN_MODE: vlan = MAX_VLAN_ID; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 1a9f8a400e50..3d64113a35af 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -6,7 +6,6 @@ */ #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/interrupt.h> #include "qlcnic.h" @@ -127,6 +126,8 @@ static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter, if (kstrtoul(buf, 2, &h_beacon)) return -EINVAL; + qlcnic_get_beacon_state(adapter); + if (ahw->beacon_state == h_beacon) return len; @@ -158,7 +159,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, struct qlcnic_hardware_context *ahw = adapter->ahw; int err, drv_sds_rings = adapter->drv_sds_rings; u16 beacon; - u8 h_beacon_state, b_state, b_rate; + u8 b_state, b_rate; if (len != sizeof(u16)) return QL_STATUS_INVALID_PARAM; @@ -168,18 +169,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, if (err) return err; - if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { - err = qlcnic_get_beacon_state(adapter, &h_beacon_state); - if (err) { - netdev_err(adapter->netdev, - "Failed to get current beacon state\n"); - } else { - if (h_beacon_state == QLCNIC_BEACON_DISABLE) - ahw->beacon_state = 0; - else if (h_beacon_state == QLCNIC_BEACON_EANBLE) - ahw->beacon_state = 2; - } - } + qlcnic_get_beacon_state(adapter); if (ahw->beacon_state == b_state) return len; @@ -360,10 +350,28 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } -static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) +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 < adapter->ahw->act_pci_func; i++) { + + for (i = 0; i < pci_func_count; i++) { if (adapter->npars[i].pci_func == pci_func) return i; } @@ -382,7 +390,6 @@ static int validate_pm_config(struct qlcnic_adapter *adapter, src_pci_func = pm_cfg[i].pci_func; dest_pci_func = pm_cfg[i].dest_npar; src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func); - if (src_index < 0) return QL_STATUS_INVALID_PARAM; @@ -439,6 +446,8 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp, for (i = 0; i < count; i++) { pci_func = pm_cfg[i].pci_func; index = qlcnic_is_valid_nic_func(adapter, pci_func); + if (index < 0) + return QL_STATUS_INVALID_PARAM; id = adapter->npars[index].phy_port; adapter->npars[index].enable_pm = !!pm_cfg[i].action; adapter->npars[index].dest_npar = id; @@ -455,17 +464,19 @@ 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); - struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC]; - int i; + 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; - if (size != sizeof(pm_cfg)) + pm_cfg_size = pci_func_count * sizeof(*pm_cfg); + if (size != pm_cfg_size) return QL_STATUS_INVALID_PARAM; - memset(&pm_cfg, 0, - sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC); + memset(buf, 0, pm_cfg_size); + pm_cfg = (struct qlcnic_pm_func_cfg *)buf; - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + for (i = 0; i < pci_func_count; i++) { pci_func = adapter->npars[i].pci_func; if (!adapter->npars[i].active) continue; @@ -477,26 +488,26 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, pm_cfg[pci_func].dest_npar = 0; pm_cfg[pci_func].pci_func = i; } - memcpy(buf, &pm_cfg, size); - return size; } 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; u8 pci_func; - int i, ret; if (qlcnic_82xx_check(adapter)) - op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE); + op_mode = readl(ahw->pci_base0 + QLCNIC_DRV_OP_MODE); else - op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE); + op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE); for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; - if (pci_func >= QLCNIC_MAX_PCI_FUNC) + if (pci_func >= pci_func_count) return QL_STATUS_INVALID_PARAM; if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) @@ -600,6 +611,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file, for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; index = qlcnic_is_valid_nic_func(adapter, pci_func); + if (index < 0) + return QL_STATUS_INVALID_PARAM; npar = &adapter->npars[index]; switch (esw_cfg[i].op_mode) { case QLCNIC_PORT_DEFAULTS: @@ -629,16 +642,19 @@ 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); - struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC]; + 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; - if (size != sizeof(esw_cfg)) + esw_cfg_size = pci_func_count * sizeof(*esw_cfg); + if (size != esw_cfg_size) return QL_STATUS_INVALID_PARAM; - memset(&esw_cfg, 0, - sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC); + memset(buf, 0, esw_cfg_size); + esw_cfg = (struct qlcnic_esw_func_cfg *)buf; - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + for (i = 0; i < pci_func_count; i++) { pci_func = adapter->npars[i].pci_func; if (!adapter->npars[i].active) continue; @@ -650,9 +666,6 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file, if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func])) return QL_STATUS_INVALID_PARAM; } - - memcpy(buf, &esw_cfg, size); - return size; } @@ -711,6 +724,8 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file, if (ret) return ret; index = qlcnic_is_valid_nic_func(adapter, pci_func); + if (index < 0) + return QL_STATUS_INVALID_PARAM; adapter->npars[index].min_bw = nic_info.min_tx_bw; adapter->npars[index].max_bw = nic_info.max_tx_bw; } @@ -726,27 +741,28 @@ 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; - struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC]; + size_t np_cfg_size; int i, ret; - if (size != sizeof(np_cfg)) + np_cfg_size = pci_func_count * sizeof(*np_cfg); + if (size != np_cfg_size) return QL_STATUS_INVALID_PARAM; memset(&nic_info, 0, sizeof(struct qlcnic_info)); - memset(&np_cfg, 0, - sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC); + memset(buf, 0, np_cfg_size); + np_cfg = (struct qlcnic_npar_func_cfg *)buf; - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + for (i = 0; i < pci_func_count; i++) { if (qlcnic_is_valid_nic_func(adapter, i) < 0) continue; ret = qlcnic_get_nic_info(adapter, &nic_info, i); if (ret) return ret; - if (!adapter->npars[i].eswitch_status) continue; - np_cfg[i].pci_func = i; np_cfg[i].op_mode = (u8)nic_info.op_mode; np_cfg[i].port_num = nic_info.phys_port; @@ -756,8 +772,6 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, np_cfg[i].max_tx_queues = nic_info.max_tx_ques; np_cfg[i].max_rx_queues = nic_info.max_rx_ques; } - - memcpy(buf, &np_cfg, size); return size; } @@ -769,6 +783,7 @@ 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; @@ -778,7 +793,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 >= QLCNIC_MAX_PCI_FUNC) + if (offset >= pci_func_count) return QL_STATUS_INVALID_PARAM; memset(&port_stats, 0, size); @@ -869,12 +884,13 @@ 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 >= QLCNIC_MAX_PCI_FUNC) + if (offset >= pci_func_count) return QL_STATUS_INVALID_PARAM; ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, @@ -898,14 +914,17 @@ 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); - struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC]; + 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; - if (size != sizeof(pci_cfg)) + pci_cfg_sz = pci_func_count * sizeof(*pci_cfg); + if (size != pci_cfg_sz) return QL_STATUS_INVALID_PARAM; - pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL); + pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; @@ -915,19 +934,17 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, return ret; } - memset(&pci_cfg, 0, - sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC); - - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + pci_cfg = (struct qlcnic_pci_func_cfg *)buf; + for (i = 0; i < pci_func_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; pci_cfg[i].port_num = pci_info[i].default_port; pci_cfg[i].min_bw = pci_info[i].tx_min_bw; pci_cfg[i].max_bw = pci_info[i].tx_max_bw; memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN); } - memcpy(buf, &pci_cfg, size); kfree(pci_info); return size; } @@ -1269,7 +1286,7 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter) device_remove_file(dev, &dev_attr_bridged_mode); } -void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) +static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; @@ -1308,7 +1325,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) dev_info(dev, "failed to create eswitch stats sysfs entry"); } -void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) +static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; |