diff options
| author | Jon Mason <jon.mason@intel.com> | 2013-04-18 20:59:44 -0400 |
|---|---|---|
| committer | Jon Mason <jon.mason@intel.com> | 2013-11-20 11:57:34 -0500 |
| commit | e8aeb60c389c2aa48d345bcf717f8cb7edf67680 (patch) | |
| tree | 3610f55a47e8f0bc722397ec8063c9a4f4091f9b | |
| parent | 78958433db077b339f3a039890148561086574e4 (diff) | |
NTB: Disable interrupts and poll under high load
Disable interrupts and poll under high load
Signed-off-by: Jon Mason <jon.mason@intel.com>
| -rw-r--r-- | drivers/ntb/ntb_hw.c | 42 | ||||
| -rw-r--r-- | drivers/ntb/ntb_hw.h | 7 | ||||
| -rw-r--r-- | drivers/ntb/ntb_transport.c | 25 |
3 files changed, 48 insertions, 26 deletions
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 80505aeecf9e..170e8e60cdb7 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c | |||
| @@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) | |||
| 141 | ndev->event_cb = NULL; | 141 | ndev->event_cb = NULL; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static void ntb_irq_work(unsigned long data) | ||
| 145 | { | ||
| 146 | struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; | ||
| 147 | int rc; | ||
| 148 | |||
| 149 | rc = db_cb->callback(db_cb->data, db_cb->db_num); | ||
| 150 | if (rc) | ||
| 151 | tasklet_schedule(&db_cb->irq_work); | ||
| 152 | else { | ||
| 153 | struct ntb_device *ndev = db_cb->ndev; | ||
| 154 | unsigned long mask; | ||
| 155 | |||
| 156 | mask = readw(ndev->reg_ofs.ldb_mask); | ||
| 157 | clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); | ||
| 158 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 144 | /** | 162 | /** |
| 145 | * ntb_register_db_callback() - register a callback for doorbell interrupt | 163 | * ntb_register_db_callback() - register a callback for doorbell interrupt |
| 146 | * @ndev: pointer to ntb_device instance | 164 | * @ndev: pointer to ntb_device instance |
| @@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) | |||
| 155 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | 173 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. |
| 156 | */ | 174 | */ |
| 157 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, | 175 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, |
| 158 | void *data, void (*func)(void *data, int db_num)) | 176 | void *data, int (*func)(void *data, int db_num)) |
| 159 | { | 177 | { |
| 160 | unsigned long mask; | 178 | unsigned long mask; |
| 161 | 179 | ||
| @@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, | |||
| 166 | 184 | ||
| 167 | ndev->db_cb[idx].callback = func; | 185 | ndev->db_cb[idx].callback = func; |
| 168 | ndev->db_cb[idx].data = data; | 186 | ndev->db_cb[idx].data = data; |
| 187 | ndev->db_cb[idx].ndev = ndev; | ||
| 188 | |||
| 189 | tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, | ||
| 190 | (unsigned long) &ndev->db_cb[idx]); | ||
| 169 | 191 | ||
| 170 | /* unmask interrupt */ | 192 | /* unmask interrupt */ |
| 171 | mask = readw(ndev->reg_ofs.ldb_mask); | 193 | mask = readw(ndev->reg_ofs.ldb_mask); |
| @@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) | |||
| 194 | set_bit(idx * ndev->bits_per_vector, &mask); | 216 | set_bit(idx * ndev->bits_per_vector, &mask); |
| 195 | writew(mask, ndev->reg_ofs.ldb_mask); | 217 | writew(mask, ndev->reg_ofs.ldb_mask); |
| 196 | 218 | ||
| 219 | tasklet_disable(&ndev->db_cb[idx].irq_work); | ||
| 220 | |||
| 197 | ndev->db_cb[idx].callback = NULL; | 221 | ndev->db_cb[idx].callback = NULL; |
| 198 | } | 222 | } |
| 199 | 223 | ||
| @@ -955,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data) | |||
| 955 | { | 979 | { |
| 956 | struct ntb_db_cb *db_cb = data; | 980 | struct ntb_db_cb *db_cb = data; |
| 957 | struct ntb_device *ndev = db_cb->ndev; | 981 | struct ntb_device *ndev = db_cb->ndev; |
| 982 | unsigned long mask; | ||
| 958 | 983 | ||
| 959 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, | 984 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, |
| 960 | db_cb->db_num); | 985 | db_cb->db_num); |
| 961 | 986 | ||
| 962 | if (db_cb->callback) | 987 | mask = readw(ndev->reg_ofs.ldb_mask); |
| 963 | db_cb->callback(db_cb->data, db_cb->db_num); | 988 | set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); |
| 989 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 990 | |||
| 991 | tasklet_schedule(&db_cb->irq_work); | ||
| 964 | 992 | ||
| 965 | /* No need to check for the specific HB irq, any interrupt means | 993 | /* No need to check for the specific HB irq, any interrupt means |
| 966 | * we're connected. | 994 | * we're connected. |
| @@ -976,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data) | |||
| 976 | { | 1004 | { |
| 977 | struct ntb_db_cb *db_cb = data; | 1005 | struct ntb_db_cb *db_cb = data; |
| 978 | struct ntb_device *ndev = db_cb->ndev; | 1006 | struct ntb_device *ndev = db_cb->ndev; |
| 1007 | unsigned long mask; | ||
| 979 | 1008 | ||
| 980 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, | 1009 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, |
| 981 | db_cb->db_num); | 1010 | db_cb->db_num); |
| 982 | 1011 | ||
| 983 | if (db_cb->callback) | 1012 | mask = readw(ndev->reg_ofs.ldb_mask); |
| 984 | db_cb->callback(db_cb->data, db_cb->db_num); | 1013 | set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); |
| 1014 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 1015 | |||
| 1016 | tasklet_schedule(&db_cb->irq_work); | ||
| 985 | 1017 | ||
| 986 | /* On Sandybridge, there are 16 bits in the interrupt register | 1018 | /* On Sandybridge, there are 16 bits in the interrupt register |
| 987 | * but only 4 vectors. So, 5 bits are assigned to the first 3 | 1019 | * but only 4 vectors. So, 5 bits are assigned to the first 3 |
diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h index 0a31cedae7d4..bbdb7edca10c 100644 --- a/drivers/ntb/ntb_hw.h +++ b/drivers/ntb/ntb_hw.h | |||
| @@ -106,10 +106,11 @@ struct ntb_mw { | |||
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | struct ntb_db_cb { | 108 | struct ntb_db_cb { |
| 109 | void (*callback) (void *data, int db_num); | 109 | int (*callback)(void *data, int db_num); |
| 110 | unsigned int db_num; | 110 | unsigned int db_num; |
| 111 | void *data; | 111 | void *data; |
| 112 | struct ntb_device *ndev; | 112 | struct ntb_device *ndev; |
| 113 | struct tasklet_struct irq_work; | ||
| 113 | }; | 114 | }; |
| 114 | 115 | ||
| 115 | struct ntb_device { | 116 | struct ntb_device { |
| @@ -228,8 +229,8 @@ struct ntb_device *ntb_register_transport(struct pci_dev *pdev, | |||
| 228 | void ntb_unregister_transport(struct ntb_device *ndev); | 229 | void ntb_unregister_transport(struct ntb_device *ndev); |
| 229 | void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); | 230 | void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); |
| 230 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, | 231 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, |
| 231 | void *data, void (*db_cb_func) (void *data, | 232 | void *data, int (*db_cb_func)(void *data, |
| 232 | int db_num)); | 233 | int db_num)); |
| 233 | void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); | 234 | void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); |
| 234 | int ntb_register_event_callback(struct ntb_device *ndev, | 235 | int ntb_register_event_callback(struct ntb_device *ndev, |
| 235 | void (*event_cb_func) (void *handle, | 236 | void (*event_cb_func) (void *handle, |
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 172501d47600..676937bd679c 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c | |||
| @@ -119,7 +119,6 @@ struct ntb_transport_qp { | |||
| 119 | 119 | ||
| 120 | void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data, | 120 | void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data, |
| 121 | void *data, int len); | 121 | void *data, int len); |
| 122 | struct tasklet_struct rx_work; | ||
| 123 | struct list_head rx_pend_q; | 122 | struct list_head rx_pend_q; |
| 124 | struct list_head rx_free_q; | 123 | struct list_head rx_free_q; |
| 125 | spinlock_t ntb_rx_pend_q_lock; | 124 | spinlock_t ntb_rx_pend_q_lock; |
| @@ -1188,11 +1187,14 @@ err: | |||
| 1188 | goto out; | 1187 | goto out; |
| 1189 | } | 1188 | } |
| 1190 | 1189 | ||
| 1191 | static void ntb_transport_rx(unsigned long data) | 1190 | static int ntb_transport_rxc_db(void *data, int db_num) |
| 1192 | { | 1191 | { |
| 1193 | struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data; | 1192 | struct ntb_transport_qp *qp = data; |
| 1194 | int rc, i; | 1193 | int rc, i; |
| 1195 | 1194 | ||
| 1195 | dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", | ||
| 1196 | __func__, db_num); | ||
| 1197 | |||
| 1196 | /* Limit the number of packets processed in a single interrupt to | 1198 | /* Limit the number of packets processed in a single interrupt to |
| 1197 | * provide fairness to others | 1199 | * provide fairness to others |
| 1198 | */ | 1200 | */ |
| @@ -1204,16 +1206,8 @@ static void ntb_transport_rx(unsigned long data) | |||
| 1204 | 1206 | ||
| 1205 | if (qp->dma_chan) | 1207 | if (qp->dma_chan) |
| 1206 | dma_async_issue_pending(qp->dma_chan); | 1208 | dma_async_issue_pending(qp->dma_chan); |
| 1207 | } | ||
| 1208 | |||
| 1209 | static void ntb_transport_rxc_db(void *data, int db_num) | ||
| 1210 | { | ||
| 1211 | struct ntb_transport_qp *qp = data; | ||
| 1212 | 1209 | ||
| 1213 | dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", | 1210 | return i; |
| 1214 | __func__, db_num); | ||
| 1215 | |||
| 1216 | tasklet_schedule(&qp->rx_work); | ||
| 1217 | } | 1211 | } |
| 1218 | 1212 | ||
| 1219 | static void ntb_tx_copy_callback(void *data) | 1213 | static void ntb_tx_copy_callback(void *data) |
| @@ -1446,19 +1440,15 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, | |||
| 1446 | &qp->tx_free_q); | 1440 | &qp->tx_free_q); |
| 1447 | } | 1441 | } |
| 1448 | 1442 | ||
| 1449 | tasklet_init(&qp->rx_work, ntb_transport_rx, (unsigned long) qp); | ||
| 1450 | |||
| 1451 | rc = ntb_register_db_callback(qp->ndev, free_queue, qp, | 1443 | rc = ntb_register_db_callback(qp->ndev, free_queue, qp, |
| 1452 | ntb_transport_rxc_db); | 1444 | ntb_transport_rxc_db); |
| 1453 | if (rc) | 1445 | if (rc) |
| 1454 | goto err3; | 1446 | goto err2; |
| 1455 | 1447 | ||
| 1456 | dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num); | 1448 | dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num); |
| 1457 | 1449 | ||
| 1458 | return qp; | 1450 | return qp; |
| 1459 | 1451 | ||
| 1460 | err3: | ||
| 1461 | tasklet_disable(&qp->rx_work); | ||
| 1462 | err2: | 1452 | err2: |
| 1463 | while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) | 1453 | while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) |
| 1464 | kfree(entry); | 1454 | kfree(entry); |
| @@ -1505,7 +1495,6 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) | |||
| 1505 | } | 1495 | } |
| 1506 | 1496 | ||
| 1507 | ntb_unregister_db_callback(qp->ndev, qp->qp_num); | 1497 | ntb_unregister_db_callback(qp->ndev, qp->qp_num); |
| 1508 | tasklet_disable(&qp->rx_work); | ||
| 1509 | 1498 | ||
| 1510 | cancel_delayed_work_sync(&qp->link_work); | 1499 | cancel_delayed_work_sync(&qp->link_work); |
| 1511 | 1500 | ||
