liquidio: allocate RX buffers in OOM conditions in PF and VF
authorSatanand Burla <satananda.burla@cavium.com>
Wed, 22 Mar 2017 18:31:13 +0000 (11:31 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Mar 2017 02:36:43 +0000 (19:36 -0700)
Add workqueue that is periodically run to try to allocate RX buffers in OOM
conditions in PF and VF.

Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.h
drivers/net/ethernet/cavium/liquidio/lio_core.c
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
drivers/net/ethernet/cavium/liquidio/octeon_droq.c
drivers/net/ethernet/cavium/liquidio/octeon_droq.h
drivers/net/ethernet/cavium/liquidio/octeon_network.h

index 2fedd91f3df88fb5ea88f288e5121a8fc8fb3cf0..dee604651ba7d309686cca04f1b41222221adfe1 100644 (file)
@@ -43,6 +43,8 @@ struct octeon_cn23xx_pf {
        struct octeon_config *conf;
 };
 
+#define CN23XX_SLI_DEF_BP                      0x40
+
 int setup_cn23xx_octeon_pf_device(struct octeon_device *oct);
 
 int validate_cn23xx_pf_config_info(struct octeon_device *oct,
index 65a1a9e7a1594135488f3f3bdd5c8aaf70ab8434..08676df6cef056f26bf77af33eacc1c4fb7ac39a 100644 (file)
@@ -26,6 +26,9 @@
 #include "octeon_main.h"
 #include "octeon_network.h"
 
+/* OOM task polling interval */
+#define LIO_OOM_POLL_INTERVAL_MS 250
+
 int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1)
 {
        struct lio *lio = GET_LIO(netdev);
@@ -293,3 +296,56 @@ void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac)
         * the PF did that already
         */
 }
+
+static void octnet_poll_check_rxq_oom_status(struct work_struct *work)
+{
+       struct cavium_wk *wk = (struct cavium_wk *)work;
+       struct lio *lio = (struct lio *)wk->ctxptr;
+       struct octeon_device *oct = lio->oct_dev;
+       struct octeon_droq *droq;
+       int q, q_no = 0;
+
+       if (ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
+               for (q = 0; q < lio->linfo.num_rxpciq; q++) {
+                       q_no = lio->linfo.rxpciq[q].s.q_no;
+                       droq = oct->droq[q_no];
+                       if (!droq)
+                               continue;
+                       octeon_droq_check_oom(droq);
+               }
+       }
+       queue_delayed_work(lio->rxq_status_wq.wq,
+                          &lio->rxq_status_wq.wk.work,
+                          msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
+}
+
+int setup_rx_oom_poll_fn(struct net_device *netdev)
+{
+       struct lio *lio = GET_LIO(netdev);
+       struct octeon_device *oct = lio->oct_dev;
+
+       lio->rxq_status_wq.wq = alloc_workqueue("rxq-oom-status",
+                                               WQ_MEM_RECLAIM, 0);
+       if (!lio->rxq_status_wq.wq) {
+               dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n");
+               return -ENOMEM;
+       }
+       INIT_DELAYED_WORK(&lio->rxq_status_wq.wk.work,
+                         octnet_poll_check_rxq_oom_status);
+       lio->rxq_status_wq.wk.ctxptr = lio;
+       queue_delayed_work(lio->rxq_status_wq.wq,
+                          &lio->rxq_status_wq.wk.work,
+                          msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
+       return 0;
+}
+
+void cleanup_rx_oom_poll_fn(struct net_device *netdev)
+{
+       struct lio *lio = GET_LIO(netdev);
+
+       if (lio->rxq_status_wq.wq) {
+               cancel_delayed_work_sync(&lio->rxq_status_wq.wk.work);
+               flush_workqueue(lio->rxq_status_wq.wq);
+               destroy_workqueue(lio->rxq_status_wq.wq);
+       }
+}
index 0bc76ad96a17391bc7a0bfcc2e92e97920165c75..86ea86cfc1336664e7ecd8480be74b2af099596c 100644 (file)
@@ -1673,6 +1673,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
 
        cleanup_link_status_change_wq(netdev);
 
+       cleanup_rx_oom_poll_fn(netdev);
+
        delete_glists(lio);
 
        free_netdev(netdev);
@@ -4147,6 +4149,9 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
                if (setup_link_status_change_wq(netdev))
                        goto setup_nic_dev_fail;
 
+               if (setup_rx_oom_poll_fn(netdev))
+                       goto setup_nic_dev_fail;
+
                /* Register the network device with the OS */
                if (register_netdev(netdev)) {
                        dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
index e03855b8d1f56dd28aaeb937897e009ca4e3b408..65e6f4bfa1cf1b2a2a4b2967941ecc053ff523df 100644 (file)
@@ -1155,6 +1155,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
        if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
                unregister_netdev(netdev);
 
+       cleanup_rx_oom_poll_fn(netdev);
+
        cleanup_link_status_change_wq(netdev);
 
        delete_glists(lio);
@@ -2995,6 +2997,9 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
                if (setup_link_status_change_wq(netdev))
                        goto setup_nic_dev_fail;
 
+               if (setup_rx_oom_poll_fn(netdev))
+                       goto setup_nic_dev_fail;
+
                /* Register the network device with the OS */
                if (register_netdev(netdev)) {
                        dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
index 00970597ada834f0969fdd845d81df588f3a8dfb..286be5539cef707c9464f1c4488cdd6134e9b343 100644 (file)
@@ -513,6 +513,32 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
        return desc_refilled;
 }
 
+/** check if we can allocate packets to get out of oom.
+ *  @param  droq - Droq being checked.
+ *  @return does not return anything
+ */
+void octeon_droq_check_oom(struct octeon_droq *droq)
+{
+       int desc_refilled;
+       struct octeon_device *oct = droq->oct_dev;
+
+       if (readl(droq->pkts_credit_reg) <= CN23XX_SLI_DEF_BP) {
+               spin_lock_bh(&droq->lock);
+               desc_refilled = octeon_droq_refill(oct, droq);
+               if (desc_refilled) {
+                       /* Flush the droq descriptor data to memory to be sure
+                        * that when we update the credits the data in memory
+                        * is accurate.
+                        */
+                       wmb();
+                       writel(desc_refilled, droq->pkts_credit_reg);
+                       /* make sure mmio write completes */
+                       mmiowb();
+               }
+               spin_unlock_bh(&droq->lock);
+       }
+}
+
 static inline u32
 octeon_droq_get_bufcount(u32 buf_size, u32 total_len)
 {
index 6982c0af5eccb7129123fcbb4ba8363bb7f9710a..9781577115e76ff7d1ef27966bf3cbdba84ee7b4 100644 (file)
@@ -426,4 +426,6 @@ int octeon_droq_process_packets(struct octeon_device *oct,
 int octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no,
                                 int cmd, u32 arg);
 
+void octeon_droq_check_oom(struct octeon_droq *droq);
+
 #endif /*__OCTEON_DROQ_H__ */
index ddb61bf25775fab2315e0dc47cfe1afea36d3d53..454ec0ca56abd1182d57e0fc3f2de8ee60823294 100644 (file)
@@ -129,6 +129,9 @@ struct lio {
        /* work queue for  txq status */
        struct cavium_wq        txq_status_wq;
 
+       /* work queue for  rxq oom status */
+       struct cavium_wq        rxq_status_wq;
+
        /* work queue for  link status */
        struct cavium_wq        link_status_wq;
 
@@ -152,6 +155,10 @@ struct lio {
  */
 int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1);
 
+int setup_rx_oom_poll_fn(struct net_device *netdev);
+
+void cleanup_rx_oom_poll_fn(struct net_device *netdev);
+
 /**
  * \brief Link control command completion callback
  * @param nctrl_ptr pointer to control packet structure