Merge tag 'net-next-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev...
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / marvell / octeontx2 / nic / otx2_pf.c
index 74c4979..fe8ea4e 100644 (file)
@@ -23,6 +23,7 @@
 #include "otx2_struct.h"
 #include "otx2_ptp.h"
 #include "cn10k.h"
+#include "qos.h"
 #include <rvu_trace.h>
 
 #define DRV_NAME       "rvu_nicpf"
@@ -789,10 +790,6 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf,
        case MBOX_MSG_NIX_LF_ALLOC:
                mbox_handler_nix_lf_alloc(pf, (struct nix_lf_alloc_rsp *)msg);
                break;
-       case MBOX_MSG_NIX_TXSCH_ALLOC:
-               mbox_handler_nix_txsch_alloc(pf,
-                                            (struct nix_txsch_alloc_rsp *)msg);
-               break;
        case MBOX_MSG_NIX_BP_ENABLE:
                mbox_handler_nix_bp_enable(pf, (struct nix_bp_cfg_rsp *)msg);
                break;
@@ -1225,6 +1222,7 @@ static char *nix_snd_status_e_str[NIX_SND_STATUS_MAX] =  {
 static irqreturn_t otx2_q_intr_handler(int irq, void *data)
 {
        struct otx2_nic *pf = data;
+       struct otx2_snd_queue *sq;
        u64 val, *ptr;
        u64 qidx = 0;
 
@@ -1254,10 +1252,14 @@ static irqreturn_t otx2_q_intr_handler(int irq, void *data)
        }
 
        /* SQ */
-       for (qidx = 0; qidx < pf->hw.tot_tx_queues; qidx++) {
+       for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
                u64 sq_op_err_dbg, mnq_err_dbg, snd_err_dbg;
                u8 sq_op_err_code, mnq_err_code, snd_err_code;
 
+               sq = &pf->qset.sq[qidx];
+               if (!sq->sqb_ptrs)
+                       continue;
+
                /* Below debug registers captures first errors corresponding to
                 * those registers. We don't have to check against SQ qid as
                 * these are fatal errors.
@@ -1380,8 +1382,11 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
        otx2_ctx_disable(&pf->mbox, NIX_AQ_CTYPE_SQ, false);
        /* Free SQB pointers */
        otx2_sq_free_sqbs(pf);
-       for (qidx = 0; qidx < pf->hw.tot_tx_queues; qidx++) {
+       for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
                sq = &qset->sq[qidx];
+               /* Skip freeing Qos queues if they are not initialized */
+               if (!sq->sqe)
+                       continue;
                qmem_free(pf->dev, sq->sqe);
                qmem_free(pf->dev, sq->tso_hdrs);
                kfree(sq->sg);
@@ -1430,7 +1435,7 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
         * so, aura count = pool count.
         */
        hw->rqpool_cnt = hw->rx_queues;
-       hw->sqpool_cnt = hw->tot_tx_queues;
+       hw->sqpool_cnt = otx2_get_total_tx_queues(pf);
        hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt;
 
        /* Maximum hardware supported transmit length */
@@ -1513,8 +1518,7 @@ err_free_nix_queues:
        otx2_free_cq_res(pf);
        otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false);
 err_free_txsch:
-       if (otx2_txschq_stop(pf))
-               dev_err(pf->dev, "%s failed to stop TX schedulers\n", __func__);
+       otx2_txschq_stop(pf);
 err_free_sq_ptrs:
        otx2_sq_free_sqbs(pf);
 err_free_rq_ptrs:
@@ -1548,22 +1552,24 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
        struct nix_lf_free_req *free_req;
        struct mbox *mbox = &pf->mbox;
        struct otx2_cq_queue *cq;
+       struct otx2_pool *pool;
        struct msg_req *req;
-       int qidx, err;
+       int pool_id;
+       int qidx;
 
        /* Ensure all SQE are processed */
        otx2_sqb_flush(pf);
 
        /* Stop transmission */
-       err = otx2_txschq_stop(pf);
-       if (err)
-               dev_err(pf->dev, "RVUPF: Failed to stop/free TX schedulers\n");
+       otx2_txschq_stop(pf);
 
 #ifdef CONFIG_DCB
        if (pf->pfc_en)
                otx2_pfc_txschq_stop(pf);
 #endif
 
+       otx2_clean_qos_queues(pf);
+
        mutex_lock(&mbox->lock);
        /* Disable backpressure */
        if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK))
@@ -1577,7 +1583,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
        for (qidx = 0; qidx < qset->cq_cnt; qidx++) {
                cq = &qset->cq[qidx];
                if (cq->cq_type == CQ_RX)
-                       otx2_cleanup_rx_cqes(pf, cq);
+                       otx2_cleanup_rx_cqes(pf, cq, qidx);
                else
                        otx2_cleanup_tx_cqes(pf, cq);
        }
@@ -1587,6 +1593,13 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
        /* Free RQ buffer pointers*/
        otx2_free_aura_ptr(pf, AURA_NIX_RQ);
 
+       for (qidx = 0; qidx < pf->hw.rx_queues; qidx++) {
+               pool_id = otx2_get_pool_idx(pf, AURA_NIX_RQ, qidx);
+               pool = &pf->qset.pool[pool_id];
+               page_pool_destroy(pool->page_pool);
+               pool->page_pool = NULL;
+       }
+
        otx2_free_cq_res(pf);
 
        /* Free all ingress bandwidth profiles allocated */
@@ -1685,11 +1698,14 @@ int otx2_open(struct net_device *netdev)
 
        netif_carrier_off(netdev);
 
-       pf->qset.cq_cnt = pf->hw.rx_queues + pf->hw.tot_tx_queues;
        /* RQ and SQs are mapped to different CQs,
         * so find out max CQ IRQs (i.e CINTs) needed.
         */
-       pf->hw.cint_cnt = max(pf->hw.rx_queues, pf->hw.tx_queues);
+       pf->hw.cint_cnt = max3(pf->hw.rx_queues, pf->hw.tx_queues,
+                              pf->hw.tc_tx_queues);
+
+       pf->qset.cq_cnt = pf->hw.rx_queues + otx2_get_total_tx_queues(pf);
+
        qset->napi = kcalloc(pf->hw.cint_cnt, sizeof(*cq_poll), GFP_KERNEL);
        if (!qset->napi)
                return -ENOMEM;
@@ -1705,7 +1721,7 @@ int otx2_open(struct net_device *netdev)
        if (!qset->cq)
                goto err_free_mem;
 
-       qset->sq = kcalloc(pf->hw.tot_tx_queues,
+       qset->sq = kcalloc(otx2_get_total_tx_queues(pf),
                           sizeof(struct otx2_snd_queue), GFP_KERNEL);
        if (!qset->sq)
                goto err_free_mem;
@@ -1740,6 +1756,11 @@ int otx2_open(struct net_device *netdev)
                else
                        cq_poll->cq_ids[CQ_XDP] = CINT_INVALID_CQ;
 
+               cq_poll->cq_ids[CQ_QOS] = (qidx < pf->hw.tc_tx_queues) ?
+                                         (qidx + pf->hw.rx_queues +
+                                          pf->hw.non_qos_queues) :
+                                         CINT_INVALID_CQ;
+
                cq_poll->dev = (void *)pf;
                cq_poll->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
                INIT_WORK(&cq_poll->dim.work, otx2_dim_work);
@@ -1823,6 +1844,9 @@ int otx2_open(struct net_device *netdev)
        /* 'intf_down' may be checked on any cpu */
        smp_wmb();
 
+       /* Enable QoS configuration before starting tx queues */
+       otx2_qos_config_txschq(pf);
+
        /* we have already received link status notification */
        if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK))
                otx2_handle_link_event(pf);
@@ -1944,6 +1968,12 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev)
        int qidx = skb_get_queue_mapping(skb);
        struct otx2_snd_queue *sq;
        struct netdev_queue *txq;
+       int sq_idx;
+
+       /* XDP SQs are not mapped with TXQs
+        * advance qid to derive correct sq mapped with QOS
+        */
+       sq_idx = (qidx >= pf->hw.tx_queues) ? (qidx + pf->hw.xdp_queues) : qidx;
 
        /* Check for minimum and maximum packet length */
        if (skb->len <= ETH_HLEN ||
@@ -1952,7 +1982,7 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       sq = &pf->qset.sq[qidx];
+       sq = &pf->qset.sq[sq_idx];
        txq = netdev_get_tx_queue(netdev, qidx);
 
        if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) {
@@ -1970,14 +2000,48 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev)
        return NETDEV_TX_OK;
 }
 
-static u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
-                            struct net_device *sb_dev)
+static int otx2_qos_select_htb_queue(struct otx2_nic *pf, struct sk_buff *skb,
+                                    u16 htb_maj_id)
+{
+       u16 classid;
+
+       if ((TC_H_MAJ(skb->priority) >> 16) == htb_maj_id)
+               classid = TC_H_MIN(skb->priority);
+       else
+               classid = READ_ONCE(pf->qos.defcls);
+
+       if (!classid)
+               return 0;
+
+       return otx2_get_txq_by_classid(pf, classid);
+}
+
+u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
+                     struct net_device *sb_dev)
 {
-#ifdef CONFIG_DCB
        struct otx2_nic *pf = netdev_priv(netdev);
+       bool qos_enabled;
+#ifdef CONFIG_DCB
        u8 vlan_prio;
 #endif
+       int txq;
+
+       qos_enabled = (netdev->real_num_tx_queues > pf->hw.tx_queues) ? true : false;
+       if (unlikely(qos_enabled)) {
+               /* This smp_load_acquire() pairs with smp_store_release() in
+                * otx2_qos_root_add() called from htb offload root creation
+                */
+               u16 htb_maj_id = smp_load_acquire(&pf->qos.maj_id);
+
+               if (unlikely(htb_maj_id)) {
+                       txq = otx2_qos_select_htb_queue(pf, skb, htb_maj_id);
+                       if (txq > 0)
+                               return txq;
+                       goto process_pfc;
+               }
+       }
 
+process_pfc:
 #ifdef CONFIG_DCB
        if (!skb_vlan_tag_present(skb))
                goto pick_tx;
@@ -1991,8 +2055,13 @@ static u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
 
 pick_tx:
 #endif
-       return netdev_pick_tx(netdev, skb, NULL);
+       txq = netdev_pick_tx(netdev, skb, NULL);
+       if (unlikely(qos_enabled))
+               return txq % pf->hw.tx_queues;
+
+       return txq;
 }
+EXPORT_SYMBOL(otx2_select_queue);
 
 static netdev_features_t otx2_fix_features(struct net_device *dev,
                                           netdev_features_t features)
@@ -2526,7 +2595,7 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog)
                xdp_features_clear_redirect_target(dev);
        }
 
-       pf->hw.tot_tx_queues += pf->hw.xdp_queues;
+       pf->hw.non_qos_queues += pf->hw.xdp_queues;
 
        if (if_up)
                otx2_open(pf->netdev);
@@ -2709,10 +2778,10 @@ static void otx2_sriov_vfcfg_cleanup(struct otx2_nic *pf)
 static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct device *dev = &pdev->dev;
+       int err, qcount, qos_txqs;
        struct net_device *netdev;
        struct otx2_nic *pf;
        struct otx2_hw *hw;
-       int err, qcount;
        int num_vec;
 
        err = pcim_enable_device(pdev);
@@ -2737,8 +2806,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Set number of queues */
        qcount = min_t(int, num_online_cpus(), OTX2_MAX_CQ_CNT);
+       qos_txqs = min_t(int, qcount, OTX2_QOS_MAX_LEAF_NODES);
 
-       netdev = alloc_etherdev_mqs(sizeof(*pf), qcount, qcount);
+       netdev = alloc_etherdev_mqs(sizeof(*pf), qcount + qos_txqs, qcount);
        if (!netdev) {
                err = -ENOMEM;
                goto err_release_regions;
@@ -2757,7 +2827,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hw->pdev = pdev;
        hw->rx_queues = qcount;
        hw->tx_queues = qcount;
-       hw->tot_tx_queues = qcount;
+       hw->non_qos_queues = qcount;
        hw->max_queues = qcount;
        hw->rbuf_len = OTX2_DEFAULT_RBUF_LEN;
        /* Use CQE of 128 byte descriptor size by default */
@@ -2926,6 +2996,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_pf_sriov_init;
 #endif
 
+       otx2_qos_init(pf, qos_txqs);
+
        return 0;
 
 err_pf_sriov_init:
@@ -3101,6 +3173,7 @@ static void otx2_remove(struct pci_dev *pdev)
        otx2_ptp_destroy(pf);
        otx2_mcam_flow_del(pf);
        otx2_shutdown_tc(pf);
+       otx2_shutdown_qos(pf);
        otx2_detach_resources(&pf->mbox);
        if (pf->hw.lmt_info)
                free_percpu(pf->hw.lmt_info);