diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qed/qed_int.c')
-rw-r--r-- | drivers/net/ethernet/qlogic/qed/qed_int.c | 83 |
1 files changed, 63 insertions, 20 deletions
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index e23980e301b6..8848d5bed6e5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c | |||
@@ -378,6 +378,9 @@ static int qed_db_rec_flush_queue(struct qed_hwfn *p_hwfn, | |||
378 | u32 count = QED_DB_REC_COUNT; | 378 | u32 count = QED_DB_REC_COUNT; |
379 | u32 usage = 1; | 379 | u32 usage = 1; |
380 | 380 | ||
381 | /* Flush any pending (e)dpms as they may never arrive */ | ||
382 | qed_wr(p_hwfn, p_ptt, DORQ_REG_DPM_FORCE_ABORT, 0x1); | ||
383 | |||
381 | /* wait for usage to zero or count to run out. This is necessary since | 384 | /* wait for usage to zero or count to run out. This is necessary since |
382 | * EDPM doorbell transactions can take multiple 64b cycles, and as such | 385 | * EDPM doorbell transactions can take multiple 64b cycles, and as such |
383 | * can "split" over the pci. Possibly, the doorbell drop can happen with | 386 | * can "split" over the pci. Possibly, the doorbell drop can happen with |
@@ -406,51 +409,74 @@ static int qed_db_rec_flush_queue(struct qed_hwfn *p_hwfn, | |||
406 | 409 | ||
407 | int qed_db_rec_handler(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) | 410 | int qed_db_rec_handler(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) |
408 | { | 411 | { |
409 | u32 overflow; | 412 | u32 attn_ovfl, cur_ovfl; |
410 | int rc; | 413 | int rc; |
411 | 414 | ||
412 | overflow = qed_rd(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY); | 415 | attn_ovfl = test_and_clear_bit(QED_OVERFLOW_BIT, |
413 | DP_NOTICE(p_hwfn, "PF Overflow sticky 0x%x\n", overflow); | 416 | &p_hwfn->db_recovery_info.overflow); |
414 | if (!overflow) { | 417 | cur_ovfl = qed_rd(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY); |
415 | qed_db_recovery_execute(p_hwfn, DB_REC_ONCE); | 418 | if (!cur_ovfl && !attn_ovfl) |
416 | return 0; | 419 | return 0; |
417 | } | ||
418 | 420 | ||
419 | if (qed_edpm_enabled(p_hwfn)) { | 421 | DP_NOTICE(p_hwfn, "PF Overflow sticky: attn %u current %u\n", |
422 | attn_ovfl, cur_ovfl); | ||
423 | |||
424 | if (cur_ovfl && !p_hwfn->db_bar_no_edpm) { | ||
420 | rc = qed_db_rec_flush_queue(p_hwfn, p_ptt); | 425 | rc = qed_db_rec_flush_queue(p_hwfn, p_ptt); |
421 | if (rc) | 426 | if (rc) |
422 | return rc; | 427 | return rc; |
423 | } | 428 | } |
424 | 429 | ||
425 | /* Flush any pending (e)dpm as they may never arrive */ | ||
426 | qed_wr(p_hwfn, p_ptt, DORQ_REG_DPM_FORCE_ABORT, 0x1); | ||
427 | |||
428 | /* Release overflow sticky indication (stop silently dropping everything) */ | 430 | /* Release overflow sticky indication (stop silently dropping everything) */ |
429 | qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY, 0x0); | 431 | qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY, 0x0); |
430 | 432 | ||
431 | /* Repeat all last doorbells (doorbell drop recovery) */ | 433 | /* Repeat all last doorbells (doorbell drop recovery) */ |
432 | qed_db_recovery_execute(p_hwfn, DB_REC_REAL_DEAL); | 434 | qed_db_recovery_execute(p_hwfn); |
433 | 435 | ||
434 | return 0; | 436 | return 0; |
435 | } | 437 | } |
436 | 438 | ||
437 | static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) | 439 | static void qed_dorq_attn_overflow(struct qed_hwfn *p_hwfn) |
438 | { | 440 | { |
439 | u32 int_sts, first_drop_reason, details, address, all_drops_reason; | ||
440 | struct qed_ptt *p_ptt = p_hwfn->p_dpc_ptt; | 441 | struct qed_ptt *p_ptt = p_hwfn->p_dpc_ptt; |
442 | u32 overflow; | ||
441 | int rc; | 443 | int rc; |
442 | 444 | ||
443 | int_sts = qed_rd(p_hwfn, p_ptt, DORQ_REG_INT_STS); | 445 | overflow = qed_rd(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY); |
444 | DP_NOTICE(p_hwfn->cdev, "DORQ attention. int_sts was %x\n", int_sts); | 446 | if (!overflow) |
447 | goto out; | ||
448 | |||
449 | /* Run PF doorbell recovery in next periodic handler */ | ||
450 | set_bit(QED_OVERFLOW_BIT, &p_hwfn->db_recovery_info.overflow); | ||
451 | |||
452 | if (!p_hwfn->db_bar_no_edpm) { | ||
453 | rc = qed_db_rec_flush_queue(p_hwfn, p_ptt); | ||
454 | if (rc) | ||
455 | goto out; | ||
456 | } | ||
457 | |||
458 | qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY, 0x0); | ||
459 | out: | ||
460 | /* Schedule the handler even if overflow was not detected */ | ||
461 | qed_periodic_db_rec_start(p_hwfn); | ||
462 | } | ||
463 | |||
464 | static int qed_dorq_attn_int_sts(struct qed_hwfn *p_hwfn) | ||
465 | { | ||
466 | u32 int_sts, first_drop_reason, details, address, all_drops_reason; | ||
467 | struct qed_ptt *p_ptt = p_hwfn->p_dpc_ptt; | ||
445 | 468 | ||
446 | /* int_sts may be zero since all PFs were interrupted for doorbell | 469 | /* int_sts may be zero since all PFs were interrupted for doorbell |
447 | * overflow but another one already handled it. Can abort here. If | 470 | * overflow but another one already handled it. Can abort here. If |
448 | * This PF also requires overflow recovery we will be interrupted again. | 471 | * This PF also requires overflow recovery we will be interrupted again. |
449 | * The masked almost full indication may also be set. Ignoring. | 472 | * The masked almost full indication may also be set. Ignoring. |
450 | */ | 473 | */ |
474 | int_sts = qed_rd(p_hwfn, p_ptt, DORQ_REG_INT_STS); | ||
451 | if (!(int_sts & ~DORQ_REG_INT_STS_DORQ_FIFO_AFULL)) | 475 | if (!(int_sts & ~DORQ_REG_INT_STS_DORQ_FIFO_AFULL)) |
452 | return 0; | 476 | return 0; |
453 | 477 | ||
478 | DP_NOTICE(p_hwfn->cdev, "DORQ attention. int_sts was %x\n", int_sts); | ||
479 | |||
454 | /* check if db_drop or overflow happened */ | 480 | /* check if db_drop or overflow happened */ |
455 | if (int_sts & (DORQ_REG_INT_STS_DB_DROP | | 481 | if (int_sts & (DORQ_REG_INT_STS_DB_DROP | |
456 | DORQ_REG_INT_STS_DORQ_FIFO_OVFL_ERR)) { | 482 | DORQ_REG_INT_STS_DORQ_FIFO_OVFL_ERR)) { |
@@ -477,11 +503,6 @@ static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) | |||
477 | GET_FIELD(details, QED_DORQ_ATTENTION_SIZE) * 4, | 503 | GET_FIELD(details, QED_DORQ_ATTENTION_SIZE) * 4, |
478 | first_drop_reason, all_drops_reason); | 504 | first_drop_reason, all_drops_reason); |
479 | 505 | ||
480 | rc = qed_db_rec_handler(p_hwfn, p_ptt); | ||
481 | qed_periodic_db_rec_start(p_hwfn); | ||
482 | if (rc) | ||
483 | return rc; | ||
484 | |||
485 | /* Clear the doorbell drop details and prepare for next drop */ | 506 | /* Clear the doorbell drop details and prepare for next drop */ |
486 | qed_wr(p_hwfn, p_ptt, DORQ_REG_DB_DROP_DETAILS_REL, 0); | 507 | qed_wr(p_hwfn, p_ptt, DORQ_REG_DB_DROP_DETAILS_REL, 0); |
487 | 508 | ||
@@ -507,6 +528,25 @@ static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) | |||
507 | return -EINVAL; | 528 | return -EINVAL; |
508 | } | 529 | } |
509 | 530 | ||
531 | static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) | ||
532 | { | ||
533 | p_hwfn->db_recovery_info.dorq_attn = true; | ||
534 | qed_dorq_attn_overflow(p_hwfn); | ||
535 | |||
536 | return qed_dorq_attn_int_sts(p_hwfn); | ||
537 | } | ||
538 | |||
539 | static void qed_dorq_attn_handler(struct qed_hwfn *p_hwfn) | ||
540 | { | ||
541 | if (p_hwfn->db_recovery_info.dorq_attn) | ||
542 | goto out; | ||
543 | |||
544 | /* Call DORQ callback if the attention was missed */ | ||
545 | qed_dorq_attn_cb(p_hwfn); | ||
546 | out: | ||
547 | p_hwfn->db_recovery_info.dorq_attn = false; | ||
548 | } | ||
549 | |||
510 | /* Instead of major changes to the data-structure, we have a some 'special' | 550 | /* Instead of major changes to the data-structure, we have a some 'special' |
511 | * identifiers for sources that changed meaning between adapters. | 551 | * identifiers for sources that changed meaning between adapters. |
512 | */ | 552 | */ |
@@ -1080,6 +1120,9 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, | |||
1080 | } | 1120 | } |
1081 | } | 1121 | } |
1082 | 1122 | ||
1123 | /* Handle missed DORQ attention */ | ||
1124 | qed_dorq_attn_handler(p_hwfn); | ||
1125 | |||
1083 | /* Clear IGU indication for the deasserted bits */ | 1126 | /* Clear IGU indication for the deasserted bits */ |
1084 | DIRECT_REG_WR((u8 __iomem *)p_hwfn->regview + | 1127 | DIRECT_REG_WR((u8 __iomem *)p_hwfn->regview + |
1085 | GTT_BAR0_MAP_REG_IGU_CMD + | 1128 | GTT_BAR0_MAP_REG_IGU_CMD + |