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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 | ||