NTB: Disable interrupts and poll under high load
authorJon Mason <jon.mason@intel.com>
Fri, 19 Apr 2013 00:59:44 +0000 (17:59 -0700)
committerJon Mason <jon.mason@intel.com>
Wed, 20 Nov 2013 16:57:34 +0000 (09:57 -0700)
Disable interrupts and poll under high load

Signed-off-by: Jon Mason <jon.mason@intel.com>
drivers/ntb/ntb_hw.c
drivers/ntb/ntb_hw.h
drivers/ntb/ntb_transport.c

index 80505aeecf9e13b40b225048f0630e3e239c0edf..170e8e60cdb7fe3d47307d4b9146039e3af7f3a8 100644 (file)
@@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev)
        ndev->event_cb = NULL;
 }
 
+static void ntb_irq_work(unsigned long data)
+{
+       struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data;
+       int rc;
+
+       rc = db_cb->callback(db_cb->data, db_cb->db_num);
+       if (rc)
+               tasklet_schedule(&db_cb->irq_work);
+       else {
+               struct ntb_device *ndev = db_cb->ndev;
+               unsigned long mask;
+
+               mask = readw(ndev->reg_ofs.ldb_mask);
+               clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+               writew(mask, ndev->reg_ofs.ldb_mask);
+       }
+}
+
 /**
  * ntb_register_db_callback() - register a callback for doorbell interrupt
  * @ndev: pointer to ntb_device instance
@@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev)
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  */
 int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-                            void *data, void (*func)(void *data, int db_num))
+                            void *data, int (*func)(void *data, int db_num))
 {
        unsigned long mask;
 
@@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
 
        ndev->db_cb[idx].callback = func;
        ndev->db_cb[idx].data = data;
+       ndev->db_cb[idx].ndev = ndev;
+
+       tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work,
+                    (unsigned long) &ndev->db_cb[idx]);
 
        /* unmask interrupt */
        mask = readw(ndev->reg_ofs.ldb_mask);
@@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
        set_bit(idx * ndev->bits_per_vector, &mask);
        writew(mask, ndev->reg_ofs.ldb_mask);
 
+       tasklet_disable(&ndev->db_cb[idx].irq_work);
+
        ndev->db_cb[idx].callback = NULL;
 }
 
@@ -955,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
 {
        struct ntb_db_cb *db_cb = data;
        struct ntb_device *ndev = db_cb->ndev;
+       unsigned long mask;
 
        dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
                db_cb->db_num);
 
-       if (db_cb->callback)
-               db_cb->callback(db_cb->data, db_cb->db_num);
+       mask = readw(ndev->reg_ofs.ldb_mask);
+       set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+       writew(mask, ndev->reg_ofs.ldb_mask);
+
+       tasklet_schedule(&db_cb->irq_work);
 
        /* No need to check for the specific HB irq, any interrupt means
         * we're connected.
@@ -976,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
 {
        struct ntb_db_cb *db_cb = data;
        struct ntb_device *ndev = db_cb->ndev;
+       unsigned long mask;
 
        dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
                db_cb->db_num);
 
-       if (db_cb->callback)
-               db_cb->callback(db_cb->data, db_cb->db_num);
+       mask = readw(ndev->reg_ofs.ldb_mask);
+       set_bit(db_cb->db_num * ndev->bits_per_vector, &mask);
+       writew(mask, ndev->reg_ofs.ldb_mask);
+
+       tasklet_schedule(&db_cb->irq_work);
 
        /* On Sandybridge, there are 16 bits in the interrupt register
         * but only 4 vectors.  So, 5 bits are assigned to the first 3
index 0a31cedae7d42f9227d125bfabe97297b47255d9..bbdb7edca10cd8647e4b739dfab29f1ed33fc1e6 100644 (file)
@@ -106,10 +106,11 @@ struct ntb_mw {
 };
 
 struct ntb_db_cb {
-       void (*callback) (void *data, int db_num);
+       int (*callback)(void *data, int db_num);
        unsigned int db_num;
        void *data;
        struct ntb_device *ndev;
+       struct tasklet_struct irq_work;
 };
 
 struct ntb_device {
@@ -228,8 +229,8 @@ struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
 void ntb_unregister_transport(struct ntb_device *ndev);
 void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
 int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
-                            void *data, void (*db_cb_func) (void *data,
-                                                            int db_num));
+                            void *data, int (*db_cb_func)(void *data,
+                                                          int db_num));
 void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
 int ntb_register_event_callback(struct ntb_device *ndev,
                                void (*event_cb_func) (void *handle,
index 172501d476009ae8035826136dddf22b975ed5b5..676937bd679c7b8ac5b41cf775bc84d7b2ae6a4f 100644 (file)
@@ -119,7 +119,6 @@ struct ntb_transport_qp {
 
        void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
                            void *data, int len);
-       struct tasklet_struct rx_work;
        struct list_head rx_pend_q;
        struct list_head rx_free_q;
        spinlock_t ntb_rx_pend_q_lock;
@@ -1188,11 +1187,14 @@ err:
        goto out;
 }
 
-static void ntb_transport_rx(unsigned long data)
+static int ntb_transport_rxc_db(void *data, int db_num)
 {
-       struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data;
+       struct ntb_transport_qp *qp = data;
        int rc, i;
 
+       dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
+               __func__, db_num);
+
        /* Limit the number of packets processed in a single interrupt to
         * provide fairness to others
         */
@@ -1204,16 +1206,8 @@ static void ntb_transport_rx(unsigned long data)
 
        if (qp->dma_chan)
                dma_async_issue_pending(qp->dma_chan);
-}
-
-static void ntb_transport_rxc_db(void *data, int db_num)
-{
-       struct ntb_transport_qp *qp = data;
 
-       dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
-               __func__, db_num);
-
-       tasklet_schedule(&qp->rx_work);
+       return i;
 }
 
 static void ntb_tx_copy_callback(void *data)
@@ -1446,19 +1440,15 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
                             &qp->tx_free_q);
        }
 
-       tasklet_init(&qp->rx_work, ntb_transport_rx, (unsigned long) qp);
-
        rc = ntb_register_db_callback(qp->ndev, free_queue, qp,
                                      ntb_transport_rxc_db);
        if (rc)
-               goto err3;
+               goto err2;
 
        dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num);
 
        return qp;
 
-err3:
-       tasklet_disable(&qp->rx_work);
 err2:
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
@@ -1505,7 +1495,6 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
        }
 
        ntb_unregister_db_callback(qp->ndev, qp->qp_num);
-       tasklet_disable(&qp->rx_work);
 
        cancel_delayed_work_sync(&qp->link_work);