diff options
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 644 |
1 files changed, 384 insertions, 260 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6eda7a022256..45b1f6635282 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -32,6 +32,10 @@ module_param(num_vfs, uint, S_IRUGO); MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); +static bool multi_rxq = true; +module_param(multi_rxq, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default"); + static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, @@ -111,6 +115,11 @@ 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; @@ -236,18 +245,27 @@ netdev_addr: void netdev_stats_update(struct be_adapter *adapter) { - struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va); + struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); struct be_rxf_stats *rxf_stats = &hw_stats->rxf; struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->netdev->stats; struct be_erx_stats *erx_stats = &hw_stats->erx; + struct be_rx_obj *rxo; + int i; + + memset(dev_stats, 0, sizeof(*dev_stats)); + for_all_rx_queues(adapter, rxo, i) { + dev_stats->rx_packets += rx_stats(rxo)->rx_pkts; + dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes; + dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts; + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped += + erx_stats->rx_drops_no_fragments[rxo->q.id]; + } - dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts; - dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts; - dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes; - dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes; - dev_stats->multicast = drvr_stats(adapter)->be_rx_mcast_pkt; + dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts; + dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes; /* bad pkts received */ dev_stats->rx_errors = port_stats->rx_crc_errors + @@ -264,18 +282,11 @@ void netdev_stats_update(struct be_adapter *adapter) port_stats->rx_ip_checksum_errs + port_stats->rx_udp_checksum_errs; - /* no space in linux buffers: best possible approximation */ - dev_stats->rx_dropped = - erx_stats->rx_drops_no_fragments[adapter->rx_obj.q.id]; - /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; - /* receive ring buffer overflow */ - dev_stats->rx_over_errors = 0; - dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ @@ -286,23 +297,6 @@ void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + port_stats->rx_input_fifo_overflow + rxf_stats->rx_drops_no_pbuf; - /* receiver missed packetd */ - dev_stats->rx_missed_errors = 0; - - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->collisions = 0; - - /* detailed tx_errors */ - dev_stats->tx_aborted_errors = 0; - dev_stats->tx_carrier_errors = 0; - dev_stats->tx_fifo_errors = 0; - dev_stats->tx_heartbeat_errors = 0; - dev_stats->tx_window_errors = 0; } void be_link_status_update(struct be_adapter *adapter, bool link_up) @@ -326,10 +320,10 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up) } /* Update the EQ delay n BE based on the RX frags consumed / sec */ -static void be_rx_eqd_update(struct be_adapter *adapter) +static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) { - struct be_eq_obj *rx_eq = &adapter->rx_eq; - struct be_drvr_stats *stats = &adapter->stats.drvr_stats; + struct be_eq_obj *rx_eq = &rxo->rx_eq; + struct be_rx_stats *stats = &rxo->stats; ulong now = jiffies; u32 eqd; @@ -346,12 +340,12 @@ static void be_rx_eqd_update(struct be_adapter *adapter) if ((now - stats->rx_fps_jiffies) < HZ) return; - stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) / + stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) / ((now - stats->rx_fps_jiffies) / HZ); stats->rx_fps_jiffies = now; - stats->be_prev_rx_frags = stats->be_rx_frags; - eqd = stats->be_rx_fps / 110000; + stats->prev_rx_frags = stats->rx_frags; + eqd = stats->rx_fps / 110000; eqd = eqd << 3; if (eqd > rx_eq->max_eqd) eqd = rx_eq->max_eqd; @@ -365,11 +359,6 @@ static void be_rx_eqd_update(struct be_adapter *adapter) rx_eq->cur_eqd = eqd; } -static struct net_device_stats *be_get_stats(struct net_device *dev) -{ - return &dev->stats; -} - static u32 be_calc_rate(u64 bytes, unsigned long ticks) { u64 rate = bytes; @@ -383,7 +372,7 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks) static void be_tx_rate_update(struct be_adapter *adapter) { - struct be_drvr_stats *stats = drvr_stats(adapter); + struct be_tx_stats *stats = tx_stats(adapter); ulong now = jiffies; /* Wrapped around? */ @@ -405,7 +394,7 @@ static void be_tx_rate_update(struct be_adapter *adapter) static void be_tx_stats_update(struct be_adapter *adapter, u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped) { - struct be_drvr_stats *stats = drvr_stats(adapter); + struct be_tx_stats *stats = tx_stats(adapter); stats->be_tx_reqs++; stats->be_tx_wrbs += wrb_cnt; stats->be_tx_bytes += copied; @@ -440,9 +429,12 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; } -static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, - bool vlan, u32 wrb_cnt, u32 len) +static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, + struct sk_buff *skb, u32 wrb_cnt, u32 len) { + u8 vlan_prio = 0; + u16 vlan_tag = 0; + memset(hdr, 0, sizeof(*hdr)); AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1); @@ -460,10 +452,15 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1); } - if (vlan && vlan_tx_tag_present(skb)) { + if (adapter->vlan_grp && vlan_tx_tag_present(skb)) { AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, - hdr, vlan_tx_tag_get(skb)); + vlan_tag = vlan_tx_tag_get(skb); + vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + /* If vlan priority provided by OS is NOT in available bmap */ + if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) + vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | + adapter->recommended_prio; + AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); } AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); @@ -543,8 +540,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, queue_head_inc(txq); } - wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false, - wrb_cnt, copied); + wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied); be_dws_cpu_to_le(hdr, sizeof(*hdr)); return copied; @@ -637,7 +633,7 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) if (adapter->vlans_added <= adapter->max_vlans) { /* Construct VLAN Table to give to HW */ - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + for (i = 0; i < VLAN_N_VID; i++) { if (adapter->vlan_tag[i]) { vtag[ntags] = cpu_to_le16(i); ntags++; @@ -656,14 +652,8 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_eq_obj *rx_eq = &adapter->rx_eq; - struct be_eq_obj *tx_eq = &adapter->tx_eq; - be_eq_notify(adapter, rx_eq->q.id, false, false, 0); - be_eq_notify(adapter, tx_eq->q.id, false, false, 0); adapter->vlan_grp = grp; - be_eq_notify(adapter, rx_eq->q.id, true, false, 0); - be_eq_notify(adapter, tx_eq->q.id, true, false, 0); } static void be_vlan_add_vid(struct net_device *netdev, u16 vid) @@ -825,40 +815,38 @@ static int be_set_vf_tx_rate(struct net_device *netdev, return status; } -static void be_rx_rate_update(struct be_adapter *adapter) +static void be_rx_rate_update(struct be_rx_obj *rxo) { - struct be_drvr_stats *stats = drvr_stats(adapter); + struct be_rx_stats *stats = &rxo->stats; ulong now = jiffies; /* Wrapped around */ - if (time_before(now, stats->be_rx_jiffies)) { - stats->be_rx_jiffies = now; + if (time_before(now, stats->rx_jiffies)) { + stats->rx_jiffies = now; return; } /* Update the rate once in two seconds */ - if ((now - stats->be_rx_jiffies) < 2 * HZ) + if ((now - stats->rx_jiffies) < 2 * HZ) return; - stats->be_rx_rate = be_calc_rate(stats->be_rx_bytes - - stats->be_rx_bytes_prev, - now - stats->be_rx_jiffies); - stats->be_rx_jiffies = now; - stats->be_rx_bytes_prev = stats->be_rx_bytes; + stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev, + now - stats->rx_jiffies); + stats->rx_jiffies = now; + stats->rx_bytes_prev = stats->rx_bytes; } -static void be_rx_stats_update(struct be_adapter *adapter, +static void be_rx_stats_update(struct be_rx_obj *rxo, u32 pktsize, u16 numfrags, u8 pkt_type) { - struct be_drvr_stats *stats = drvr_stats(adapter); - - stats->be_rx_compl++; - stats->be_rx_frags += numfrags; - stats->be_rx_bytes += pktsize; - stats->be_rx_pkts++; + struct be_rx_stats *stats = &rxo->stats; + stats->rx_compl++; + stats->rx_frags += numfrags; + stats->rx_bytes += pktsize; + stats->rx_pkts++; if (pkt_type == BE_MULTICAST_PACKET) - stats->be_rx_mcast_pkt++; + stats->rx_mcast_pkts++; } static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) @@ -878,12 +866,14 @@ static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) } static struct be_rx_page_info * -get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) +get_rx_page_info(struct be_adapter *adapter, + struct be_rx_obj *rxo, + u16 frag_idx) { struct be_rx_page_info *rx_page_info; - struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_queue_info *rxq = &rxo->q; - rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx]; + rx_page_info = &rxo->page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); if (rx_page_info->last_page_user) { @@ -898,9 +888,10 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) /* Throwaway the data in the Rx completion */ static void be_rx_compl_discard(struct be_adapter *adapter, - struct be_eth_rx_compl *rxcp) + struct be_rx_obj *rxo, + struct be_eth_rx_compl *rxcp) { - struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 rxq_idx, i, num_rcvd; @@ -908,7 +899,7 @@ static void be_rx_compl_discard(struct be_adapter *adapter, num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); for (i = 0; i < num_rcvd; i++) { - page_info = get_rx_page_info(adapter, rxq_idx); + page_info = get_rx_page_info(adapter, rxo, rxq_idx); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); index_inc(&rxq_idx, rxq->len); @@ -919,11 +910,11 @@ static void be_rx_compl_discard(struct be_adapter *adapter, * skb_fill_rx_data forms a complete skb for an ether frame * indicated by rxcp. */ -static void skb_fill_rx_data(struct be_adapter *adapter, +static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, struct sk_buff *skb, struct be_eth_rx_compl *rxcp, u16 num_rcvd) { - struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 rxq_idx, i, j; u32 pktsize, hdr_len, curr_frag_len, size; @@ -934,7 +925,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp); - page_info = get_rx_page_info(adapter, rxq_idx); + page_info = get_rx_page_info(adapter, rxo, rxq_idx); start = page_address(page_info->page) + page_info->page_offset; prefetch(start); @@ -972,7 +963,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, for (i = 1, j = 0; i < num_rcvd; i++) { size -= curr_frag_len; index_inc(&rxq_idx, rxq->len); - page_info = get_rx_page_info(adapter, rxq_idx); + page_info = get_rx_page_info(adapter, rxo, rxq_idx); curr_frag_len = min(size, rx_frag_size); @@ -998,11 +989,12 @@ static void skb_fill_rx_data(struct be_adapter *adapter, BUG_ON(j > MAX_SKB_FRAGS); done: - be_rx_stats_update(adapter, pktsize, num_rcvd, pkt_type); + be_rx_stats_update(rxo, pktsize, num_rcvd, pkt_type); } /* Process the RX completion indicated by rxcp when GRO is disabled */ static void be_rx_compl_process(struct be_adapter *adapter, + struct be_rx_obj *rxo, struct be_eth_rx_compl *rxcp) { struct sk_buff *skb; @@ -1019,14 +1011,14 @@ static void be_rx_compl_process(struct be_adapter *adapter, if (unlikely(!skb)) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); - be_rx_compl_discard(adapter, rxcp); + be_rx_compl_discard(adapter, rxo, rxcp); return; } - skb_fill_rx_data(adapter, skb, rxcp, num_rcvd); + skb_fill_rx_data(adapter, rxo, skb, rxcp, num_rcvd); if (do_pkt_csum(rxcp, adapter->rx_csum)) - skb->ip_summed = CHECKSUM_NONE; + skb_checksum_none_assert(skb); else skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1056,12 +1048,13 @@ static void be_rx_compl_process(struct be_adapter *adapter, /* Process the RX completion indicated by rxcp when GRO is enabled */ static void be_rx_compl_process_gro(struct be_adapter *adapter, - struct be_eth_rx_compl *rxcp) + struct be_rx_obj *rxo, + struct be_eth_rx_compl *rxcp) { struct be_rx_page_info *page_info; struct sk_buff *skb = NULL; - struct be_queue_info *rxq = &adapter->rx_obj.q; - struct be_eq_obj *eq_obj = &adapter->rx_eq; + struct be_queue_info *rxq = &rxo->q; + struct be_eq_obj *eq_obj = &rxo->rx_eq; u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; u16 i, rxq_idx = 0, vid, j; u8 vtm; @@ -1085,13 +1078,13 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, skb = napi_get_frags(&eq_obj->napi); if (!skb) { - be_rx_compl_discard(adapter, rxcp); + be_rx_compl_discard(adapter, rxo, rxcp); return; } remaining = pkt_size; for (i = 0, j = -1; i < num_rcvd; i++) { - page_info = get_rx_page_info(adapter, rxq_idx); + page_info = get_rx_page_info(adapter, rxo, rxq_idx); curr_frag_len = min(remaining, rx_frag_size); @@ -1132,12 +1125,12 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); } - be_rx_stats_update(adapter, pkt_size, num_rcvd, pkt_type); + be_rx_stats_update(rxo, pkt_size, num_rcvd, pkt_type); } -static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) +static struct be_eth_rx_compl *be_rx_compl_get(struct be_rx_obj *rxo) { - struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq); + struct be_eth_rx_compl *rxcp = queue_tail_node(&rxo->cq); if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0) return NULL; @@ -1145,7 +1138,7 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) rmb(); be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - queue_tail_inc(&adapter->rx_obj.cq); + queue_tail_inc(&rxo->cq); return rxcp; } @@ -1171,22 +1164,23 @@ static inline struct page *be_alloc_pages(u32 size) * Allocate a page, split it to fragments of size rx_frag_size and post as * receive buffers to BE */ -static void be_post_rx_frags(struct be_adapter *adapter) +static void be_post_rx_frags(struct be_rx_obj *rxo) { - struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl; + struct be_adapter *adapter = rxo->adapter; + struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl; struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL; - struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_queue_info *rxq = &rxo->q; struct page *pagep = NULL; struct be_eth_rx_d *rxd; u64 page_dmaaddr = 0, frag_dmaaddr; u32 posted, page_offset = 0; - page_info = &page_info_tbl[rxq->head]; + page_info = &rxo->page_info_tbl[rxq->head]; for (posted = 0; posted < MAX_RX_POST && !page_info->page; posted++) { if (!pagep) { pagep = be_alloc_pages(adapter->big_page_size); if (unlikely(!pagep)) { - drvr_stats(adapter)->be_ethrx_post_fail++; + rxo->stats.rx_post_fail++; break; } page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0, @@ -1225,7 +1219,7 @@ static void be_post_rx_frags(struct be_adapter *adapter) be_rxq_notify(adapter, rxq->id, posted); } else if (atomic_read(&rxq->used) == 0) { /* Let be_worker replenish when memory is available */ - adapter->rx_post_starved = true; + rxo->rx_post_starved = true; } } @@ -1328,17 +1322,17 @@ static void be_eq_clean(struct be_adapter *adapter, be_eq_notify(adapter, eq_obj->q.id, false, true, num); } -static void be_rx_q_clean(struct be_adapter *adapter) +static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) { struct be_rx_page_info *page_info; - struct be_queue_info *rxq = &adapter->rx_obj.q; - struct be_queue_info *rx_cq = &adapter->rx_obj.cq; + struct be_queue_info *rxq = &rxo->q; + struct be_queue_info *rx_cq = &rxo->cq; struct be_eth_rx_compl *rxcp; u16 tail; /* First cleanup pending rx completions */ - while ((rxcp = be_rx_compl_get(adapter)) != NULL) { - be_rx_compl_discard(adapter, rxcp); + while ((rxcp = be_rx_compl_get(rxo)) != NULL) { + be_rx_compl_discard(adapter, rxo, rxcp); be_rx_compl_reset(rxcp); be_cq_notify(adapter, rx_cq->id, true, 1); } @@ -1346,7 +1340,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* Then free posted rx buffer that were not used */ tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { - page_info = get_rx_page_info(adapter, tail); + page_info = get_rx_page_info(adapter, rxo, tail); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); } @@ -1524,92 +1518,101 @@ tx_eq_free: static void be_rx_queues_destroy(struct be_adapter *adapter) { struct be_queue_info *q; - - q = &adapter->rx_obj.q; - if (q->created) { - be_cmd_q_destroy(adapter, q, QTYPE_RXQ); - - /* After the rxq is invalidated, wait for a grace time - * of 1ms for all dma to end and the flush compl to arrive - */ - mdelay(1); - be_rx_q_clean(adapter); + struct be_rx_obj *rxo; + int i; + + for_all_rx_queues(adapter, rxo, i) { + q = &rxo->q; + if (q->created) { + be_cmd_q_destroy(adapter, q, QTYPE_RXQ); + /* After the rxq is invalidated, wait for a grace time + * of 1ms for all dma to end and the flush compl to + * arrive + */ + mdelay(1); + be_rx_q_clean(adapter, rxo); + } + be_queue_free(adapter, q); + + q = &rxo->cq; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_CQ); + be_queue_free(adapter, q); + + /* Clear any residual events */ + q = &rxo->rx_eq.q; + if (q->created) { + be_eq_clean(adapter, &rxo->rx_eq); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); + } + be_queue_free(adapter, q); } - be_queue_free(adapter, q); - - q = &adapter->rx_obj.cq; - if (q->created) - be_cmd_q_destroy(adapter, q, QTYPE_CQ); - be_queue_free(adapter, q); - - /* Clear any residual events */ - be_eq_clean(adapter, &adapter->rx_eq); - - q = &adapter->rx_eq.q; - if (q->created) - be_cmd_q_destroy(adapter, q, QTYPE_EQ); - be_queue_free(adapter, q); } static int be_rx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; - int rc; + struct be_rx_obj *rxo; + int rc, i; adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; - adapter->rx_eq.max_eqd = BE_MAX_EQD; - adapter->rx_eq.min_eqd = 0; - adapter->rx_eq.cur_eqd = 0; - adapter->rx_eq.enable_aic = true; - - /* Alloc Rx Event queue */ - eq = &adapter->rx_eq.q; - rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, - sizeof(struct be_eq_entry)); - if (rc) - return rc; - - /* Ask BE to create Rx Event queue */ - rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd); - if (rc) - goto rx_eq_free; - - /* Alloc RX eth compl queue */ - cq = &adapter->rx_obj.cq; - rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, - sizeof(struct be_eth_rx_compl)); - if (rc) - goto rx_eq_destroy; - - /* Ask BE to create Rx eth compl queue */ - rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); - if (rc) - goto rx_cq_free; - - /* Alloc RX eth queue */ - q = &adapter->rx_obj.q; - rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d)); - if (rc) - goto rx_cq_destroy; - - /* Ask BE to create Rx eth queue */ - rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, - BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); - if (rc) - goto rx_q_free; + for_all_rx_queues(adapter, rxo, i) { + rxo->adapter = adapter; + rxo->rx_eq.max_eqd = BE_MAX_EQD; + rxo->rx_eq.enable_aic = true; + + /* EQ */ + eq = &rxo->rx_eq.q; + rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, + sizeof(struct be_eq_entry)); + if (rc) + goto err; + + rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd); + if (rc) + goto err; + + /* CQ */ + cq = &rxo->cq; + rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, + sizeof(struct be_eth_rx_compl)); + if (rc) + goto err; + + rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); + if (rc) + goto err; + + /* Rx Q */ + q = &rxo->q; + rc = be_queue_alloc(adapter, q, RX_Q_LEN, + sizeof(struct be_eth_rx_d)); + if (rc) + goto err; + + rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, + BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, + (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id); + if (rc) + goto err; + } + + if (be_multi_rxq(adapter)) { + u8 rsstable[MAX_RSS_QS]; + + for_all_rss_queues(adapter, rxo, i) + rsstable[i] = rxo->rss_id; + + rc = be_cmd_rss_config(adapter, rsstable, + adapter->num_rx_qs - 1); + if (rc) + goto err; + } return 0; -rx_q_free: - be_queue_free(adapter, q); -rx_cq_destroy: - be_cmd_q_destroy(adapter, cq, QTYPE_CQ); -rx_cq_free: - be_queue_free(adapter, cq); -rx_eq_destroy: - be_cmd_q_destroy(adapter, eq, QTYPE_EQ); -rx_eq_free: - be_queue_free(adapter, eq); - return rc; +err: + be_rx_queues_destroy(adapter); + return -1; } /* There are 8 evt ids per func. Retruns the evt id's bit number */ @@ -1621,24 +1624,31 @@ static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id) static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; - int isr; + struct be_rx_obj *rxo; + int isr, i; isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + (adapter->tx_eq.q.id/ 8) * CEV_ISR_SIZE); if (!isr) return IRQ_NONE; - event_handle(adapter, &adapter->tx_eq); - event_handle(adapter, &adapter->rx_eq); + if ((1 << be_evt_bit_get(adapter, adapter->tx_eq.q.id) & isr)) + event_handle(adapter, &adapter->tx_eq); + + for_all_rx_queues(adapter, rxo, i) { + if ((1 << be_evt_bit_get(adapter, rxo->rx_eq.q.id) & isr)) + event_handle(adapter, &rxo->rx_eq); + } return IRQ_HANDLED; } static irqreturn_t be_msix_rx(int irq, void *dev) { - struct be_adapter *adapter = dev; + struct be_rx_obj *rxo = dev; + struct be_adapter *adapter = rxo->adapter; - event_handle(adapter, &adapter->rx_eq); + event_handle(adapter, &rxo->rx_eq); return IRQ_HANDLED; } @@ -1652,14 +1662,14 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) return IRQ_HANDLED; } -static inline bool do_gro(struct be_adapter *adapter, +static inline bool do_gro(struct be_adapter *adapter, struct be_rx_obj *rxo, struct be_eth_rx_compl *rxcp) { int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); if (err) - drvr_stats(adapter)->be_rxcp_err++; + rxo->stats.rxcp_err++; return (tcp_frame && !err) ? true : false; } @@ -1667,29 +1677,29 @@ static inline bool do_gro(struct be_adapter *adapter, int be_poll_rx(struct napi_struct *napi, int budget) { struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi); - struct be_adapter *adapter = - container_of(rx_eq, struct be_adapter, rx_eq); - struct be_queue_info *rx_cq = &adapter->rx_obj.cq; + struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq); + struct be_adapter *adapter = rxo->adapter; + struct be_queue_info *rx_cq = &rxo->cq; struct be_eth_rx_compl *rxcp; u32 work_done; - adapter->stats.drvr_stats.be_rx_polls++; + rxo->stats.rx_polls++; for (work_done = 0; work_done < budget; work_done++) { - rxcp = be_rx_compl_get(adapter); + rxcp = be_rx_compl_get(rxo); if (!rxcp) break; - if (do_gro(adapter, rxcp)) - be_rx_compl_process_gro(adapter, rxcp); + if (do_gro(adapter, rxo, rxcp)) + be_rx_compl_process_gro(adapter, rxo, rxcp); else - be_rx_compl_process(adapter, rxcp); + be_rx_compl_process(adapter, rxo, rxcp); be_rx_compl_reset(rxcp); } /* Refill the queue */ - if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) - be_post_rx_frags(adapter); + if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM) + be_post_rx_frags(rxo); /* All consumed */ if (work_done < budget) { @@ -1743,8 +1753,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) netif_wake_queue(adapter->netdev); } - drvr_stats(adapter)->be_tx_events++; - drvr_stats(adapter)->be_tx_compl += tx_compl; + tx_stats(adapter)->be_tx_events++; + tx_stats(adapter)->be_tx_compl += tx_compl; } return 1; @@ -1793,20 +1803,24 @@ static void be_worker(struct work_struct *work) { struct be_adapter *adapter = container_of(work, struct be_adapter, work.work); + struct be_rx_obj *rxo; + int i; if (!adapter->stats_ioctl_sent) - be_cmd_get_stats(adapter, &adapter->stats.cmd); - - /* Set EQ delay */ - be_rx_eqd_update(adapter); + be_cmd_get_stats(adapter, &adapter->stats_cmd); be_tx_rate_update(adapter); - be_rx_rate_update(adapter); - if (adapter->rx_post_starved) { - adapter->rx_post_starved = false; - be_post_rx_frags(adapter); + for_all_rx_queues(adapter, rxo, i) { + be_rx_rate_update(rxo); + be_rx_eqd_update(adapter, rxo); + + if (rxo->rx_post_starved) { + rxo->rx_post_starved = false; + be_post_rx_frags(rxo); + } } + if (!adapter->ue_detected) be_detect_dump_ue(adapter); @@ -1821,17 +1835,45 @@ static void be_msix_disable(struct be_adapter *adapter) } } +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; + } +} + static void be_msix_enable(struct be_adapter *adapter) { +#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ int i, status; - for (i = 0; i < BE_NUM_MSIX_VECTORS; i++) + adapter->num_rx_qs = be_num_rxqs_get(adapter); + + for (i = 0; i < (adapter->num_rx_qs + 1); i++) adapter->msix_entries[i].entry = i; status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - BE_NUM_MSIX_VECTORS); - if (status == 0) - adapter->msix_enabled = true; + adapter->num_rx_qs + 1); + if (status == 0) { + goto done; + } else if (status >= BE_MIN_MSIX_VECTORS) { + 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); + goto done; + } + } + return; +done: + adapter->msix_enabled = true; } static void be_sriov_enable(struct be_adapter *adapter) @@ -1865,38 +1907,50 @@ static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) static int be_request_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj, - void *handler, char *desc) + void *handler, char *desc, void *context) { struct net_device *netdev = adapter->netdev; int vec; sprintf(eq_obj->desc, "%s-%s", netdev->name, desc); vec = be_msix_vec_get(adapter, eq_obj->q.id); - return request_irq(vec, handler, 0, eq_obj->desc, adapter); + return request_irq(vec, handler, 0, eq_obj->desc, context); } -static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj) +static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj, + void *context) { int vec = be_msix_vec_get(adapter, eq_obj->q.id); - free_irq(vec, adapter); + free_irq(vec, context); } static int be_msix_register(struct be_adapter *adapter) { - int status; + struct be_rx_obj *rxo; + int status, i; + char qname[10]; - status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx"); + status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx", + adapter); if (status) goto err; - status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx"); - if (status) - goto free_tx_irq; + for_all_rx_queues(adapter, rxo, i) { + sprintf(qname, "rxq%d", i); + status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx, + qname, rxo); + if (status) + goto err_msix; + } return 0; -free_tx_irq: - be_free_irq(adapter, &adapter->tx_eq); +err_msix: + be_free_irq(adapter, &adapter->tx_eq, adapter); + + for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--) + be_free_irq(adapter, &rxo->rx_eq, rxo); + err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); @@ -1936,6 +1990,8 @@ done: static void be_irq_unregister(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct be_rx_obj *rxo; + int i; if (!adapter->isr_registered) return; @@ -1947,8 +2003,11 @@ static void be_irq_unregister(struct be_adapter *adapter) } /* MSIx */ - be_free_irq(adapter, &adapter->tx_eq); - be_free_irq(adapter, &adapter->rx_eq); + be_free_irq(adapter, &adapter->tx_eq, adapter); + + for_all_rx_queues(adapter, rxo, i) + be_free_irq(adapter, &rxo->rx_eq, rxo); + done: adapter->isr_registered = false; } @@ -1956,9 +2015,9 @@ done: static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_eq_obj *rx_eq = &adapter->rx_eq; + struct be_rx_obj *rxo; struct be_eq_obj *tx_eq = &adapter->tx_eq; - int vec; + int vec, i; cancel_delayed_work_sync(&adapter->work); @@ -1973,14 +2032,19 @@ static int be_close(struct net_device *netdev) if (adapter->msix_enabled) { vec = be_msix_vec_get(adapter, tx_eq->q.id); synchronize_irq(vec); - vec = be_msix_vec_get(adapter, rx_eq->q.id); - synchronize_irq(vec); + + for_all_rx_queues(adapter, rxo, i) { + vec = be_msix_vec_get(adapter, rxo->rx_eq.q.id); + synchronize_irq(vec); + } } else { synchronize_irq(netdev->irq); } be_irq_unregister(adapter); - napi_disable(&rx_eq->napi); + for_all_rx_queues(adapter, rxo, i) + napi_disable(&rxo->rx_eq.napi); + napi_disable(&tx_eq->napi); /* Wait for all pending tx completions to arrive so that @@ -1994,17 +2058,17 @@ static int be_close(struct net_device *netdev) static int be_open(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; + struct be_rx_obj *rxo; bool link_up; - int status; + int status, i; u8 mac_speed; u16 link_speed; - /* First time posting */ - be_post_rx_frags(adapter); - - napi_enable(&rx_eq->napi); + for_all_rx_queues(adapter, rxo, i) { + be_post_rx_frags(rxo); + napi_enable(&rxo->rx_eq.napi); + } napi_enable(&tx_eq->napi); be_irq_register(adapter); @@ -2012,12 +2076,12 @@ static int be_open(struct net_device *netdev) be_intr_set(adapter, true); /* The evt queues are created in unarmed state; arm them */ - be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + for_all_rx_queues(adapter, rxo, i) { + be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0); + be_cq_notify(adapter, rxo->cq.id, true, 0); + } be_eq_notify(adapter, tx_eq->q.id, true, false, 0); - /* Rx compl queue may be in unarmed state; rearm it */ - be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0); - /* Now that interrupts are on we can process async mcc */ be_async_mcc_enable(adapter); @@ -2084,6 +2148,47 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) return status; } +/* + * Generate a seed MAC address from the PF MAC Address using jhash. + * MAC Address for VFs are assigned incrementally starting from the seed. + * These addresses are programmed in the ASIC by the PF and the VF driver + * queries for the MAC address during its probe. + */ +static inline int be_vf_eth_addr_config(struct be_adapter *adapter) +{ + u32 vf = 0; + int status = 0; + u8 mac[ETH_ALEN]; + + be_vf_eth_addr_generate(adapter, mac); + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_pmac_add(adapter, mac, + adapter->vf_cfg[vf].vf_if_handle, + &adapter->vf_cfg[vf].vf_pmac_id); + if (status) + dev_err(&adapter->pdev->dev, + "Mac address add failed for VF %d\n", vf); + else + memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); + + mac[5] += 1; + } + return status; +} + +static inline void be_vf_eth_addr_rem(struct be_adapter *adapter) +{ + u32 vf; + + for (vf = 0; vf < num_vfs; vf++) { + if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) + be_cmd_pmac_del(adapter, + adapter->vf_cfg[vf].vf_if_handle, + adapter->vf_cfg[vf].vf_pmac_id); + } +} + static int be_setup(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -2098,6 +2203,11 @@ static int be_setup(struct be_adapter *adapter) BE_IF_FLAGS_PROMISCUOUS | BE_IF_FLAGS_PASS_L3L4_ERRORS; en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; + + if (be_multi_rxq(adapter)) { + cap_flags |= BE_IF_FLAGS_RSS; + en_flags |= BE_IF_FLAGS_RSS; + } } status = be_cmd_if_create(adapter, cap_flags, en_flags, @@ -2143,10 +2253,20 @@ static int be_setup(struct be_adapter *adapter) if (status != 0) goto rx_qs_destroy; + if (be_physfn(adapter)) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto mcc_q_destroy; + } + adapter->link_speed = -1; return 0; +mcc_q_destroy: + if (be_physfn(adapter)) + be_vf_eth_addr_rem(adapter); + be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: @@ -2163,6 +2283,9 @@ do_none: static int be_clear(struct be_adapter *adapter) { + if (be_physfn(adapter)) + be_vf_eth_addr_rem(adapter); + be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); @@ -2390,7 +2513,6 @@ static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, .ndo_start_xmit = be_xmit, - .ndo_get_stats = be_get_stats, .ndo_set_rx_mode = be_set_multicast_list, .ndo_set_mac_address = be_mac_addr_set, .ndo_change_mtu = be_change_mtu, @@ -2407,6 +2529,8 @@ static struct net_device_ops be_netdev_ops = { static void be_netdev_init(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(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_HW_CSUM | @@ -2428,8 +2552,10 @@ static void be_netdev_init(struct net_device *netdev) SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); - netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, - BE_NAPI_WEIGHT); + for_all_rx_queues(adapter, rxo, i) + netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx, + BE_NAPI_WEIGHT); + netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, BE_NAPI_WEIGHT); @@ -2563,8 +2689,7 @@ done: static void be_stats_cleanup(struct be_adapter *adapter) { - struct be_stats_obj *stats = &adapter->stats; - struct be_dma_mem *cmd = &stats->cmd; + struct be_dma_mem *cmd = &adapter->stats_cmd; if (cmd->va) pci_free_consistent(adapter->pdev, cmd->size, @@ -2573,8 +2698,7 @@ static void be_stats_cleanup(struct be_adapter *adapter) static int be_stats_init(struct be_adapter *adapter) { - struct be_stats_obj *stats = &adapter->stats; - struct be_dma_mem *cmd = &stats->cmd; + struct be_dma_mem *cmd = &adapter->stats_cmd; cmd->size = sizeof(struct be_cmd_req_get_stats); cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); @@ -2619,8 +2743,8 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - status = be_cmd_query_fw_cfg(adapter, - &adapter->port_num, &adapter->function_mode); + status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, + &adapter->function_mode, &adapter->function_caps); if (status) return status; @@ -2655,7 +2779,6 @@ static int __devinit be_probe(struct pci_dev *pdev, struct be_adapter *adapter; struct net_device *netdev; - status = pci_enable_device(pdev); if (status) goto do_none; @@ -2688,11 +2811,8 @@ static int __devinit be_probe(struct pci_dev *pdev, adapter->pdev = pdev; pci_set_drvdata(pdev, adapter); adapter->netdev = netdev; - be_netdev_init(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); - be_msix_enable(adapter); - status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (!status) { netdev->features |= NETIF_F_HIGHDMA; @@ -2736,12 +2856,15 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto stats_clean; + be_msix_enable(adapter); + INIT_DELAYED_WORK(&adapter->work, be_worker); status = be_setup(adapter); if (status) - goto stats_clean; + goto msix_disable; + be_netdev_init(netdev); status = register_netdev(netdev); if (status != 0) goto unsetup; @@ -2751,12 +2874,13 @@ static int __devinit be_probe(struct pci_dev *pdev, unsetup: be_clear(adapter); +msix_disable: + be_msix_disable(adapter); stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); free_netdev: - be_msix_disable(adapter); be_sriov_disable(adapter); free_netdev(adapter->netdev); pci_set_drvdata(pdev, NULL); |