diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qede/qede_main.c')
-rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede_main.c | 195 |
1 files changed, 169 insertions, 26 deletions
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 6a796040a32c..46d0f2eaa0c0 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -536,6 +536,97 @@ static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return 0; } +static int qede_setup_tc(struct net_device *ndev, u8 num_tc) +{ + struct qede_dev *edev = netdev_priv(ndev); + int cos, count, offset; + + if (num_tc > edev->dev_info.num_tc) + return -EINVAL; + + netdev_reset_tc(ndev); + netdev_set_num_tc(ndev, num_tc); + + for_each_cos_in_txq(edev, cos) { + count = QEDE_TSS_COUNT(edev); + offset = cos * QEDE_TSS_COUNT(edev); + netdev_set_tc_queue(ndev, cos, count, offset); + } + + return 0; +} + +static int +qede_set_flower(struct qede_dev *edev, struct tc_cls_flower_offload *f, + __be16 proto) +{ + switch (f->command) { + case TC_CLSFLOWER_REPLACE: + return qede_add_tc_flower_fltr(edev, proto, f); + case TC_CLSFLOWER_DESTROY: + return qede_delete_flow_filter(edev, f->cookie); + default: + return -EOPNOTSUPP; + } +} + +static int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data, + void *cb_priv) +{ + struct tc_cls_flower_offload *f; + struct qede_dev *edev = cb_priv; + + if (!tc_cls_can_offload_and_chain0(edev->ndev, type_data)) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_CLSFLOWER: + f = type_data; + return qede_set_flower(edev, f, f->common.protocol); + default: + return -EOPNOTSUPP; + } +} + +static int qede_setup_tc_block(struct qede_dev *edev, + struct tc_block_offload *f) +{ + if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) + return -EOPNOTSUPP; + + switch (f->command) { + case TC_BLOCK_BIND: + return tcf_block_cb_register(f->block, + qede_setup_tc_block_cb, + edev, edev, f->extack); + case TC_BLOCK_UNBIND: + tcf_block_cb_unregister(f->block, qede_setup_tc_block_cb, edev); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int +qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type, + void *type_data) +{ + struct qede_dev *edev = netdev_priv(dev); + struct tc_mqprio_qopt *mqprio; + + switch (type) { + case TC_SETUP_BLOCK: + return qede_setup_tc_block(edev, type_data); + case TC_SETUP_QDISC_MQPRIO: + mqprio = type_data; + + mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; + return qede_setup_tc(dev, mqprio->num_tc); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops qede_netdev_ops = { .ndo_open = qede_open, .ndo_stop = qede_close, @@ -568,6 +659,7 @@ static const struct net_device_ops qede_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = qede_rx_flow_steer, #endif + .ndo_setup_tc = qede_setup_tc_offload, }; static const struct net_device_ops qede_netdev_vf_ops = { @@ -621,7 +713,8 @@ static struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, struct qede_dev *edev; ndev = alloc_etherdev_mqs(sizeof(*edev), - info->num_queues, info->num_queues); + info->num_queues * info->num_tc, + info->num_queues); if (!ndev) { pr_err("etherdev allocation failed\n"); return NULL; @@ -688,7 +781,7 @@ static void qede_init_ndev(struct qede_dev *edev) /* user-changeble features */ hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6; + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_TC; if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) hw_features |= NETIF_F_NTUPLE; @@ -830,7 +923,8 @@ static int qede_alloc_fp_array(struct qede_dev *edev) } if (fp->type & QEDE_FASTPATH_TX) { - fp->txq = kzalloc(sizeof(*fp->txq), GFP_KERNEL); + fp->txq = kcalloc(edev->dev_info.num_tc, + sizeof(*fp->txq), GFP_KERNEL); if (!fp->txq) goto err; } @@ -879,10 +973,15 @@ static void qede_sp_task(struct work_struct *work) static void qede_update_pf_params(struct qed_dev *cdev) { struct qed_pf_params pf_params; + u16 num_cons; /* 64 rx + 64 tx + 64 XDP */ memset(&pf_params, 0, sizeof(struct qed_pf_params)); - pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * 3; + + /* 1 rx + 1 xdp + max tx cos */ + num_cons = QED_MIN_L2_CONS; + + pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * num_cons; /* Same for VFs - make sure they'll have sufficient connections * to support XDP Tx queues. @@ -1363,8 +1462,12 @@ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) if (fp->type & QEDE_FASTPATH_XDP) qede_free_mem_txq(edev, fp->xdp_tx); - if (fp->type & QEDE_FASTPATH_TX) - qede_free_mem_txq(edev, fp->txq); + if (fp->type & QEDE_FASTPATH_TX) { + int cos; + + for_each_cos_in_txq(edev, cos) + qede_free_mem_txq(edev, &fp->txq[cos]); + } } /* This function allocates all memory needed for a single fp (i.e. an entity @@ -1391,9 +1494,13 @@ static int qede_alloc_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) } if (fp->type & QEDE_FASTPATH_TX) { - rc = qede_alloc_mem_txq(edev, fp->txq); - if (rc) - goto out; + int cos; + + for_each_cos_in_txq(edev, cos) { + rc = qede_alloc_mem_txq(edev, &fp->txq[cos]); + if (rc) + goto out; + } } out: @@ -1466,10 +1573,23 @@ static void qede_init_fp(struct qede_dev *edev) } if (fp->type & QEDE_FASTPATH_TX) { - fp->txq->index = txq_index++; - if (edev->dev_info.is_legacy) - fp->txq->is_legacy = 1; - fp->txq->dev = &edev->pdev->dev; + int cos; + + for_each_cos_in_txq(edev, cos) { + struct qede_tx_queue *txq = &fp->txq[cos]; + u16 ndev_tx_id; + + txq->cos = cos; + txq->index = txq_index; + ndev_tx_id = QEDE_TXQ_TO_NDEV_TXQ_ID(edev, txq); + txq->ndev_txq_id = ndev_tx_id; + + if (edev->dev_info.is_legacy) + txq->is_legacy = 1; + txq->dev = &edev->pdev->dev; + } + + txq_index++; } snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", @@ -1483,7 +1603,9 @@ static int qede_set_real_num_queues(struct qede_dev *edev) { int rc = 0; - rc = netif_set_real_num_tx_queues(edev->ndev, QEDE_TSS_COUNT(edev)); + rc = netif_set_real_num_tx_queues(edev->ndev, + QEDE_TSS_COUNT(edev) * + edev->dev_info.num_tc); if (rc) { DP_NOTICE(edev, "Failed to set real number of Tx queues\n"); return rc; @@ -1685,9 +1807,13 @@ static int qede_stop_queues(struct qede_dev *edev) fp = &edev->fp_array[i]; if (fp->type & QEDE_FASTPATH_TX) { - rc = qede_drain_txq(edev, fp->txq, true); - if (rc) - return rc; + int cos; + + for_each_cos_in_txq(edev, cos) { + rc = qede_drain_txq(edev, &fp->txq[cos], true); + if (rc) + return rc; + } } if (fp->type & QEDE_FASTPATH_XDP) { @@ -1703,9 +1829,13 @@ static int qede_stop_queues(struct qede_dev *edev) /* Stop the Tx Queue(s) */ if (fp->type & QEDE_FASTPATH_TX) { - rc = qede_stop_txq(edev, fp->txq, i); - if (rc) - return rc; + int cos; + + for_each_cos_in_txq(edev, cos) { + rc = qede_stop_txq(edev, &fp->txq[cos], i); + if (rc) + return rc; + } } /* Stop the Rx Queue */ @@ -1758,6 +1888,7 @@ static int qede_start_txq(struct qede_dev *edev, params.p_sb = fp->sb_info; params.sb_idx = sb_idx; + params.tc = txq->cos; rc = edev->ops->q_tx_start(edev->cdev, rss_id, ¶ms, phys_table, page_cnt, &ret_params); @@ -1877,9 +2008,14 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats) } if (fp->type & QEDE_FASTPATH_TX) { - rc = qede_start_txq(edev, fp, fp->txq, i, TX_PI(0)); - if (rc) - goto out; + int cos; + + for_each_cos_in_txq(edev, cos) { + rc = qede_start_txq(edev, fp, &fp->txq[cos], i, + TX_PI(cos)); + if (rc) + goto out; + } } } @@ -1973,6 +2109,7 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, bool is_locked) { struct qed_link_params link_params; + u8 num_tc; int rc; DP_INFO(edev, "Starting qede load\n"); @@ -2019,6 +2156,10 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto err4; DP_INFO(edev, "Start VPORT, RXQ and TXQ succeeded\n"); + num_tc = netdev_get_num_tc(edev->ndev); + num_tc = num_tc ? num_tc : edev->dev_info.num_tc; + qede_setup_tc(edev->ndev, num_tc); + /* Program un-configured VLANs */ qede_configure_vlan_filters(edev); @@ -2143,7 +2284,7 @@ static bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq) { struct netdev_queue *netdev_txq; - netdev_txq = netdev_get_tx_queue(edev->ndev, txq->index); + netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); if (netif_xmit_stopped(netdev_txq)) return true; @@ -2208,9 +2349,11 @@ static void qede_get_eth_tlv_data(void *dev, void *data) for_each_queue(i) { fp = &edev->fp_array[i]; if (fp->type & QEDE_FASTPATH_TX) { - if (fp->txq->sw_tx_cons != fp->txq->sw_tx_prod) + struct qede_tx_queue *txq = QEDE_FP_TC0_TXQ(fp); + + if (txq->sw_tx_cons != txq->sw_tx_prod) etlv->txqs_empty = false; - if (qede_is_txq_full(edev, fp->txq)) + if (qede_is_txq_full(edev, txq)) etlv->num_txqs_full++; } if (fp->type & QEDE_FASTPATH_RX) { |