aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qed/qed_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/qlogic/qed/qed_int.c')
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_int.c83
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
407int qed_db_rec_handler(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 410int 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
437static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) 439static 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);
459out:
460 /* Schedule the handler even if overflow was not detected */
461 qed_periodic_db_rec_start(p_hwfn);
462}
463
464static 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
531static 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
539static 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);
546out:
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 +