diff options
Diffstat (limited to 'drivers/net/ethernet/emulex')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 92 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 213 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 104 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 326 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_hw.h | 80 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 590 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_roce.c | 182 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_roce.h | 75 |
9 files changed, 1311 insertions, 353 deletions
diff --git a/drivers/net/ethernet/emulex/benet/Makefile b/drivers/net/ethernet/emulex/benet/Makefile index a60cd8051135..1a91b276940d 100644 --- a/drivers/net/ethernet/emulex/benet/Makefile +++ b/drivers/net/ethernet/emulex/benet/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_BE2NET) += be2net.o -be2net-y := be_main.o be_cmds.o be_ethtool.o +be2net-y := be_main.o be_cmds.o be_ethtool.o be_roce.o diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 9576ac002c23..c5c4c0e83bd1 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -32,8 +32,9 @@ #include <linux/u64_stats_sync.h> #include "be_hw.h" +#include "be_roce.h" -#define DRV_VER "4.2.116u" +#define DRV_VER "4.2.220u" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" @@ -102,7 +103,8 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ #define MAX_TX_QS 8 -#define MAX_MSIX_VECTORS MAX_RSS_QS +#define MAX_ROCE_EQS 5 +#define MAX_MSIX_VECTORS (MAX_RSS_QS + MAX_ROCE_EQS) /* RSS qs + RoCE */ #define BE_TX_BUDGET 256 #define BE_NAPI_WEIGHT 64 #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ @@ -162,6 +164,11 @@ static inline void queue_head_inc(struct be_queue_info *q) index_inc(&q->head, q->len); } +static inline void index_dec(u16 *index, u16 limit) +{ + *index = MODULO((*index - 1), limit); +} + static inline void queue_tail_inc(struct be_queue_info *q) { index_inc(&q->tail, q->len); @@ -308,11 +315,33 @@ struct be_vf_cfg { u32 tx_rate; }; +enum vf_state { + ENABLED = 0, + ASSIGNED = 1 +}; + #define BE_FLAGS_LINK_STATUS_INIT 1 #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 +struct phy_info { + u8 transceiver; + u8 autoneg; + u8 fc_autoneg; + u8 port_type; + u16 phy_type; + u16 interface_type; + u32 misc_params; + u16 auto_speeds_supported; + u16 fixed_speeds_supported; + int link_speed; + int forced_port_speed; + u32 dac_cable_len; + u32 advertising; + u32 supported; +}; + struct be_adapter { struct pci_dev *pdev; struct net_device *netdev; @@ -377,29 +406,41 @@ struct be_adapter { u32 rx_fc; /* Rx flow control */ u32 tx_fc; /* Tx flow control */ bool stats_cmd_sent; - int link_speed; - u8 port_type; - u8 transceiver; - u8 autoneg; u8 generation; /* BladeEngine ASIC generation */ + u32 if_type; + struct { + u8 __iomem *base; /* Door Bell */ + u32 size; + u32 total_size; + u64 io_addr; + } roce_db; + u32 num_msix_roce_vec; + struct ocrdma_dev *ocrdma_dev; + struct list_head entry; + u32 flash_status; struct completion flash_compl; - u32 num_vfs; - u8 is_virtfn; + u32 num_vfs; /* Number of VFs provisioned by PF driver */ + u32 dev_num_vfs; /* Number of VFs supported by HW */ + u8 virtfn; struct be_vf_cfg *vf_cfg; bool be3_native; u32 sli_family; u8 hba_port_num; u16 pvid; + struct phy_info phy; u8 wol_cap; bool wol; u32 max_pmac_cnt; /* Max secondary UC MACs programmable */ u32 uc_macs; /* Count of secondary UC MAC programmed */ + u32 msg_enable; }; -#define be_physfn(adapter) (!adapter->is_virtfn) +#define be_physfn(adapter) (!adapter->virtfn) #define sriov_enabled(adapter) (adapter->num_vfs > 0) +#define sriov_want(adapter) (adapter->dev_num_vfs && num_vfs && \ + be_physfn(adapter)) #define for_all_vfs(adapter, vf_cfg, i) \ for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ i++, vf_cfg++) @@ -413,6 +454,10 @@ struct be_adapter { #define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \ (adapter->pdev->device == OC_DEVICE_ID4)) +#define be_roce_supported(adapter) ((adapter->if_type == SLI_INTF_TYPE_3 || \ + adapter->sli_family == SKYHAWK_SLI_FAMILY) && \ + (adapter->function_mode & RDMA_ENABLED)) + extern const struct ethtool_ops be_ethtool_ops; #define msix_enabled(adapter) (adapter->num_msix_vec > 0) @@ -528,14 +573,6 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) return val; } -static inline void be_check_sriov_fn_type(struct be_adapter *adapter) -{ - u32 sli_intf; - - pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); - adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; -} - static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) { u32 addr; @@ -577,10 +614,31 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter) } } +static inline bool be_type_2_3(struct be_adapter *adapter) +{ + return (adapter->if_type == SLI_INTF_TYPE_2 || + adapter->if_type == SLI_INTF_TYPE_3) ? true : false; +} + 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, u8 link_status); extern void be_parse_stats(struct be_adapter *adapter); extern int be_load_fw(struct be_adapter *adapter, u8 *func); extern bool be_is_wol_supported(struct be_adapter *adapter); +extern bool be_pause_supported(struct be_adapter *adapter); +extern u32 be_get_fw_log_level(struct be_adapter *adapter); + +/* + * internal function to initialize-cleanup roce device. + */ +extern void be_roce_dev_add(struct be_adapter *); +extern void be_roce_dev_remove(struct be_adapter *); + +/* + * internal function to open-close roce device during ifup-ifdown. + */ +extern void be_roce_dev_open(struct be_adapter *); +extern void be_roce_dev_close(struct be_adapter *); + #endif /* BE_H */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 67b030d72df1..921c2082af4c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -15,6 +15,7 @@ * Costa Mesa, CA 92626 */ +#include <linux/module.h> #include "be.h" #include "be_cmds.h" @@ -61,10 +62,21 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl) compl->flags = 0; } +static struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1) +{ + unsigned long addr; + + addr = tag1; + addr = ((addr << 16) << 16) | tag0; + return (void *)addr; +} + static int be_mcc_compl_process(struct be_adapter *adapter, - struct be_mcc_compl *compl) + struct be_mcc_compl *compl) { u16 compl_status, extd_status; + struct be_cmd_resp_hdr *resp_hdr; + u8 opcode = 0, subsystem = 0; /* Just swap the status to host endian; mcc tag is opaquely copied * from mcc_wrb */ @@ -73,32 +85,36 @@ static int be_mcc_compl_process(struct be_adapter *adapter, compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & CQE_STATUS_COMPL_MASK; - if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) || - (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) && - (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { + resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1); + + if (resp_hdr) { + opcode = resp_hdr->opcode; + subsystem = resp_hdr->subsystem; + } + + if (((opcode == OPCODE_COMMON_WRITE_FLASHROM) || + (opcode == OPCODE_COMMON_WRITE_OBJECT)) && + (subsystem == CMD_SUBSYSTEM_COMMON)) { adapter->flash_status = compl_status; complete(&adapter->flash_compl); } if (compl_status == MCC_STATUS_SUCCESS) { - if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) || - (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) && - (compl->tag1 == CMD_SUBSYSTEM_ETH)) { + if (((opcode == OPCODE_ETH_GET_STATISTICS) || + (opcode == OPCODE_ETH_GET_PPORT_STATS)) && + (subsystem == CMD_SUBSYSTEM_ETH)) { be_parse_stats(adapter); adapter->stats_cmd_sent = false; } - if (compl->tag0 == - OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) { - struct be_mcc_wrb *mcc_wrb = - queue_index_node(&adapter->mcc_obj.q, - compl->tag1); + if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES && + subsystem == CMD_SUBSYSTEM_COMMON) { struct be_cmd_resp_get_cntl_addnl_attribs *resp = - embedded_payload(mcc_wrb); + (void *)resp_hdr; adapter->drv_stats.be_on_die_temperature = resp->on_die_temperature; } } else { - if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) + if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) be_get_temp_freq = 0; if (compl_status == MCC_STATUS_NOT_SUPPORTED || @@ -106,15 +122,15 @@ static int be_mcc_compl_process(struct be_adapter *adapter, goto done; if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) { - dev_warn(&adapter->pdev->dev, "This domain(VM) is not " - "permitted to execute this cmd (opcode %d)\n", - compl->tag0); + dev_warn(&adapter->pdev->dev, + "opcode %d-%d is not permitted\n", + opcode, subsystem); } else { extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & CQE_STATUS_EXTD_MASK; - dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:" - "status %d, extd-status %d\n", - compl->tag0, compl_status, extd_status); + dev_err(&adapter->pdev->dev, + "opcode %d-%d failed:status %d-%d\n", + opcode, subsystem, compl_status, extd_status); } } done: @@ -126,7 +142,7 @@ static void be_async_link_state_process(struct be_adapter *adapter, struct be_async_event_link_state *evt) { /* When link status changes, link speed must be re-queried from FW */ - adapter->link_speed = -1; + adapter->phy.link_speed = -1; /* For the initial link status do not rely on the ASYNC event as * it may not be received in some cases. @@ -153,7 +169,7 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, { if (evt->physical_port == adapter->port_num) { /* qos_link_speed is in units of 10 Mbps */ - adapter->link_speed = evt->qos_link_speed * 10; + adapter->phy.link_speed = evt->qos_link_speed * 10; } } @@ -286,7 +302,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) if (i == mcc_timeout) { dev_err(&adapter->pdev->dev, "FW not responding\n"); adapter->fw_timeout = true; - return -1; + return -EIO; } return status; } @@ -294,8 +310,26 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) /* Notify MCC requests and wait for completion */ static int be_mcc_notify_wait(struct be_adapter *adapter) { + int status; + struct be_mcc_wrb *wrb; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + u16 index = mcc_obj->q.head; + struct be_cmd_resp_hdr *resp; + + index_dec(&index, mcc_obj->q.len); + wrb = queue_index_node(&mcc_obj->q, index); + + resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1); + be_mcc_notify(adapter); - return be_mcc_wait_compl(adapter); + + status = be_mcc_wait_compl(adapter); + if (status == -EIO) + goto out; + + status = resp->status; +out: + return status; } static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) @@ -435,14 +469,17 @@ static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, struct be_mcc_wrb *wrb, struct be_dma_mem *mem) { struct be_sge *sge; + unsigned long addr = (unsigned long)req_hdr; + u64 req_addr = addr; req_hdr->opcode = opcode; req_hdr->subsystem = subsystem; req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); req_hdr->version = 0; - wrb->tag0 = opcode; - wrb->tag1 = subsystem; + wrb->tag0 = req_addr & 0xFFFFFFFF; + wrb->tag1 = upper_32_bits(req_addr); + wrb->payload_length = cmd_len; if (mem) { wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) << @@ -1221,7 +1258,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter, OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size, wrb, nonemb_cmd); - req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num); + req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); req->cmd_params.params.reset_stats = 0; be_mcc_notify(adapter); @@ -1283,13 +1320,10 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_cntl_addnl_attribs *req; - u16 mccq_index; int status; spin_lock_bh(&adapter->mcc_lock); - mccq_index = adapter->mcc_obj.q.head; - wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; @@ -1301,8 +1335,6 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req), wrb, NULL); - wrb->tag1 = mccq_index; - be_mcc_notify(adapter); err: @@ -1824,18 +1856,16 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->flash_compl, - msecs_to_jiffies(12000))) + msecs_to_jiffies(30000))) status = -1; else status = adapter->flash_status; resp = embedded_payload(wrb); - if (!status) { + if (!status) *data_written = le32_to_cpu(resp->actual_write_len); - } else { + else *addn_status = resp->additional_status; - status = resp->status; - } return status; @@ -1950,7 +1980,7 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4, wrb, NULL); - req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT); + req->params.op_type = cpu_to_le32(OPTYPE_REDBOOT); req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); req->params.offset = cpu_to_le32(offset); req->params.data_buf_size = cpu_to_le32(0x4); @@ -2136,8 +2166,7 @@ err: return status; } -int be_cmd_get_phy_info(struct be_adapter *adapter, - struct be_phy_info *phy_info) +int be_cmd_get_phy_info(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_phy_info *req; @@ -2170,9 +2199,15 @@ int be_cmd_get_phy_info(struct be_adapter *adapter, if (!status) { struct be_phy_info *resp_phy_info = cmd.va + sizeof(struct be_cmd_req_hdr); - phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type); - phy_info->interface_type = + adapter->phy.phy_type = le16_to_cpu(resp_phy_info->phy_type); + adapter->phy.interface_type = le16_to_cpu(resp_phy_info->interface_type); + adapter->phy.auto_speeds_supported = + le16_to_cpu(resp_phy_info->auto_speeds_supported); + adapter->phy.fixed_speeds_supported = + le16_to_cpu(resp_phy_info->fixed_speeds_supported); + adapter->phy.misc_params = + le32_to_cpu(resp_phy_info->misc_params); } pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); @@ -2555,4 +2590,98 @@ err: mutex_unlock(&adapter->mbox_lock); pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; + +} +int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, + struct be_dma_mem *cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_ext_fat_caps *req; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = cmd->va; + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_EXT_FAT_CAPABILITES, + cmd->size, wrb, cmd); + req->parameter_type = cpu_to_le32(1); + + status = be_mbox_notify_wait(adapter); +err: + mutex_unlock(&adapter->mbox_lock); + return status; +} + +int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, + struct be_dma_mem *cmd, + struct be_fat_conf_params *configs) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_ext_fat_caps *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = cmd->va; + memcpy(&req->set_params, configs, sizeof(struct be_fat_conf_params)); + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_EXT_FAT_CAPABILITES, + cmd->size, wrb, cmd); + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, + int wrb_payload_size, u16 *cmd_status, u16 *ext_status) +{ + struct be_adapter *adapter = netdev_priv(netdev_handle); + struct be_mcc_wrb *wrb; + struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *) wrb_payload; + struct be_cmd_req_hdr *req; + struct be_cmd_resp_hdr *resp; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + resp = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(req, hdr->subsystem, + hdr->opcode, wrb_payload_size, wrb, NULL); + memcpy(req, wrb_payload, wrb_payload_size); + be_dws_cpu_to_le(req, wrb_payload_size); + + status = be_mcc_notify_wait(adapter); + if (cmd_status) + *cmd_status = (status & 0xffff); + if (ext_status) + *ext_status = 0; + memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length); + be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; } +EXPORT_SYMBOL(be_roce_mcc_cmd); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index d5b680c56af0..b3f3fc3d1323 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -189,6 +189,8 @@ 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_EXT_FAT_CAPABILITES 125 +#define OPCODE_COMMON_SET_EXT_FAT_CAPABILITES 126 #define OPCODE_COMMON_GET_MAC_LIST 147 #define OPCODE_COMMON_SET_MAC_LIST 148 #define OPCODE_COMMON_GET_HSW_CONFIG 152 @@ -225,8 +227,12 @@ struct be_cmd_req_hdr { #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ #define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */ struct be_cmd_resp_hdr { - u32 info; /* dword 0 */ - u32 status; /* dword 1 */ + u8 opcode; /* dword 0 */ + u8 subsystem; /* dword 0 */ + u8 rsvd[2]; /* dword 0 */ + u8 status; /* dword 1 */ + u8 add_status; /* dword 1 */ + u8 rsvd1[2]; /* dword 1 */ u32 response_length; /* dword 2 */ u32 actual_resp_len; /* dword 3 */ }; @@ -1056,6 +1062,7 @@ struct be_cmd_resp_modify_eq_delay { /* The HW can come up in either of the following multi-channel modes * based on the skew/IPL. */ +#define RDMA_ENABLED 0x4 #define FLEX10_MODE 0x400 #define VNIC_MODE 0x20000 #define UMC_ENABLED 0x1000000 @@ -1309,9 +1316,36 @@ enum { PHY_TYPE_KX4_10GB, PHY_TYPE_BASET_10GB, PHY_TYPE_BASET_1GB, + PHY_TYPE_BASEX_1GB, + PHY_TYPE_SGMII, PHY_TYPE_DISABLED = 255 }; +#define BE_SUPPORTED_SPEED_NONE 0 +#define BE_SUPPORTED_SPEED_10MBPS 1 +#define BE_SUPPORTED_SPEED_100MBPS 2 +#define BE_SUPPORTED_SPEED_1GBPS 4 +#define BE_SUPPORTED_SPEED_10GBPS 8 + +#define BE_AN_EN 0x2 +#define BE_PAUSE_SYM_EN 0x80 + +/* MAC speed valid values */ +#define SPEED_DEFAULT 0x0 +#define SPEED_FORCED_10GB 0x1 +#define SPEED_FORCED_1GB 0x2 +#define SPEED_AUTONEG_10GB 0x3 +#define SPEED_AUTONEG_1GB 0x4 +#define SPEED_AUTONEG_100MB 0x5 +#define SPEED_AUTONEG_10GB_1GB 0x6 +#define SPEED_AUTONEG_10GB_1GB_100MB 0x7 +#define SPEED_AUTONEG_1GB_100MB 0x8 +#define SPEED_AUTONEG_10MB 0x9 +#define SPEED_AUTONEG_1GB_100MB_10MB 0xa +#define SPEED_AUTONEG_100MB_10MB 0xb +#define SPEED_FORCED_100MB 0xc +#define SPEED_FORCED_10MB 0xd + struct be_cmd_req_get_phy_info { struct be_cmd_req_hdr hdr; u8 rsvd0[24]; @@ -1321,7 +1355,11 @@ struct be_phy_info { u16 phy_type; u16 interface_type; u32 misc_params; - u32 future_use[4]; + u16 ext_phy_details; + u16 rsvd; + u16 auto_speeds_supported; + u16 fixed_speeds_supported; + u32 future_use[2]; }; struct be_cmd_resp_get_phy_info { @@ -1528,7 +1566,7 @@ struct be_hw_stats_v1 { u32 rsvd0[BE_TXP_SW_SZ]; struct be_erx_stats_v1 erx; struct be_pmem_stats pmem; - u32 rsvd1[3]; + u32 rsvd1[18]; }; struct be_cmd_req_get_stats_v1 { @@ -1567,6 +1605,56 @@ static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) } } + +/************** get fat capabilites *******************/ +#define MAX_MODULES 27 +#define MAX_MODES 4 +#define MODE_UART 0 +#define FW_LOG_LEVEL_DEFAULT 48 +#define FW_LOG_LEVEL_FATAL 64 + +struct ext_fat_mode { + u8 mode; + u8 rsvd0; + u16 port_mask; + u32 dbg_lvl; + u64 fun_mask; +} __packed; + +struct ext_fat_modules { + u8 modules_str[32]; + u32 modules_id; + u32 num_modes; + struct ext_fat_mode trace_lvl[MAX_MODES]; +} __packed; + +struct be_fat_conf_params { + u32 max_log_entries; + u32 log_entry_size; + u8 log_type; + u8 max_log_funs; + u8 max_log_ports; + u8 rsvd0; + u32 supp_modes; + u32 num_modules; + struct ext_fat_modules module[MAX_MODULES]; +} __packed; + +struct be_cmd_req_get_ext_fat_caps { + struct be_cmd_req_hdr hdr; + u32 parameter_type; +}; + +struct be_cmd_resp_get_ext_fat_caps { + struct be_cmd_resp_hdr hdr; + struct be_fat_conf_params get_params; +}; + +struct be_cmd_req_set_ext_fat_caps { + struct be_cmd_req_hdr hdr; + struct be_fat_conf_params set_params; +}; + 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, @@ -1655,8 +1743,7 @@ extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, u8 loopback_type, u8 enable); -extern int be_cmd_get_phy_info(struct be_adapter *adapter, - struct be_phy_info *phy_info); +extern int be_cmd_get_phy_info(struct be_adapter *adapter); extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain); extern void be_detect_dump_ue(struct be_adapter *adapter); extern int be_cmd_get_die_temperature(struct be_adapter *adapter); @@ -1673,4 +1760,9 @@ extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, u32 domain, u16 intf_id); extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); +extern int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, + struct be_dma_mem *cmd); +extern int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, + struct be_dma_mem *cmd, + struct be_fat_conf_params *cfgs); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index c1ff73cb0e62..63e51d476900 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -433,102 +433,193 @@ static int be_get_sset_count(struct net_device *netdev, int stringset) } } +static u32 be_get_port_type(u32 phy_type, u32 dac_cable_len) +{ + u32 port; + + switch (phy_type) { + case PHY_TYPE_BASET_1GB: + case PHY_TYPE_BASEX_1GB: + case PHY_TYPE_SGMII: + port = PORT_TP; + break; + case PHY_TYPE_SFP_PLUS_10GB: + port = dac_cable_len ? PORT_DA : PORT_FIBRE; + break; + case PHY_TYPE_XFP_10GB: + case PHY_TYPE_SFP_1GB: + port = PORT_FIBRE; + break; + case PHY_TYPE_BASET_10GB: + port = PORT_TP; + break; + default: + port = PORT_OTHER; + } + + return port; +} + +static u32 convert_to_et_setting(u32 if_type, u32 if_speeds) +{ + u32 val = 0; + + switch (if_type) { + case PHY_TYPE_BASET_1GB: + case PHY_TYPE_BASEX_1GB: + case PHY_TYPE_SGMII: + val |= SUPPORTED_TP; + if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) + val |= SUPPORTED_1000baseT_Full; + if (if_speeds & BE_SUPPORTED_SPEED_100MBPS) + val |= SUPPORTED_100baseT_Full; + if (if_speeds & BE_SUPPORTED_SPEED_10MBPS) + val |= SUPPORTED_10baseT_Full; + break; + case PHY_TYPE_KX4_10GB: + val |= SUPPORTED_Backplane; + if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) + val |= SUPPORTED_1000baseKX_Full; + if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) + val |= SUPPORTED_10000baseKX4_Full; + break; + case PHY_TYPE_KR_10GB: + val |= SUPPORTED_Backplane | + SUPPORTED_10000baseKR_Full; + break; + case PHY_TYPE_SFP_PLUS_10GB: + case PHY_TYPE_XFP_10GB: + case PHY_TYPE_SFP_1GB: + val |= SUPPORTED_FIBRE; + if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) + val |= SUPPORTED_10000baseT_Full; + if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) + val |= SUPPORTED_1000baseT_Full; + break; + case PHY_TYPE_BASET_10GB: + val |= SUPPORTED_TP; + if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) + val |= SUPPORTED_10000baseT_Full; + if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) + val |= SUPPORTED_1000baseT_Full; + if (if_speeds & BE_SUPPORTED_SPEED_100MBPS) + val |= SUPPORTED_100baseT_Full; + break; + default: + val |= SUPPORTED_TP; + } + + return val; +} + +static int convert_to_et_speed(u32 be_speed) +{ + int et_speed = SPEED_10000; + + switch (be_speed) { + case PHY_LINK_SPEED_10MBPS: + et_speed = SPEED_10; + break; + case PHY_LINK_SPEED_100MBPS: + et_speed = SPEED_100; + break; + case PHY_LINK_SPEED_1GBPS: + et_speed = SPEED_1000; + break; + case PHY_LINK_SPEED_10GBPS: + et_speed = SPEED_10000; + break; + } + + return et_speed; +} + +bool be_pause_supported(struct be_adapter *adapter) +{ + return (adapter->phy.interface_type == PHY_TYPE_SFP_PLUS_10GB || + adapter->phy.interface_type == PHY_TYPE_XFP_10GB) ? + false : true; +} + static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_phy_info phy_info; - u8 mac_speed = 0; + u8 port_speed = 0; u16 link_speed = 0; u8 link_status; + u32 et_speed = 0; int status; - if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { - status = be_cmd_link_status_query(adapter, &mac_speed, - &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) { - ethtool_cmd_speed_set(ecmd, link_speed*10); + if (adapter->phy.link_speed < 0 || !(netdev->flags & IFF_UP)) { + if (adapter->phy.forced_port_speed < 0) { + status = be_cmd_link_status_query(adapter, &port_speed, + &link_speed, &link_status, 0); + if (!status) + be_link_status_update(adapter, link_status); + if (link_speed) + et_speed = link_speed * 10; + else if (link_status) + et_speed = convert_to_et_speed(port_speed); } else { - switch (mac_speed) { - case PHY_LINK_SPEED_10MBPS: - ethtool_cmd_speed_set(ecmd, SPEED_10); - break; - case PHY_LINK_SPEED_100MBPS: - ethtool_cmd_speed_set(ecmd, SPEED_100); - break; - case PHY_LINK_SPEED_1GBPS: - ethtool_cmd_speed_set(ecmd, SPEED_1000); - break; - case PHY_LINK_SPEED_10GBPS: - ethtool_cmd_speed_set(ecmd, SPEED_10000); - break; - case PHY_LINK_SPEED_ZERO: - ethtool_cmd_speed_set(ecmd, 0); - break; - } + et_speed = adapter->phy.forced_port_speed; } - status = be_cmd_get_phy_info(adapter, &phy_info); - if (!status) { - switch (phy_info.interface_type) { - case PHY_TYPE_XFP_10GB: - case PHY_TYPE_SFP_1GB: - case PHY_TYPE_SFP_PLUS_10GB: - ecmd->port = PORT_FIBRE; - break; - default: - ecmd->port = PORT_TP; - break; - } + ethtool_cmd_speed_set(ecmd, et_speed); + + status = be_cmd_get_phy_info(adapter); + if (status) + return status; + + ecmd->supported = + convert_to_et_setting(adapter->phy.interface_type, + adapter->phy.auto_speeds_supported | + adapter->phy.fixed_speeds_supported); + ecmd->advertising = + convert_to_et_setting(adapter->phy.interface_type, + adapter->phy.auto_speeds_supported); + + ecmd->port = be_get_port_type(adapter->phy.interface_type, + adapter->phy.dac_cable_len); + + if (adapter->phy.auto_speeds_supported) { + ecmd->supported |= SUPPORTED_Autoneg; + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= ADVERTISED_Autoneg; + } - switch (phy_info.interface_type) { - case PHY_TYPE_KR_10GB: - case PHY_TYPE_KX4_10GB: - ecmd->autoneg = AUTONEG_ENABLE; + if (be_pause_supported(adapter)) { + ecmd->supported |= SUPPORTED_Pause; + ecmd->advertising |= ADVERTISED_Pause; + } + + switch (adapter->phy.interface_type) { + case PHY_TYPE_KR_10GB: + case PHY_TYPE_KX4_10GB: ecmd->transceiver = XCVR_INTERNAL; - break; - default: - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->transceiver = XCVR_EXTERNAL; - break; - } + break; + default: + ecmd->transceiver = XCVR_EXTERNAL; + break; } /* Save for future use */ - adapter->link_speed = ethtool_cmd_speed(ecmd); - adapter->port_type = ecmd->port; - adapter->transceiver = ecmd->transceiver; - adapter->autoneg = ecmd->autoneg; + adapter->phy.link_speed = ethtool_cmd_speed(ecmd); + adapter->phy.port_type = ecmd->port; + adapter->phy.transceiver = ecmd->transceiver; + adapter->phy.autoneg = ecmd->autoneg; + adapter->phy.advertising = ecmd->advertising; + adapter->phy.supported = ecmd->supported; } else { - ethtool_cmd_speed_set(ecmd, adapter->link_speed); - ecmd->port = adapter->port_type; - ecmd->transceiver = adapter->transceiver; - ecmd->autoneg = adapter->autoneg; + ethtool_cmd_speed_set(ecmd, adapter->phy.link_speed); + ecmd->port = adapter->phy.port_type; + ecmd->transceiver = adapter->phy.transceiver; + ecmd->autoneg = adapter->phy.autoneg; + ecmd->advertising = adapter->phy.advertising; + ecmd->supported = adapter->phy.supported; } - ecmd->duplex = DUPLEX_FULL; + ecmd->duplex = netif_carrier_ok(netdev) ? DUPLEX_FULL : DUPLEX_UNKNOWN; ecmd->phy_address = adapter->port_num; - switch (ecmd->port) { - case PORT_FIBRE: - ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); - break; - case PORT_TP: - ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); - break; - case PORT_AUI: - ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_AUI); - break; - } - - if (ecmd->autoneg) { - ecmd->supported |= SUPPORTED_1000baseT_Full; - ecmd->supported |= SUPPORTED_Autoneg; - ecmd->advertising |= (ADVERTISED_10000baseT_Full | - ADVERTISED_1000baseT_Full); - } return 0; } @@ -548,7 +639,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) struct be_adapter *adapter = netdev_priv(netdev); be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause); - ecmd->autoneg = 0; + ecmd->autoneg = adapter->phy.fc_autoneg; } static int @@ -702,7 +793,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) } } - if (be_test_ddr_dma(adapter) != 0) { + if (!lancer_chip(adapter) && be_test_ddr_dma(adapter) != 0) { data[3] = 1; test->flags |= ETH_TEST_FL_FAILED; } @@ -787,6 +878,81 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, return status; } +static u32 be_get_msg_level(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + if (lancer_chip(adapter)) { + dev_err(&adapter->pdev->dev, "Operation not supported\n"); + return -EOPNOTSUPP; + } + + return adapter->msg_enable; +} + +static void be_set_fw_log_level(struct be_adapter *adapter, u32 level) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status; + int i, j; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + if (!extfat_cmd.va) { + dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", + __func__); + goto err; + } + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (!status) { + cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + + sizeof(struct be_cmd_resp_hdr)); + for (i = 0; i < cfgs->num_modules; i++) { + for (j = 0; j < cfgs->module[i].num_modes; j++) { + if (cfgs->module[i].trace_lvl[j].mode == + MODE_UART) + cfgs->module[i].trace_lvl[j].dbg_lvl = + cpu_to_le32(level); + } + } + status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, + cfgs); + if (status) + dev_err(&adapter->pdev->dev, + "Message level set failed\n"); + } else { + dev_err(&adapter->pdev->dev, "Message level get failed\n"); + } + + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); +err: + return; +} + +static void be_set_msg_level(struct net_device *netdev, u32 level) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + if (lancer_chip(adapter)) { + dev_err(&adapter->pdev->dev, "Operation not supported\n"); + return; + } + + if (adapter->msg_enable == level) + return; + + if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW)) + be_set_fw_log_level(adapter, level & NETIF_MSG_HW ? + FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL); + adapter->msg_enable = level; + + return; +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -802,6 +968,8 @@ const struct ethtool_ops be_ethtool_ops = { .set_pauseparam = be_set_pauseparam, .get_strings = be_get_stat_strings, .set_phys_id = be_set_phys_id, + .get_msglevel = be_get_msg_level, + .set_msglevel = be_set_msg_level, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, .get_regs_len = be_get_reg_len, diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index f2c89e3ccabd..d9fb0c501fa1 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -58,6 +58,8 @@ #define SLI_PORT_CONTROL_IP_MASK 0x08000000 +#define PCICFG_CUST_SCRATCHPAD_CSR 0x1EC + /********* Memory BAR register ************/ #define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt @@ -98,11 +100,13 @@ #define SLI_INTF_REV_SHIFT 4 #define SLI_INTF_FT_MASK 0x00000001 +#define SLI_INTF_TYPE_2 2 +#define SLI_INTF_TYPE_3 3 /* SLI family */ #define BE_SLI_FAMILY 0x0 #define LANCER_A0_SLI_FAMILY 0xA - +#define SKYHAWK_SLI_FAMILY 0x2 /********* ISR0 Register offset **********/ #define CEV_ISR0_OFFSET 0xC18 @@ -162,22 +166,23 @@ #define QUERY_FAT 1 /* Flashrom related descriptors */ +#define MAX_FLASH_COMP 32 #define IMAGE_TYPE_FIRMWARE 160 #define IMAGE_TYPE_BOOTCODE 224 #define IMAGE_TYPE_OPTIONROM 32 #define NUM_FLASHDIR_ENTRIES 32 -#define IMG_TYPE_ISCSI_ACTIVE 0 -#define IMG_TYPE_REDBOOT 1 -#define IMG_TYPE_BIOS 2 -#define IMG_TYPE_PXE_BIOS 3 -#define IMG_TYPE_FCOE_BIOS 8 -#define IMG_TYPE_ISCSI_BACKUP 9 -#define IMG_TYPE_FCOE_FW_ACTIVE 10 -#define IMG_TYPE_FCOE_FW_BACKUP 11 -#define IMG_TYPE_NCSI_FW 13 -#define IMG_TYPE_PHY_FW 99 +#define OPTYPE_ISCSI_ACTIVE 0 +#define OPTYPE_REDBOOT 1 +#define OPTYPE_BIOS 2 +#define OPTYPE_PXE_BIOS 3 +#define OPTYPE_FCOE_BIOS 8 +#define OPTYPE_ISCSI_BACKUP 9 +#define OPTYPE_FCOE_FW_ACTIVE 10 +#define OPTYPE_FCOE_FW_BACKUP 11 +#define OPTYPE_NCSI_FW 13 +#define OPTYPE_PHY_FW 99 #define TN_8022 13 #define ILLEGAL_IOCTL_REQ 2 @@ -223,6 +228,24 @@ #define FLASH_REDBOOT_START_g3 (262144) #define FLASH_PHY_FW_START_g3 1310720 +#define IMAGE_NCSI 16 +#define IMAGE_OPTION_ROM_PXE 32 +#define IMAGE_OPTION_ROM_FCoE 33 +#define IMAGE_OPTION_ROM_ISCSI 34 +#define IMAGE_FLASHISM_JUMPVECTOR 48 +#define IMAGE_FLASH_ISM 49 +#define IMAGE_JUMP_VECTOR 50 +#define IMAGE_FIRMWARE_iSCSI 160 +#define IMAGE_FIRMWARE_COMP_iSCSI 161 +#define IMAGE_FIRMWARE_FCoE 162 +#define IMAGE_FIRMWARE_COMP_FCoE 163 +#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 +#define IMAGE_FIRMWARE_BACKUP_COMP_iSCSI 177 +#define IMAGE_FIRMWARE_BACKUP_FCoE 178 +#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179 +#define IMAGE_FIRMWARE_PHY 192 +#define IMAGE_BOOT_CODE 224 + /************* Rx Packet Type Encoding **************/ #define BE_UNICAST_PACKET 0 #define BE_MULTICAST_PACKET 1 @@ -445,6 +468,7 @@ struct flash_comp { unsigned long offset; int optype; int size; + int img_type; }; struct image_hdr { @@ -481,17 +505,19 @@ struct flash_section_hdr { u32 format_rev; u32 cksum; u32 antidote; - u32 build_no; - u8 id_string[64]; - u32 active_entry_mask; - u32 valid_entry_mask; - u32 org_content_mask; - u32 rsvd0; - u32 rsvd1; - u32 rsvd2; - u32 rsvd3; - u32 rsvd4; -}; + u32 num_images; + u8 id_string[128]; + u32 rsvd[4]; +} __packed; + +struct flash_section_hdr_g2 { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 build_num; + u8 id_string[128]; + u32 rsvd[8]; +} __packed; struct flash_section_entry { u32 type; @@ -503,10 +529,16 @@ struct flash_section_entry { u32 rsvd0; u32 rsvd1; u8 ver_data[32]; -}; +} __packed; struct flash_section_info { u8 cookie[32]; struct flash_section_hdr fsec_hdr; struct flash_section_entry fsec_entry[32]; -}; +} __packed; + +struct flash_section_info_g2 { + u8 cookie[32]; + struct flash_section_hdr_g2 fsec_hdr; + struct flash_section_entry fsec_entry[32]; +} __packed; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 528a886bc2cd..501dfa9c88ec 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -421,6 +421,9 @@ void be_parse_stats(struct be_adapter *adapter) populate_be2_stats(adapter); } + if (lancer_chip(adapter)) + goto done; + /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */ for_all_rx_queues(adapter, rxo, i) { /* below erx HW counter can actually wrap around after @@ -429,6 +432,8 @@ void be_parse_stats(struct be_adapter *adapter) accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags, (u16)erx->rx_drops_no_fragments[rxo->q.id]); } +done: + return; } static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, @@ -731,6 +736,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); if (copied) { + int gso_segs = skb_shinfo(skb)->gso_segs; + /* record the sent skb in the sent_skb table */ BUG_ON(txo->sent_skb_list[start]); txo->sent_skb_list[start] = skb; @@ -748,8 +755,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, be_txq_notify(adapter, txq->id, wrb_cnt); - be_tx_stats_update(txo, wrb_cnt, copied, - skb_shinfo(skb)->gso_segs, stopped); + be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped); } else { txq->head = start; dev_kfree_skb_any(skb); @@ -797,22 +803,30 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) if (adapter->promiscuous) return 0; - if (adapter->vlans_added <= adapter->max_vlans) { - /* Construct VLAN Table to give to HW */ - for (i = 0; i < VLAN_N_VID; i++) { - if (adapter->vlan_tag[i]) { - vtag[ntags] = cpu_to_le16(i); - ntags++; - } - } - status = be_cmd_vlan_config(adapter, adapter->if_handle, - vtag, ntags, 1, 0); - } else { - status = be_cmd_vlan_config(adapter, adapter->if_handle, - NULL, 0, 1, 1); + if (adapter->vlans_added > adapter->max_vlans) + goto set_vlan_promisc; + + /* Construct VLAN Table to give to HW */ + for (i = 0; i < VLAN_N_VID; i++) + if (adapter->vlan_tag[i]) + vtag[ntags++] = cpu_to_le16(i); + + status = be_cmd_vlan_config(adapter, adapter->if_handle, + vtag, ntags, 1, 0); + + /* Set to VLAN promisc mode as setting VLAN filter failed */ + if (status) { + dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n"); + dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n"); + goto set_vlan_promisc; } return status; + +set_vlan_promisc: + status = be_cmd_vlan_config(adapter, adapter->if_handle, + NULL, 0, 1, 1); + return status; } static int be_vlan_add_vid(struct net_device *netdev, u16 vid) @@ -862,6 +876,7 @@ ret: static void be_set_rx_mode(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); + int status; if (netdev->flags & IFF_PROMISC) { be_cmd_rx_filter(adapter, IFF_PROMISC, ON); @@ -908,7 +923,14 @@ static void be_set_rx_mode(struct net_device *netdev) } } - be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); + status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); + + /* Set to MCAST promisc mode if setting MULTICAST address fails */ + if (status) { + dev_info(&adapter->pdev->dev, "Exhausted multicast HW filters.\n"); + dev_info(&adapter->pdev->dev, "Disabling HW multicast filtering.\n"); + be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); + } done: return; } @@ -1028,6 +1050,29 @@ static int be_set_vf_tx_rate(struct net_device *netdev, return status; } +static int be_find_vfs(struct be_adapter *adapter, int vf_state) +{ + struct pci_dev *dev, *pdev = adapter->pdev; + int vfs = 0, assigned_vfs = 0, pos, vf_fn; + u16 offset, stride; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset); + pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride); + + dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL); + while (dev) { + vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF; + if (dev->is_virtfn && dev->devfn == vf_fn) { + vfs++; + if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) + assigned_vfs++; + } + dev = pci_get_device(pdev->vendor, PCI_ANY_ID, dev); + } + return (vf_state == ASSIGNED) ? assigned_vfs : vfs; +} + static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo) { struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]); @@ -1238,6 +1283,7 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); + skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]); if (netdev->features & NETIF_F_RXHASH) skb->rxhash = rxcp->rss_hash; @@ -1294,6 +1340,7 @@ void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct napi_struct *napi, skb->len = rxcp->pkt_size; skb->data_len = rxcp->pkt_size; skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]); if (adapter->netdev->features & NETIF_F_RXHASH) skb->rxhash = rxcp->rss_hash; @@ -1555,7 +1602,9 @@ static int event_handle(struct be_eq_obj *eqo) if (!num) rearm = true; - be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num); + if (num || msix_enabled(eqo->adapter)) + be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num); + if (num) napi_schedule(&eqo->napi); @@ -1764,9 +1813,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) static int be_num_txqs_want(struct be_adapter *adapter) { - if (sriov_enabled(adapter) || be_is_mc(adapter) || - lancer_chip(adapter) || !be_physfn(adapter) || - adapter->generation == BE_GEN2) + if (sriov_want(adapter) || be_is_mc(adapter) || + lancer_chip(adapter) || !be_physfn(adapter) || + adapter->generation == BE_GEN2) return 1; else return MAX_TX_QS; @@ -2093,7 +2142,7 @@ static void be_msix_disable(struct be_adapter *adapter) static uint be_num_rss_want(struct be_adapter *adapter) { if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - adapter->num_vfs == 0 && be_physfn(adapter) && + !sriov_want(adapter) && be_physfn(adapter) && !be_is_mc(adapter)) return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS; else @@ -2103,10 +2152,17 @@ static uint be_num_rss_want(struct be_adapter *adapter) static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS 1 - int i, status, num_vec; + int i, status, num_vec, num_roce_vec = 0; /* If RSS queues are not used, need a vec for default RX Q */ num_vec = min(be_num_rss_want(adapter), num_online_cpus()); + if (be_roce_supported(adapter)) { + num_roce_vec = min_t(u32, MAX_ROCE_MSIX_VECTORS, + (num_online_cpus() + 1)); + num_roce_vec = min(num_roce_vec, MAX_ROCE_EQS); + num_vec += num_roce_vec; + num_vec = min(num_vec, MAX_MSIX_VECTORS); + } num_vec = max(num_vec, BE_MIN_MSIX_VECTORS); for (i = 0; i < num_vec; i++) @@ -2123,55 +2179,18 @@ static void be_msix_enable(struct be_adapter *adapter) } return; done: - adapter->num_msix_vec = num_vec; - return; -} - -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 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, &dev_vfs); - - 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", - adapter->num_vfs, num_vfs); - - status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); - if (status) - adapter->num_vfs = 0; - - if (adapter->num_vfs) { - adapter->vf_cfg = kcalloc(num_vfs, - sizeof(struct be_vf_cfg), - GFP_KERNEL); - if (!adapter->vf_cfg) - return -ENOMEM; + if (be_roce_supported(adapter)) { + if (num_vec > num_roce_vec) { + adapter->num_msix_vec = num_vec - num_roce_vec; + adapter->num_msix_roce_vec = + num_vec - adapter->num_msix_vec; + } else { + adapter->num_msix_vec = num_vec; + adapter->num_msix_roce_vec = 0; } - } -#endif - return 0; -} - -static void be_sriov_disable(struct be_adapter *adapter) -{ -#ifdef CONFIG_PCI_IOV - if (sriov_enabled(adapter)) { - pci_disable_sriov(adapter->pdev); - kfree(adapter->vf_cfg); - adapter->num_vfs = 0; - } -#endif + } else + adapter->num_msix_vec = num_vec; + return; } static inline int be_msix_vec_get(struct be_adapter *adapter, @@ -2282,6 +2301,8 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *eqo; int i; + be_roce_dev_close(adapter); + be_async_mcc_disable(adapter); if (!lancer_chip(adapter)) @@ -2390,6 +2411,7 @@ static int be_open(struct net_device *netdev) if (!status) be_link_status_update(adapter, link_status); + be_roce_dev_open(adapter); return 0; err: be_close(adapter->netdev); @@ -2475,6 +2497,11 @@ static void be_vf_clear(struct be_adapter *adapter) struct be_vf_cfg *vf_cfg; u32 vf; + if (be_find_vfs(adapter, ASSIGNED)) { + dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n"); + goto done; + } + for_all_vfs(adapter, vf_cfg, vf) { if (lancer_chip(adapter)) be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); @@ -2484,6 +2511,10 @@ static void be_vf_clear(struct be_adapter *adapter) be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1); } + pci_disable_sriov(adapter->pdev); +done: + kfree(adapter->vf_cfg); + adapter->num_vfs = 0; } static int be_clear(struct be_adapter *adapter) @@ -2513,29 +2544,60 @@ static int be_clear(struct be_adapter *adapter) be_cmd_fw_clean(adapter); be_msix_disable(adapter); - kfree(adapter->pmac_id); + pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0); return 0; } -static void be_vf_setup_init(struct be_adapter *adapter) +static int be_vf_setup_init(struct be_adapter *adapter) { struct be_vf_cfg *vf_cfg; int vf; + adapter->vf_cfg = kcalloc(adapter->num_vfs, sizeof(*vf_cfg), + GFP_KERNEL); + if (!adapter->vf_cfg) + return -ENOMEM; + for_all_vfs(adapter, vf_cfg, vf) { vf_cfg->if_handle = -1; vf_cfg->pmac_id = -1; } + return 0; } static int be_vf_setup(struct be_adapter *adapter) { struct be_vf_cfg *vf_cfg; + struct device *dev = &adapter->pdev->dev; u32 cap_flags, en_flags, vf; u16 def_vlan, lnk_speed; - int status; + int status, enabled_vfs; + + enabled_vfs = be_find_vfs(adapter, ENABLED); + if (enabled_vfs) { + dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs); + dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs); + return 0; + } - be_vf_setup_init(adapter); + if (num_vfs > adapter->dev_num_vfs) { + dev_warn(dev, "Device supports %d VFs and not %d\n", + adapter->dev_num_vfs, num_vfs); + num_vfs = adapter->dev_num_vfs; + } + + status = pci_enable_sriov(adapter->pdev, num_vfs); + if (!status) { + adapter->num_vfs = num_vfs; + } else { + /* Platform doesn't support SRIOV though device supports it */ + dev_warn(dev, "SRIOV enable failed\n"); + return 0; + } + + status = be_vf_setup_init(adapter); + if (status) + goto err; cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST; @@ -2546,9 +2608,11 @@ static int be_vf_setup(struct be_adapter *adapter) goto err; } - status = be_vf_eth_addr_config(adapter); - if (status) - goto err; + if (!enabled_vfs) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto err; + } for_all_vfs(adapter, vf_cfg, vf) { status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, @@ -2571,11 +2635,12 @@ err: static void be_setup_init(struct be_adapter *adapter) { adapter->vlan_prio_bmap = 0xff; - adapter->link_speed = -1; + adapter->phy.link_speed = -1; adapter->if_handle = -1; adapter->be3_native = false; adapter->promiscuous = false; adapter->eq_next_idx = 0; + adapter->phy.forced_port_speed = -1; } static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) @@ -2604,9 +2669,25 @@ do_none: return status; } +/* Routine to query per function resource limits */ +static int be_get_config(struct be_adapter *adapter) +{ + int pos; + u16 dev_num_vfs; + + pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV); + if (pos) { + pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF, + &dev_num_vfs); + adapter->dev_num_vfs = dev_num_vfs; + } + return 0; +} + static int be_setup(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct device *dev = &adapter->pdev->dev; u32 cap_flags, en_flags; u32 tx_fc, rx_fc; int status; @@ -2614,6 +2695,8 @@ static int be_setup(struct be_adapter *adapter) be_setup_init(adapter); + be_get_config(adapter); + be_cmd_req_native_mode(adapter); be_msix_enable(adapter); @@ -2680,36 +2763,33 @@ static int be_setup(struct be_adapter *adapter) be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); - status = be_vid_config(adapter, false, 0); - if (status) - goto err; + be_vid_config(adapter, false, 0); be_set_rx_mode(adapter->netdev); - status = be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); - /* For Lancer: It is legal for this cmd to fail on VF */ - if (status && (be_physfn(adapter) || !lancer_chip(adapter))) - goto err; + be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); - if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) { - status = be_cmd_set_flow_control(adapter, adapter->tx_fc, + if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) + be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); - /* 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 (sriov_enabled(adapter)) { - status = be_vf_setup(adapter); - if (status) - goto err; + if (be_physfn(adapter) && num_vfs) { + if (adapter->dev_num_vfs) + be_vf_setup(adapter); + else + dev_warn(dev, "device doesn't support SRIOV\n"); } + be_cmd_get_phy_info(adapter); + if (be_pause_supported(adapter)) + adapter->phy.fc_autoneg = 1; + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); adapter->flags |= BE_FLAGS_WORKER_SCHEDULED; + pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1); return 0; err: be_clear(adapter); @@ -2731,6 +2811,8 @@ static void be_netpoll(struct net_device *netdev) #endif #define FW_FILE_HDR_SIGN "ServerEngines Corp. " +char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; + static bool be_flash_redboot(struct be_adapter *adapter, const u8 *p, u32 img_start, int image_size, int hdr_size) @@ -2760,71 +2842,105 @@ static bool be_flash_redboot(struct be_adapter *adapter, static bool phy_flashing_required(struct be_adapter *adapter) { - int status = 0; - struct be_phy_info phy_info; + return (adapter->phy.phy_type == TN_8022 && + adapter->phy.interface_type == PHY_TYPE_BASET_10GB); +} - status = be_cmd_get_phy_info(adapter, &phy_info); - if (status) - return false; - if ((phy_info.phy_type == TN_8022) && - (phy_info.interface_type == PHY_TYPE_BASET_10GB)) { - return true; +static bool is_comp_in_ufi(struct be_adapter *adapter, + struct flash_section_info *fsec, int type) +{ + int i = 0, img_type = 0; + struct flash_section_info_g2 *fsec_g2 = NULL; + + if (adapter->generation != BE_GEN3) + fsec_g2 = (struct flash_section_info_g2 *)fsec; + + for (i = 0; i < MAX_FLASH_COMP; i++) { + if (fsec_g2) + img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); + else + img_type = le32_to_cpu(fsec->fsec_entry[i].type); + + if (img_type == type) + return true; } return false; + +} + +struct flash_section_info *get_fsec_info(struct be_adapter *adapter, + int header_size, + const struct firmware *fw) +{ + struct flash_section_info *fsec = NULL; + const u8 *p = fw->data; + + p += header_size; + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) + return fsec; + p += 32; + } + return NULL; } static int be_flash_data(struct be_adapter *adapter, - const struct firmware *fw, - struct be_dma_mem *flash_cmd, int num_of_images) + const struct firmware *fw, + struct be_dma_mem *flash_cmd, + int num_of_images) { int status = 0, i, filehdr_size = 0; + int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); u32 total_bytes = 0, flash_op; int num_bytes; const u8 *p = fw->data; struct be_cmd_write_flashrom *req = flash_cmd->va; const struct flash_comp *pflashcomp; - int num_comp; - - static const struct flash_comp gen3_flash_types[10] = { - { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE, - FLASH_IMAGE_MAX_SIZE_g3}, - { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT, - FLASH_REDBOOT_IMAGE_MAX_SIZE_g3}, - { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g3}, - { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g3}, - { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g3}, - { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP, - FLASH_IMAGE_MAX_SIZE_g3}, - { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE, - FLASH_IMAGE_MAX_SIZE_g3}, - { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP, - FLASH_IMAGE_MAX_SIZE_g3}, - { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW, - FLASH_NCSI_IMAGE_MAX_SIZE_g3}, - { FLASH_PHY_FW_START_g3, IMG_TYPE_PHY_FW, - FLASH_PHY_FW_IMAGE_MAX_SIZE_g3} + int num_comp, hdr_size; + struct flash_section_info *fsec = NULL; + + struct flash_comp gen3_flash_types[] = { + { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, OPTYPE_ISCSI_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_iSCSI}, + { FLASH_REDBOOT_START_g3, OPTYPE_REDBOOT, + FLASH_REDBOOT_IMAGE_MAX_SIZE_g3, IMAGE_BOOT_CODE}, + { FLASH_iSCSI_BIOS_START_g3, OPTYPE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_ISCSI}, + { FLASH_PXE_BIOS_START_g3, OPTYPE_PXE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_PXE}, + { FLASH_FCoE_BIOS_START_g3, OPTYPE_FCOE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_FCoE}, + { FLASH_iSCSI_BACKUP_IMAGE_START_g3, OPTYPE_ISCSI_BACKUP, + FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_BACKUP_iSCSI}, + { FLASH_FCoE_PRIMARY_IMAGE_START_g3, OPTYPE_FCOE_FW_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_FCoE}, + { FLASH_FCoE_BACKUP_IMAGE_START_g3, OPTYPE_FCOE_FW_BACKUP, + FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_BACKUP_FCoE}, + { FLASH_NCSI_START_g3, OPTYPE_NCSI_FW, + FLASH_NCSI_IMAGE_MAX_SIZE_g3, IMAGE_NCSI}, + { FLASH_PHY_FW_START_g3, OPTYPE_PHY_FW, + FLASH_PHY_FW_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_PHY} }; - static const struct flash_comp gen2_flash_types[8] = { - { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE, - FLASH_IMAGE_MAX_SIZE_g2}, - { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT, - FLASH_REDBOOT_IMAGE_MAX_SIZE_g2}, - { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g2}, - { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g2}, - { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS, - FLASH_BIOS_IMAGE_MAX_SIZE_g2}, - { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP, - FLASH_IMAGE_MAX_SIZE_g2}, - { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE, - FLASH_IMAGE_MAX_SIZE_g2}, - { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP, - FLASH_IMAGE_MAX_SIZE_g2} + + struct flash_comp gen2_flash_types[] = { + { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, OPTYPE_ISCSI_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_iSCSI}, + { FLASH_REDBOOT_START_g2, OPTYPE_REDBOOT, + FLASH_REDBOOT_IMAGE_MAX_SIZE_g2, IMAGE_BOOT_CODE}, + { FLASH_iSCSI_BIOS_START_g2, OPTYPE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_ISCSI}, + { FLASH_PXE_BIOS_START_g2, OPTYPE_PXE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_PXE}, + { FLASH_FCoE_BIOS_START_g2, OPTYPE_FCOE_BIOS, + FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_FCoE}, + { FLASH_iSCSI_BACKUP_IMAGE_START_g2, OPTYPE_ISCSI_BACKUP, + FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_BACKUP_iSCSI}, + { FLASH_FCoE_PRIMARY_IMAGE_START_g2, OPTYPE_FCOE_FW_ACTIVE, + FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_FCoE}, + { FLASH_FCoE_BACKUP_IMAGE_START_g2, OPTYPE_FCOE_FW_BACKUP, + FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_BACKUP_FCoE} }; if (adapter->generation == BE_GEN3) { @@ -2836,22 +2952,37 @@ static int be_flash_data(struct be_adapter *adapter, filehdr_size = sizeof(struct flash_file_hdr_g2); num_comp = ARRAY_SIZE(gen2_flash_types); } + /* Get flash section info*/ + fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); + if (!fsec) { + dev_err(&adapter->pdev->dev, + "Invalid Cookie. UFI corrupted ?\n"); + return -1; + } for (i = 0; i < num_comp; i++) { - if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) && - memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) + if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) + continue; + + if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && + memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) continue; - if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) { + + if (pflashcomp[i].optype == OPTYPE_PHY_FW) { if (!phy_flashing_required(adapter)) continue; } - if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && - (!be_flash_redboot(adapter, fw->data, - pflashcomp[i].offset, pflashcomp[i].size, filehdr_size + - (num_of_images * sizeof(struct image_hdr))))) + + hdr_size = filehdr_size + + (num_of_images * sizeof(struct image_hdr)); + + if ((pflashcomp[i].optype == OPTYPE_REDBOOT) && + (!be_flash_redboot(adapter, fw->data, pflashcomp[i].offset, + pflashcomp[i].size, hdr_size))) continue; + + /* Flash the component */ p = fw->data; - p += filehdr_size + pflashcomp[i].offset - + (num_of_images * sizeof(struct image_hdr)); + p += filehdr_size + pflashcomp[i].offset + img_hdrs_size; if (p + pflashcomp[i].size > fw->data + fw->size) return -1; total_bytes = pflashcomp[i].size; @@ -2862,12 +2993,12 @@ static int be_flash_data(struct be_adapter *adapter, num_bytes = total_bytes; total_bytes -= num_bytes; if (!total_bytes) { - if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) + if (pflashcomp[i].optype == OPTYPE_PHY_FW) flash_op = FLASHROM_OPER_PHY_FLASH; else flash_op = FLASHROM_OPER_FLASH; } else { - if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) + if (pflashcomp[i].optype == OPTYPE_PHY_FW) flash_op = FLASHROM_OPER_PHY_SAVE; else flash_op = FLASHROM_OPER_SAVE; @@ -2879,7 +3010,7 @@ static int be_flash_data(struct be_adapter *adapter, if (status) { if ((status == ILLEGAL_IOCTL_REQ) && (pflashcomp[i].optype == - IMG_TYPE_PHY_FW)) + OPTYPE_PHY_FW)) break; dev_err(&adapter->pdev->dev, "cmd to write to flash rom failed.\n"); @@ -3106,7 +3237,7 @@ static void be_netdev_init(struct net_device *netdev) netdev->flags |= IFF_MULTICAST; - netif_set_gso_max_size(netdev, 65535); + netif_set_gso_max_size(netdev, 65535 - ETH_HLEN); netdev->netdev_ops = &be_netdev_ops; @@ -3122,6 +3253,24 @@ static void be_unmap_pci_bars(struct be_adapter *adapter) iounmap(adapter->csr); if (adapter->db) iounmap(adapter->db); + if (adapter->roce_db.base) + pci_iounmap(adapter->pdev, adapter->roce_db.base); +} + +static int lancer_roce_map_pci_bars(struct be_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + u8 __iomem *addr; + + addr = pci_iomap(pdev, 2, 0); + if (addr == NULL) + return -ENOMEM; + + adapter->roce_db.base = addr; + adapter->roce_db.io_addr = pci_resource_start(pdev, 2); + adapter->roce_db.size = 8192; + adapter->roce_db.total_size = pci_resource_len(pdev, 2); + return 0; } static int be_map_pci_bars(struct be_adapter *adapter) @@ -3130,11 +3279,18 @@ static int be_map_pci_bars(struct be_adapter *adapter) int db_reg; if (lancer_chip(adapter)) { - addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0), - pci_resource_len(adapter->pdev, 0)); - if (addr == NULL) - return -ENOMEM; - adapter->db = addr; + if (be_type_2_3(adapter)) { + addr = ioremap_nocache( + pci_resource_start(adapter->pdev, 0), + pci_resource_len(adapter->pdev, 0)); + if (addr == NULL) + return -ENOMEM; + adapter->db = addr; + } + if (adapter->if_type == SLI_INTF_TYPE_3) { + if (lancer_roce_map_pci_bars(adapter)) + goto pci_map_err; + } return 0; } @@ -3159,14 +3315,19 @@ static int be_map_pci_bars(struct be_adapter *adapter) if (addr == NULL) goto pci_map_err; adapter->db = addr; - + if (adapter->sli_family == SKYHAWK_SLI_FAMILY) { + adapter->roce_db.size = 4096; + adapter->roce_db.io_addr = + pci_resource_start(adapter->pdev, db_reg); + adapter->roce_db.total_size = + pci_resource_len(adapter->pdev, db_reg); + } return 0; pci_map_err: be_unmap_pci_bars(adapter); return -ENOMEM; } - static void be_ctrl_cleanup(struct be_adapter *adapter) { struct be_dma_mem *mem = &adapter->mbox_mem_alloced; @@ -3272,6 +3433,8 @@ static void __devexit be_remove(struct pci_dev *pdev) if (!adapter) return; + be_roce_dev_remove(adapter); + unregister_netdev(adapter->netdev); be_clear(adapter); @@ -3280,8 +3443,6 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); - be_sriov_disable(adapter); - pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); pci_disable_device(pdev); @@ -3295,9 +3456,43 @@ bool be_is_wol_supported(struct be_adapter *adapter) !be_is_wol_excluded(adapter)) ? true : false; } -static int be_get_config(struct be_adapter *adapter) +u32 be_get_fw_log_level(struct be_adapter *adapter) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status; + u32 level = 0; + int j; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + + if (!extfat_cmd.va) { + dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", + __func__); + goto err; + } + + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (!status) { + cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + + sizeof(struct be_cmd_resp_hdr)); + for (j = 0; j < cfgs->module[0].num_modes; j++) { + if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) + level = cfgs->module[0].trace_lvl[j].dbg_lvl; + } + } + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); +err: + return level; +} +static int be_get_initial_config(struct be_adapter *adapter) { int status; + u32 level; status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, &adapter->function_mode, &adapter->function_caps); @@ -3335,10 +3530,13 @@ static int be_get_config(struct be_adapter *adapter) if (be_is_wol_supported(adapter)) adapter->wol = true; + level = be_get_fw_log_level(adapter); + adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; + return 0; } -static int be_dev_family_check(struct be_adapter *adapter) +static int be_dev_type_check(struct be_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; u32 sli_intf = 0, if_type; @@ -3350,17 +3548,27 @@ 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: case OC_DEVICE_ID4: pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf); + adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> + SLI_INTF_IF_TYPE_SHIFT; if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> SLI_INTF_IF_TYPE_SHIFT; - if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) || - if_type != 0x02) { + !be_type_2_3(adapter)) { + dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n"); + return -EINVAL; + } + adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >> + SLI_INTF_FAMILY_SHIFT); + adapter->generation = BE_GEN3; + break; + case OC_DEVICE_ID5: + pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf); + if ((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) { dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n"); return -EINVAL; } @@ -3371,6 +3579,9 @@ static int be_dev_family_check(struct be_adapter *adapter) default: adapter->generation = 0; } + + pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); + adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; return 0; } @@ -3514,6 +3725,14 @@ reschedule: schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } +static bool be_reset_required(struct be_adapter *adapter) +{ + u32 reg; + + pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, ®); + return reg; +} + static int __devinit be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { @@ -3539,7 +3758,7 @@ static int __devinit be_probe(struct pci_dev *pdev, adapter->pdev = pdev; pci_set_drvdata(pdev, adapter); - status = be_dev_family_check(adapter); + status = be_dev_type_check(adapter); if (status) goto free_netdev; @@ -3557,13 +3776,9 @@ static int __devinit be_probe(struct pci_dev *pdev, } } - status = be_sriov_enable(adapter); - if (status) - goto free_netdev; - status = be_ctrl_init(adapter); if (status) - goto disable_sriov; + goto free_netdev; if (lancer_chip(adapter)) { status = lancer_wait_ready(adapter); @@ -3590,9 +3805,11 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto ctrl_clean; - status = be_cmd_reset_function(adapter); - if (status) - goto ctrl_clean; + if (be_reset_required(adapter)) { + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; + } /* The INTR bit may be set in the card when probed by a kdump kernel * after a crash. @@ -3604,7 +3821,7 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto ctrl_clean; - status = be_get_config(adapter); + status = be_get_initial_config(adapter); if (status) goto stats_clean; @@ -3620,6 +3837,8 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status != 0) goto unsetup; + be_roce_dev_add(adapter); + dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), adapter->port_num); @@ -3633,8 +3852,6 @@ stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); -disable_sriov: - be_sriov_disable(adapter); free_netdev: free_netdev(netdev); pci_set_drvdata(pdev, NULL); @@ -3749,6 +3966,11 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, pci_disable_device(pdev); + /* The error could cause the FW to trigger a flash debug dump. + * Resetting the card while flash dump is in progress + * can cause it not to recover; wait for it to finish + */ + ssleep(30); return PCI_ERS_RESULT_NEED_RESET; } diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c new file mode 100644 index 000000000000..deecc44b3617 --- /dev/null +++ b/drivers/net/ethernet/emulex/benet/be_roce.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2005 - 2011 Emulex + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@emulex.com + * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 + */ + +#include <linux/mutex.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <linux/module.h> + +#include "be.h" +#include "be_cmds.h" + +static struct ocrdma_driver *ocrdma_drv; +static LIST_HEAD(be_adapter_list); +static DEFINE_MUTEX(be_adapter_list_lock); + +static void _be_roce_dev_add(struct be_adapter *adapter) +{ + struct be_dev_info dev_info; + int i, num_vec; + struct pci_dev *pdev = adapter->pdev; + + if (!ocrdma_drv) + return; + if (pdev->device == OC_DEVICE_ID5) { + /* only msix is supported on these devices */ + if (!msix_enabled(adapter)) + return; + /* DPP region address and length */ + dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2); + dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2); + } else { + dev_info.dpp_unmapped_addr = 0; + dev_info.dpp_unmapped_len = 0; + } + dev_info.pdev = adapter->pdev; + if (adapter->sli_family == SKYHAWK_SLI_FAMILY) + dev_info.db = adapter->db; + else + dev_info.db = adapter->roce_db.base; + dev_info.unmapped_db = adapter->roce_db.io_addr; + dev_info.db_page_size = adapter->roce_db.size; + dev_info.db_total_size = adapter->roce_db.total_size; + dev_info.netdev = adapter->netdev; + memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN); + dev_info.dev_family = adapter->sli_family; + if (msix_enabled(adapter)) { + /* provide all the vectors, so that EQ creation response + * can decide which one to use. + */ + num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec; + dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX; + dev_info.msix.num_vectors = min(num_vec, MAX_ROCE_MSIX_VECTORS); + /* provide start index of the vector, + * so in case of linear usage, + * it can use the base as starting point. + */ + dev_info.msix.start_vector = adapter->num_evt_qs; + for (i = 0; i < dev_info.msix.num_vectors; i++) { + dev_info.msix.vector_list[i] = + adapter->msix_entries[i].vector; + } + } else { + dev_info.msix.num_vectors = 0; + dev_info.intr_mode = BE_INTERRUPT_MODE_INTX; + } + adapter->ocrdma_dev = ocrdma_drv->add(&dev_info); +} + +void be_roce_dev_add(struct be_adapter *adapter) +{ + if (be_roce_supported(adapter)) { + INIT_LIST_HEAD(&adapter->entry); + mutex_lock(&be_adapter_list_lock); + list_add_tail(&adapter->entry, &be_adapter_list); + + /* invoke add() routine of roce driver only if + * valid driver registered with add method and add() is not yet + * invoked on a given adapter. + */ + _be_roce_dev_add(adapter); + mutex_unlock(&be_adapter_list_lock); + } +} + +void _be_roce_dev_remove(struct be_adapter *adapter) +{ + if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev) + ocrdma_drv->remove(adapter->ocrdma_dev); + adapter->ocrdma_dev = NULL; +} + +void be_roce_dev_remove(struct be_adapter *adapter) +{ + if (be_roce_supported(adapter)) { + mutex_lock(&be_adapter_list_lock); + _be_roce_dev_remove(adapter); + list_del(&adapter->entry); + mutex_unlock(&be_adapter_list_lock); + } +} + +void _be_roce_dev_open(struct be_adapter *adapter) +{ + if (ocrdma_drv && adapter->ocrdma_dev && + ocrdma_drv->state_change_handler) + ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 0); +} + +void be_roce_dev_open(struct be_adapter *adapter) +{ + if (be_roce_supported(adapter)) { + mutex_lock(&be_adapter_list_lock); + _be_roce_dev_open(adapter); + mutex_unlock(&be_adapter_list_lock); + } +} + +void _be_roce_dev_close(struct be_adapter *adapter) +{ + if (ocrdma_drv && adapter->ocrdma_dev && + ocrdma_drv->state_change_handler) + ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1); +} + +void be_roce_dev_close(struct be_adapter *adapter) +{ + if (be_roce_supported(adapter)) { + mutex_lock(&be_adapter_list_lock); + _be_roce_dev_close(adapter); + mutex_unlock(&be_adapter_list_lock); + } +} + +int be_roce_register_driver(struct ocrdma_driver *drv) +{ + struct be_adapter *dev; + + mutex_lock(&be_adapter_list_lock); + if (ocrdma_drv) { + mutex_unlock(&be_adapter_list_lock); + return -EINVAL; + } + ocrdma_drv = drv; + list_for_each_entry(dev, &be_adapter_list, entry) { + struct net_device *netdev; + _be_roce_dev_add(dev); + netdev = dev->netdev; + if (netif_running(netdev) && netif_oper_up(netdev)) + _be_roce_dev_open(dev); + } + mutex_unlock(&be_adapter_list_lock); + return 0; +} +EXPORT_SYMBOL(be_roce_register_driver); + +void be_roce_unregister_driver(struct ocrdma_driver *drv) +{ + struct be_adapter *dev; + + mutex_lock(&be_adapter_list_lock); + list_for_each_entry(dev, &be_adapter_list, entry) { + if (dev->ocrdma_dev) + _be_roce_dev_remove(dev); + } + ocrdma_drv = NULL; + mutex_unlock(&be_adapter_list_lock); +} +EXPORT_SYMBOL(be_roce_unregister_driver); diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h new file mode 100644 index 000000000000..db4ea8081c07 --- /dev/null +++ b/drivers/net/ethernet/emulex/benet/be_roce.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005 - 2011 Emulex + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@emulex.com + * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 + */ + +#ifndef BE_ROCE_H +#define BE_ROCE_H + +#include <linux/pci.h> +#include <linux/netdevice.h> + +struct ocrdma_dev; + +enum be_interrupt_mode { + BE_INTERRUPT_MODE_MSIX = 0, + BE_INTERRUPT_MODE_INTX = 1, + BE_INTERRUPT_MODE_MSI = 2, +}; + +#define MAX_ROCE_MSIX_VECTORS 16 +struct be_dev_info { + u8 __iomem *db; + u64 unmapped_db; + u32 db_page_size; + u32 db_total_size; + u64 dpp_unmapped_addr; + u32 dpp_unmapped_len; + struct pci_dev *pdev; + struct net_device *netdev; + u8 mac_addr[ETH_ALEN]; + u32 dev_family; + enum be_interrupt_mode intr_mode; + struct { + int num_vectors; + int start_vector; + u32 vector_list[MAX_ROCE_MSIX_VECTORS]; + } msix; +}; + +/* ocrdma driver register's the callback functions with nic driver. */ +struct ocrdma_driver { + unsigned char name[32]; + struct ocrdma_dev *(*add) (struct be_dev_info *dev_info); + void (*remove) (struct ocrdma_dev *); + void (*state_change_handler) (struct ocrdma_dev *, u32 new_state); +}; + +enum { + BE_DEV_UP = 0, + BE_DEV_DOWN = 1 +}; + +/* APIs for RoCE driver to register callback handlers, + * which will be invoked when device is added, removed, ifup, ifdown + */ +int be_roce_register_driver(struct ocrdma_driver *drv); +void be_roce_unregister_driver(struct ocrdma_driver *drv); + +/* API for RoCE driver to issue mailbox commands */ +int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, + int wrb_payload_size, u16 *cmd_status, u16 *ext_status); + +#endif /* BE_ROCE_H */ |