diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_main.c')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 227 |
1 files changed, 158 insertions, 69 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2c38cc402119..393e3dc05a36 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -306,10 +306,14 @@ static void *hw_stats_from_cmd(struct be_adapter *adapter) struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va; return &cmd->hw_stats; - } else { + } else if (BE3_chip(adapter)) { struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va; return &cmd->hw_stats; + } else { + struct be_cmd_resp_get_stats_v2 *cmd = adapter->stats_cmd.va; + + return &cmd->hw_stats; } } @@ -320,10 +324,14 @@ static void *be_erx_stats_from_cmd(struct be_adapter *adapter) struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); return &hw_stats->erx; - } else { + } else if (BE3_chip(adapter)) { struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); return &hw_stats->erx; + } else { + struct be_hw_stats_v2 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->erx; } } @@ -422,6 +430,60 @@ static void populate_be_v1_stats(struct be_adapter *adapter) adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; } +static void populate_be_v2_stats(struct be_adapter *adapter) +{ + struct be_hw_stats_v2 *hw_stats = hw_stats_from_cmd(adapter); + struct be_pmem_stats *pmem_sts = &hw_stats->pmem; + struct be_rxf_stats_v2 *rxf_stats = &hw_stats->rxf; + struct be_port_rxf_stats_v2 *port_stats = + &rxf_stats->port[adapter->port_num]; + struct be_drv_stats *drvs = &adapter->drv_stats; + + be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats)); + drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop; + drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames; + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; + drvs->rx_in_range_errors = port_stats->rx_in_range_errors; + drvs->rx_frame_too_long = port_stats->rx_frame_too_long; + drvs->rx_dropped_runt = port_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; + drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; + drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; + drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; + drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = port_stats->rx_out_range_errors; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow_drop; + drvs->rx_address_filtered = port_stats->rx_address_filtered; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop; + drvs->tx_pauseframes = port_stats->tx_pauseframes; + drvs->tx_controlframes = port_stats->tx_controlframes; + drvs->tx_priority_pauseframes = port_stats->tx_priority_pauseframes; + drvs->jabber_events = port_stats->jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr; + drvs->rx_drops_too_many_frags = rxf_stats->rx_drops_too_many_frags; + adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; + if (be_roce_supported(adapter)) { + drvs->rx_roce_bytes_lsd = port_stats->roce_bytes_received_lsd; + drvs->rx_roce_bytes_msd = port_stats->roce_bytes_received_msd; + drvs->rx_roce_frames = port_stats->roce_frames_received; + drvs->roce_drops_crc = port_stats->roce_drops_crc; + drvs->roce_drops_payload_len = + port_stats->roce_drops_payload_len; + } +} + static void populate_lancer_stats(struct be_adapter *adapter) { @@ -489,7 +551,7 @@ static void populate_erx_stats(struct be_adapter *adapter, void be_parse_stats(struct be_adapter *adapter) { - struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter); + struct be_erx_stats_v2 *erx = be_erx_stats_from_cmd(adapter); struct be_rx_obj *rxo; int i; u32 erx_stat; @@ -499,11 +561,13 @@ void be_parse_stats(struct be_adapter *adapter) } else { if (BE2_chip(adapter)) populate_be_v0_stats(adapter); - else - /* for BE3 and Skyhawk */ + else if (BE3_chip(adapter)) + /* for BE3 */ populate_be_v1_stats(adapter); + else + populate_be_v2_stats(adapter); - /* as erx_v1 is longer than v0, ok to use v1 for v0 access */ + /* erx_v2 is longer than v0, v1. use v2 for v0, v1 access */ for_all_rx_queues(adapter, rxo, i) { erx_stat = erx->rx_drops_no_fragments[rxo->q.id]; populate_erx_stats(adapter, rxo, erx_stat); @@ -935,8 +999,10 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) u32 start = txq->head; skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); - if (!skb) + if (!skb) { + tx_stats(txo)->tx_drv_drops++; return NETDEV_TX_OK; + } wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); @@ -965,6 +1031,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped); } else { txq->head = start; + tx_stats(txo)->tx_drv_drops++; dev_kfree_skb_any(skb); } return NETDEV_TX_OK; @@ -1275,53 +1342,79 @@ static int be_set_vf_tx_rate(struct net_device *netdev, return status; } -static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo) +static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts, + ulong now) { - struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]); - ulong now = jiffies; - ulong delta = now - stats->rx_jiffies; - u64 pkts; - unsigned int start, eqd; + aic->rx_pkts_prev = rx_pkts; + aic->tx_reqs_prev = tx_pkts; + aic->jiffies = now; +} - if (!eqo->enable_aic) { - eqd = eqo->eqd; - goto modify_eqd; - } +static void be_eqd_update(struct be_adapter *adapter) +{ + struct be_set_eqd set_eqd[MAX_EVT_QS]; + int eqd, i, num = 0, start; + struct be_aic_obj *aic; + struct be_eq_obj *eqo; + struct be_rx_obj *rxo; + struct be_tx_obj *txo; + u64 rx_pkts, tx_pkts; + ulong now; + u32 pps, delta; - if (eqo->idx >= adapter->num_rx_qs) - return; + for_all_evt_queues(adapter, eqo, i) { + aic = &adapter->aic_obj[eqo->idx]; + if (!aic->enable) { + if (aic->jiffies) + aic->jiffies = 0; + eqd = aic->et_eqd; + goto modify_eqd; + } - stats = rx_stats(&adapter->rx_obj[eqo->idx]); + rxo = &adapter->rx_obj[eqo->idx]; + do { + start = u64_stats_fetch_begin_bh(&rxo->stats.sync); + rx_pkts = rxo->stats.rx_pkts; + } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start)); - /* Wrapped around */ - if (time_before(now, stats->rx_jiffies)) { - stats->rx_jiffies = now; - return; - } + txo = &adapter->tx_obj[eqo->idx]; + do { + start = u64_stats_fetch_begin_bh(&txo->stats.sync); + tx_pkts = txo->stats.tx_reqs; + } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start)); - /* Update once a second */ - if (delta < HZ) - return; - do { - start = u64_stats_fetch_begin_bh(&stats->sync); - pkts = stats->rx_pkts; - } while (u64_stats_fetch_retry_bh(&stats->sync, start)); - - stats->rx_pps = (unsigned long)(pkts - stats->rx_pkts_prev) / (delta / HZ); - stats->rx_pkts_prev = pkts; - stats->rx_jiffies = now; - eqd = (stats->rx_pps / 110000) << 3; - eqd = min(eqd, eqo->max_eqd); - eqd = max(eqd, eqo->min_eqd); - if (eqd < 10) - eqd = 0; + /* Skip, if wrapped around or first calculation */ + now = jiffies; + if (!aic->jiffies || time_before(now, aic->jiffies) || + rx_pkts < aic->rx_pkts_prev || + tx_pkts < aic->tx_reqs_prev) { + be_aic_update(aic, rx_pkts, tx_pkts, now); + continue; + } + delta = jiffies_to_msecs(now - aic->jiffies); + pps = (((u32)(rx_pkts - aic->rx_pkts_prev) * 1000) / delta) + + (((u32)(tx_pkts - aic->tx_reqs_prev) * 1000) / delta); + eqd = (pps / 15000) << 2; + + if (eqd < 8) + eqd = 0; + eqd = min_t(u32, eqd, aic->max_eqd); + eqd = max_t(u32, eqd, aic->min_eqd); + + be_aic_update(aic, rx_pkts, tx_pkts, now); modify_eqd: - if (eqd != eqo->cur_eqd) { - be_cmd_modify_eqd(adapter, eqo->q.id, eqd); - eqo->cur_eqd = eqd; + if (eqd != aic->prev_eqd) { + set_eqd[num].delay_multiplier = (eqd * 65)/100; + set_eqd[num].eq_id = eqo->q.id; + aic->prev_eqd = eqd; + num++; + } } + + if (num) + be_cmd_modify_eqd(adapter, set_eqd, num); } static void be_rx_stats_update(struct be_rx_obj *rxo, @@ -1938,6 +2031,7 @@ static int be_evt_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq; struct be_eq_obj *eqo; + struct be_aic_obj *aic; int i, rc; adapter->num_evt_qs = min_t(u16, num_irqs(adapter), @@ -1946,11 +2040,12 @@ static int be_evt_queues_create(struct be_adapter *adapter) for_all_evt_queues(adapter, eqo, i) { netif_napi_add(adapter->netdev, &eqo->napi, be_poll, BE_NAPI_WEIGHT); + aic = &adapter->aic_obj[i]; eqo->adapter = adapter; eqo->tx_budget = BE_TX_BUDGET; eqo->idx = i; - eqo->max_eqd = BE_MAX_EQD; - eqo->enable_aic = true; + aic->max_eqd = BE_MAX_EQD; + aic->enable = true; eq = &eqo->q; rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, @@ -2937,7 +3032,8 @@ static int be_vf_setup(struct be_adapter *adapter) goto err; vf_cfg->def_vid = def_vlan; - be_cmd_enable_vf(adapter, vf + 1); + if (!old_vfs) + be_cmd_enable_vf(adapter, vf + 1); } if (!old_vfs) { @@ -2962,12 +3058,12 @@ static void BEx_get_resources(struct be_adapter *adapter, struct pci_dev *pdev = adapter->pdev; bool use_sriov = false; - if (BE3_chip(adapter) && be_physfn(adapter)) { + if (BE3_chip(adapter) && sriov_want(adapter)) { int max_vfs; max_vfs = pci_sriov_get_totalvfs(pdev); res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; - use_sriov = res->max_vfs && num_vfs; + use_sriov = res->max_vfs; } if (be_physfn(adapter)) @@ -2983,8 +3079,9 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_vlans = BE_NUM_VLANS_SUPPORTED; res->max_mcast_mac = BE_MAX_MC; + /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */ if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) || - !be_physfn(adapter)) + !be_physfn(adapter) || (adapter->port_num > 1)) res->max_tx_qs = 1; else res->max_tx_qs = BE3_MAX_TX_QS; @@ -3026,14 +3123,6 @@ static int be_get_resources(struct be_adapter *adapter) adapter->res = res; } - /* For BE3 only check if FW suggests a different max-txqs value */ - if (BE3_chip(adapter)) { - status = be_cmd_get_profile_config(adapter, &res, 0); - if (!status && res.max_tx_qs) - adapter->res.max_tx_qs = - min(adapter->res.max_tx_qs, res.max_tx_qs); - } - /* For Lancer, SH etc read per-function resource limits from FW. * GET_FUNC_CONFIG returns per function guaranteed limits. * GET_PROFILE_CONFIG returns PCI-E related limits PF-pool limits @@ -3258,7 +3347,7 @@ static int be_setup(struct be_adapter *adapter) be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); - if (be_physfn(adapter) && num_vfs) { + if (sriov_want(adapter)) { if (be_max_vfs(adapter)) be_vf_setup(adapter); else @@ -4077,9 +4166,11 @@ static int be_stats_init(struct be_adapter *adapter) cmd->size = sizeof(struct lancer_cmd_req_pport_stats); else if (BE2_chip(adapter)) cmd->size = sizeof(struct be_cmd_req_get_stats_v0); - else - /* BE3 and Skyhawk */ + else if (BE3_chip(adapter)) cmd->size = sizeof(struct be_cmd_req_get_stats_v1); + else + /* ALL non-BE ASICs */ + cmd->size = sizeof(struct be_cmd_req_get_stats_v2); cmd->va = dma_zalloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); @@ -4113,7 +4204,6 @@ static void be_remove(struct pci_dev *pdev) pci_disable_pcie_error_reporting(pdev); - pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); pci_disable_device(pdev); @@ -4262,7 +4352,6 @@ 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; - struct be_eq_obj *eqo; int i; /* when interrupts are not yet enabled, just reap any pending @@ -4293,8 +4382,7 @@ static void be_worker(struct work_struct *work) } } - for_all_evt_queues(adapter, eqo, i) - be_eqd_update(adapter, eqo); + be_eqd_update(adapter); reschedule: adapter->work_counter++; @@ -4370,9 +4458,11 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) } } - status = pci_enable_pcie_error_reporting(pdev); - if (status) - dev_info(&pdev->dev, "Could not use PCIe error reporting\n"); + if (be_physfn(adapter)) { + status = pci_enable_pcie_error_reporting(pdev); + if (!status) + dev_info(&pdev->dev, "PCIe error reporting enabled\n"); + } status = be_ctrl_init(adapter); if (status) @@ -4443,7 +4533,6 @@ ctrl_clean: be_ctrl_cleanup(adapter); free_netdev: free_netdev(netdev); - pci_set_drvdata(pdev, NULL); rel_reg: pci_release_regions(pdev); disable_dev: |