From 2e9d722db6617ed10204bfa9cd60552620592a43 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Tue, 1 Jun 2010 11:28:51 +0000 Subject: qlcnic: NIC Partitioning - Add basic infrastructure support Following changes have been added to enable the adapter to work in NIC partitioning mode where multiple PCI functions of an adapter port can be configured to work as NIC functions. The first function that is enumerated on the PCI bus assumes the role of management function which, besides being able to do all the NIC functionality, can configure other NIC partitions. Other NIC functions can be configured as privileged or non privileged functions. Privileged function can not configure other NIC functions but can do all the NIC functionality including any firmware initialization, chip reset etc. Non privileged functions can do only basic IO. For chip reset etc, it depends on the privilege or management function. 1. Added code to determine PCI function number independent of kernel API. 2. Added Driver - FW version 2.0 support. 3. Changed producer and consumer register offset calculation. 4. Added management and privileged operation modes for npar functions. A module parameter has been added to control it. 5. Added support for configuring the eswitch in the adapter. Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 121 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 8 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 896d40df9a1..31a0b430a9d 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -197,8 +197,7 @@ struct cmd_desc_type0 { __le64 addr_buffer4; - __le32 reserved2; - __le16 reserved; + u8 eth_addr[ETH_ALEN]; __le16 vlan_TCI; } __attribute__ ((aligned(64))); @@ -315,6 +314,8 @@ struct uni_data_desc{ #define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032 #define QLCNIC_BRDTYPE_P3_10G_TP 0x0080 +#define QLCNIC_MSIX_TABLE_OFFSET 0x44 + /* Flash memory map */ #define QLCNIC_BRDCFG_START 0x4000 /* board config */ #define QLCNIC_BOOTLD_START 0x10000 /* bootld */ @@ -542,7 +543,17 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c #define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d #define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e -#define QLCNIC_CDRP_CMD_MAX 0x0000001f +#define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f + +#define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020 +#define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021 +#define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022 +#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023 +#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024 +#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025 +#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 +#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027 +#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028 #define QLCNIC_RCODE_SUCCESS 0 #define QLCNIC_RCODE_TIMEOUT 17 @@ -560,7 +571,6 @@ struct qlcnic_recv_context { /* * Context state */ -#define QLCHAL_VERSION 1 #define QLCNIC_HOST_CTX_STATE_ACTIVE 2 @@ -887,6 +897,7 @@ struct qlcnic_mac_req { #define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS #define QLCNIC_MSIX_TBL_SPACE 8192 #define QLCNIC_PCI_REG_MSIX_TBL 0x44 +#define QLCNIC_MSIX_TBL_PGSIZE 4096 #define QLCNIC_NETDEV_WEIGHT 128 #define QLCNIC_ADAPTER_UP_MAGIC 777 @@ -923,7 +934,6 @@ struct qlcnic_adapter { u8 mc_enabled; u8 max_mc_count; u8 rss_supported; - u8 rsrvd1; u8 fw_wait_cnt; u8 fw_fail_cnt; u8 tx_timeo_cnt; @@ -940,6 +950,15 @@ struct qlcnic_adapter { u16 link_autoneg; u16 module_type; + u16 op_mode; + u16 switch_mode; + u16 max_tx_ques; + u16 max_rx_ques; + u16 min_tx_bw; + u16 max_tx_bw; + u16 max_mtu; + + u32 fw_hal_version; u32 capabilities; u32 flags; u32 irq; @@ -948,18 +967,22 @@ struct qlcnic_adapter { u32 int_vec_bit; u32 heartbit; + u8 max_mac_filters; u8 dev_state; u8 diag_test; u8 diag_cnt; u8 reset_ack_timeo; u8 dev_init_timeo; - u8 rsrd1; u16 msg_enable; u8 mac_addr[ETH_ALEN]; u64 dev_rst_time; + struct qlcnic_pci_info *npars; + struct qlcnic_eswitch *eswitch; + struct qlcnic_nic_template *nic_ops; + struct qlcnic_adapter_stats stats; struct qlcnic_recv_context recv_ctx; @@ -984,6 +1007,53 @@ struct qlcnic_adapter { const struct firmware *fw; }; +struct qlcnic_info { + __le16 pci_func; + __le16 op_mode; /* 1 = Priv, 2 = NP, 3 = NP passthru */ + __le16 phys_port; + __le16 switch_mode; /* 0 = disabled, 1 = int, 2 = ext */ + + __le32 capabilities; + u8 max_mac_filters; + u8 reserved1; + __le16 max_mtu; + + __le16 max_tx_ques; + __le16 max_rx_ques; + __le16 min_tx_bw; + __le16 max_tx_bw; + u8 reserved2[104]; +}; + +struct qlcnic_pci_info { + __le16 id; /* pci function id */ + __le16 active; /* 1 = Enabled */ + __le16 type; /* 1 = NIC, 2 = FCoE, 3 = iSCSI */ + __le16 default_port; /* default port number */ + + __le16 tx_min_bw; /* Multiple of 100mbpc */ + __le16 tx_max_bw; + __le16 reserved1[2]; + + u8 mac[ETH_ALEN]; + u8 reserved2[106]; +}; + +struct qlcnic_eswitch { + u8 port; + u8 active_vports; + u8 active_vlans; + u8 active_ucast_filters; + u8 max_ucast_filters; + u8 max_active_vlans; + + u32 flags; +#define QLCNIC_SWITCH_ENABLE BIT_1 +#define QLCNIC_SWITCH_VLAN_FILTERING BIT_2 +#define QLCNIC_SWITCH_PROMISC_MODE BIT_3 +#define QLCNIC_SWITCH_PORT_MIRRORING BIT_4 +}; + int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); @@ -1070,13 +1140,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); -int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable); +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_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring); -int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac); +int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac); void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter); int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter); +void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *); /* Functions from qlcnic_main.c */ int qlcnic_reset_context(struct qlcnic_adapter *); @@ -1088,6 +1159,32 @@ int qlcnic_check_loopback_buff(unsigned char *data); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring); +/* Functions from qlcnic_vf.c */ +int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); +int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); +int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter); +void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter); +void qlcnicvf_set_port_mode(struct qlcnic_adapter *adapter); + +/* Management functions */ +int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*); +int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); +int qlcnic_get_nic_info(struct qlcnic_adapter *, u8); +int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); +int qlcnic_get_pci_info(struct qlcnic_adapter *); +int qlcnic_reset_partition(struct qlcnic_adapter *, u8); + +/* eSwitch management functions */ +int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8, + struct qlcnic_eswitch *); +int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8, + struct qlcnic_eswitch *); +int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8); +int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8, + u8, u8, u16); +int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8); +extern int qlcnic_config_tso; + /* * QLOGIC Board information */ @@ -1131,6 +1228,14 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) extern const struct ethtool_ops qlcnic_ethtool_ops; +struct qlcnic_nic_template { + int (*get_mac_addr) (struct qlcnic_adapter *, u8*); + int (*config_bridged_mode) (struct qlcnic_adapter *, u32); + int (*config_led) (struct qlcnic_adapter *, u32, u32); + int (*set_ilb_mode) (struct qlcnic_adapter *); + void (*clear_ilb_mode) (struct qlcnic_adapter *); +}; + #define QLCDB(adapter, lvl, _fmt, _args...) do { \ if (NETIF_MSG_##lvl & adapter->msg_enable) \ printk(KERN_INFO "%s: %s: " _fmt, \ -- cgit v1.2.3-70-g09d2 From 9f26f547a587ce9015ffe495d2af604580b4b784 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Tue, 1 Jun 2010 11:33:09 +0000 Subject: qlcnic: NIC Partitioning - Add non privileged mode support Added support for NIC functions that work in non privileged mode where these functions are privileged to do IO only, the control operations are handled via privileged functions. Bumped up version number to 5.0.3. Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 13 ++-- drivers/net/qlcnic/qlcnic_hdr.h | 14 +++-- drivers/net/qlcnic/qlcnic_main.c | 124 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 128 insertions(+), 23 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 31a0b430a9d..02db363f20c 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -51,8 +51,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 2 -#define QLCNIC_LINUX_VERSIONID "5.0.2" +#define _QLCNIC_LINUX_SUBVERSION 3 +#define QLCNIC_LINUX_VERSIONID "5.0.3" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) @@ -891,6 +891,7 @@ struct qlcnic_mac_req { #define QLCNIC_LRO_ENABLED 0x08 #define QLCNIC_BRIDGE_ENABLED 0X10 #define QLCNIC_DIAG_ENABLED 0x20 +#define QLCNIC_NPAR_ENABLED 0x40 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) @@ -1159,13 +1160,6 @@ int qlcnic_check_loopback_buff(unsigned char *data); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring); -/* Functions from qlcnic_vf.c */ -int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); -int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); -int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter); -void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter); -void qlcnicvf_set_port_mode(struct qlcnic_adapter *adapter); - /* Management functions */ int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*); int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); @@ -1234,6 +1228,7 @@ struct qlcnic_nic_template { int (*config_led) (struct qlcnic_adapter *, u32, u32); int (*set_ilb_mode) (struct qlcnic_adapter *); void (*clear_ilb_mode) (struct qlcnic_adapter *); + int (*start_firmware) (struct qlcnic_adapter *); }; #define QLCDB(adapter, lvl, _fmt, _args...) do { \ diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h index 1bcfb121a89..7b81cab2700 100644 --- a/drivers/net/qlcnic/qlcnic_hdr.h +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -701,10 +701,11 @@ enum { #define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138)) #define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140)) -#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144)) -#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148)) -#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c)) +#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144)) +#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148)) +#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c)) #define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x174)) +#define QLCNIC_CRB_DEV_NPAR_STATE (QLCNIC_CAM_RAM(0x19c)) #define QLCNIC_ROM_DEV_INIT_TIMEOUT (0x3e885c) #define QLCNIC_ROM_DRV_RESET_TIMEOUT (0x3e8860) @@ -717,6 +718,9 @@ enum { #define QLCNIC_DEV_FAILED 0x6 #define QLCNIC_DEV_QUISCENT 0x7 +#define QLCNIC_DEV_NPAR_NOT_RDY 0 +#define QLCNIC_DEV_NPAR_RDY 1 + #define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) &= (1 << (FN * 4))) #define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4))) #define QLC_DEV_CLR_REF_CNT(VAL, FN) ((VAL) &= ~(1 << (FN * 4))) @@ -732,8 +736,8 @@ enum { #define QLCNIC_TYPE_ISCSI 3 #define QLCNIC_RCODE_DRIVER_INFO 0x20000000 -#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000 -#define QLCNIC_RCODE_FATAL_ERROR 0x80000000 +#define QLCNIC_RCODE_DRIVER_CAN_RELOAD BIT_30 +#define QLCNIC_RCODE_FATAL_ERROR BIT_31 #define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff) #define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 1e5e66facab..119bcae5e74 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -103,7 +103,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data); static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev); static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); - +static int qlcnic_start_firmware(struct qlcnic_adapter *); + +static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *); +static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *); +static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *); +static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); +static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); +static int qlcnicvf_start_firmware(struct qlcnic_adapter *); /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ @@ -375,7 +382,8 @@ static struct qlcnic_nic_template qlcnic_ops = { .config_bridged_mode = qlcnic_config_bridged_mode, .config_led = qlcnic_config_led, .set_ilb_mode = qlcnic_set_ilb_mode, - .clear_ilb_mode = qlcnic_clear_ilb_mode + .clear_ilb_mode = qlcnic_clear_ilb_mode, + .start_firmware = qlcnic_start_firmware }; static struct qlcnic_nic_template qlcnic_pf_ops = { @@ -383,7 +391,17 @@ static struct qlcnic_nic_template qlcnic_pf_ops = { .config_bridged_mode = qlcnic_config_bridged_mode, .config_led = qlcnic_config_led, .set_ilb_mode = qlcnic_set_ilb_mode, - .clear_ilb_mode = qlcnic_clear_ilb_mode + .clear_ilb_mode = qlcnic_clear_ilb_mode, + .start_firmware = qlcnic_start_firmware +}; + +static struct qlcnic_nic_template qlcnic_vf_ops = { + .get_mac_addr = qlcnic_get_mac_address, + .config_bridged_mode = qlcnicvf_config_bridged_mode, + .config_led = qlcnicvf_config_led, + .set_ilb_mode = qlcnicvf_set_ilb_mode, + .clear_ilb_mode = qlcnicvf_clear_ilb_mode, + .start_firmware = qlcnicvf_start_firmware }; static void @@ -467,7 +485,6 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) iounmap(adapter->ahw.pci_base0); } -/* Use api lock to access this function */ static int qlcnic_set_function_modes(struct qlcnic_adapter *adapter) { @@ -567,6 +584,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) /* Set privilege level for other functions */ if (qlcnic_config_npars) qlcnic_set_function_modes(adapter); + qlcnic_dev_set_npar_ready(adapter); dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n", adapter->fw_hal_version); @@ -578,6 +596,13 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) adapter->fw_hal_version); adapter->nic_ops = &qlcnic_pf_ops; break; + case QLCNIC_NON_PRIV_FUNC: + adapter->op_mode = QLCNIC_NON_PRIV_FUNC; + dev_info(&adapter->pdev->dev, + "HAL Version: %d Non Privileged function\n", + adapter->fw_hal_version); + adapter->nic_ops = &qlcnic_vf_ops; + break; default: dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n", priv_level); @@ -772,6 +797,8 @@ wait_init: QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY); qlcnic_idc_debug_info(adapter, 1); + qlcnic_dev_set_npar_ready(adapter); + qlcnic_check_options(adapter); if (adapter->fw_hal_version != QLCNIC_FW_BASE && @@ -1244,7 +1271,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (qlcnic_setup_idc_param(adapter)) goto err_out_iounmap; - err = qlcnic_start_firmware(adapter); + err = adapter->nic_ops->start_firmware(adapter); if (err) { dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); goto err_out_decr_ref; @@ -1410,7 +1437,7 @@ qlcnic_resume(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); - err = qlcnic_start_firmware(adapter); + err = adapter->nic_ops->start_firmware(adapter); if (err) { dev_err(&pdev->dev, "failed to start firmware\n"); return err; @@ -2260,7 +2287,7 @@ qlcnic_fwinit_work(struct work_struct *work) { struct qlcnic_adapter *adapter = container_of(work, struct qlcnic_adapter, fw_work.work); - u32 dev_state = 0xf; + u32 dev_state = 0xf, npar_state; if (qlcnic_api_lock(adapter)) goto err_ret; @@ -2273,6 +2300,19 @@ qlcnic_fwinit_work(struct work_struct *work) return; } + if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) { + npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE); + if (npar_state == QLCNIC_DEV_NPAR_RDY) { + qlcnic_api_unlock(adapter); + goto wait_npar; + } else { + qlcnic_schedule_work(adapter, qlcnic_fwinit_work, + FW_POLL_DELAY); + qlcnic_api_unlock(adapter); + return; + } + } + if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) { dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n", adapter->reset_ack_timeo); @@ -2305,7 +2345,7 @@ skip_ack_check: qlcnic_api_unlock(adapter); - if (!qlcnic_start_firmware(adapter)) { + if (!adapter->nic_ops->start_firmware(adapter)) { qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); return; } @@ -2314,6 +2354,7 @@ skip_ack_check: qlcnic_api_unlock(adapter); +wait_npar: dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state); @@ -2328,7 +2369,7 @@ skip_ack_check: break; default: - if (!qlcnic_start_firmware(adapter)) { + if (!adapter->nic_ops->start_firmware(adapter)) { qlcnic_schedule_work(adapter, qlcnic_attach_work, 0); return; } @@ -2402,6 +2443,30 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) qlcnic_api_unlock(adapter); } +/* Transit to NPAR READY state from NPAR NOT READY state */ +static void +qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter) +{ + u32 state; + + if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC || + adapter->fw_hal_version == QLCNIC_FW_BASE) + return; + + if (qlcnic_api_lock(adapter)) + return; + + state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE); + + if (state != QLCNIC_DEV_NPAR_RDY) { + QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, + QLCNIC_DEV_NPAR_RDY); + QLCDB(adapter, DRV, "NPAR READY state set\n"); + } + + qlcnic_api_unlock(adapter); +} + static void qlcnic_schedule_work(struct qlcnic_adapter *adapter, work_func_t func, int delay) @@ -2889,6 +2954,47 @@ done: return NOTIFY_DONE; } +static int +qlcnicvf_start_firmware(struct qlcnic_adapter *adapter) +{ + int err; + + err = qlcnic_can_start_firmware(adapter); + if (err) + return err; + + qlcnic_check_options(adapter); + + adapter->need_fw_reset = 0; + + return err; +} + +static int +qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable) +{ + return -EOPNOTSUPP; +} + +static int +qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) +{ + return -EOPNOTSUPP; +} + +static int +qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter) +{ + return -EOPNOTSUPP; +} + +static void +qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter) +{ + return; +} + + static struct notifier_block qlcnic_netdev_cb = { .notifier_call = qlcnic_netdev_event, }; -- cgit v1.2.3-70-g09d2 From 0e33c6649eea99f03d6b444d93fe67d856f1b10d Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Wed, 16 Jun 2010 09:07:27 +0000 Subject: qlcnic: Fix a bug in setting up NIC partitioning mode The driver was not detecting the presence of NIC partitioning capability of the firmware properly. Now, it checks the eswitch set bit in the FW capabilities register and accordingly sets the driver mode as NPAR capable or not. Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 2 +- drivers/net/qlcnic/qlcnic_ctx.c | 5 +++ drivers/net/qlcnic/qlcnic_main.c | 82 +++++++++++++++------------------------- 3 files changed, 37 insertions(+), 52 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 02db363f20c..eb1bdb222ca 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -891,7 +891,7 @@ struct qlcnic_mac_req { #define QLCNIC_LRO_ENABLED 0x08 #define QLCNIC_BRIDGE_ENABLED 0X10 #define QLCNIC_DIAG_ENABLED 0x20 -#define QLCNIC_NPAR_ENABLED 0x40 +#define QLCNIC_ESWITCH_ENABLED 0x40 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 1e1dc58cddc..42feb23dec1 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -637,6 +637,11 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id) adapter->capabilities = le32_to_cpu(nic_info->capabilities); adapter->max_mac_filters = nic_info->max_mac_filters; + if (adapter->capabilities & BIT_6) + adapter->flags |= QLCNIC_ESWITCH_ENABLED; + else + adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; + dev_info(&adapter->pdev->dev, "phy port: %d switch_mode: %d,\n" "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n" diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 99371bcaa54..128a0a72a23 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -502,39 +502,28 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func)) goto err_npar; - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { - id = adapter->npars[i].id; - if (adapter->npars[i].type != QLCNIC_TYPE_NIC || - id == adapter->ahw.pci_func) - continue; - data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id)); + if (qlcnic_config_npars) { + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + id = adapter->npars[i].id; + if (adapter->npars[i].type != QLCNIC_TYPE_NIC || + id == adapter->ahw.pci_func) + continue; + data |= (qlcnic_config_npars & + QLC_DEV_SET_DRV(0xf, id)); + } + } else { + data = readl(priv_op); + data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) | + (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, + adapter->ahw.pci_func)); } writel(data, priv_op); - err_npar: qlcnic_api_unlock(adapter); err_lock: return ret; } -static u8 -qlcnic_set_mgmt_driver(struct qlcnic_adapter *adapter) -{ - u8 i, ret = 0; - - if (qlcnic_get_pci_info(adapter)) - return ret; - /* Set the eswitch */ - for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) { - if (!qlcnic_get_eswitch_capabilities(adapter, i, - &adapter->eswitch[i])) { - ret++; - qlcnic_toggle_eswitch(adapter, i, ret); - } - } - return ret; -} - static u32 qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) { @@ -550,6 +539,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) adapter->nic_ops = &qlcnic_ops; adapter->fw_hal_version = QLCNIC_FW_BASE; adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn); + adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1); dev_info(&adapter->pdev->dev, "FW does not support nic partion\n"); return adapter->fw_hal_version; @@ -562,29 +552,28 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE; adapter->ahw.pci_func = func; + qlcnic_get_nic_info(adapter, adapter->ahw.pci_func); + + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + adapter->nic_ops = &qlcnic_ops; + return adapter->fw_hal_version; + } + /* Determine function privilege level */ priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); - if (op_mode == QLC_DEV_DRV_DEFAULT) { + if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; - if (qlcnic_api_lock(adapter)) - return 0; - op_mode = (op_mode & ~QLC_DEV_SET_DRV(0xf, func)) | - (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, func)); - writel(op_mode, priv_op); - qlcnic_api_unlock(adapter); - - } else + else priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); switch (priv_level) { case QLCNIC_MGMT_FUNC: adapter->op_mode = QLCNIC_MGMT_FUNC; adapter->nic_ops = &qlcnic_pf_ops; + qlcnic_get_pci_info(adapter); /* Set privilege level for other functions */ - if (qlcnic_config_npars) - qlcnic_set_function_modes(adapter); - qlcnic_dev_set_npar_ready(adapter); + qlcnic_set_function_modes(adapter); dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n", adapter->fw_hal_version); @@ -716,11 +705,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "firmware v%d.%d.%d\n", fw_major, fw_minor, fw_build); - if (adapter->fw_hal_version == QLCNIC_FW_NPAR) - qlcnic_get_nic_info(adapter, adapter->ahw.pci_func); - else - adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1); - adapter->flags &= ~QLCNIC_LRO_ENABLED; if (adapter->ahw.port_type == QLCNIC_XGBE) { @@ -731,6 +715,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; } + qlcnic_get_nic_info(adapter, adapter->ahw.pci_func); + adapter->msix_supported = !!use_msi_x; adapter->rss_supported = !!use_msi_x; @@ -797,13 +783,11 @@ wait_init: QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY); qlcnic_idc_debug_info(adapter, 1); - qlcnic_dev_set_npar_ready(adapter); - qlcnic_check_options(adapter); - if (adapter->fw_hal_version != QLCNIC_FW_BASE && - adapter->op_mode == QLCNIC_MGMT_FUNC) - qlcnic_set_mgmt_driver(adapter); + if (adapter->flags & QLCNIC_ESWITCH_ENABLED && + adapter->op_mode != QLCNIC_NON_PRIV_FUNC) + qlcnic_dev_set_npar_ready(adapter); adapter->need_fw_reset = 0; @@ -2449,10 +2433,6 @@ qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter) { u32 state; - if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC || - adapter->fw_hal_version == QLCNIC_FW_BASE) - return; - if (qlcnic_api_lock(adapter)) return; -- cgit v1.2.3-70-g09d2 From 434d7b380f2bfc2161b9aaee2cada177a4a4261f Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Wed, 16 Jun 2010 09:07:36 +0000 Subject: qlcnic: Bumped up version number Changed the driver version number to 5.0.4 Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index eb1bdb222ca..7d31caaf2fa 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -51,8 +51,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 3 -#define QLCNIC_LINUX_VERSIONID "5.0.3" +#define _QLCNIC_LINUX_SUBVERSION 4 +#define QLCNIC_LINUX_VERSIONID "5.0.4" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -- cgit v1.2.3-70-g09d2 From 8f891387aa73b85d2ea8d953e04dac224f687e52 Mon Sep 17 00:00:00 2001 From: schacko Date: Thu, 17 Jun 2010 02:56:40 +0000 Subject: qlcnic: seperate interrupt for TX Earlier all poll routine can process rx and tx, But now one poll routine to process rx + tx and other for rx only. Last msix vector will be used for separate tx interrupt. o This is supported from fw version 4.4.2. o Bump version 5.0.5 Signed-off-by: Sony Chacko Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 14 +++++++++----- drivers/net/qlcnic/qlcnic_ctx.c | 7 ++++++- drivers/net/qlcnic/qlcnic_init.c | 35 +++++++++++++++++++++++++---------- drivers/net/qlcnic/qlcnic_main.c | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 19 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 7d31caaf2fa..9970cff598d 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -51,8 +51,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 4 -#define QLCNIC_LINUX_VERSIONID "5.0.4" +#define _QLCNIC_LINUX_SUBVERSION 5 +#define QLCNIC_LINUX_VERSIONID "5.0.5" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) @@ -68,6 +68,7 @@ #define QLCNIC_DECODE_VERSION(v) \ QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16)) +#define QLCNIC_MIN_FW_VERSION QLCNIC_VERSION_CODE(4, 4, 2) #define QLCNIC_NUM_FLASH_SECTORS (64) #define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024) #define QLCNIC_FLASH_TOTAL_SIZE (QLCNIC_NUM_FLASH_SECTORS \ @@ -567,6 +568,7 @@ struct qlcnic_recv_context { #define QLCNIC_CAP0_LSO (1 << 6) #define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7) #define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8) +#define QLCNIC_CAP0_VALIDOFF (1 << 11) /* * Context state @@ -602,9 +604,10 @@ struct qlcnic_hostrq_rx_ctx { __le32 sds_ring_offset; /* Offset to SDS config */ __le16 num_rds_rings; /* Count of RDS rings */ __le16 num_sds_rings; /* Count of SDS rings */ - __le16 rsvd1; /* Padding */ - __le16 rsvd2; /* Padding */ - u8 reserved[128]; /* reserve space for future expansion*/ + __le16 valid_field_offset; + u8 txrx_sds_binding; + u8 msix_handler; + u8 reserved[128]; /* reserve space for future expansion*/ /* MUST BE 64-bit aligned. The following is packed: - N hostrq_rds_rings @@ -1109,6 +1112,7 @@ void qlcnic_request_firmware(struct qlcnic_adapter *adapter); void qlcnic_release_firmware(struct qlcnic_adapter *adapter); int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter); int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter); +int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter); int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp); int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 90ed6fbaee3..7c96c8e06c3 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -152,9 +152,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr); - cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN); + cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN + | QLCNIC_CAP0_VALIDOFF); cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS); + prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx, + msix_handler); + prq->txrx_sds_binding = nsds_rings - 1; + prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED); diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 317750d6793..2bd00d54dd3 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -543,16 +543,34 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) { return 0; } +int +qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter) +{ + u32 ver = -1, min_ver; + + qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET, (int *)&ver); + + ver = QLCNIC_DECODE_VERSION(ver); + min_ver = QLCNIC_MIN_FW_VERSION; + + if (ver < min_ver) { + dev_err(&adapter->pdev->dev, + "firmware version %d.%d.%d unsupported." + "Min supported version %d.%d.%d\n", + _major(ver), _minor(ver), _build(ver), + _major(min_ver), _minor(min_ver), _build(min_ver)); + return -EINVAL; + } + + return 0; +} + static int qlcnic_has_mn(struct qlcnic_adapter *adapter) { - u32 capability, flashed_ver; + u32 capability; capability = 0; - qlcnic_rom_fast_read(adapter, - QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver); - flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver); - capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) return 1; @@ -1006,7 +1024,7 @@ static int qlcnic_validate_firmware(struct qlcnic_adapter *adapter) { __le32 val; - u32 ver, min_ver, bios, min_size; + u32 ver, bios, min_size; struct pci_dev *pdev = adapter->pdev; const struct firmware *fw = adapter->fw; u8 fw_type = adapter->fw_type; @@ -1028,12 +1046,9 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter) return -EINVAL; val = qlcnic_get_fw_version(adapter); - - min_ver = QLCNIC_VERSION_CODE(4, 0, 216); - ver = QLCNIC_DECODE_VERSION(val); - if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) { + if (ver < QLCNIC_MIN_FW_VERSION) { dev_err(&pdev->dev, "%s: firmware version %d.%d.%d unsupported\n", fw_name[fw_type], _major(ver), _minor(ver), _build(ver)); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 28ed28c1cbc..06d2dfd646f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -83,6 +83,7 @@ static void qlcnic_schedule_work(struct qlcnic_adapter *adapter, work_func_t func, int delay); static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter); static int qlcnic_poll(struct napi_struct *napi, int budget); +static int qlcnic_rx_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void qlcnic_poll_controller(struct net_device *netdev); #endif @@ -195,8 +196,13 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - netif_napi_add(netdev, &sds_ring->napi, - qlcnic_poll, QLCNIC_NETDEV_WEIGHT); + + if (ring == adapter->max_sds_rings - 1) + netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll, + QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings); + else + netif_napi_add(netdev, &sds_ring->napi, + qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2); } return 0; @@ -743,8 +749,12 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter) if (load_fw_file) qlcnic_request_firmware(adapter); - else + else { + if (qlcnic_check_flash_fw_ver(adapter)) + goto err_out; + adapter->fw_type = QLCNIC_FLASH_ROMIMAGE; + } err = qlcnic_need_fw_reset(adapter); if (err < 0) @@ -2060,6 +2070,25 @@ static int qlcnic_poll(struct napi_struct *napi, int budget) return work_done; } +static int qlcnic_rx_poll(struct napi_struct *napi, int budget) +{ + struct qlcnic_host_sds_ring *sds_ring = + container_of(napi, struct qlcnic_host_sds_ring, napi); + + struct qlcnic_adapter *adapter = sds_ring->adapter; + int work_done; + + work_done = qlcnic_process_rcv_ring(sds_ring, budget); + + if (work_done < budget) { + napi_complete(&sds_ring->napi); + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) + qlcnic_enable_int(sds_ring); + } + + return work_done; +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void qlcnic_poll_controller(struct net_device *netdev) { -- cgit v1.2.3-70-g09d2 From ef71ff833acfd3795c3af1bb800ac186561508ef Mon Sep 17 00:00:00 2001 From: Rajesh K Borundia Date: Thu, 17 Jun 2010 02:56:41 +0000 Subject: qlcnic: fix race in tx stop queue There is a race between netif_stop_queue and netif_stopped_queue check. So check once again if buffers are available to avoid race. With above logic we can also get rid of tx lock in process_cmd_ring. Signed-off-by: Rajesh K Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 8 +++++--- drivers/net/qlcnic/qlcnic_hw.c | 12 +++++++++--- drivers/net/qlcnic/qlcnic_init.c | 2 ++ drivers/net/qlcnic/qlcnic_main.c | 23 ++++++++++------------- 4 files changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 9970cff598d..99ccdd8ac41 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -113,8 +113,10 @@ #define TX_UDPV6_PKT 0x0c /* Tx defines */ -#define MAX_BUFFERS_PER_CMD 32 -#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) +#define MAX_TSO_HEADER_DESC 2 +#define MGMT_CMD_DESC_RESV 4 +#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ + + MGMT_CMD_DESC_RESV) #define QLCNIC_MAX_TX_TIMEOUTS 2 /* @@ -369,7 +371,7 @@ struct qlcnic_recv_crb { */ struct qlcnic_cmd_buffer { struct sk_buff *skb; - struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + struct qlcnic_skb_frag frag_array[MAX_SKB_FRAGS + 1]; u32 frag_count; }; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index f776956d2d6..d9becb96d40 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -338,9 +338,15 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, if (nr_desc >= qlcnic_tx_avail(tx_ring)) { netif_tx_stop_queue(tx_ring->txq); - __netif_tx_unlock_bh(tx_ring->txq); - adapter->stats.xmit_off++; - return -EBUSY; + smp_mb(); + if (qlcnic_tx_avail(tx_ring) > nr_desc) { + if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) + netif_tx_wake_queue(tx_ring->txq); + } else { + adapter->stats.xmit_off++; + __netif_tx_unlock_bh(tx_ring->txq); + return -EBUSY; + } } do { diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 2bd00d54dd3..058ce61501c 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -181,7 +181,9 @@ skip_rds: tx_ring = adapter->tx_ring; vfree(tx_ring->cmd_buf_arr); + tx_ring->cmd_buf_arr = NULL; kfree(adapter->tx_ring); + adapter->tx_ring = NULL; } int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 06d2dfd646f..655bccd7f8f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -132,12 +132,6 @@ qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring) { writel(tx_ring->producer, tx_ring->crb_cmd_producer); - - if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) { - netif_stop_queue(adapter->netdev); - smp_mb(); - adapter->stats.xmit_off++; - } } static const u32 msi_tgt_status[8] = { @@ -1137,7 +1131,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, adapter->max_mc_count = 38; netdev->netdev_ops = &qlcnic_netdev_ops; - netdev->watchdog_timeo = 2*HZ; + netdev->watchdog_timeo = 5*HZ; qlcnic_change_mtu(netdev, netdev->mtu); @@ -1709,10 +1703,15 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; - if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) { + if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) { netif_stop_queue(netdev); - adapter->stats.xmit_off++; - return NETDEV_TX_BUSY; + smp_mb(); + if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) + netif_start_queue(netdev); + else { + adapter->stats.xmit_off++; + return NETDEV_TX_BUSY; + } } producer = tx_ring->producer; @@ -2018,14 +2017,12 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter) smp_mb(); if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { - __netif_tx_lock(tx_ring->txq, smp_processor_id()); if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { netif_wake_queue(netdev); - adapter->tx_timeo_cnt = 0; adapter->stats.xmit_on++; } - __netif_tx_unlock(tx_ring->txq); } + adapter->tx_timeo_cnt = 0; } /* * If everything is freed up to consumer then check if the ring is full -- cgit v1.2.3-70-g09d2 From 9665982885f0e11ea9e3c5d9bfc7ead48d08c83f Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:18:58 +0000 Subject: qlcnic: cleanup skb allocation No need to maintian separate state for alloced and freed skb. This can be done by null check. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 2 -- drivers/net/qlcnic/qlcnic_ethtool.c | 2 -- drivers/net/qlcnic/qlcnic_init.c | 30 +++++++++++++----------------- 3 files changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 99ccdd8ac41..86e47811c25 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -381,7 +381,6 @@ struct qlcnic_rx_buffer { struct sk_buff *skb; u64 dma; u16 ref_handle; - u16 state; }; /* Board types */ @@ -423,7 +422,6 @@ struct qlcnic_adapter_stats { u64 xmit_on; u64 xmit_off; u64 skb_alloc_failure; - u64 null_skb; u64 null_rxbuf; u64 rx_dma_map_error; u64 tx_dma_map_error; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 3e4822ad5a8..a4f11202271 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -69,8 +69,6 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), QLC_OFF(stats.skb_alloc_failure)}, - {"null skb", - QLC_SIZEOF(stats.null_skb), QLC_OFF(stats.null_skb)}, {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)}, {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error), diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 058ce61501c..1c3d5a90d21 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -112,14 +112,15 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[ring]; for (i = 0; i < rds_ring->num_desc; ++i) { rx_buf = &(rds_ring->rx_buf_arr[i]); - if (rx_buf->state == QLCNIC_BUFFER_FREE) + if (rx_buf->skb == NULL) continue; + pci_unmap_single(adapter->pdev, rx_buf->dma, rds_ring->dma_size, PCI_DMA_FROMDEVICE); - if (rx_buf->skb != NULL) - dev_kfree_skb_any(rx_buf->skb); + + dev_kfree_skb_any(rx_buf->skb); } } } @@ -266,7 +267,6 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) list_add_tail(&rx_buf->list, &rds_ring->free_list); rx_buf->ref_handle = i; - rx_buf->state = QLCNIC_BUFFER_FREE; rx_buf++; } spin_lock_init(&rds_ring->lock); @@ -1281,14 +1281,12 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, dma_addr_t dma; struct pci_dev *pdev = adapter->pdev; - buffer->skb = dev_alloc_skb(rds_ring->skb_size); - if (!buffer->skb) { + skb = dev_alloc_skb(rds_ring->skb_size); + if (!skb) { adapter->stats.skb_alloc_failure++; return -ENOMEM; } - skb = buffer->skb; - skb_reserve(skb, 2); dma = pci_map_single(pdev, skb->data, @@ -1297,13 +1295,11 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, if (pci_dma_mapping_error(pdev, dma)) { adapter->stats.rx_dma_map_error++; dev_kfree_skb_any(skb); - buffer->skb = NULL; return -ENOMEM; } buffer->skb = skb; buffer->dma = dma; - buffer->state = QLCNIC_BUFFER_BUSY; return 0; } @@ -1316,14 +1312,15 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, buffer = &rds_ring->rx_buf_arr[index]; + if (unlikely(buffer->skb == NULL)) { + WARN_ON(1); + return NULL; + } + pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size, PCI_DMA_FROMDEVICE); skb = buffer->skb; - if (!skb) { - adapter->stats.null_skb++; - goto no_skb; - } if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { adapter->stats.csummed++; @@ -1335,8 +1332,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, skb->dev = adapter->netdev; buffer->skb = NULL; -no_skb: - buffer->state = QLCNIC_BUFFER_FREE; + return skb; } @@ -1511,7 +1507,7 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) WARN_ON(desc_cnt > 1); - if (rxbuf) + if (likely(rxbuf)) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); else adapter->stats.null_rxbuf++; -- cgit v1.2.3-70-g09d2 From 900c6cfffac668199aaa30a20e31d07602f8a8ce Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:18:59 +0000 Subject: qlcnic: handshake with card after fw load Instead of delaying rcv handshake till interface comes up, do it just after fw load. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 1 - drivers/net/qlcnic/qlcnic_init.c | 9 +++++++-- drivers/net/qlcnic/qlcnic_main.c | 6 ++---- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 86e47811c25..588b9a9611a 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1105,7 +1105,6 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter); int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate); /* Functions from qlcnic_init.c */ -int qlcnic_phantom_init(struct qlcnic_adapter *adapter); int qlcnic_load_firmware(struct qlcnic_adapter *adapter); int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter); void qlcnic_request_firmware(struct qlcnic_adapter *adapter); diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 1c3d5a90d21..d19d0120e5b 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1138,7 +1138,7 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter) adapter->fw = NULL; } -int qlcnic_phantom_init(struct qlcnic_adapter *adapter) +static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter) { u32 val; int retries = 60; @@ -1163,7 +1163,8 @@ int qlcnic_phantom_init(struct qlcnic_adapter *adapter) QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); out_err: - dev_err(&adapter->pdev->dev, "firmware init failed\n"); + dev_err(&adapter->pdev->dev, "Command Peg initialization not " + "complete, state: 0x%x.\n", val); return -EIO; } @@ -1196,6 +1197,10 @@ int qlcnic_init_firmware(struct qlcnic_adapter *adapter) { int err; + err = qlcnic_cmd_peg_ready(adapter); + if (err) + return err; + err = qlcnic_receive_peg_ready(adapter); if (err) return err; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 655bccd7f8f..9658b184938 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -758,6 +758,7 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter) if (first_boot != 0x55555555) { QLCWR32(adapter, CRB_CMDPEG_STATE, 0); + QLCWR32(adapter, CRB_RCVPEG_STATE, 0); qlcnic_pinit_from_rom(adapter); msleep(1); } @@ -780,7 +781,7 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter) wait_init: /* Handshake with the card before we register the devices. */ - err = qlcnic_phantom_init(adapter); + err = qlcnic_init_firmware(adapter); if (err) goto err_out; @@ -962,9 +963,6 @@ qlcnic_attach(struct qlcnic_adapter *adapter) if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) return 0; - err = qlcnic_init_firmware(adapter); - if (err) - return err; err = qlcnic_napi_add(adapter, netdev); if (err) -- cgit v1.2.3-70-g09d2 From 8a15ad1fb14d67450742cf975a76e744b3189f4d Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:19:01 +0000 Subject: qlcnic: release device resources during interface down Previously we were allocating device resources during probe and release them during remove. Now alloc during interface up and release in interface down. This helps in device performance, as it doesn't need to keep track of inactive resources. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 4 +++ drivers/net/qlcnic/qlcnic_ctx.c | 50 +++++++++++++++++++++---------- drivers/net/qlcnic/qlcnic_ethtool.c | 7 +++-- drivers/net/qlcnic/qlcnic_hw.c | 4 +-- drivers/net/qlcnic/qlcnic_init.c | 26 ++++++++++++++++ drivers/net/qlcnic/qlcnic_main.c | 60 ++++++++++++++++++++++++++----------- 6 files changed, 114 insertions(+), 37 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 588b9a9611a..5c7d474e560 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1124,6 +1124,10 @@ void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32); int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter); void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter); +int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter); +void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter); + +void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter); void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter); void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 7c96c8e06c3..be341c1564b 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -180,6 +180,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) for (i = 0; i < nrds_rings; i++) { rds_ring = &recv_ctx->rds_rings[i]; + rds_ring->producer = 0; prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr); prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc); @@ -193,6 +194,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) for (i = 0; i < nsds_rings; i++) { sds_ring = &recv_ctx->sds_rings[i]; + sds_ring->consumer = 0; + memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring)); prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr); prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc); @@ -293,6 +296,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) dma_addr_t rq_phys_addr, rsp_phys_addr; struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + /* reset host resources */ + tx_ring->producer = 0; + tx_ring->sw_consumer = 0; + *(tx_ring->hw_consumer) = 0; + rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); rq_addr = pci_alloc_consistent(adapter->pdev, rq_size, &rq_phys_addr); @@ -476,15 +484,6 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) sds_ring->desc_head = (struct status_desc *)addr; } - - err = qlcnic_fw_cmd_create_rx_ctx(adapter); - if (err) - goto err_out_free; - err = qlcnic_fw_cmd_create_tx_ctx(adapter); - if (err) - goto err_out_free; - - set_bit(__QLCNIC_FW_ATTACHED, &adapter->state); return 0; err_out_free: @@ -492,15 +491,27 @@ err_out_free: return err; } -void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) + +int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter) { - struct qlcnic_recv_context *recv_ctx; - struct qlcnic_host_rds_ring *rds_ring; - struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_host_tx_ring *tx_ring; - int ring; + int err; + + err = qlcnic_fw_cmd_create_rx_ctx(adapter); + if (err) + return err; + err = qlcnic_fw_cmd_create_tx_ctx(adapter); + if (err) { + qlcnic_fw_cmd_destroy_rx_ctx(adapter); + return err; + } + + set_bit(__QLCNIC_FW_ATTACHED, &adapter->state); + return 0; +} +void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter) +{ if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) { qlcnic_fw_cmd_destroy_rx_ctx(adapter); qlcnic_fw_cmd_destroy_tx_ctx(adapter); @@ -508,6 +519,15 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) /* Allow dma queues to drain after context reset */ msleep(20); } +} + +void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_tx_ring *tx_ring; + int ring; recv_ctx = &adapter->recv_ctx; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index a4f11202271..d4e803e2a97 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -348,7 +348,7 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) for (i = 0; diag_registers[i] != -1; i++) regs_buff[i] = QLCRD32(adapter, diag_registers[i]); - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return; regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ @@ -833,6 +833,9 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val) struct qlcnic_adapter *adapter = netdev_priv(dev); int ret; + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) + return -EIO; + ret = adapter->nic_ops->config_led(adapter, 1, 0xf); if (ret) { dev_err(&adapter->pdev->dev, @@ -904,7 +907,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return -EINVAL; /* diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index ad124254b6a..e08c8b0556a 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -327,7 +327,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, i = 0; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return -EIO; tx_ring = adapter->tx_ring; @@ -431,7 +431,7 @@ void qlcnic_set_multi(struct net_device *netdev) u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u32 mode = VPORT_MISS_MODE_DROP; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; qlcnic_nic_add_mac(adapter, adapter->mac_addr); diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index d19d0120e5b..6678127ed4f 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -125,6 +125,32 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) } } +void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter) +{ + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_rx_buffer *rx_buf; + int i, ring; + + recv_ctx = &adapter->recv_ctx; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + + spin_lock(&rds_ring->lock); + + INIT_LIST_HEAD(&rds_ring->free_list); + + rx_buf = rds_ring->rx_buf_arr; + for (i = 0; i < rds_ring->num_desc; i++) { + list_add_tail(&rx_buf->list, + &rds_ring->free_list); + rx_buf++; + } + + spin_unlock(&rds_ring->lock); + } +} + void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) { struct qlcnic_cmd_buffer *cmd_buf; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 9658b184938..38d8fe08b7f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -346,7 +346,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EINVAL; - if (netif_running(netdev)) { + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { netif_device_detach(netdev); qlcnic_napi_disable(adapter); } @@ -355,7 +355,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); qlcnic_set_multi(adapter->netdev); - if (netif_running(netdev)) { + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { netif_device_attach(netdev); qlcnic_napi_enable(adapter); } @@ -877,9 +877,23 @@ qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) static int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { + int ring; + struct qlcnic_host_rds_ring *rds_ring; + if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return -EIO; + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) + return 0; + + if (qlcnic_fw_create_ctx(adapter)) + return -EIO; + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &adapter->recv_ctx.rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, ring, rds_ring); + } + qlcnic_set_multi(netdev); qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); @@ -936,6 +950,9 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) qlcnic_napi_disable(adapter); + qlcnic_fw_destroy_ctx(adapter); + + qlcnic_reset_rx_buffers_list(adapter); qlcnic_release_tx_buffers(adapter); spin_unlock(&adapter->tx_clean_lock); } @@ -957,13 +974,11 @@ qlcnic_attach(struct qlcnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - int err, ring; - struct qlcnic_host_rds_ring *rds_ring; + int err; if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) return 0; - err = qlcnic_napi_add(adapter, netdev); if (err) return err; @@ -971,7 +986,7 @@ qlcnic_attach(struct qlcnic_adapter *adapter) err = qlcnic_alloc_sw_resources(adapter); if (err) { dev_err(&pdev->dev, "Error in setting sw resources\n"); - return err; + goto err_out_napi_del; } err = qlcnic_alloc_hw_resources(adapter); @@ -980,16 +995,10 @@ qlcnic_attach(struct qlcnic_adapter *adapter) goto err_out_free_sw; } - - for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); - } - err = qlcnic_request_irq(adapter); if (err) { dev_err(&pdev->dev, "failed to setup interrupt\n"); - goto err_out_free_rxbuf; + goto err_out_free_hw; } qlcnic_init_coalesce_defaults(adapter); @@ -999,11 +1008,12 @@ qlcnic_attach(struct qlcnic_adapter *adapter) adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; return 0; -err_out_free_rxbuf: - qlcnic_release_rx_buffers(adapter); +err_out_free_hw: qlcnic_free_hw_resources(adapter); err_out_free_sw: qlcnic_free_sw_resources(adapter); +err_out_napi_del: + qlcnic_napi_del(adapter); return err; } @@ -1038,6 +1048,8 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) } } + qlcnic_fw_destroy_ctx(adapter); + qlcnic_detach(adapter); adapter->diag_test = 0; @@ -1056,6 +1068,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_host_rds_ring *rds_ring; int ring; int ret; @@ -1075,6 +1088,17 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) return ret; } + ret = qlcnic_fw_create_ctx(adapter); + if (ret) { + qlcnic_detach(adapter); + return ret; + } + + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &adapter->recv_ctx.rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, ring, rds_ring); + } + if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &adapter->recv_ctx.sds_rings[ring]; @@ -2636,7 +2660,7 @@ qlcnic_store_bridged_mode(struct device *dev, if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)) goto err_out; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) goto err_out; if (strict_strtoul(buf, 2, &new)) @@ -2944,7 +2968,7 @@ recheck: if (!adapter) goto done; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) goto done; qlcnic_config_indev_addr(dev, event); @@ -2980,7 +3004,7 @@ recheck: if (!adapter) goto done; - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) goto done; switch (event) { -- cgit v1.2.3-70-g09d2 From 68bf1c68a4b3d9ad0a98f3310f2f79dca075a035 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:19:03 +0000 Subject: qlcnic: offload tx timeout recovery Offload tx timeout recovery to fw recovery func(check_health). In check_health, first check health of device, if it its ok, then do tx timeout recovery otherwise device recovery. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 3 +- drivers/net/qlcnic/qlcnic_main.c | 65 +++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 36 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 5c7d474e560..6ec34a7fba6 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -934,6 +934,7 @@ struct qlcnic_adapter { u8 rx_csum; u8 portnum; u8 physical_port; + u8 reset_context; u8 mc_enabled; u8 max_mc_count; @@ -1001,8 +1002,6 @@ struct qlcnic_adapter { struct delayed_work fw_work; - struct work_struct tx_timeout_task; - struct qlcnic_nic_intr_coalesce coal; unsigned long state; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index c4602fa866d..3b71dfcd6d4 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -75,7 +75,6 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev); static int qlcnic_open(struct net_device *netdev); static int qlcnic_close(struct net_device *netdev); static void qlcnic_tx_timeout(struct net_device *netdev); -static void qlcnic_tx_timeout_task(struct work_struct *work); static void qlcnic_attach_work(struct work_struct *work); static void qlcnic_fwinit_work(struct work_struct *work); static void qlcnic_fw_poll_work(struct work_struct *work); @@ -911,6 +910,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) qlcnic_linkevent_request(adapter, 1); + adapter->reset_context = 0; set_bit(__QLCNIC_DEV_UP, &adapter->state); return 0; } @@ -1110,6 +1110,27 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) return 0; } +/* Reset context in hardware only */ +static int +qlcnic_reset_hw_context(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EBUSY; + + netif_device_detach(netdev); + + qlcnic_down(adapter, netdev); + + qlcnic_up(adapter, netdev); + + netif_device_attach(netdev); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return 0; +} + int qlcnic_reset_context(struct qlcnic_adapter *adapter) { @@ -1178,8 +1199,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task); - if (qlcnic_read_mac_addr(adapter)) dev_warn(&pdev->dev, "failed to read mac addr\n"); @@ -1350,8 +1369,6 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) unregister_netdev(netdev); - cancel_work_sync(&adapter->tx_timeout_task); - qlcnic_detach(adapter); if (adapter->npars != NULL) @@ -1390,8 +1407,6 @@ static int __qlcnic_shutdown(struct pci_dev *pdev) if (netif_running(netdev)) qlcnic_down(adapter, netdev); - cancel_work_sync(&adapter->tx_timeout_task); - qlcnic_clr_all_drv_state(adapter); clear_bit(__QLCNIC_RESETTING, &adapter->state); @@ -1854,35 +1869,11 @@ static void qlcnic_tx_timeout(struct net_device *netdev) return; dev_err(&netdev->dev, "transmit timeout, resetting.\n"); - schedule_work(&adapter->tx_timeout_task); -} - -static void qlcnic_tx_timeout_task(struct work_struct *work) -{ - struct qlcnic_adapter *adapter = - container_of(work, struct qlcnic_adapter, tx_timeout_task); - - if (!netif_running(adapter->netdev)) - return; - - if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) - return; if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) - goto request_reset; - - clear_bit(__QLCNIC_RESETTING, &adapter->state); - if (!qlcnic_reset_context(adapter)) { - adapter->netdev->trans_start = jiffies; - return; - - /* context reset failed, fall through for fw reset */ - } - -request_reset: - adapter->need_fw_reset = 1; - clear_bit(__QLCNIC_RESETTING, &adapter->state); - QLCDB(adapter, DRV, "Resetting adapter\n"); + adapter->need_fw_reset = 1; + else + adapter->reset_context = 1; } static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) @@ -2540,6 +2531,12 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) adapter->fw_fail_cnt = 0; if (adapter->need_fw_reset) goto detach; + + if (adapter->reset_context) { + qlcnic_reset_hw_context(adapter); + adapter->netdev->trans_start = jiffies; + } + return 0; } -- cgit v1.2.3-70-g09d2 From d626ad4d84dba1e5bf176320e19765e6dc539b04 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:19:04 +0000 Subject: qlcnic: mark context state freed after destroy After destroying recv ctx, context state remain same. Fix it by marking as FREED. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 2 +- drivers/net/qlcnic/qlcnic_ctx.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 6ec34a7fba6..7fa761ac15c 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -573,7 +573,7 @@ struct qlcnic_recv_context { /* * Context state */ - +#define QLCNIC_HOST_CTX_STATE_FREED 0 #define QLCNIC_HOST_CTX_STATE_ACTIVE 2 /* diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index be341c1564b..941cd0873f8 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -280,6 +280,8 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) dev_err(&adapter->pdev->dev, "Failed to destroy rx ctx in firmware\n"); } + + recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED; } static int -- cgit v1.2.3-70-g09d2 From 4eaef482df464d1038b75769d43ac06ce0d16cd2 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 22 Jun 2010 03:19:05 +0000 Subject: qlcnic: update version to 5.0.6 Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 7fa761ac15c..3675678bbf0 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -51,8 +51,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 5 -#define QLCNIC_LINUX_VERSIONID "5.0.5" +#define _QLCNIC_LINUX_SUBVERSION 6 +#define QLCNIC_LINUX_VERSIONID "5.0.6" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -- cgit v1.2.3-70-g09d2 From 346fe763d7706cccdf90ba24f04f0facdd79b91a Mon Sep 17 00:00:00 2001 From: Rajesh K Borundia Date: Tue, 29 Jun 2010 08:01:20 +0000 Subject: qlcnic: Add support for configuring eswitch and npars Following changes are made: 1.Obtain capabilities of Nic partition. 2.Configure tx bandwidth of particular Nic partition. 3.Configure the eswitch for setting port mirroring, enable mac learning, promiscous mode. Signed-off-by: Rajesh K Borundia Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 77 ++++++- drivers/net/qlcnic/qlcnic_ctx.c | 90 +++----- drivers/net/qlcnic/qlcnic_main.c | 450 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 542 insertions(+), 75 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 3675678bbf0..60ea7cb3308 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -959,8 +959,6 @@ struct qlcnic_adapter { u16 switch_mode; u16 max_tx_ques; u16 max_rx_ques; - u16 min_tx_bw; - u16 max_tx_bw; u16 max_mtu; u32 fw_hal_version; @@ -984,7 +982,7 @@ struct qlcnic_adapter { u64 dev_rst_time; - struct qlcnic_pci_info *npars; + struct qlcnic_npar_info *npars; struct qlcnic_eswitch *eswitch; struct qlcnic_nic_template *nic_ops; @@ -1042,6 +1040,18 @@ struct qlcnic_pci_info { u8 reserved2[106]; }; +struct qlcnic_npar_info { + u16 vlan_id; + u8 phy_port; + u8 type; + u8 active; + u8 enable_pm; + u8 dest_npar; + u8 host_vlan_tag; + u8 promisc_mode; + u8 discard_tagged; + u8 mac_learning; +}; struct qlcnic_eswitch { u8 port; u8 active_vports; @@ -1057,6 +1067,63 @@ struct qlcnic_eswitch { #define QLCNIC_SWITCH_PORT_MIRRORING BIT_4 }; + +/* Return codes for Error handling */ +#define QL_STATUS_INVALID_PARAM -1 + +#define MAX_BW 10000 +#define MIN_BW 100 +#define MAX_VLAN_ID 4095 +#define MIN_VLAN_ID 2 +#define MAX_TX_QUEUES 1 +#define MAX_RX_QUEUES 4 +#define DEFAULT_MAC_LEARN 1 + +#define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID) +#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW \ + && (bw % 100) == 0) +#define IS_VALID_TX_QUEUES(que) (que > 0 && que <= MAX_TX_QUEUES) +#define IS_VALID_RX_QUEUES(que) (que > 0 && que <= MAX_RX_QUEUES) +#define IS_VALID_MODE(mode) (mode == 0 || mode == 1) + +struct qlcnic_pci_func_cfg { + u16 func_type; + u16 min_bw; + u16 max_bw; + u16 port_num; + u8 pci_func; + u8 func_state; + u8 def_mac_addr[6]; +}; + +struct qlcnic_npar_func_cfg { + u32 fw_capab; + u16 port_num; + u16 min_bw; + u16 max_bw; + u16 max_tx_queues; + u16 max_rx_queues; + u8 pci_func; + u8 op_mode; +}; + +struct qlcnic_pm_func_cfg { + u8 pci_func; + u8 action; + u8 dest_npar; + u8 reserved[5]; +}; + +struct qlcnic_esw_func_cfg { + u16 vlan_id; + u8 pci_func; + u8 host_vlan_tag; + u8 promisc_mode; + u8 discard_tagged; + u8 mac_learning; + u8 reserved; +}; + int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); @@ -1169,9 +1236,9 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring); /* Management functions */ int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*); int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); -int qlcnic_get_nic_info(struct qlcnic_adapter *, u8); +int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8); int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); -int qlcnic_get_pci_info(struct qlcnic_adapter *); +int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*); int qlcnic_reset_partition(struct qlcnic_adapter *, u8); /* eSwitch management functions */ diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 7969a7a87c8..cdd44b4136a 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -611,7 +611,8 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac) } /* Get info of a NIC partition */ -int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id) +int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, + struct qlcnic_info *npar_info, u8 func_id) { int err; dma_addr_t nic_dma_t; @@ -635,29 +636,23 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id) QLCNIC_CDRP_CMD_GET_NIC_INFO); if (err == QLCNIC_RCODE_SUCCESS) { - adapter->physical_port = le16_to_cpu(nic_info->phys_port); - adapter->switch_mode = le16_to_cpu(nic_info->switch_mode); - adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques); - adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques); - adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw); - adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw); - adapter->max_mtu = le16_to_cpu(nic_info->max_mtu); - adapter->capabilities = le32_to_cpu(nic_info->capabilities); - adapter->max_mac_filters = nic_info->max_mac_filters; - - if (adapter->capabilities & BIT_6) - adapter->flags |= QLCNIC_ESWITCH_ENABLED; - else - adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; + npar_info->phys_port = le16_to_cpu(nic_info->phys_port); + npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode); + npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques); + npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques); + npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw); + npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw); + npar_info->capabilities = le32_to_cpu(nic_info->capabilities); + npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu); dev_info(&adapter->pdev->dev, "phy port: %d switch_mode: %d,\n" "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n" "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n", - adapter->physical_port, adapter->switch_mode, - adapter->max_tx_ques, adapter->max_rx_ques, - adapter->min_tx_bw, adapter->max_tx_bw, - adapter->max_mtu, adapter->capabilities); + npar_info->phys_port, npar_info->switch_mode, + npar_info->max_tx_ques, npar_info->max_rx_ques, + npar_info->min_tx_bw, npar_info->max_tx_bw, + npar_info->max_mtu, npar_info->capabilities); } else { dev_err(&adapter->pdev->dev, "Failed to get nic info%d\n", err); @@ -672,7 +667,6 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id) int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) { int err = -EIO; - u32 func_state; dma_addr_t nic_dma_t; void *nic_info_addr; struct qlcnic_info *nic_info; @@ -681,17 +675,6 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) if (adapter->op_mode != QLCNIC_MGMT_FUNC) return err; - if (qlcnic_api_lock(adapter)) - return err; - - func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT); - if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) { - qlcnic_api_unlock(adapter); - return err; - } - - qlcnic_api_unlock(adapter); - nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size, &nic_dma_t); if (!nic_info_addr) @@ -716,7 +699,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), - nic_size, + ((nic->pci_func << 16) | nic_size), QLCNIC_CDRP_CMD_SET_NIC_INFO); if (err != QLCNIC_RCODE_SUCCESS) { @@ -730,7 +713,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) } /* Get PCI Info of a partition */ -int qlcnic_get_pci_info(struct qlcnic_adapter *adapter) +int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, + struct qlcnic_pci_info *pci_info) { int err = 0, i; dma_addr_t pci_info_dma_t; @@ -745,21 +729,6 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter) return -ENOMEM; memset(pci_info_addr, 0, pci_size); - if (!adapter->npars) - adapter->npars = kzalloc(pci_size, GFP_KERNEL); - if (!adapter->npars) { - err = -ENOMEM; - goto err_npar; - } - - if (!adapter->eswitch) - adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) * - QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL); - if (!adapter->eswitch) { - err = -ENOMEM; - goto err_eswitch; - } - npar = (struct qlcnic_pci_info *) pci_info_addr; err = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, @@ -770,31 +739,24 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter) QLCNIC_CDRP_CMD_GET_PCI_INFO); if (err == QLCNIC_RCODE_SUCCESS) { - for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) { - adapter->npars[i].id = le32_to_cpu(npar->id); - adapter->npars[i].active = le32_to_cpu(npar->active); - adapter->npars[i].type = le32_to_cpu(npar->type); - adapter->npars[i].default_port = + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) { + pci_info->id = le32_to_cpu(npar->id); + pci_info->active = le32_to_cpu(npar->active); + pci_info->type = le32_to_cpu(npar->type); + pci_info->default_port = le32_to_cpu(npar->default_port); - adapter->npars[i].tx_min_bw = + pci_info->tx_min_bw = le32_to_cpu(npar->tx_min_bw); - adapter->npars[i].tx_max_bw = + pci_info->tx_max_bw = le32_to_cpu(npar->tx_max_bw); - memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN); + memcpy(pci_info->mac, npar->mac, ETH_ALEN); } } else { dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n", err); - kfree(adapter->npars); err = -EIO; } - goto err_npar; - -err_eswitch: - kfree(adapter->npars); - adapter->npars = NULL; -err_npar: pci_free_consistent(adapter->pdev, pci_size, pci_info_addr, pci_info_dma_t); return err; @@ -1012,9 +974,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id, if (err != QLCNIC_RCODE_SUCCESS) { dev_err(&adapter->pdev->dev, "Failed to configure eswitch port%d\n", eswitch->port); - eswitch->flags |= QLCNIC_SWITCH_ENABLE; } else { - eswitch->flags &= ~QLCNIC_SWITCH_ENABLE; dev_info(&adapter->pdev->dev, "Configured eSwitch for port %d\n", eswitch->port); } diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 981aa91efc8..18e2b2e6626 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -475,6 +475,53 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) iounmap(adapter->ahw.pci_base0); } +static int +qlcnic_init_pci_info(struct qlcnic_adapter *adapter) +{ + struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC]; + int i, ret = 0, err; + u8 pfn; + + if (!adapter->npars) + adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) * + QLCNIC_MAX_PCI_FUNC, GFP_KERNEL); + if (!adapter->npars) + return -ENOMEM; + + if (!adapter->eswitch) + adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) * + QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL); + if (!adapter->eswitch) { + err = -ENOMEM; + goto err_eswitch; + } + + ret = qlcnic_get_pci_info(adapter, pci_info); + if (!ret) { + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + pfn = pci_info[i].id; + if (pfn > QLCNIC_MAX_PCI_FUNC) + return QL_STATUS_INVALID_PARAM; + adapter->npars[pfn].active = pci_info[i].active; + adapter->npars[pfn].type = pci_info[i].type; + adapter->npars[pfn].phy_port = pci_info[i].default_port; + adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN; + } + + for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) + adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE; + + return ret; + } + + kfree(adapter->eswitch); + adapter->eswitch = NULL; +err_eswitch: + kfree(adapter->npars); + + return ret; +} + static int qlcnic_set_function_modes(struct qlcnic_adapter *adapter) { @@ -494,7 +541,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) if (qlcnic_config_npars) { for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { - id = adapter->npars[i].id; + id = i; if (adapter->npars[i].type != QLCNIC_TYPE_NIC || id == adapter->ahw.pci_func) continue; @@ -519,6 +566,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) { void __iomem *msix_base_addr; void __iomem *priv_op; + struct qlcnic_info nic_info; u32 func; u32 msix_base; u32 op_mode, priv_level; @@ -533,7 +581,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE; adapter->ahw.pci_func = func; - qlcnic_get_nic_info(adapter, adapter->ahw.pci_func); + if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) { + adapter->capabilities = nic_info.capabilities; + + if (adapter->capabilities & BIT_6) + adapter->flags |= QLCNIC_ESWITCH_ENABLED; + else + adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; + } if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { adapter->nic_ops = &qlcnic_ops; @@ -552,7 +607,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter) case QLCNIC_MGMT_FUNC: adapter->op_mode = QLCNIC_MGMT_FUNC; adapter->nic_ops = &qlcnic_ops; - qlcnic_get_pci_info(adapter); + qlcnic_init_pci_info(adapter); /* Set privilege level for other functions */ qlcnic_set_function_modes(adapter); dev_info(&adapter->pdev->dev, @@ -654,7 +709,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) int i, offset, val; int *ptr32; struct pci_dev *pdev = adapter->pdev; - + struct qlcnic_info nic_info; adapter->driver_mismatch = 0; ptr32 = (int *)&serial_num; @@ -696,7 +751,15 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; } - qlcnic_get_nic_info(adapter, adapter->ahw.pci_func); + if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) { + adapter->physical_port = nic_info.phys_port; + adapter->switch_mode = nic_info.switch_mode; + adapter->max_tx_ques = nic_info.max_tx_ques; + adapter->max_rx_ques = nic_info.max_rx_ques; + adapter->capabilities = nic_info.capabilities; + adapter->max_mac_filters = nic_info.max_mac_filters; + adapter->max_mtu = nic_info.max_mtu; + } adapter->msix_supported = !!use_msi_x; adapter->rss_supported = !!use_msi_x; @@ -2822,6 +2885,364 @@ static struct bin_attribute bin_attr_mem = { .write = qlcnic_sysfs_write_mem, }; +int +validate_pm_config(struct qlcnic_adapter *adapter, + struct qlcnic_pm_func_cfg *pm_cfg, int count) +{ + + u8 src_pci_func, s_esw_id, d_esw_id; + u8 dest_pci_func; + int i; + + for (i = 0; i < count; i++) { + src_pci_func = pm_cfg[i].pci_func; + dest_pci_func = pm_cfg[i].dest_npar; + if (src_pci_func >= QLCNIC_MAX_PCI_FUNC + || dest_pci_func >= QLCNIC_MAX_PCI_FUNC) + return QL_STATUS_INVALID_PARAM; + + if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC) + return QL_STATUS_INVALID_PARAM; + + if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC) + return QL_STATUS_INVALID_PARAM; + + if (!IS_VALID_MODE(pm_cfg[i].action)) + return QL_STATUS_INVALID_PARAM; + + s_esw_id = adapter->npars[src_pci_func].phy_port; + d_esw_id = adapter->npars[dest_pci_func].phy_port; + + if (s_esw_id != d_esw_id) + return QL_STATUS_INVALID_PARAM; + + } + return 0; + +} + +static ssize_t +qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_pm_func_cfg *pm_cfg; + u32 id, action, pci_func; + int count, rem, i, ret; + + count = size / sizeof(struct qlcnic_pm_func_cfg); + rem = size % sizeof(struct qlcnic_pm_func_cfg); + if (rem) + return QL_STATUS_INVALID_PARAM; + + pm_cfg = (struct qlcnic_pm_func_cfg *) buf; + + ret = validate_pm_config(adapter, pm_cfg, count); + if (ret) + return ret; + for (i = 0; i < count; i++) { + pci_func = pm_cfg[i].pci_func; + action = pm_cfg[i].action; + id = adapter->npars[pci_func].phy_port; + ret = qlcnic_config_port_mirroring(adapter, id, + action, pci_func); + if (ret) + return ret; + } + + for (i = 0; i < count; i++) { + pci_func = pm_cfg[i].pci_func; + id = adapter->npars[pci_func].phy_port; + adapter->npars[pci_func].enable_pm = pm_cfg[i].action; + adapter->npars[pci_func].dest_npar = id; + } + return size; +} + +static ssize_t +qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC]; + int i; + + if (size != sizeof(pm_cfg)) + return QL_STATUS_INVALID_PARAM; + + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + if (adapter->npars[i].type != QLCNIC_TYPE_NIC) + continue; + pm_cfg[i].action = adapter->npars[i].enable_pm; + pm_cfg[i].dest_npar = 0; + pm_cfg[i].pci_func = i; + } + memcpy(buf, &pm_cfg, size); + + return size; +} + +int +validate_esw_config(struct qlcnic_adapter *adapter, + struct qlcnic_esw_func_cfg *esw_cfg, int count) +{ + u8 pci_func; + int i; + + for (i = 0; i < count; i++) { + pci_func = esw_cfg[i].pci_func; + if (pci_func >= QLCNIC_MAX_PCI_FUNC) + return QL_STATUS_INVALID_PARAM; + + if (adapter->npars[i].type != QLCNIC_TYPE_NIC) + return QL_STATUS_INVALID_PARAM; + + if (esw_cfg->host_vlan_tag == 1) + if (!IS_VALID_VLAN(esw_cfg[i].vlan_id)) + return QL_STATUS_INVALID_PARAM; + + if (!IS_VALID_MODE(esw_cfg[i].promisc_mode) + || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag) + || !IS_VALID_MODE(esw_cfg[i].mac_learning) + || !IS_VALID_MODE(esw_cfg[i].discard_tagged)) + return QL_STATUS_INVALID_PARAM; + } + + return 0; +} + +static ssize_t +qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_esw_func_cfg *esw_cfg; + u8 id, discard_tagged, promsc_mode, mac_learn; + u8 vlan_tagging, pci_func, vlan_id; + int count, rem, i, ret; + + count = size / sizeof(struct qlcnic_esw_func_cfg); + rem = size % sizeof(struct qlcnic_esw_func_cfg); + if (rem) + return QL_STATUS_INVALID_PARAM; + + esw_cfg = (struct qlcnic_esw_func_cfg *) buf; + ret = validate_esw_config(adapter, esw_cfg, count); + if (ret) + return ret; + + for (i = 0; i < count; i++) { + pci_func = esw_cfg[i].pci_func; + id = adapter->npars[pci_func].phy_port; + vlan_tagging = esw_cfg[i].host_vlan_tag; + promsc_mode = esw_cfg[i].promisc_mode; + mac_learn = esw_cfg[i].mac_learning; + vlan_id = esw_cfg[i].vlan_id; + discard_tagged = esw_cfg[i].discard_tagged; + ret = qlcnic_config_switch_port(adapter, id, vlan_tagging, + discard_tagged, + promsc_mode, + mac_learn, + pci_func, + vlan_id); + if (ret) + return ret; + } + + for (i = 0; i < count; i++) { + pci_func = esw_cfg[i].pci_func; + adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode; + adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning; + adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id; + adapter->npars[pci_func].discard_tagged = + esw_cfg[i].discard_tagged; + adapter->npars[pci_func].host_vlan_tag = + esw_cfg[i].host_vlan_tag; + } + + return size; +} + +static ssize_t +qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC]; + int i; + + if (size != sizeof(esw_cfg)) + return QL_STATUS_INVALID_PARAM; + + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + if (adapter->npars[i].type != QLCNIC_TYPE_NIC) + continue; + + esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag; + esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode; + esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged; + esw_cfg[i].vlan_id = adapter->npars[i].vlan_id; + esw_cfg[i].mac_learning = adapter->npars[i].mac_learning; + } + memcpy(buf, &esw_cfg, size); + + return size; +} + +int +validate_npar_config(struct qlcnic_adapter *adapter, + struct qlcnic_npar_func_cfg *np_cfg, int count) +{ + u8 pci_func, i; + + for (i = 0; i < count; i++) { + pci_func = np_cfg[i].pci_func; + if (pci_func >= QLCNIC_MAX_PCI_FUNC) + return QL_STATUS_INVALID_PARAM; + + if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC) + return QL_STATUS_INVALID_PARAM; + + if (!IS_VALID_BW(np_cfg[i].min_bw) + || !IS_VALID_BW(np_cfg[i].max_bw) + || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues) + || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues)) + return QL_STATUS_INVALID_PARAM; + } + return 0; +} + +static ssize_t +qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_info nic_info; + struct qlcnic_npar_func_cfg *np_cfg; + int i, count, rem, ret; + u8 pci_func; + + count = size / sizeof(struct qlcnic_npar_func_cfg); + rem = size % sizeof(struct qlcnic_npar_func_cfg); + if (rem) + return QL_STATUS_INVALID_PARAM; + + np_cfg = (struct qlcnic_npar_func_cfg *) buf; + ret = validate_npar_config(adapter, np_cfg, count); + if (ret) + return ret; + + for (i = 0; i < count ; i++) { + pci_func = np_cfg[i].pci_func; + ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func); + if (ret) + return ret; + nic_info.pci_func = pci_func; + nic_info.min_tx_bw = np_cfg[i].min_bw; + nic_info.max_tx_bw = np_cfg[i].max_bw; + ret = qlcnic_set_nic_info(adapter, &nic_info); + if (ret) + return ret; + } + + return size; + +} +static ssize_t +qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_info nic_info; + struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC]; + int i, ret; + + if (size != sizeof(np_cfg)) + return QL_STATUS_INVALID_PARAM; + + for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) { + if (adapter->npars[i].type != QLCNIC_TYPE_NIC) + continue; + ret = qlcnic_get_nic_info(adapter, &nic_info, i); + if (ret) + return ret; + + np_cfg[i].pci_func = i; + np_cfg[i].op_mode = nic_info.op_mode; + np_cfg[i].port_num = nic_info.phys_port; + np_cfg[i].fw_capab = nic_info.capabilities; + np_cfg[i].min_bw = nic_info.min_tx_bw ; + np_cfg[i].max_bw = nic_info.max_tx_bw; + 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; +} + +static ssize_t +qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC]; + struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC]; + int i, ret; + + if (size != sizeof(pci_cfg)) + return QL_STATUS_INVALID_PARAM; + + ret = qlcnic_get_pci_info(adapter, pci_info); + if (ret) + return ret; + + for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) { + pci_cfg[i].pci_func = pci_info[i].id; + pci_cfg[i].func_type = pci_info[i].type; + 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); + return size; + +} +static struct bin_attribute bin_attr_npar_config = { + .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_npar_config, + .write = qlcnic_sysfs_write_npar_config, +}; + +static struct bin_attribute bin_attr_pci_config = { + .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_pci_config, + .write = NULL, +}; + +static struct bin_attribute bin_attr_esw_config = { + .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_esw_config, + .write = qlcnic_sysfs_write_esw_config, +}; + +static struct bin_attribute bin_attr_pm_config = { + .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_pm_config, + .write = qlcnic_sysfs_write_pm_config, +}; + static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) { @@ -2853,6 +3274,18 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) || + adapter->op_mode != QLCNIC_MGMT_FUNC) + return; + if (device_create_bin_file(dev, &bin_attr_pci_config)) + dev_info(dev, "failed to create pci config sysfs entry"); + if (device_create_bin_file(dev, &bin_attr_npar_config)) + dev_info(dev, "failed to create npar config sysfs entry"); + if (device_create_bin_file(dev, &bin_attr_esw_config)) + dev_info(dev, "failed to create esw config sysfs entry"); + if (device_create_bin_file(dev, &bin_attr_pm_config)) + dev_info(dev, "failed to create pm config sysfs entry"); + } @@ -2864,6 +3297,13 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) device_remove_file(dev, &dev_attr_diag_mode); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) || + adapter->op_mode != QLCNIC_MGMT_FUNC) + return; + device_remove_bin_file(dev, &bin_attr_pci_config); + device_remove_bin_file(dev, &bin_attr_npar_config); + device_remove_bin_file(dev, &bin_attr_esw_config); + device_remove_bin_file(dev, &bin_attr_pm_config); } #ifdef CONFIG_INET -- cgit v1.2.3-70-g09d2 From ac8d0c4feb5577a830bbf1d9a3bb5b1d30298e2c Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 9 Jul 2010 13:14:58 +0000 Subject: qlcnic: Check FW capability for TSO Driver checks TSO capability from FW before enabling it. Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 7 ++++--- drivers/net/qlcnic/qlcnic_ethtool.c | 3 +++ drivers/net/qlcnic/qlcnic_main.c | 10 +++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 60ea7cb3308..02a50e60166 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -821,9 +821,10 @@ struct qlcnic_nic_intr_coalesce { #define QLCNIC_LRO_REQUEST_CLEANUP 4 /* Capabilites received */ -#define QLCNIC_FW_CAPABILITY_BDG (1 << 8) -#define QLCNIC_FW_CAPABILITY_FVLANTX (1 << 9) -#define QLCNIC_FW_CAPABILITY_HW_LRO (1 << 10) +#define QLCNIC_FW_CAPABILITY_TSO BIT_1 +#define QLCNIC_FW_CAPABILITY_BDG BIT_8 +#define QLCNIC_FW_CAPABILITY_FVLANTX BIT_9 +#define QLCNIC_FW_CAPABILITY_HW_LRO BIT_10 /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index f8e39e4cfe0..baf5a52b2a4 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -820,6 +820,9 @@ static u32 qlcnic_get_tso(struct net_device *dev) static int qlcnic_set_tso(struct net_device *dev, u32 data) { + struct qlcnic_adapter *adapter = netdev_priv(dev); + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)) + return -EOPNOTSUPP; if (data) dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); else diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 18e2b2e6626..c334f1a0a2a 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1226,10 +1226,14 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6); - + NETIF_F_IPV6_CSUM | NETIF_F_GRO); netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6); + NETIF_F_IPV6_CSUM); + + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { + netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); + } if (pci_using_dac) { netdev->features |= NETIF_F_HIGHDMA; -- cgit v1.2.3-70-g09d2 From 451724c821c1fe5af076a0def72362f947e1b6a0 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Tue, 13 Jul 2010 20:33:34 +0000 Subject: qlcnic: aer support Pci error recovery support added. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 1 + drivers/net/qlcnic/qlcnic_main.c | 137 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 02a50e60166..064464201cb 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -911,6 +911,7 @@ struct qlcnic_mac_req { #define __QLCNIC_DEV_UP 1 #define __QLCNIC_RESETTING 2 #define __QLCNIC_START_FW 4 +#define __QLCNIC_AER 5 #define QLCNIC_INTERRUPT_TEST 1 #define QLCNIC_LOOPBACK_TEST 2 diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 0995f90b0ba..d5c94a3364f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -34,6 +34,7 @@ #include #include #include +#include MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -1306,6 +1307,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_disable_pdev; pci_set_master(pdev); + pci_enable_pcie_error_reporting(pdev); netdev = alloc_etherdev(sizeof(struct qlcnic_adapter)); if (!netdev) { @@ -1437,6 +1439,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) qlcnic_release_firmware(adapter); + pci_disable_pcie_error_reporting(pdev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -2521,6 +2524,9 @@ static void qlcnic_schedule_work(struct qlcnic_adapter *adapter, work_func_t func, int delay) { + if (test_bit(__QLCNIC_AER, &adapter->state)) + return; + INIT_DELAYED_WORK(&adapter->fw_work, func); schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay)); } @@ -2631,6 +2637,128 @@ reschedule: qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); } +static int qlcnic_is_first_func(struct pci_dev *pdev) +{ + struct pci_dev *oth_pdev; + int val = pdev->devfn; + + while (val-- > 0) { + oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr + (pdev->bus), pdev->bus->number, + PCI_DEVFN(PCI_SLOT(pdev->devfn), val)); + + if (oth_pdev && (oth_pdev->current_state != PCI_D3cold)) + return 0; + } + return 1; +} + +static int qlcnic_attach_func(struct pci_dev *pdev) +{ + int err, first_func; + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + + pdev->error_state = pci_channel_io_normal; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_restore_state(pdev); + + first_func = qlcnic_is_first_func(pdev); + + if (qlcnic_api_lock(adapter)) + return -EINVAL; + + if (first_func) { + adapter->need_fw_reset = 1; + set_bit(__QLCNIC_START_FW, &adapter->state); + QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING); + QLCDB(adapter, DRV, "Restarting fw\n"); + } + qlcnic_api_unlock(adapter); + + err = adapter->nic_ops->start_firmware(adapter); + if (err) + return err; + + qlcnic_clr_drv_state(adapter); + qlcnic_setup_intr(adapter); + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) { + qlcnic_clr_all_drv_state(adapter); + clear_bit(__QLCNIC_AER, &adapter->state); + netif_device_attach(netdev); + return err; + } + + err = qlcnic_up(adapter, netdev); + if (err) + goto done; + + qlcnic_config_indev_addr(netdev, NETDEV_UP); + } + done: + netif_device_attach(netdev); + return err; +} + +static pci_ers_result_t qlcnic_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; + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (state == pci_channel_io_normal) + return PCI_ERS_RESULT_RECOVERED; + + set_bit(__QLCNIC_AER, &adapter->state); + netif_device_detach(netdev); + + cancel_delayed_work_sync(&adapter->fw_work); + + if (netif_running(netdev)) + qlcnic_down(adapter, netdev); + + qlcnic_detach(adapter); + qlcnic_teardown_intr(adapter); + + clear_bit(__QLCNIC_RESETTING, &adapter->state); + + pci_save_state(pdev); + pci_disable_device(pdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev) +{ + return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT : + PCI_ERS_RESULT_RECOVERED; +} + +static void qlcnic_io_resume(struct pci_dev *pdev) +{ + struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); + + pci_cleanup_aer_uncorrect_error_status(pdev); + + if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY && + test_and_clear_bit(__QLCNIC_AER, &adapter->state)) + qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, + FW_POLL_DELAY); +} + + static int qlcnicvf_start_firmware(struct qlcnic_adapter *adapter) { @@ -3436,6 +3564,11 @@ static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long event) { } #endif +static struct pci_error_handlers qlcnic_err_handler = { + .error_detected = qlcnic_io_error_detected, + .slot_reset = qlcnic_io_slot_reset, + .resume = qlcnic_io_resume, +}; static struct pci_driver qlcnic_driver = { .name = qlcnic_driver_name, @@ -3446,7 +3579,9 @@ static struct pci_driver qlcnic_driver = { .suspend = qlcnic_suspend, .resume = qlcnic_resume, #endif - .shutdown = qlcnic_shutdown + .shutdown = qlcnic_shutdown, + .err_handler = &qlcnic_err_handler + }; static int __init qlcnic_init_module(void) -- cgit v1.2.3-70-g09d2 From cea8975e84409f01fc4cf92775d2d0028ccc1665 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Tue, 13 Jul 2010 20:33:35 +0000 Subject: qlcnic: restore NPAR config data after recovery o NPAR configuration which is programmed in fw, need to restore after fw recovery. o Update version to 5.0.7 Signed-off-by: Anirban Chakraborty Signed-off-by: Rajesh Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 7 ++-- drivers/net/qlcnic/qlcnic_ctx.c | 2 + drivers/net/qlcnic/qlcnic_main.c | 86 ++++++++++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 23 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 064464201cb..e1894775e5a 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -51,8 +51,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 6 -#define QLCNIC_LINUX_VERSIONID "5.0.6" +#define _QLCNIC_LINUX_SUBVERSION 7 +#define QLCNIC_LINUX_VERSIONID "5.0.7" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) @@ -949,7 +949,6 @@ struct qlcnic_adapter { u8 has_link_events; u8 fw_type; u16 tx_context_id; - u16 mtu; u16 is_up; u16 link_speed; @@ -1044,6 +1043,8 @@ struct qlcnic_pci_info { struct qlcnic_npar_info { u16 vlan_id; + u16 min_bw; + u16 max_bw; u8 phy_port; u8 type; u8 active; diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index cdd44b4136a..cc5d861d9a1 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -636,6 +636,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, QLCNIC_CDRP_CMD_GET_NIC_INFO); if (err == QLCNIC_RCODE_SUCCESS) { + npar_info->pci_func = le16_to_cpu(nic_info->pci_func); + npar_info->op_mode = le16_to_cpu(nic_info->op_mode); npar_info->phys_port = le16_to_cpu(nic_info->phys_port); npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode); npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index d5c94a3364f..8d2d62ff1a3 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -507,6 +507,8 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter) adapter->npars[pfn].type = pci_info[i].type; adapter->npars[pfn].phy_port = pci_info[i].default_port; adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN; + adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw; + adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw; } for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) @@ -770,6 +772,50 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->max_rds_rings = 2; } +static int +qlcnic_reset_npar_config(struct qlcnic_adapter *adapter) +{ + int i, err = 0; + struct qlcnic_npar_info *npar; + struct qlcnic_info nic_info; + + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) || + !adapter->need_fw_reset) + return 0; + + if (adapter->op_mode == QLCNIC_MGMT_FUNC) { + /* Set the NPAR config data after FW reset */ + for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { + npar = &adapter->npars[i]; + if (npar->type != QLCNIC_TYPE_NIC) + continue; + err = qlcnic_get_nic_info(adapter, &nic_info, i); + if (err) + goto err_out; + nic_info.min_tx_bw = npar->min_bw; + nic_info.max_tx_bw = npar->max_bw; + err = qlcnic_set_nic_info(adapter, &nic_info); + if (err) + goto err_out; + + if (npar->enable_pm) { + err = qlcnic_config_port_mirroring(adapter, + npar->dest_npar, 1, i); + if (err) + goto err_out; + + } + npar->mac_learning = DEFAULT_MAC_LEARN; + npar->host_vlan_tag = 0; + npar->promisc_mode = 0; + npar->discard_tagged = 0; + npar->vlan_id = 0; + } + } +err_out: + return err; +} + static int qlcnic_start_firmware(struct qlcnic_adapter *adapter) { @@ -834,10 +880,9 @@ wait_init: qlcnic_idc_debug_info(adapter, 1); qlcnic_check_options(adapter); - - if (adapter->flags & QLCNIC_ESWITCH_ENABLED && - adapter->op_mode != QLCNIC_NON_PRIV_FUNC) - qlcnic_dev_set_npar_ready(adapter); + if (qlcnic_reset_npar_config(adapter)) + goto err_out; + qlcnic_dev_set_npar_ready(adapter); adapter->need_fw_reset = 0; @@ -2486,6 +2531,7 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) { u32 state; + adapter->need_fw_reset = 1; if (qlcnic_api_lock(adapter)) return; @@ -2506,6 +2552,9 @@ qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter) { u32 state; + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) || + adapter->op_mode == QLCNIC_NON_PRIV_FUNC) + return; if (qlcnic_api_lock(adapter)) return; @@ -3019,7 +3068,7 @@ static struct bin_attribute bin_attr_mem = { .write = qlcnic_sysfs_write_mem, }; -int +static int validate_pm_config(struct qlcnic_adapter *adapter, struct qlcnic_pm_func_cfg *pm_cfg, int count) { @@ -3118,7 +3167,7 @@ qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj, return size; } -int +static int validate_esw_config(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg, int count) { @@ -3154,9 +3203,8 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); struct qlcnic_esw_func_cfg *esw_cfg; - u8 id, discard_tagged, promsc_mode, mac_learn; - u8 vlan_tagging, pci_func, vlan_id; int count, rem, i, ret; + u8 id, pci_func; count = size / sizeof(struct qlcnic_esw_func_cfg); rem = size % sizeof(struct qlcnic_esw_func_cfg); @@ -3171,17 +3219,13 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; id = adapter->npars[pci_func].phy_port; - vlan_tagging = esw_cfg[i].host_vlan_tag; - promsc_mode = esw_cfg[i].promisc_mode; - mac_learn = esw_cfg[i].mac_learning; - vlan_id = esw_cfg[i].vlan_id; - discard_tagged = esw_cfg[i].discard_tagged; - ret = qlcnic_config_switch_port(adapter, id, vlan_tagging, - discard_tagged, - promsc_mode, - mac_learn, - pci_func, - vlan_id); + ret = qlcnic_config_switch_port(adapter, id, + esw_cfg[i].host_vlan_tag, + esw_cfg[i].discard_tagged, + esw_cfg[i].promisc_mode, + esw_cfg[i].mac_learning, + esw_cfg[i].pci_func, + esw_cfg[i].vlan_id); if (ret) return ret; } @@ -3227,7 +3271,7 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj, return size; } -int +static int validate_npar_config(struct qlcnic_adapter *adapter, struct qlcnic_npar_func_cfg *np_cfg, int count) { @@ -3282,6 +3326,8 @@ qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj, ret = qlcnic_set_nic_info(adapter, &nic_info); if (ret) return ret; + adapter->npars[i].min_bw = nic_info.min_tx_bw; + adapter->npars[i].max_bw = nic_info.max_tx_bw; } return size; -- cgit v1.2.3-70-g09d2 From 9963a8bde60f3c139b7683e2ec7e0bf83c0d7581 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 23 Jul 2010 21:24:25 +0000 Subject: qlcnic: fix bandwidth check Fix maximum and minmum bandwith value. Signed-off-by: Rajesh Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index e1894775e5a..fad8e9a51a5 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1074,8 +1074,8 @@ struct qlcnic_eswitch { /* Return codes for Error handling */ #define QL_STATUS_INVALID_PARAM -1 -#define MAX_BW 10000 -#define MIN_BW 100 +#define MAX_BW 100 +#define MIN_BW 1 #define MAX_VLAN_ID 4095 #define MIN_VLAN_ID 2 #define MAX_TX_QUEUES 1 @@ -1083,8 +1083,7 @@ struct qlcnic_eswitch { #define DEFAULT_MAC_LEARN 1 #define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID) -#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW \ - && (bw % 100) == 0) +#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW) #define IS_VALID_TX_QUEUES(que) (que > 0 && que <= MAX_TX_QUEUES) #define IS_VALID_RX_QUEUES(que) (que > 0 && que <= MAX_RX_QUEUES) #define IS_VALID_MODE(mode) (mode == 0 || mode == 1) -- cgit v1.2.3-70-g09d2 From 36a1898ddfde3e36a6813ac72540e011a3de57ae Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sat, 24 Jul 2010 18:32:17 +0000 Subject: qlcnic: fix loopback test o Loopback not supported for virtual function. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 2 -- drivers/net/qlcnic/qlcnic_ethtool.c | 10 ++++++++-- drivers/net/qlcnic/qlcnic_main.c | 18 ------------------ 3 files changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers/net/qlcnic/qlcnic.h') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index fad8e9a51a5..970389331bb 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1301,8 +1301,6 @@ struct qlcnic_nic_template { int (*get_mac_addr) (struct qlcnic_adapter *, u8*); int (*config_bridged_mode) (struct qlcnic_adapter *, u32); int (*config_led) (struct qlcnic_adapter *, u32, u32); - int (*set_ilb_mode) (struct qlcnic_adapter *); - void (*clear_ilb_mode) (struct qlcnic_adapter *); int (*start_firmware) (struct qlcnic_adapter *); }; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 7d6558e33dc..9328d59e21e 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -678,6 +678,12 @@ static int qlcnic_loopback_test(struct net_device *netdev) int max_sds_rings = adapter->max_sds_rings; int ret; + if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) { + dev_warn(&adapter->pdev->dev, "Loopback test not supported" + "for non privilege function\n"); + return 0; + } + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) return -EIO; @@ -685,13 +691,13 @@ static int qlcnic_loopback_test(struct net_device *netdev) if (ret) goto clear_it; - ret = adapter->nic_ops->set_ilb_mode(adapter); + ret = qlcnic_set_ilb_mode(adapter); if (ret) goto done; ret = qlcnic_do_ilb_test(adapter); - adapter->nic_ops->clear_ilb_mode(adapter); + qlcnic_clear_ilb_mode(adapter); done: qlcnic_diag_free_res(netdev, max_sds_rings); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index f1f7acfbf41..f147958e05a 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -107,8 +107,6 @@ static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); static int qlcnic_start_firmware(struct qlcnic_adapter *); static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *); -static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *); -static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *); static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); static int qlcnicvf_start_firmware(struct qlcnic_adapter *); @@ -381,8 +379,6 @@ static struct qlcnic_nic_template qlcnic_ops = { .get_mac_addr = qlcnic_get_mac_address, .config_bridged_mode = qlcnic_config_bridged_mode, .config_led = qlcnic_config_led, - .set_ilb_mode = qlcnic_set_ilb_mode, - .clear_ilb_mode = qlcnic_clear_ilb_mode, .start_firmware = qlcnic_start_firmware }; @@ -390,8 +386,6 @@ static struct qlcnic_nic_template qlcnic_vf_ops = { .get_mac_addr = qlcnic_get_mac_address, .config_bridged_mode = qlcnicvf_config_bridged_mode, .config_led = qlcnicvf_config_led, - .set_ilb_mode = qlcnicvf_set_ilb_mode, - .clear_ilb_mode = qlcnicvf_clear_ilb_mode, .start_firmware = qlcnicvf_start_firmware }; @@ -2841,18 +2835,6 @@ qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return -EOPNOTSUPP; } -static int -qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter) -{ - return -EOPNOTSUPP; -} - -static void -qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter) -{ - return; -} - static ssize_t qlcnic_store_bridged_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -- cgit v1.2.3-70-g09d2