diff options
author | Vipul Pandya <vipul@chelsio.com> | 2012-05-18 05:59:24 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-05-18 16:22:25 -0400 |
commit | 881806bc155c0d5d78196c8bfae0ea2e76ae7386 (patch) | |
tree | 20ac25b6859424a3bed1c4d64664d9264a013056 | |
parent | 14b9222808bb8bfefc71f72bc0dbdcf3b2f0140f (diff) |
cxgb4: Detect DB FULL events and notify RDMA ULD
Signed-off-by: Vipul Pandya <vipul@chelsio.com>
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 77 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/sge.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 9 |
5 files changed, 103 insertions, 0 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 0fe18850c838..f91b259f19be 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | |||
@@ -504,6 +504,8 @@ struct adapter { | |||
504 | void **tid_release_head; | 504 | void **tid_release_head; |
505 | spinlock_t tid_release_lock; | 505 | spinlock_t tid_release_lock; |
506 | struct work_struct tid_release_task; | 506 | struct work_struct tid_release_task; |
507 | struct work_struct db_full_task; | ||
508 | struct work_struct db_drop_task; | ||
507 | bool tid_release_task_busy; | 509 | bool tid_release_task_busy; |
508 | 510 | ||
509 | struct dentry *debugfs_root; | 511 | struct dentry *debugfs_root; |
@@ -719,4 +721,6 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, | |||
719 | int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, | 721 | int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, |
720 | unsigned int vf, unsigned int eqid); | 722 | unsigned int vf, unsigned int eqid); |
721 | int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); | 723 | int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); |
724 | void t4_db_full(struct adapter *adapter); | ||
725 | void t4_db_dropped(struct adapter *adapter); | ||
722 | #endif /* __CXGB4_H__ */ | 726 | #endif /* __CXGB4_H__ */ |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b126b98065a9..c243f932099e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -2366,6 +2366,16 @@ unsigned int cxgb4_port_chan(const struct net_device *dev) | |||
2366 | } | 2366 | } |
2367 | EXPORT_SYMBOL(cxgb4_port_chan); | 2367 | EXPORT_SYMBOL(cxgb4_port_chan); |
2368 | 2368 | ||
2369 | unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo) | ||
2370 | { | ||
2371 | struct adapter *adap = netdev2adap(dev); | ||
2372 | u32 v; | ||
2373 | |||
2374 | v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); | ||
2375 | return lpfifo ? G_LP_COUNT(v) : G_HP_COUNT(v); | ||
2376 | } | ||
2377 | EXPORT_SYMBOL(cxgb4_dbfifo_count); | ||
2378 | |||
2369 | /** | 2379 | /** |
2370 | * cxgb4_port_viid - get the VI id of a port | 2380 | * cxgb4_port_viid - get the VI id of a port |
2371 | * @dev: the net device for the port | 2381 | * @dev: the net device for the port |
@@ -2446,6 +2456,69 @@ static struct notifier_block cxgb4_netevent_nb = { | |||
2446 | .notifier_call = netevent_cb | 2456 | .notifier_call = netevent_cb |
2447 | }; | 2457 | }; |
2448 | 2458 | ||
2459 | static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd) | ||
2460 | { | ||
2461 | mutex_lock(&uld_mutex); | ||
2462 | if (adap->uld_handle[CXGB4_ULD_RDMA]) | ||
2463 | ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA], | ||
2464 | cmd); | ||
2465 | mutex_unlock(&uld_mutex); | ||
2466 | } | ||
2467 | |||
2468 | static void process_db_full(struct work_struct *work) | ||
2469 | { | ||
2470 | struct adapter *adap; | ||
2471 | static int delay = 1000; | ||
2472 | u32 v; | ||
2473 | |||
2474 | adap = container_of(work, struct adapter, db_full_task); | ||
2475 | |||
2476 | |||
2477 | /* stop LLD queues */ | ||
2478 | |||
2479 | notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); | ||
2480 | do { | ||
2481 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
2482 | schedule_timeout(usecs_to_jiffies(delay)); | ||
2483 | v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); | ||
2484 | if (G_LP_COUNT(v) == 0 && G_HP_COUNT(v) == 0) | ||
2485 | break; | ||
2486 | } while (1); | ||
2487 | notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); | ||
2488 | |||
2489 | |||
2490 | /* | ||
2491 | * The more we get db full interrupts, the more we'll delay | ||
2492 | * in re-enabling db rings on queues, capped off at 200ms. | ||
2493 | */ | ||
2494 | delay = min(delay << 1, 200000); | ||
2495 | |||
2496 | /* resume LLD queues */ | ||
2497 | } | ||
2498 | |||
2499 | static void process_db_drop(struct work_struct *work) | ||
2500 | { | ||
2501 | struct adapter *adap; | ||
2502 | adap = container_of(work, struct adapter, db_drop_task); | ||
2503 | |||
2504 | |||
2505 | /* | ||
2506 | * sync the PIDX values in HW and SW for LLD queues. | ||
2507 | */ | ||
2508 | |||
2509 | notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP); | ||
2510 | } | ||
2511 | |||
2512 | void t4_db_full(struct adapter *adap) | ||
2513 | { | ||
2514 | schedule_work(&adap->db_full_task); | ||
2515 | } | ||
2516 | |||
2517 | void t4_db_dropped(struct adapter *adap) | ||
2518 | { | ||
2519 | schedule_work(&adap->db_drop_task); | ||
2520 | } | ||
2521 | |||
2449 | static void uld_attach(struct adapter *adap, unsigned int uld) | 2522 | static void uld_attach(struct adapter *adap, unsigned int uld) |
2450 | { | 2523 | { |
2451 | void *handle; | 2524 | void *handle; |
@@ -2649,6 +2722,8 @@ static void cxgb_down(struct adapter *adapter) | |||
2649 | { | 2722 | { |
2650 | t4_intr_disable(adapter); | 2723 | t4_intr_disable(adapter); |
2651 | cancel_work_sync(&adapter->tid_release_task); | 2724 | cancel_work_sync(&adapter->tid_release_task); |
2725 | cancel_work_sync(&adapter->db_full_task); | ||
2726 | cancel_work_sync(&adapter->db_drop_task); | ||
2652 | adapter->tid_release_task_busy = false; | 2727 | adapter->tid_release_task_busy = false; |
2653 | adapter->tid_release_head = NULL; | 2728 | adapter->tid_release_head = NULL; |
2654 | 2729 | ||
@@ -3601,6 +3676,8 @@ static int __devinit init_one(struct pci_dev *pdev, | |||
3601 | spin_lock_init(&adapter->tid_release_lock); | 3676 | spin_lock_init(&adapter->tid_release_lock); |
3602 | 3677 | ||
3603 | INIT_WORK(&adapter->tid_release_task, process_tid_release_list); | 3678 | INIT_WORK(&adapter->tid_release_task, process_tid_release_list); |
3679 | INIT_WORK(&adapter->db_full_task, process_db_full); | ||
3680 | INIT_WORK(&adapter->db_drop_task, process_db_drop); | ||
3604 | 3681 | ||
3605 | err = t4_prep_adapter(adapter); | 3682 | err = t4_prep_adapter(adapter); |
3606 | if (err) | 3683 | if (err) |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index b1d39b8d141a..5cc2f27d60c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | |||
@@ -163,6 +163,12 @@ enum cxgb4_state { | |||
163 | CXGB4_STATE_DETACH | 163 | CXGB4_STATE_DETACH |
164 | }; | 164 | }; |
165 | 165 | ||
166 | enum cxgb4_control { | ||
167 | CXGB4_CONTROL_DB_FULL, | ||
168 | CXGB4_CONTROL_DB_EMPTY, | ||
169 | CXGB4_CONTROL_DB_DROP, | ||
170 | }; | ||
171 | |||
166 | struct pci_dev; | 172 | struct pci_dev; |
167 | struct l2t_data; | 173 | struct l2t_data; |
168 | struct net_device; | 174 | struct net_device; |
@@ -225,6 +231,7 @@ struct cxgb4_uld_info { | |||
225 | int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); | 231 | int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); |
226 | int cxgb4_unregister_uld(enum cxgb4_uld type); | 232 | int cxgb4_unregister_uld(enum cxgb4_uld type); |
227 | int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb); | 233 | int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb); |
234 | unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo); | ||
228 | unsigned int cxgb4_port_chan(const struct net_device *dev); | 235 | unsigned int cxgb4_port_chan(const struct net_device *dev); |
229 | unsigned int cxgb4_port_viid(const struct net_device *dev); | 236 | unsigned int cxgb4_port_viid(const struct net_device *dev); |
230 | unsigned int cxgb4_port_idx(const struct net_device *dev); | 237 | unsigned int cxgb4_port_idx(const struct net_device *dev); |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 2dae7959f000..234c157a4879 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c | |||
@@ -2415,6 +2415,12 @@ void t4_sge_init(struct adapter *adap) | |||
2415 | RXPKTCPLMODE | | 2415 | RXPKTCPLMODE | |
2416 | (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0)); | 2416 | (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0)); |
2417 | 2417 | ||
2418 | t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS, | ||
2419 | V_HP_INT_THRESH(5) | V_LP_INT_THRESH(5), | ||
2420 | V_HP_INT_THRESH(5) | V_LP_INT_THRESH(5)); | ||
2421 | t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP, | ||
2422 | F_ENABLE_DROP); | ||
2423 | |||
2418 | for (i = v = 0; i < 32; i += 4) | 2424 | for (i = v = 0; i < 32; i += 4) |
2419 | v |= (PAGE_SHIFT - 10) << i; | 2425 | v |= (PAGE_SHIFT - 10) << i; |
2420 | t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v); | 2426 | t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v); |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index d1ec111aebd8..13609bf056b0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | |||
@@ -1013,6 +1013,8 @@ static void sge_intr_handler(struct adapter *adapter) | |||
1013 | { ERR_INVALID_CIDX_INC, | 1013 | { ERR_INVALID_CIDX_INC, |
1014 | "SGE GTS CIDX increment too large", -1, 0 }, | 1014 | "SGE GTS CIDX increment too large", -1, 0 }, |
1015 | { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, | 1015 | { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, |
1016 | { F_DBFIFO_LP_INT, NULL, -1, 0 }, | ||
1017 | { F_DBFIFO_HP_INT, NULL, -1, 0 }, | ||
1016 | { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, | 1018 | { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, |
1017 | { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, | 1019 | { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, |
1018 | "SGE IQID > 1023 received CPL for FL", -1, 0 }, | 1020 | "SGE IQID > 1023 received CPL for FL", -1, 0 }, |
@@ -1042,6 +1044,12 @@ static void sge_intr_handler(struct adapter *adapter) | |||
1042 | t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); | 1044 | t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); |
1043 | } | 1045 | } |
1044 | 1046 | ||
1047 | err = t4_read_reg(adapter, A_SGE_INT_CAUSE3); | ||
1048 | if (err & (F_DBFIFO_HP_INT|F_DBFIFO_LP_INT)) | ||
1049 | t4_db_full(adapter); | ||
1050 | if (err & F_ERR_DROPPED_DB) | ||
1051 | t4_db_dropped(adapter); | ||
1052 | |||
1045 | if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || | 1053 | if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || |
1046 | v != 0) | 1054 | v != 0) |
1047 | t4_fatal_err(adapter); | 1055 | t4_fatal_err(adapter); |
@@ -1513,6 +1521,7 @@ void t4_intr_enable(struct adapter *adapter) | |||
1513 | ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | | 1521 | ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | |
1514 | ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | | 1522 | ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | |
1515 | ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | | 1523 | ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | |
1524 | F_DBFIFO_HP_INT | F_DBFIFO_LP_INT | | ||
1516 | EGRESS_SIZE_ERR); | 1525 | EGRESS_SIZE_ERR); |
1517 | t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); | 1526 | t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); |
1518 | t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); | 1527 | t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); |