diff options
Diffstat (limited to 'drivers/net/benet')
-rw-r--r-- | drivers/net/benet/be.h | 31 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.c | 116 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.h | 23 | ||||
-rw-r--r-- | drivers/net/benet/be_ethtool.c | 109 | ||||
-rw-r--r-- | drivers/net/benet/be_hw.h | 4 | ||||
-rw-r--r-- | drivers/net/benet/be_main.c | 202 |
6 files changed, 336 insertions, 149 deletions
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 66823eded7a..a0b4743d722 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -84,15 +84,14 @@ static inline char *nic_name(struct pci_dev *pdev) #define MCC_CQ_LEN 256 #define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ -#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */ +#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ +#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */ #define BE_NAPI_WEIGHT 64 #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) #define FW_VER_LEN 32 -#define BE_MAX_VF 32 - struct be_dma_mem { void *va; dma_addr_t dma; @@ -276,7 +275,7 @@ struct be_adapter { spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; - bool msix_enabled; + u32 num_msix_vec; bool isr_registered; /* TX Rings */ @@ -287,7 +286,7 @@ struct be_adapter { u32 cache_line_break[8]; /* Rx rings */ - struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */ + struct be_rx_obj rx_obj[MAX_RX_QS]; u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ @@ -308,10 +307,10 @@ struct be_adapter { u16 work_counter; /* Ethtool knobs and info */ - bool rx_csum; /* BE card must perform rx-checksumming */ char fw_ver[FW_VER_LEN]; u32 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 link_up; @@ -334,7 +333,7 @@ struct be_adapter { bool be3_native; bool sriov_enabled; - struct be_vf_cfg vf_cfg[BE_MAX_VF]; + struct be_vf_cfg *vf_cfg; u8 is_virtfn; u32 sli_family; u8 hba_port_num; @@ -351,6 +350,7 @@ struct be_adapter { extern const struct ethtool_ops be_ethtool_ops; +#define msix_enabled(adapter) (adapter->num_msix_vec > 0) #define tx_stats(adapter) (&adapter->tx_stats) #define rx_stats(rxo) (&rxo->stats) @@ -455,18 +455,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) static inline void be_check_sriov_fn_type(struct be_adapter *adapter) { - u8 data; u32 sli_intf; - if (lancer_chip(adapter)) { - pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, - &sli_intf); - adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; - } else { - pci_write_config_byte(adapter->pdev, 0xFE, 0xAA); - pci_read_config_byte(adapter->pdev, 0xFE, &data); - adapter->is_virtfn = (data != 0xAA); - } + 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) @@ -482,6 +474,11 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) memcpy(mac, adapter->netdev->dev_addr, 3); } +static inline bool be_multi_rxq(const struct be_adapter *adapter) +{ + return adapter->num_rx_qs > 1; +} + 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, bool link_up); diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1e2d825bb94..0fc06d36380 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -78,7 +78,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, } if (compl_status == MCC_STATUS_SUCCESS) { - if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) { + if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) && + (compl->tag1 == CMD_SUBSYSTEM_ETH)) { struct be_cmd_resp_get_stats *resp = adapter->stats_cmd.va; be_dws_le_to_cpu(&resp->hw_stats, @@ -1096,6 +1097,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_GET_STATISTICS, sizeof(*req)); + wrb->tag1 = CMD_SUBSYSTEM_ETH; sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); @@ -1110,7 +1112,7 @@ err: /* Uses synchronous mcc */ int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed) + bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_link_status *req; @@ -1186,6 +1188,116 @@ err: return status; } +/* Uses synchronous mcc */ +int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); + req->fat_operation = cpu_to_le32(QUERY_FAT); + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + if (log_size && resp->log_size) + *log_size = le32_to_cpu(resp->log_size) - + sizeof(u32); + } +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +{ + struct be_dma_mem get_fat_cmd; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + struct be_sge *sge; + u32 offset = 0, total_size, buf_size, + log_offset = sizeof(u32), payload_len; + int status; + + if (buf_len == 0) + return; + + total_size = buf_len; + + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + return; + } + + spin_lock_bh(&adapter->mcc_lock); + + while (total_size) { + buf_size = min(total_size, (u32)60*1024); + total_size -= buf_size; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = get_fat_cmd.va; + sge = nonembedded_sgl(wrb); + + payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; + be_wrb_hdr_prepare(wrb, payload_len, false, 1, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, payload_len); + + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma)); + sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(get_fat_cmd.size); + + req->fat_operation = cpu_to_le32(RETRIEVE_FAT); + req->read_log_offset = cpu_to_le32(log_offset); + req->read_log_length = cpu_to_le32(buf_size); + req->data_buffer_size = cpu_to_le32(buf_size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; + memcpy(buf + offset, + resp->data_buffer, + resp->read_log_length); + } else { + dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); + goto err; + } + offset += buf_size; + log_offset += buf_size; + } +err: + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); + spin_unlock_bh(&adapter->mcc_lock); +} + /* Uses Mbox */ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 4f254cfaabe..af4bbff5feb 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -186,6 +186,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 #define OPCODE_COMMON_FUNCTION_RESET 61 +#define OPCODE_COMMON_MANAGE_FAT 68 #define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69 #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 @@ -380,6 +381,24 @@ struct be_cmd_resp_cq_create { u16 rsvd0; } __packed; +struct be_cmd_req_get_fat { + struct be_cmd_req_hdr hdr; + u32 fat_operation; + u32 read_log_offset; + u32 read_log_length; + u32 data_buffer_size; + u32 data_buffer[1]; +} __packed; + +struct be_cmd_resp_get_fat { + struct be_cmd_resp_hdr hdr; + u32 log_size; + u32 read_log_length; + u32 rsvd[2]; + u32 data_buffer[1]; +} __packed; + + /******************** Create MCCQ ***************************/ /* Pseudo amap definition in which each bit of the actual structure is defined * as a byte: used to calculate offset/shift/mask of each field */ @@ -1093,7 +1112,7 @@ extern int be_cmd_rxq_create(struct be_adapter *adapter, extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); extern int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed); + bool *link_up, u8 *mac_speed, u16 *link_speed, 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); @@ -1148,4 +1167,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter); extern int be_cmd_get_die_temperature(struct be_adapter *adapter); extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); extern int be_cmd_check_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); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index aac248fbd18..6565f3e55b2 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -156,6 +156,29 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) } 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); + + return log_size; +} + +static void +be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + if (be_physfn(adapter)) { + memset(buf, 0, regs->len); + be_cmd_get_regs(adapter, regs->len, buf); + } +} + +static int be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { struct be_adapter *adapter = netdev_priv(netdev); @@ -186,9 +209,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_rx_obj *rxo; struct be_eq_obj *rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - u32 tx_max, tx_min, tx_cur; u32 rx_max, rx_min, rx_cur; int status = 0, i; + u32 tx_cur; if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; @@ -227,8 +250,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } } - tx_max = coalesce->tx_coalesce_usecs_high; - tx_min = coalesce->tx_coalesce_usecs_low; tx_cur = coalesce->tx_coalesce_usecs; if (tx_cur > BE_MAX_EQD) @@ -242,25 +263,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) return 0; } -static u32 be_get_rx_csum(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -static int be_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (data) - adapter->rx_csum = true; - else - adapter->rx_csum = false; - - return 0; -} - static void be_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) @@ -374,7 +376,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { status = be_cmd_link_status_query(adapter, &link_up, - &mac_speed, &link_speed); + &mac_speed, &link_speed, 0); be_link_status_update(adapter, link_up); /* link_speed is in units of 10 Mbps */ @@ -382,12 +384,21 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->speed = link_speed*10; } else { switch (mac_speed) { + case PHY_LINK_SPEED_10MBPS: + ecmd->speed = SPEED_10; + break; + case PHY_LINK_SPEED_100MBPS: + ecmd->speed = SPEED_100; + break; case PHY_LINK_SPEED_1GBPS: ecmd->speed = SPEED_1000; break; case PHY_LINK_SPEED_10GBPS: ecmd->speed = SPEED_10000; break; + case PHY_LINK_SPEED_ZERO: + ecmd->speed = 0; + break; } } @@ -507,29 +518,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) } static int -be_phys_id(struct net_device *netdev, u32 data) +be_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct be_adapter *adapter = netdev_priv(netdev); - int status; - u32 cur; - be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur); + switch (state) { + case ETHTOOL_ID_ACTIVE: + be_cmd_get_beacon_state(adapter, adapter->hba_port_num, + &adapter->beacon_state); + return 1; /* cycle on/off once per second */ - if (cur == BEACON_STATE_ENABLED) - return 0; - - if (data < 2) - data = 2; + case ETHTOOL_ID_ON: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_ENABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_ENABLED); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(data*HZ); + case ETHTOOL_ID_OFF: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_DISABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_DISABLED); + case ETHTOOL_ID_INACTIVE: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + adapter->beacon_state); + } - return status; + return 0; } static bool @@ -646,7 +661,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) } if (be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &qos_link_speed) != 0) { + &qos_link_speed, 0) != 0) { test->flags |= ETH_TEST_FL_FAILED; data[4] = -1; } else if (!mac_speed) { @@ -660,11 +675,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) { struct be_adapter *adapter = netdev_priv(netdev); char file_name[ETHTOOL_FLASH_MAX_FILENAME]; - u32 region; file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; strcpy(file_name, efl->data); - region = efl->region; return be_load_fw(adapter, file_name); } @@ -725,18 +738,12 @@ const struct ethtool_ops be_ethtool_ops = { .get_ringparam = be_get_ringparam, .get_pauseparam = be_get_pauseparam, .set_pauseparam = be_set_pauseparam, - .get_rx_csum = be_get_rx_csum, - .set_rx_csum = be_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = be_get_stat_strings, - .phys_id = be_phys_id, + .set_phys_id = be_set_phys_id, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, + .get_regs_len = be_get_reg_len, + .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d4344a06090..53d658afea2 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -155,6 +155,10 @@ /********** SRIOV VF PCICFG OFFSET ********/ #define SRIOV_VF_PCICFG_OFFSET (4096) +/********** FAT TABLE ********/ +#define RETRIEVE_FAT 0 +#define QUERY_FAT 1 + /* Flashrom related descriptors */ #define IMAGE_TYPE_FIRMWARE 160 #define IMAGE_TYPE_BOOTCODE 224 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 02a0443d182..7b19931acba 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -116,11 +116,6 @@ static char *ue_status_hi_desc[] = { "Unknown" }; -static inline bool be_multi_rxq(struct be_adapter *adapter) -{ - return (adapter->num_rx_qs > 1); -} - static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; @@ -993,9 +988,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { + struct net_device *netdev = adapter->netdev; struct sk_buff *skb; - skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); + skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); if (unlikely(!skb)) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -1005,13 +1001,16 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, rxo, skb, rxcp); - if (likely(adapter->rx_csum && csum_passed(rxcp))) + if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); skb->truesize = skb->len + sizeof(struct sk_buff); - skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->protocol = eth_type_trans(skb, netdev); + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + if (unlikely(rxcp->vlanf)) { if (!adapter->vlan_grp || adapter->vlans_added == 0) { @@ -1072,6 +1071,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, skb->data_len = rxcp->pkt_size; skb->truesize += rxcp->pkt_size; skb->ip_summed = CHECKSUM_UNNECESSARY; + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); @@ -1101,8 +1102,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); + } } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1127,8 +1134,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); + } } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1150,15 +1163,19 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) else be_parse_rx_compl_v0(adapter, compl, rxcp); - /* vlanf could be wrongly set in some cards. ignore if vtm is not set */ - if ((adapter->function_mode & 0x400) && !rxcp->vtm) - rxcp->vlanf = 0; + if (rxcp->vlanf) { + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->function_mode & 0x400) && !rxcp->vtm) + rxcp->vlanf = 0; - if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + if (!lancer_chip(adapter)) + rxcp->vid = swab16(rxcp->vid); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) - rxcp->vlanf = 0; + if ((adapter->pvid == rxcp->vid) && + !adapter->vlan_tag[rxcp->vid]) + rxcp->vlanf = 0; + } /* As the compl has been parsed, reset it; we wont touch it again */ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; @@ -1567,12 +1584,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) } } +static u32 be_num_rxqs_want(struct be_adapter *adapter) +{ + if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && + !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, + "No support for multiple RX queues\n"); + return 1; + } +} + static int be_rx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; struct be_rx_obj *rxo; int rc, i; + adapter->num_rx_qs = min(be_num_rxqs_want(adapter), + msix_enabled(adapter) ? + adapter->num_msix_vec - 1 : 1); + if (adapter->num_rx_qs != MAX_RX_QS) + dev_warn(&adapter->pdev->dev, + "Can create only %d RX queues", adapter->num_rx_qs); + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; for_all_rx_queues(adapter, rxo, i) { rxo->adapter = adapter; @@ -1837,6 +1873,9 @@ static void be_worker(struct work_struct *work) struct be_rx_obj *rxo; int i; + if (!adapter->ue_detected && !lancer_chip(adapter)) + be_detect_dump_ue(adapter); + /* when interrupts are not yet enabled, just reap any pending * mcc completions */ if (!netif_running(adapter->netdev)) { @@ -1849,9 +1888,6 @@ static void be_worker(struct work_struct *work) be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); - goto reschedule; } @@ -1869,8 +1905,6 @@ static void be_worker(struct work_struct *work) be_post_rx_frags(rxo, GFP_KERNEL); } } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); reschedule: adapter->work_counter++; @@ -1879,51 +1913,35 @@ reschedule: static void be_msix_disable(struct be_adapter *adapter) { - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; - } -} - -static int be_num_rxqs_get(struct be_adapter *adapter) -{ - if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { - return 1 + MAX_RSS_QS; /* one default non-RSS queue */ - } else { - dev_warn(&adapter->pdev->dev, - "No support for multiple RX queues\n"); - return 1; + adapter->num_msix_vec = 0; } } static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ - int i, status; + int i, status, num_vec; - adapter->num_rx_qs = be_num_rxqs_get(adapter); + num_vec = be_num_rxqs_want(adapter) + 1; - for (i = 0; i < (adapter->num_rx_qs + 1); i++) + for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - adapter->num_rx_qs + 1); + status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); if (status == 0) { goto done; } else if (status >= BE_MIN_MSIX_VECTORS) { + num_vec = status; if (pci_enable_msix(adapter->pdev, adapter->msix_entries, - status) == 0) { - adapter->num_rx_qs = status - 1; - dev_warn(&adapter->pdev->dev, - "Could alloc only %d MSIx vectors. " - "Using %d RX Qs\n", status, adapter->num_rx_qs); + num_vec) == 0) goto done; - } } return; done: - adapter->msix_enabled = true; + adapter->num_msix_vec = num_vec; + return; } static void be_sriov_enable(struct be_adapter *adapter) @@ -1931,7 +1949,20 @@ static void 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; + int status, pos; + u16 nvfs; + + pos = pci_find_ext_capability(adapter->pdev, + PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(adapter->pdev, + pos + PCI_SRIOV_TOTAL_VF, &nvfs); + + if (num_vfs > nvfs) { + dev_info(&adapter->pdev->dev, + "Device supports %d VFs and not %d\n", + nvfs, num_vfs); + num_vfs = nvfs; + } status = pci_enable_sriov(adapter->pdev, num_vfs); adapter->sriov_enabled = status ? false : true; @@ -2004,8 +2035,7 @@ err_msix: err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); - pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; + be_msix_disable(adapter); return status; } @@ -2014,7 +2044,7 @@ static int be_irq_register(struct be_adapter *adapter) struct net_device *netdev = adapter->netdev; int status; - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { status = be_msix_register(adapter); if (status == 0) goto done; @@ -2047,7 +2077,7 @@ static void be_irq_unregister(struct be_adapter *adapter) return; /* INTx */ - if (!adapter->msix_enabled) { + if (!msix_enabled(adapter)) { free_irq(netdev->irq, adapter); goto done; } @@ -2089,7 +2119,7 @@ static int be_close(struct net_device *netdev) be_cq_notify(adapter, rxo->cq.id, false, 0); } - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { vec = be_msix_vec_get(adapter, tx_eq); synchronize_irq(vec); @@ -2142,7 +2172,7 @@ static int be_open(struct net_device *netdev) be_async_mcc_enable(adapter); status = be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &link_speed); + &link_speed, 0); if (status) goto err; be_link_status_update(adapter, link_up); @@ -2262,7 +2292,7 @@ static int be_setup(struct be_adapter *adapter) BE_IF_FLAGS_PASS_L3L4_ERRORS; en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (be_multi_rxq(adapter)) { + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { cap_flags |= BE_IF_FLAGS_RSS; en_flags |= BE_IF_FLAGS_RSS; } @@ -2319,7 +2349,6 @@ static int be_setup(struct be_adapter *adapter) return 0; - be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: @@ -2600,10 +2629,14 @@ static void be_netdev_init(struct net_device *netdev) struct be_rx_obj *rxo; int i; - netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_GRO | NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX; + if (be_multi_rxq(adapter)) + netdev->hw_features |= NETIF_F_RXHASH; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -2613,8 +2646,6 @@ static void be_netdev_init(struct net_device *netdev) netdev->flags |= IFF_MULTICAST; - adapter->rx_csum = true; - /* Default settings for Rx and Tx flow control */ adapter->rx_fc = true; adapter->tx_fc = true; @@ -2808,6 +2839,7 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); + kfree(adapter->vf_cfg); be_sriov_disable(adapter); be_msix_disable(adapter); @@ -2992,16 +3024,23 @@ static int __devinit be_probe(struct pci_dev *pdev, } be_sriov_enable(adapter); + if (adapter->sriov_enabled) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), GFP_KERNEL); + + if (!adapter->vf_cfg) + goto free_netdev; + } status = be_ctrl_init(adapter); if (status) - goto free_netdev; + goto free_vf_cfg; if (lancer_chip(adapter)) { status = lancer_test_and_set_rdy_state(adapter); if (status) { dev_err(&pdev->dev, "Adapter in non recoverable error\n"); - goto free_netdev; + goto ctrl_clean; } } @@ -3044,9 +3083,22 @@ static int __devinit be_probe(struct pci_dev *pdev, netif_carrier_off(netdev); if (be_physfn(adapter) && adapter->sriov_enabled) { + u8 mac_speed; + bool link_up; + u16 vf, lnk_speed; + status = be_vf_eth_addr_config(adapter); if (status) goto unreg_netdev; + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_link_status_query(adapter, &link_up, + &mac_speed, &lnk_speed, vf + 1); + if (!status) + adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; + else + goto unreg_netdev; + } } dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); @@ -3063,6 +3115,8 @@ stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); +free_vf_cfg: + kfree(adapter->vf_cfg); free_netdev: be_sriov_disable(adapter); free_netdev(netdev); @@ -3147,16 +3201,15 @@ static void be_shutdown(struct pci_dev *pdev) if (!adapter) return; - if (netif_running(adapter->netdev)) - cancel_delayed_work_sync(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_device_detach(adapter->netdev); - be_cmd_reset_function(adapter); - if (adapter->wol) be_setup_wol(adapter, true); + be_cmd_reset_function(adapter); + pci_disable_device(pdev); } @@ -3268,13 +3321,6 @@ static int __init be_init_module(void) rx_frag_size = 2048; } - if (num_vfs > 32) { - printk(KERN_WARNING DRV_NAME - " : Module param num_vfs must not be greater than 32." - "Using 32\n"); - num_vfs = 32; - } - return pci_register_driver(&be_driver); } module_init(be_init_module); |