diff options
Diffstat (limited to 'drivers/infiniband/hw/cxgb4/qp.c')
| -rw-r--r-- | drivers/infiniband/hw/cxgb4/qp.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index beec66758aec..ba1343ee1414 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c | |||
| @@ -42,6 +42,11 @@ static int ocqp_support = 1; | |||
| 42 | module_param(ocqp_support, int, 0644); | 42 | module_param(ocqp_support, int, 0644); |
| 43 | MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)"); | 43 | MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)"); |
| 44 | 44 | ||
| 45 | int db_fc_threshold = 2000; | ||
| 46 | module_param(db_fc_threshold, int, 0644); | ||
| 47 | MODULE_PARM_DESC(db_fc_threshold, "QP count/threshold that triggers automatic " | ||
| 48 | "db flow control mode (default = 2000)"); | ||
| 49 | |||
| 45 | static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) | 50 | static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) |
| 46 | { | 51 | { |
| 47 | unsigned long flag; | 52 | unsigned long flag; |
| @@ -1143,13 +1148,19 @@ static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc) | |||
| 1143 | 1148 | ||
| 1144 | mutex_lock(&qhp->rhp->db_mutex); | 1149 | mutex_lock(&qhp->rhp->db_mutex); |
| 1145 | do { | 1150 | do { |
| 1146 | if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) < 768) { | 1151 | |
| 1152 | /* | ||
| 1153 | * The interrupt threshold is dbfifo_int_thresh << 6. So | ||
| 1154 | * make sure we don't cross that and generate an interrupt. | ||
| 1155 | */ | ||
| 1156 | if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) < | ||
| 1157 | (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) { | ||
| 1147 | writel(V_QID(qid) | V_PIDX(inc), qhp->wq.db); | 1158 | writel(V_QID(qid) | V_PIDX(inc), qhp->wq.db); |
| 1148 | break; | 1159 | break; |
| 1149 | } | 1160 | } |
| 1150 | set_current_state(TASK_UNINTERRUPTIBLE); | 1161 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 1151 | schedule_timeout(usecs_to_jiffies(delay)); | 1162 | schedule_timeout(usecs_to_jiffies(delay)); |
| 1152 | delay = min(delay << 1, 200000); | 1163 | delay = min(delay << 1, 2000); |
| 1153 | } while (1); | 1164 | } while (1); |
| 1154 | mutex_unlock(&qhp->rhp->db_mutex); | 1165 | mutex_unlock(&qhp->rhp->db_mutex); |
| 1155 | return 0; | 1166 | return 0; |
| @@ -1388,6 +1399,14 @@ out: | |||
| 1388 | return ret; | 1399 | return ret; |
| 1389 | } | 1400 | } |
| 1390 | 1401 | ||
| 1402 | static int enable_qp_db(int id, void *p, void *data) | ||
| 1403 | { | ||
| 1404 | struct c4iw_qp *qp = p; | ||
| 1405 | |||
| 1406 | t4_enable_wq_db(&qp->wq); | ||
| 1407 | return 0; | ||
| 1408 | } | ||
| 1409 | |||
| 1391 | int c4iw_destroy_qp(struct ib_qp *ib_qp) | 1410 | int c4iw_destroy_qp(struct ib_qp *ib_qp) |
| 1392 | { | 1411 | { |
| 1393 | struct c4iw_dev *rhp; | 1412 | struct c4iw_dev *rhp; |
| @@ -1405,7 +1424,16 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) | |||
| 1405 | c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); | 1424 | c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); |
| 1406 | wait_event(qhp->wait, !qhp->ep); | 1425 | wait_event(qhp->wait, !qhp->ep); |
| 1407 | 1426 | ||
| 1408 | remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid); | 1427 | spin_lock_irq(&rhp->lock); |
| 1428 | remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid); | ||
| 1429 | rhp->qpcnt--; | ||
| 1430 | BUG_ON(rhp->qpcnt < 0); | ||
| 1431 | if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) { | ||
| 1432 | rhp->rdev.stats.db_state_transitions++; | ||
| 1433 | rhp->db_state = NORMAL; | ||
| 1434 | idr_for_each(&rhp->qpidr, enable_qp_db, NULL); | ||
| 1435 | } | ||
| 1436 | spin_unlock_irq(&rhp->lock); | ||
| 1409 | atomic_dec(&qhp->refcnt); | 1437 | atomic_dec(&qhp->refcnt); |
| 1410 | wait_event(qhp->wait, !atomic_read(&qhp->refcnt)); | 1438 | wait_event(qhp->wait, !atomic_read(&qhp->refcnt)); |
| 1411 | 1439 | ||
| @@ -1419,6 +1447,14 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) | |||
| 1419 | return 0; | 1447 | return 0; |
| 1420 | } | 1448 | } |
| 1421 | 1449 | ||
| 1450 | static int disable_qp_db(int id, void *p, void *data) | ||
| 1451 | { | ||
| 1452 | struct c4iw_qp *qp = p; | ||
| 1453 | |||
| 1454 | t4_disable_wq_db(&qp->wq); | ||
| 1455 | return 0; | ||
| 1456 | } | ||
| 1457 | |||
| 1422 | struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, | 1458 | struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, |
| 1423 | struct ib_udata *udata) | 1459 | struct ib_udata *udata) |
| 1424 | { | 1460 | { |
| @@ -1508,6 +1544,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, | |||
| 1508 | spin_lock_irq(&rhp->lock); | 1544 | spin_lock_irq(&rhp->lock); |
| 1509 | if (rhp->db_state != NORMAL) | 1545 | if (rhp->db_state != NORMAL) |
| 1510 | t4_disable_wq_db(&qhp->wq); | 1546 | t4_disable_wq_db(&qhp->wq); |
| 1547 | if (++rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) { | ||
| 1548 | rhp->rdev.stats.db_state_transitions++; | ||
| 1549 | rhp->db_state = FLOW_CONTROL; | ||
| 1550 | idr_for_each(&rhp->qpidr, disable_qp_db, NULL); | ||
| 1551 | } | ||
| 1511 | ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid); | 1552 | ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid); |
| 1512 | spin_unlock_irq(&rhp->lock); | 1553 | spin_unlock_irq(&rhp->lock); |
| 1513 | if (ret) | 1554 | if (ret) |
