diff options
Diffstat (limited to 'drivers/net/ethernet/emulex')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 237 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 84 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 120 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 588 |
5 files changed, 801 insertions, 267 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 644e8fed836..cbdec2536da 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -40,6 +40,7 @@ #define OC_NAME "Emulex OneConnect 10Gbps NIC" #define OC_NAME_BE OC_NAME "(be3)" #define OC_NAME_LANCER OC_NAME "(Lancer)" +#define OC_NAME_SH OC_NAME "(Skyhawk)" #define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver" #define BE_VENDOR_ID 0x19a2 @@ -50,6 +51,7 @@ #define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */ #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ #define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ +#define OC_DEVICE_ID5 0x720 /* Device Id for Skyhawk cards */ static inline char *nic_name(struct pci_dev *pdev) { @@ -63,6 +65,8 @@ static inline char *nic_name(struct pci_dev *pdev) return OC_NAME_LANCER; case BE_DEVICE_ID2: return BE3_NAME; + case OC_DEVICE_ID5: + return OC_NAME_SH; default: return BE_NAME; } @@ -288,14 +292,14 @@ struct be_drv_stats { }; struct be_vf_cfg { - unsigned char vf_mac_addr[ETH_ALEN]; - u32 vf_if_handle; - u32 vf_pmac_id; - u16 vf_vlan_tag; - u32 vf_tx_rate; + unsigned char mac_addr[ETH_ALEN]; + int if_handle; + int pmac_id; + u16 vlan_tag; + u32 tx_rate; }; -#define BE_INVALID_PMAC_ID 0xffffffff +#define BE_FLAGS_LINK_STATUS_INIT 1 struct be_adapter { struct pci_dev *pdev; @@ -345,13 +349,16 @@ struct be_adapter { struct delayed_work work; u16 work_counter; + u32 flags; /* Ethtool knobs and info */ char fw_ver[FW_VER_LEN]; - u32 if_handle; /* Used to configure filtering */ + int if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ u32 beacon_state; /* for set_phys_id */ bool eeh_err; + bool ue_detected; + bool fw_timeout; u32 port_num; bool promiscuous; bool wol; @@ -359,7 +366,6 @@ struct be_adapter { u32 function_caps; u32 rx_fc; /* Rx flow control */ u32 tx_fc; /* Tx flow control */ - bool ue_detected; bool stats_cmd_sent; int link_speed; u8 port_type; @@ -369,16 +375,20 @@ struct be_adapter { u32 flash_status; struct completion flash_compl; - bool be3_native; - bool sriov_enabled; - struct be_vf_cfg *vf_cfg; + u32 num_vfs; u8 is_virtfn; + struct be_vf_cfg *vf_cfg; + bool be3_native; u32 sli_family; u8 hba_port_num; u16 pvid; }; #define be_physfn(adapter) (!adapter->is_virtfn) +#define sriov_enabled(adapter) (adapter->num_vfs > 0) +#define for_all_vfs(adapter, vf_cfg, i) \ + for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ + i++, vf_cfg++) /* BladeEngine Generation numbers */ #define BE_GEN2 2 @@ -524,9 +534,14 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter) return adapter->num_rx_qs > 1; } +static inline bool be_error(struct be_adapter *adapter) +{ + return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); -extern void be_link_status_update(struct be_adapter *adapter, u32 link_status); +extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); extern void be_parse_stats(struct be_adapter *adapter); extern int be_load_fw(struct be_adapter *adapter, u8 *func); #endif /* BE_H */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 2c7b36673df..0fcb4562479 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -31,11 +31,8 @@ static void be_mcc_notify(struct be_adapter *adapter) struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; - if (adapter->eeh_err) { - dev_info(&adapter->pdev->dev, - "Error in Card Detected! Cannot issue commands\n"); + if (be_error(adapter)) return; - } val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; @@ -128,7 +125,14 @@ done: static void be_async_link_state_process(struct be_adapter *adapter, struct be_async_event_link_state *evt) { - be_link_status_update(adapter, evt->port_link_status); + /* When link status changes, link speed must be re-queried from FW */ + adapter->link_speed = -1; + + /* For the initial link status do not rely on the ASYNC event as + * it may not be received in some cases. + */ + if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) + be_link_status_update(adapter, evt->port_link_status); } /* Grp5 CoS Priority evt */ @@ -266,10 +270,10 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) int i, num, status = 0; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; - if (adapter->eeh_err) - return -EIO; - for (i = 0; i < mcc_timeout; i++) { + if (be_error(adapter)) + return -EIO; + num = be_process_mcc(adapter, &status); if (num) be_cq_notify(adapter, mcc_obj->cq.id, @@ -280,7 +284,8 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) udelay(100); } if (i == mcc_timeout) { - dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); + dev_err(&adapter->pdev->dev, "FW not responding\n"); + adapter->fw_timeout = true; return -1; } return status; @@ -298,26 +303,21 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) int msecs = 0; u32 ready; - if (adapter->eeh_err) { - dev_err(&adapter->pdev->dev, - "Error detected in card.Cannot issue commands\n"); - return -EIO; - } - do { + if (be_error(adapter)) + return -EIO; + ready = ioread32(db); - if (ready == 0xffffffff) { - dev_err(&adapter->pdev->dev, - "pci slot disconnected\n"); + if (ready == 0xffffffff) return -1; - } ready &= MPU_MAILBOX_DB_RDY_MASK; if (ready) break; if (msecs > 4000) { - dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); + dev_err(&adapter->pdev->dev, "FW not responding\n"); + adapter->fw_timeout = true; be_detect_dump_ue(adapter); return -1; } @@ -555,9 +555,6 @@ int be_cmd_fw_clean(struct be_adapter *adapter) u8 *wrb; int status; - if (adapter->eeh_err) - return -EIO; - if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -619,7 +616,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, /* Use MCC */ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, - u8 type, bool permanent, u32 if_handle) + u8 type, bool permanent, u32 if_handle, u32 pmac_id) { struct be_mcc_wrb *wrb; struct be_cmd_req_mac_query *req; @@ -641,6 +638,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, req->permanent = 1; } else { req->if_id = cpu_to_le16((u16) if_handle); + req->pmac_id = cpu_to_le32(pmac_id); req->permanent = 0; } @@ -695,12 +693,15 @@ err: } /* Uses synchronous MCCQ */ -int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom) +int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_pmac_del *req; int status; + if (pmac_id == -1) + return 0; + spin_lock_bh(&adapter->mcc_lock); wrb = wrb_from_mccq(adapter); @@ -923,10 +924,14 @@ int be_cmd_txq_create(struct be_adapter *adapter, void *ctxt; int status; - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } - wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); ctxt = &req->context; @@ -952,14 +957,15 @@ int be_cmd_txq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_notify_wait(adapter); + status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); txq->id = le16_to_cpu(resp->cid); txq->created = true; } - mutex_unlock(&adapter->mbox_lock); +err: + spin_unlock_bh(&adapter->mcc_lock); return status; } @@ -1018,9 +1024,6 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, u8 subsys = 0, opcode = 0; int status; - if (adapter->eeh_err) - return -EIO; - if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -1136,16 +1139,13 @@ err: } /* Uses MCCQ */ -int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) +int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_if_destroy *req; int status; - if (adapter->eeh_err) - return -EIO; - - if (!interface_id) + if (interface_id == -1) return 0; spin_lock_bh(&adapter->mcc_lock); @@ -1239,7 +1239,7 @@ err: /* Uses synchronous mcc */ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, - u16 *link_speed, u32 dom) + u16 *link_speed, u8 *link_status, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_link_status *req; @@ -1247,6 +1247,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, spin_lock_bh(&adapter->mcc_lock); + if (link_status) + *link_status = LINK_DOWN; + wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; @@ -1254,6 +1257,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, } req = embedded_payload(wrb); + if (adapter->generation == BE_GEN3 || lancer_chip(adapter)) + req->hdr.version = 1; + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL); @@ -1261,10 +1267,13 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) { - *link_speed = le16_to_cpu(resp->link_speed); + if (link_speed) + *link_speed = le16_to_cpu(resp->link_speed); if (mac_speed) *mac_speed = resp->mac_speed; } + if (link_status) + *link_status = resp->logical_link_status; } err: @@ -1673,8 +1682,9 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) { struct be_mcc_wrb *wrb; struct be_cmd_req_rss_config *req; - u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF, - 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF}; + u32 myhash[10] = {0x15d43fa5, 0x2534685a, 0x5f87693a, 0x5668494e, + 0x33cf6a53, 0x383334c6, 0x76ac4257, 0x59b242b2, + 0x3ea83c02, 0x4a110304}; int status; if (mutex_lock_interruptible(&adapter->mbox_lock)) @@ -1836,6 +1846,53 @@ err_unlock: return status; } +int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, const char *obj_name, + u32 *data_read, u32 *eof, u8 *addn_status) +{ + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_read_object *req; + struct lancer_cmd_resp_read_object *resp; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err_unlock; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_READ_OBJECT, + sizeof(struct lancer_cmd_req_read_object), wrb, + NULL); + + req->desired_read_len = cpu_to_le32(data_size); + req->read_offset = cpu_to_le32(data_offset); + strcpy(req->object_name, obj_name); + req->descriptor_count = cpu_to_le32(1); + req->buf_len = cpu_to_le32(data_size); + req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF)); + req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma)); + + status = be_mcc_notify_wait(adapter); + + resp = embedded_payload(wrb); + if (!status) { + *data_read = le32_to_cpu(resp->actual_read_len); + *eof = le32_to_cpu(resp->eof); + } else { + *addn_status = resp->additional_status; + } + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_type, u32 flash_opcode, u32 buf_size) { @@ -2238,3 +2295,99 @@ err: mutex_unlock(&adapter->mbox_lock); return status; } + +/* Uses synchronous MCCQ */ +int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, + u32 *pmac_id) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_list *req; + int status; + int mac_count; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_MAC_LIST, sizeof(*req), + wrb, NULL); + + req->hdr.domain = domain; + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_mac_list *resp = + embedded_payload(wrb); + int i; + u8 *ctxt = &resp->context[0][0]; + status = -EIO; + mac_count = resp->mac_count; + be_dws_le_to_cpu(&resp->context, sizeof(resp->context)); + for (i = 0; i < mac_count; i++) { + if (!AMAP_GET_BITS(struct amap_get_mac_list_context, + act, ctxt)) { + *pmac_id = AMAP_GET_BITS + (struct amap_get_mac_list_context, + macid, ctxt); + status = 0; + break; + } + ctxt += sizeof(struct amap_get_mac_list_context) / 8; + } + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +/* Uses synchronous MCCQ */ +int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, + u8 mac_count, u32 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_mac_list *req; + int status; + struct be_dma_mem cmd; + + memset(&cmd, 0, sizeof(struct be_dma_mem)); + cmd.size = sizeof(struct be_cmd_req_set_mac_list); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, + &cmd.dma, GFP_KERNEL); + if (!cmd.va) { + dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); + return -ENOMEM; + } + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = cmd.va; + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_MAC_LIST, sizeof(*req), + wrb, &cmd); + + req->hdr.domain = domain; + req->mac_count = mac_count; + if (mac_count) + memcpy(req->mac, mac_array, ETH_ALEN*mac_count); + + status = be_mcc_notify_wait(adapter); + +err: + dma_free_coherent(&adapter->pdev->dev, cmd.size, + cmd.va, cmd.dma); + spin_unlock_bh(&adapter->mcc_lock); + return status; +} diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index a35cd03fac4..dca89249088 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -189,6 +189,9 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_PHY_DETAILS 102 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 +#define OPCODE_COMMON_GET_MAC_LIST 147 +#define OPCODE_COMMON_SET_MAC_LIST 148 +#define OPCODE_COMMON_READ_OBJECT 171 #define OPCODE_COMMON_WRITE_OBJECT 172 #define OPCODE_ETH_RSS_CONFIG 1 @@ -294,6 +297,7 @@ struct be_cmd_req_mac_query { u8 type; u8 permanent; u16 if_id; + u32 pmac_id; } __packed; struct be_cmd_resp_mac_query { @@ -956,7 +960,8 @@ struct be_cmd_resp_link_status { u8 mgmt_mac_duplex; u8 mgmt_mac_speed; u16 link_speed; - u32 rsvd0; + u8 logical_link_status; + u8 rsvd1[3]; } __packed; /******************** Port Identification ***************************/ @@ -1161,6 +1166,38 @@ struct lancer_cmd_resp_write_object { u32 actual_write_len; }; +/************************ Lancer Read FW info **************/ +#define LANCER_READ_FILE_CHUNK (32*1024) +#define LANCER_READ_FILE_EOF_MASK 0x80000000 + +#define LANCER_FW_DUMP_FILE "/dbg/dump.bin" +#define LANCER_VPD_PF_FILE "/vpd/ntr_pf.vpd" +#define LANCER_VPD_VF_FILE "/vpd/ntr_vf.vpd" + +struct lancer_cmd_req_read_object { + struct be_cmd_req_hdr hdr; + u32 desired_read_len; + u32 read_offset; + u8 object_name[104]; + u32 descriptor_count; + u32 buf_len; + u32 addr_low; + u32 addr_high; +}; + +struct lancer_cmd_resp_read_object { + u8 opcode; + u8 subsystem; + u8 rsvd1[2]; + u8 status; + u8 additional_status; + u8 rsvd2[2]; + u32 resp_len; + u32 actual_resp_len; + u32 actual_read_len; + u32 eof; +}; + /************************ WOL *******************************/ struct be_cmd_req_acpi_wol_magic_config{ struct be_cmd_req_hdr hdr; @@ -1307,6 +1344,34 @@ struct be_cmd_resp_set_func_cap { u8 rsvd[212]; }; +/******************** GET/SET_MACLIST **************************/ +#define BE_MAX_MAC 64 +struct amap_get_mac_list_context { + u8 macid[31]; + u8 act; +} __packed; + +struct be_cmd_req_get_mac_list { + struct be_cmd_req_hdr hdr; + u32 rsvd; +} __packed; + +struct be_cmd_resp_get_mac_list { + struct be_cmd_resp_hdr hdr; + u8 mac_count; + u8 rsvd1; + u16 rsvd2; + u8 context[sizeof(struct amap_get_mac_list_context) / 8][BE_MAX_MAC]; +} __packed; + +struct be_cmd_req_set_mac_list { + struct be_cmd_req_hdr hdr; + u8 mac_count; + u8 rsvd1; + u16 rsvd2; + struct macaddr mac[BE_MAX_MAC]; +} __packed; + /*************** HW Stats Get v1 **********************************/ #define BE_TXP_SW_SZ 48 struct be_port_rxf_stats_v1 { @@ -1413,15 +1478,15 @@ static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, - u8 type, bool permanent, u32 if_handle); + u8 type, bool permanent, u32 if_handle, u32 pmac_id); extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, u32 if_id, u32 *pmac_id, u32 domain); extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, - u32 pmac_id, u32 domain); + int pmac_id, u32 domain); extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id, u32 domain); -extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle, +extern int be_cmd_if_destroy(struct be_adapter *adapter, int if_handle, u32 domain); extern int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay); @@ -1443,8 +1508,8 @@ extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); extern int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q); -extern int be_cmd_link_status_query(struct be_adapter *adapter, - u8 *mac_speed, u16 *link_speed, u32 dom); +extern int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + u16 *link_speed, u8 *link_status, u32 dom); extern int be_cmd_reset(struct be_adapter *adapter); extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); @@ -1480,6 +1545,9 @@ extern int lancer_cmd_write_object(struct be_adapter *adapter, u32 data_size, u32 data_offset, const char *obj_name, u32 *data_written, u8 *addn_status); +int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, const char *obj_name, + u32 *data_read, u32 *eof, u8 *addn_status); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, int offset); extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, @@ -1506,4 +1574,8 @@ extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); extern int be_cmd_req_native_mode(struct be_adapter *adapter); extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); +extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, + u32 *pmac_id); +extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, + u8 mac_count, u32 domain); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index bf8153ea4ed..6db6b6ae5e9 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -127,8 +127,8 @@ static void be_get_drvinfo(struct net_device *netdev, memset(fw_on_flash, 0 , sizeof(fw_on_flash)); be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash); - strcpy(drvinfo->driver, DRV_NAME); - strcpy(drvinfo->version, DRV_VER); + strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version)); strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN); if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) { strcat(drvinfo->fw_version, " ["); @@ -136,21 +136,84 @@ static void be_get_drvinfo(struct net_device *netdev, strcat(drvinfo->fw_version, "]"); } - strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; } +static u32 +lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name) +{ + u32 data_read = 0, eof; + u8 addn_status; + struct be_dma_mem data_len_cmd; + int status; + + memset(&data_len_cmd, 0, sizeof(data_len_cmd)); + /* data_offset and data_size should be 0 to get reg len */ + status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0, + file_name, &data_read, &eof, &addn_status); + + return data_read; +} + +static int +lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name, + u32 buf_len, void *buf) +{ + struct be_dma_mem read_cmd; + u32 read_len = 0, total_read_len = 0, chunk_size; + u32 eof = 0; + u8 addn_status; + int status = 0; + + read_cmd.size = LANCER_READ_FILE_CHUNK; + read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size, + &read_cmd.dma); + + if (!read_cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure while reading dump\n"); + return -ENOMEM; + } + + while ((total_read_len < buf_len) && !eof) { + chunk_size = min_t(u32, (buf_len - total_read_len), + LANCER_READ_FILE_CHUNK); + chunk_size = ALIGN(chunk_size, 4); + status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size, + total_read_len, file_name, &read_len, + &eof, &addn_status); + if (!status) { + memcpy(buf + total_read_len, read_cmd.va, read_len); + total_read_len += read_len; + eof &= LANCER_READ_FILE_EOF_MASK; + } else { + status = -EIO; + break; + } + } + pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va, + read_cmd.dma); + + return status; +} + static int be_get_reg_len(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); u32 log_size = 0; - if (be_physfn(adapter)) - be_cmd_get_reg_len(adapter, &log_size); - + if (be_physfn(adapter)) { + if (lancer_chip(adapter)) + log_size = lancer_cmd_get_file_len(adapter, + LANCER_FW_DUMP_FILE); + else + be_cmd_get_reg_len(adapter, &log_size); + } return log_size; } @@ -161,7 +224,11 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) if (be_physfn(adapter)) { memset(buf, 0, regs->len); - be_cmd_get_regs(adapter, regs->len, buf); + if (lancer_chip(adapter)) + lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE, + regs->len, buf); + else + be_cmd_get_regs(adapter, regs->len, buf); } } @@ -362,11 +429,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) struct be_phy_info phy_info; u8 mac_speed = 0; u16 link_speed = 0; + u8 link_status; int status; if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { status = be_cmd_link_status_query(adapter, &mac_speed, - &link_speed, 0); + &link_speed, &link_status, 0); + if (!status) + be_link_status_update(adapter, link_status); /* link_speed is in units of 10 Mbps */ if (link_speed) { @@ -453,16 +523,13 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) return 0; } -static void -be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) +static void be_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) { struct be_adapter *adapter = netdev_priv(netdev); - ring->rx_max_pending = adapter->rx_obj[0].q.len; - ring->tx_max_pending = adapter->tx_obj[0].q.len; - - ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used); - ring->tx_pending = atomic_read(&adapter->tx_obj[0].q.used); + ring->rx_max_pending = ring->rx_pending = adapter->rx_obj[0].q.len; + ring->tx_max_pending = ring->tx_pending = adapter->tx_obj[0].q.len; } static void @@ -636,7 +703,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) } if (be_cmd_link_status_query(adapter, &mac_speed, - &qos_link_speed, 0) != 0) { + &qos_link_speed, NULL, 0) != 0) { test->flags |= ETH_TEST_FL_FAILED; data[4] = -1; } else if (!mac_speed) { @@ -660,7 +727,17 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) static int be_get_eeprom_len(struct net_device *netdev) { - return BE_READ_SEEPROM_LEN; + struct be_adapter *adapter = netdev_priv(netdev); + if (lancer_chip(adapter)) { + if (be_physfn(adapter)) + return lancer_cmd_get_file_len(adapter, + LANCER_VPD_PF_FILE); + else + return lancer_cmd_get_file_len(adapter, + LANCER_VPD_VF_FILE); + } else { + return BE_READ_SEEPROM_LEN; + } } static int @@ -675,6 +752,15 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, if (!eeprom->len) return -EINVAL; + if (lancer_chip(adapter)) { + if (be_physfn(adapter)) + return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE, + eeprom->len, data); + else + return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE, + eeprom->len, data); + } + eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16); memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index bf266a00c77..a6bcdb5cd2b 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -27,13 +27,14 @@ MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); MODULE_AUTHOR("ServerEngines Corporation"); MODULE_LICENSE("GPL"); -static ushort rx_frag_size = 2048; static unsigned int num_vfs; -module_param(rx_frag_size, ushort, S_IRUGO); module_param(num_vfs, uint, S_IRUGO); -MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); +static ushort rx_frag_size = 2048; +module_param(rx_frag_size, ushort, S_IRUGO); +MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); + static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, @@ -41,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)}, + { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID5)}, { 0 } }; MODULE_DEVICE_TABLE(pci, be_dev_ids); @@ -237,7 +239,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) return -EADDRNOTAVAIL; status = be_cmd_mac_addr_query(adapter, current_mac, - MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); + MAC_ADDRESS_TYPE_NETWORK, false, + adapter->if_handle, 0); if (status) goto err; @@ -315,6 +318,8 @@ static void populate_be3_stats(struct be_adapter *adapter) struct be_drv_stats *drvs = &adapter->drv_stats; be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats)); + drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop; + drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames; drvs->rx_pause_frames = port_stats->rx_pause_frames; drvs->rx_crc_errors = port_stats->rx_crc_errors; drvs->rx_control_frames = port_stats->rx_control_frames; @@ -491,19 +496,19 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, return stats; } -void be_link_status_update(struct be_adapter *adapter, u32 link_status) +void be_link_status_update(struct be_adapter *adapter, u8 link_status) { struct net_device *netdev = adapter->netdev; - /* when link status changes, link speed must be re-queried from card */ - adapter->link_speed = -1; - if ((link_status & LINK_STATUS_MASK) == LINK_UP) { - netif_carrier_on(netdev); - dev_info(&adapter->pdev->dev, "%s: Link up\n", netdev->name); - } else { + if (!(adapter->flags & BE_FLAGS_LINK_STATUS_INIT)) { netif_carrier_off(netdev); - dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name); + adapter->flags |= BE_FLAGS_LINK_STATUS_INIT; } + + if ((link_status & LINK_STATUS_MASK) == LINK_UP) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); } static void be_tx_stats_update(struct be_tx_obj *txo, @@ -549,11 +554,26 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; } +static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, + struct sk_buff *skb) +{ + u8 vlan_prio; + u16 vlan_tag; + + vlan_tag = vlan_tx_tag_get(skb); + vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + /* If vlan priority provided by OS is NOT in available bmap */ + if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) + vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | + adapter->recommended_prio; + + return vlan_tag; +} + static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, u32 wrb_cnt, u32 len) { - u8 vlan_prio = 0; - u16 vlan_tag = 0; + u16 vlan_tag; memset(hdr, 0, sizeof(*hdr)); @@ -584,12 +604,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, if (vlan_tx_tag_present(skb)) { AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); - vlan_tag = vlan_tx_tag_get(skb); - vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - /* If vlan priority provided by OS is NOT in available bmap */ - if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) - vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | - adapter->recommended_prio; + vlan_tag = be_get_tx_vlan_tag(adapter, skb); AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); } @@ -692,6 +707,25 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, u32 start = txq->head; bool dummy_wrb, stopped = false; + /* For vlan tagged pkts, BE + * 1) calculates checksum even when CSO is not requested + * 2) calculates checksum wrongly for padded pkt less than + * 60 bytes long. + * As a workaround disable TX vlan offloading in such cases. + */ + if (unlikely(vlan_tx_tag_present(skb) && + (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb)) + goto tx_drop; + + skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb)); + if (unlikely(!skb)) + goto tx_drop; + + skb->vlan_tci = 0; + } + wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); @@ -719,6 +753,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, txq->head = start; dev_kfree_skb_any(skb); } +tx_drop: return NETDEV_TX_OK; } @@ -746,15 +781,15 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) */ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) { + struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num]; u16 vtag[BE_NUM_VLANS_SUPPORTED]; u16 ntags = 0, i; int status = 0; - u32 if_handle; if (vf) { - if_handle = adapter->vf_cfg[vf_num].vf_if_handle; - vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag); - status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0); + vtag[0] = cpu_to_le16(vf_cfg->vlan_tag); + status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag, + 1, 1, 0); } /* No need to further configure vids if in promiscuous mode */ @@ -779,31 +814,48 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) return status; } -static void be_vlan_add_vid(struct net_device *netdev, u16 vid) +static int be_vlan_add_vid(struct net_device *netdev, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); + int status = 0; - adapter->vlans_added++; - if (!be_physfn(adapter)) - return; + if (!be_physfn(adapter)) { + status = -EINVAL; + goto ret; + } adapter->vlan_tag[vid] = 1; if (adapter->vlans_added <= (adapter->max_vlans + 1)) - be_vid_config(adapter, false, 0); + status = be_vid_config(adapter, false, 0); + + if (!status) + adapter->vlans_added++; + else + adapter->vlan_tag[vid] = 0; +ret: + return status; } -static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) +static int be_vlan_rem_vid(struct net_device *netdev, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); + int status = 0; - adapter->vlans_added--; - - if (!be_physfn(adapter)) - return; + if (!be_physfn(adapter)) { + status = -EINVAL; + goto ret; + } adapter->vlan_tag[vid] = 0; if (adapter->vlans_added <= adapter->max_vlans) - be_vid_config(adapter, false, 0); + status = be_vid_config(adapter, false, 0); + + if (!status) + adapter->vlans_added--; + else + adapter->vlan_tag[vid] = 1; +ret: + return status; } static void be_set_rx_mode(struct net_device *netdev) @@ -840,28 +892,30 @@ done: static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct be_adapter *adapter = netdev_priv(netdev); + struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf]; int status; - if (!adapter->sriov_enabled) + if (!sriov_enabled(adapter)) return -EPERM; - if (!is_valid_ether_addr(mac) || (vf >= num_vfs)) + if (!is_valid_ether_addr(mac) || vf >= adapter->num_vfs) return -EINVAL; - if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) - status = be_cmd_pmac_del(adapter, - adapter->vf_cfg[vf].vf_if_handle, - adapter->vf_cfg[vf].vf_pmac_id, vf + 1); + if (lancer_chip(adapter)) { + status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); + } else { + status = be_cmd_pmac_del(adapter, vf_cfg->if_handle, + vf_cfg->pmac_id, vf + 1); - status = be_cmd_pmac_add(adapter, mac, - adapter->vf_cfg[vf].vf_if_handle, - &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); + status = be_cmd_pmac_add(adapter, mac, vf_cfg->if_handle, + &vf_cfg->pmac_id, vf + 1); + } if (status) dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", mac, vf); else - memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); + memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); return status; } @@ -870,18 +924,19 @@ static int be_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *vi) { struct be_adapter *adapter = netdev_priv(netdev); + struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf]; - if (!adapter->sriov_enabled) + if (!sriov_enabled(adapter)) return -EPERM; - if (vf >= num_vfs) + if (vf >= adapter->num_vfs) return -EINVAL; vi->vf = vf; - vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate; - vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag; + vi->tx_rate = vf_cfg->tx_rate; + vi->vlan = vf_cfg->vlan_tag; vi->qos = 0; - memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN); + memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN); return 0; } @@ -892,17 +947,17 @@ static int be_set_vf_vlan(struct net_device *netdev, struct be_adapter *adapter = netdev_priv(netdev); int status = 0; - if (!adapter->sriov_enabled) + if (!sriov_enabled(adapter)) return -EPERM; - if ((vf >= num_vfs) || (vlan > 4095)) + if (vf >= adapter->num_vfs || vlan > 4095) return -EINVAL; if (vlan) { - adapter->vf_cfg[vf].vf_vlan_tag = vlan; + adapter->vf_cfg[vf].vlan_tag = vlan; adapter->vlans_added++; } else { - adapter->vf_cfg[vf].vf_vlan_tag = 0; + adapter->vf_cfg[vf].vlan_tag = 0; adapter->vlans_added--; } @@ -920,21 +975,25 @@ static int be_set_vf_tx_rate(struct net_device *netdev, struct be_adapter *adapter = netdev_priv(netdev); int status = 0; - if (!adapter->sriov_enabled) + if (!sriov_enabled(adapter)) return -EPERM; - if ((vf >= num_vfs) || (rate < 0)) + if (vf >= adapter->num_vfs) return -EINVAL; - if (rate > 10000) - rate = 10000; + if (rate < 100 || rate > 10000) { + dev_err(&adapter->pdev->dev, + "tx rate must be between 100 and 10000 Mbps\n"); + return -EINVAL; + } - adapter->vf_cfg[vf].vf_tx_rate = rate; status = be_cmd_set_qos(adapter, rate / 10, vf + 1); if (status) - dev_info(&adapter->pdev->dev, + dev_err(&adapter->pdev->dev, "tx rate %d on VF %d failed\n", rate, vf); + else + adapter->vf_cfg[vf].tx_rate = rate; return status; } @@ -1645,8 +1704,7 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) static int be_num_txqs_want(struct be_adapter *adapter) { - if ((num_vfs && adapter->sriov_enabled) || - be_is_mc(adapter) || + if (sriov_enabled(adapter) || be_is_mc(adapter) || lancer_chip(adapter) || !be_physfn(adapter) || adapter->generation == BE_GEN2) return 1; @@ -1662,9 +1720,12 @@ static int be_tx_queues_create(struct be_adapter *adapter) u8 i; adapter->num_tx_qs = be_num_txqs_want(adapter); - if (adapter->num_tx_qs != MAX_TX_QS) + if (adapter->num_tx_qs != MAX_TX_QS) { + rtnl_lock(); netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_qs); + rtnl_unlock(); + } adapter->tx_eq.max_eqd = 0; adapter->tx_eq.min_eqd = 0; @@ -1693,9 +1754,6 @@ static int be_tx_queues_create(struct be_adapter *adapter) if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb))) goto err; - - if (be_cmd_txq_create(adapter, q, cq)) - goto err; } return 0; @@ -1728,8 +1786,8 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) static u32 be_num_rxqs_want(struct be_adapter *adapter) { if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !adapter->sriov_enabled && be_physfn(adapter) && - !be_is_mc(adapter)) { + !sriov_enabled(adapter) && be_physfn(adapter) && + !be_is_mc(adapter)) { return 1 + MAX_RSS_QS; /* one default non-RSS queue */ } else { dev_warn(&adapter->pdev->dev, @@ -1929,6 +1987,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); struct be_adapter *adapter = container_of(tx_eq, struct be_adapter, tx_eq); + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; struct be_tx_obj *txo; struct be_eth_tx_compl *txcp; int tx_compl, mcc_compl, status = 0; @@ -1965,12 +2024,19 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) mcc_compl = be_process_mcc(adapter, &status); if (mcc_compl) { - struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl); } napi_complete(napi); + /* Arm CQ again to regenerate EQEs for Lancer in INTx mode */ + if (lancer_chip(adapter) && !msix_enabled(adapter)) { + for_all_tx_queues(adapter, txo, i) + be_cq_notify(adapter, txo->cq.id, true, 0); + + be_cq_notify(adapter, mcc_obj->cq.id, true, 0); + } + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); adapter->drv_stats.tx_events++; return 1; @@ -1982,6 +2048,9 @@ void be_detect_dump_ue(struct be_adapter *adapter) u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; u32 i; + if (adapter->eeh_err || adapter->ue_detected) + return; + if (lancer_chip(adapter)) { sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); if (sliport_status & SLIPORT_STATUS_ERR_MASK) { @@ -2008,7 +2077,8 @@ void be_detect_dump_ue(struct be_adapter *adapter) sliport_status & SLIPORT_STATUS_ERR_MASK) { adapter->ue_detected = true; adapter->eeh_err = true; - dev_err(&adapter->pdev->dev, "UE Detected!!\n"); + dev_err(&adapter->pdev->dev, + "Unrecoverable error in the card\n"); } if (ue_lo) { @@ -2036,53 +2106,6 @@ void be_detect_dump_ue(struct be_adapter *adapter) } } -static void be_worker(struct work_struct *work) -{ - struct be_adapter *adapter = - container_of(work, struct be_adapter, work.work); - struct be_rx_obj *rxo; - int i; - - if (!adapter->ue_detected) - be_detect_dump_ue(adapter); - - /* when interrupts are not yet enabled, just reap any pending - * mcc completions */ - if (!netif_running(adapter->netdev)) { - int mcc_compl, status = 0; - - mcc_compl = be_process_mcc(adapter, &status); - - if (mcc_compl) { - struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; - be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); - } - - goto reschedule; - } - - if (!adapter->stats_cmd_sent) { - if (lancer_chip(adapter)) - lancer_cmd_get_pport_stats(adapter, - &adapter->stats_cmd); - else - be_cmd_get_stats(adapter, &adapter->stats_cmd); - } - - for_all_rx_queues(adapter, rxo, i) { - be_rx_eqd_update(adapter, rxo); - - if (rxo->rx_post_starved) { - rxo->rx_post_starved = false; - be_post_rx_frags(rxo, GFP_KERNEL); - } - } - -reschedule: - adapter->work_counter++; - schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); -} - static void be_msix_disable(struct be_adapter *adapter) { if (msix_enabled(adapter)) { @@ -2119,27 +2142,28 @@ done: static int be_sriov_enable(struct be_adapter *adapter) { be_check_sriov_fn_type(adapter); + #ifdef CONFIG_PCI_IOV if (be_physfn(adapter) && num_vfs) { int status, pos; - u16 nvfs; + u16 dev_vfs; pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV); pci_read_config_word(adapter->pdev, - pos + PCI_SRIOV_TOTAL_VF, &nvfs); + pos + PCI_SRIOV_TOTAL_VF, &dev_vfs); - if (num_vfs > nvfs) { + adapter->num_vfs = min_t(u16, num_vfs, dev_vfs); + if (adapter->num_vfs != num_vfs) dev_info(&adapter->pdev->dev, - "Device supports %d VFs and not %d\n", - nvfs, num_vfs); - num_vfs = nvfs; - } + "Device supports %d VFs and not %d\n", + adapter->num_vfs, num_vfs); - status = pci_enable_sriov(adapter->pdev, num_vfs); - adapter->sriov_enabled = status ? false : true; + status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); + if (status) + adapter->num_vfs = 0; - if (adapter->sriov_enabled) { + if (adapter->num_vfs) { adapter->vf_cfg = kcalloc(num_vfs, sizeof(struct be_vf_cfg), GFP_KERNEL); @@ -2154,10 +2178,10 @@ static int be_sriov_enable(struct be_adapter *adapter) static void be_sriov_disable(struct be_adapter *adapter) { #ifdef CONFIG_PCI_IOV - if (adapter->sriov_enabled) { + if (sriov_enabled(adapter)) { pci_disable_sriov(adapter->pdev); kfree(adapter->vf_cfg); - adapter->sriov_enabled = false; + adapter->num_vfs = 0; } #endif } @@ -2351,8 +2375,8 @@ static int be_close(struct net_device *netdev) static int be_rx_queues_setup(struct be_adapter *adapter) { struct be_rx_obj *rxo; - int rc, i; - u8 rsstable[MAX_RSS_QS]; + int rc, i, j; + u8 rsstable[128]; for_all_rx_queues(adapter, rxo, i) { rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, @@ -2364,11 +2388,15 @@ static int be_rx_queues_setup(struct be_adapter *adapter) } if (be_multi_rxq(adapter)) { - for_all_rss_queues(adapter, rxo, i) - rsstable[i] = rxo->rss_id; + for (j = 0; j < 128; j += adapter->num_rx_qs - 1) { + for_all_rss_queues(adapter, rxo, i) { + if ((j + i) >= 128) + break; + rsstable[j + i] = rxo->rss_id; + } + } + rc = be_cmd_rss_config(adapter, rsstable, 128); - rc = be_cmd_rss_config(adapter, rsstable, - adapter->num_rx_qs - 1); if (rc) return rc; } @@ -2386,6 +2414,7 @@ static int be_open(struct net_device *netdev) struct be_adapter *adapter = netdev_priv(netdev); struct be_eq_obj *tx_eq = &adapter->tx_eq; struct be_rx_obj *rxo; + u8 link_status; int status, i; status = be_rx_queues_setup(adapter); @@ -2409,6 +2438,11 @@ static int be_open(struct net_device *netdev) /* Now that interrupts are on we can process async mcc */ be_async_mcc_enable(adapter); + status = be_cmd_link_status_query(adapter, NULL, NULL, + &link_status, 0); + if (!status) + be_link_status_update(adapter, link_status); + return 0; err: be_close(adapter->netdev); @@ -2465,19 +2499,24 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) u32 vf; int status = 0; u8 mac[ETH_ALEN]; + struct be_vf_cfg *vf_cfg; be_vf_eth_addr_generate(adapter, mac); - for (vf = 0; vf < num_vfs; vf++) { - status = be_cmd_pmac_add(adapter, mac, - adapter->vf_cfg[vf].vf_if_handle, - &adapter->vf_cfg[vf].vf_pmac_id, - vf + 1); + for_all_vfs(adapter, vf_cfg, vf) { + if (lancer_chip(adapter)) { + status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); + } else { + status = be_cmd_pmac_add(adapter, mac, + vf_cfg->if_handle, + &vf_cfg->pmac_id, vf + 1); + } + if (status) dev_err(&adapter->pdev->dev, - "Mac address add failed for VF %d\n", vf); + "Mac address assignment failed for VF %d\n", vf); else - memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); + memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); mac[5] += 1; } @@ -2486,24 +2525,23 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) static void be_vf_clear(struct be_adapter *adapter) { + struct be_vf_cfg *vf_cfg; u32 vf; - for (vf = 0; vf < num_vfs; vf++) { - if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) - be_cmd_pmac_del(adapter, - adapter->vf_cfg[vf].vf_if_handle, - adapter->vf_cfg[vf].vf_pmac_id, vf + 1); - } + for_all_vfs(adapter, vf_cfg, vf) { + if (lancer_chip(adapter)) + be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); + else + be_cmd_pmac_del(adapter, vf_cfg->if_handle, + vf_cfg->pmac_id, vf + 1); - for (vf = 0; vf < num_vfs; vf++) - if (adapter->vf_cfg[vf].vf_if_handle) - be_cmd_if_destroy(adapter, - adapter->vf_cfg[vf].vf_if_handle, vf + 1); + be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1); + } } static int be_clear(struct be_adapter *adapter) { - if (be_physfn(adapter) && adapter->sriov_enabled) + if (sriov_enabled(adapter)) be_vf_clear(adapter); be_cmd_if_destroy(adapter, adapter->if_handle, 0); @@ -2511,61 +2549,94 @@ static int be_clear(struct be_adapter *adapter) be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); - adapter->eq_next_idx = 0; - - adapter->be3_native = false; - adapter->promiscuous = false; /* tell fw we're done with firing cmds */ be_cmd_fw_clean(adapter); return 0; } +static void be_vf_setup_init(struct be_adapter *adapter) +{ + struct be_vf_cfg *vf_cfg; + int vf; + + for_all_vfs(adapter, vf_cfg, vf) { + vf_cfg->if_handle = -1; + vf_cfg->pmac_id = -1; + } +} + static int be_vf_setup(struct be_adapter *adapter) { + struct be_vf_cfg *vf_cfg; u32 cap_flags, en_flags, vf; u16 lnk_speed; int status; - cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST; - for (vf = 0; vf < num_vfs; vf++) { + be_vf_setup_init(adapter); + + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST; + for_all_vfs(adapter, vf_cfg, vf) { status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, - &adapter->vf_cfg[vf].vf_if_handle, - NULL, vf+1); + &vf_cfg->if_handle, NULL, vf + 1); if (status) goto err; - adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID; } - if (!lancer_chip(adapter)) { - status = be_vf_eth_addr_config(adapter); - if (status) - goto err; - } + status = be_vf_eth_addr_config(adapter); + if (status) + goto err; - for (vf = 0; vf < num_vfs; vf++) { + for_all_vfs(adapter, vf_cfg, vf) { status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, - vf + 1); + NULL, vf + 1); if (status) goto err; - adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; + vf_cfg->tx_rate = lnk_speed * 10; } return 0; err: return status; } +static void be_setup_init(struct be_adapter *adapter) +{ + adapter->vlan_prio_bmap = 0xff; + adapter->link_speed = -1; + adapter->if_handle = -1; + adapter->be3_native = false; + adapter->promiscuous = false; + adapter->eq_next_idx = 0; +} + +static int be_configure_mac_from_list(struct be_adapter *adapter, u8 *mac) +{ + u32 pmac_id; + int status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id); + if (status != 0) + goto do_none; + status = be_cmd_mac_addr_query(adapter, mac, + MAC_ADDRESS_TYPE_NETWORK, + false, adapter->if_handle, pmac_id); + if (status != 0) + goto do_none; + status = be_cmd_pmac_add(adapter, mac, adapter->if_handle, + &adapter->pmac_id, 0); +do_none: + return status; +} + static int be_setup(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; u32 cap_flags, en_flags; u32 tx_fc, rx_fc; - int status; + int status, i; u8 mac[ETH_ALEN]; + struct be_tx_obj *txo; - /* Allow all priorities by default. A GRP5 evt may modify this */ - adapter->vlan_prio_bmap = 0xff; - adapter->link_speed = -1; + be_setup_init(adapter); be_cmd_req_native_mode(adapter); @@ -2583,7 +2654,7 @@ static int be_setup(struct be_adapter *adapter) memset(mac, 0, ETH_ALEN); status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, - true /*permanent */, 0); + true /*permanent */, 0, 0); if (status) return status; memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); @@ -2592,7 +2663,8 @@ static int be_setup(struct be_adapter *adapter) en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS | - BE_IF_FLAGS_PROMISCUOUS; + BE_IF_FLAGS_VLAN_PROMISCUOUS | BE_IF_FLAGS_PROMISCUOUS; + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { cap_flags |= BE_IF_FLAGS_RSS; en_flags |= BE_IF_FLAGS_RSS; @@ -2603,12 +2675,23 @@ static int be_setup(struct be_adapter *adapter) if (status != 0) goto err; - /* For BEx, the VF's permanent mac queried from card is incorrect. - * Query the mac configued by the PF using if_handle - */ - if (!be_physfn(adapter) && !lancer_chip(adapter)) { - status = be_cmd_mac_addr_query(adapter, mac, - MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); + for_all_tx_queues(adapter, txo, i) { + status = be_cmd_txq_create(adapter, &txo->q, &txo->cq); + if (status) + goto err; + } + + /* The VF's permanent mac queried from card is incorrect. + * For BEx: Query the mac configued by the PF using if_handle + * For Lancer: Get and use mac_list to obtain mac address. + */ + if (!be_physfn(adapter)) { + if (lancer_chip(adapter)) + status = be_configure_mac_from_list(adapter, mac); + else + status = be_cmd_mac_addr_query(adapter, mac, + MAC_ADDRESS_TYPE_NETWORK, false, + adapter->if_handle, 0); if (!status) { memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); @@ -2624,18 +2707,21 @@ static int be_setup(struct be_adapter *adapter) be_set_rx_mode(adapter->netdev); status = be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); - if (status) + /* For Lancer: It is legal for this cmd to fail on VF */ + if (status && (be_physfn(adapter) || !lancer_chip(adapter))) goto err; + if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) { status = be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); - if (status) + /* For Lancer: It is legal for this cmd to fail on VF */ + if (status && (be_physfn(adapter) || !lancer_chip(adapter))) goto err; } pcie_set_readrq(adapter->pdev, 4096); - if (be_physfn(adapter) && adapter->sriov_enabled) { + if (sriov_enabled(adapter)) { status = be_vf_setup(adapter); if (status) goto err; @@ -2647,6 +2733,19 @@ err: return status; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void be_netpoll(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); + struct be_rx_obj *rxo; + int i; + + event_handle(adapter, &adapter->tx_eq, false); + for_all_rx_queues(adapter, rxo, i) + event_handle(adapter, &rxo->rx_eq, true); +} +#endif + #define FW_FILE_HDR_SIGN "ServerEngines Corp. " static bool be_flash_redboot(struct be_adapter *adapter, const u8 *p, u32 img_start, int image_size, @@ -2981,7 +3080,7 @@ fw_exit: return status; } -static struct net_device_ops be_netdev_ops = { +static const struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, .ndo_start_xmit = be_xmit, @@ -2995,7 +3094,10 @@ static struct net_device_ops be_netdev_ops = { .ndo_set_vf_mac = be_set_vf_mac, .ndo_set_vf_vlan = be_set_vf_vlan, .ndo_set_vf_tx_rate = be_set_vf_tx_rate, - .ndo_get_vf_config = be_get_vf_config + .ndo_get_vf_config = be_get_vf_config, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = be_netpoll, +#endif }; static void be_netdev_init(struct net_device *netdev) @@ -3242,6 +3344,7 @@ static int be_dev_family_check(struct be_adapter *adapter) break; case BE_DEVICE_ID2: case OC_DEVICE_ID2: + case OC_DEVICE_ID5: adapter->generation = BE_GEN3; break; case OC_DEVICE_ID3: @@ -3267,7 +3370,7 @@ static int be_dev_family_check(struct be_adapter *adapter) static int lancer_wait_ready(struct be_adapter *adapter) { -#define SLIPORT_READY_TIMEOUT 500 +#define SLIPORT_READY_TIMEOUT 30 u32 sliport_status; int status = 0, i; @@ -3276,7 +3379,7 @@ static int lancer_wait_ready(struct be_adapter *adapter) if (sliport_status & SLIPORT_STATUS_RDY_MASK) break; - msleep(20); + msleep(1000); } if (i == SLIPORT_READY_TIMEOUT) @@ -3313,6 +3416,104 @@ static int lancer_test_and_set_rdy_state(struct be_adapter *adapter) return status; } +static void lancer_test_and_recover_fn_err(struct be_adapter *adapter) +{ + int status; + u32 sliport_status; + + if (adapter->eeh_err || adapter->ue_detected) + return; + + sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); + + if (sliport_status & SLIPORT_STATUS_ERR_MASK) { + dev_err(&adapter->pdev->dev, + "Adapter in error state." + "Trying to recover.\n"); + + status = lancer_test_and_set_rdy_state(adapter); + if (status) + goto err; + + netif_device_detach(adapter->netdev); + + if (netif_running(adapter->netdev)) + be_close(adapter->netdev); + + be_clear(adapter); + + adapter->fw_timeout = false; + + status = be_setup(adapter); + if (status) + goto err; + + if (netif_running(adapter->netdev)) { + status = be_open(adapter->netdev); + if (status) + goto err; + } + + netif_device_attach(adapter->netdev); + + dev_err(&adapter->pdev->dev, + "Adapter error recovery succeeded\n"); + } + return; +err: + dev_err(&adapter->pdev->dev, + "Adapter error recovery failed\n"); +} + +static void be_worker(struct work_struct *work) +{ + struct be_adapter *adapter = + container_of(work, struct be_adapter, work.work); + struct be_rx_obj *rxo; + int i; + + if (lancer_chip(adapter)) + lancer_test_and_recover_fn_err(adapter); + + be_detect_dump_ue(adapter); + + /* when interrupts are not yet enabled, just reap any pending + * mcc completions */ + if (!netif_running(adapter->netdev)) { + int mcc_compl, status = 0; + + mcc_compl = be_process_mcc(adapter, &status); + + if (mcc_compl) { + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); + } + + goto reschedule; + } + + if (!adapter->stats_cmd_sent) { + if (lancer_chip(adapter)) + lancer_cmd_get_pport_stats(adapter, + &adapter->stats_cmd); + else + be_cmd_get_stats(adapter, &adapter->stats_cmd); + } + + for_all_rx_queues(adapter, rxo, i) { + be_rx_eqd_update(adapter, rxo); + + if (rxo->rx_post_starved) { + rxo->rx_post_starved = false; + be_post_rx_frags(rxo, GFP_KERNEL); + } + } + +reschedule: + adapter->work_counter++; + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); +} + static int __devinit be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { @@ -3365,7 +3566,12 @@ static int __devinit be_probe(struct pci_dev *pdev, goto disable_sriov; if (lancer_chip(adapter)) { - status = lancer_test_and_set_rdy_state(adapter); + status = lancer_wait_ready(adapter); + if (!status) { + iowrite32(SLI_PORT_CONTROL_IP_MASK, + adapter->db + SLIPORT_CONTROL_OFFSET); + status = lancer_test_and_set_rdy_state(adapter); + } if (status) { dev_err(&pdev->dev, "Adapter in non recoverable error\n"); goto ctrl_clean; @@ -3559,6 +3765,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) dev_info(&adapter->pdev->dev, "EEH reset\n"); adapter->eeh_err = false; + adapter->ue_detected = false; + adapter->fw_timeout = false; status = pci_enable_device(pdev); if (status) |