diff options
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_init.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_init.c | 109 |
1 files changed, 89 insertions, 20 deletions
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index eb8256bec516..8e0e7a3bbf9e 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c | |||
@@ -46,6 +46,9 @@ static void | |||
46 | qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, | 46 | qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, |
47 | struct qlcnic_host_rds_ring *rds_ring); | 47 | struct qlcnic_host_rds_ring *rds_ring); |
48 | 48 | ||
49 | static int | ||
50 | qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter); | ||
51 | |||
49 | static void crb_addr_transform_setup(void) | 52 | static void crb_addr_transform_setup(void) |
50 | { | 53 | { |
51 | crb_addr_transform(XDMA); | 54 | crb_addr_transform(XDMA); |
@@ -544,31 +547,77 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) | |||
544 | return 0; | 547 | return 0; |
545 | } | 548 | } |
546 | 549 | ||
547 | int | 550 | static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter) |
548 | qlcnic_check_fw_status(struct qlcnic_adapter *adapter) | ||
549 | { | 551 | { |
550 | u32 heartbit, cmdpeg_state, ret = -EIO; | 552 | u32 val; |
551 | int retries = QLCNIC_HEARTBEAT_RETRY_COUNT; | 553 | int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT; |
552 | 554 | ||
553 | adapter->heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | ||
554 | do { | 555 | do { |
555 | msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS); | 556 | val = QLCRD32(adapter, CRB_CMDPEG_STATE); |
556 | heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | 557 | |
557 | if (heartbit != adapter->heartbit) { | 558 | switch (val) { |
558 | cmdpeg_state = QLCRD32(adapter, CRB_CMDPEG_STATE); | 559 | case PHAN_INITIALIZE_COMPLETE: |
559 | /* Ensure peg states are initialized */ | 560 | case PHAN_INITIALIZE_ACK: |
560 | if (cmdpeg_state == PHAN_INITIALIZE_COMPLETE || | 561 | return 0; |
561 | cmdpeg_state == PHAN_INITIALIZE_ACK) { | 562 | case PHAN_INITIALIZE_FAILED: |
562 | /* Complete firmware handshake */ | 563 | goto out_err; |
563 | QLCWR32(adapter, CRB_CMDPEG_STATE, | 564 | default: |
564 | PHAN_INITIALIZE_ACK); | 565 | break; |
565 | ret = QLCNIC_RCODE_SUCCESS; | ||
566 | break; | ||
567 | } | ||
568 | } | 566 | } |
567 | |||
568 | msleep(QLCNIC_CMDPEG_CHECK_DELAY); | ||
569 | |||
569 | } while (--retries); | 570 | } while (--retries); |
570 | 571 | ||
571 | return ret; | 572 | QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); |
573 | |||
574 | out_err: | ||
575 | dev_err(&adapter->pdev->dev, "Command Peg initialization not " | ||
576 | "complete, state: 0x%x.\n", val); | ||
577 | return -EIO; | ||
578 | } | ||
579 | |||
580 | static int | ||
581 | qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter) | ||
582 | { | ||
583 | u32 val; | ||
584 | int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT; | ||
585 | |||
586 | do { | ||
587 | val = QLCRD32(adapter, CRB_RCVPEG_STATE); | ||
588 | |||
589 | if (val == PHAN_PEG_RCV_INITIALIZED) | ||
590 | return 0; | ||
591 | |||
592 | msleep(QLCNIC_RCVPEG_CHECK_DELAY); | ||
593 | |||
594 | } while (--retries); | ||
595 | |||
596 | if (!retries) { | ||
597 | dev_err(&adapter->pdev->dev, "Receive Peg initialization not " | ||
598 | "complete, state: 0x%x.\n", val); | ||
599 | return -EIO; | ||
600 | } | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | int | ||
606 | qlcnic_check_fw_status(struct qlcnic_adapter *adapter) | ||
607 | { | ||
608 | int err; | ||
609 | |||
610 | err = qlcnic_cmd_peg_ready(adapter); | ||
611 | if (err) | ||
612 | return err; | ||
613 | |||
614 | err = qlcnic_receive_peg_ready(adapter); | ||
615 | if (err) | ||
616 | return err; | ||
617 | |||
618 | QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); | ||
619 | |||
620 | return err; | ||
572 | } | 621 | } |
573 | 622 | ||
574 | int | 623 | int |
@@ -943,12 +992,32 @@ static void qlcnic_rom_lock_recovery(struct qlcnic_adapter *adapter) | |||
943 | qlcnic_pcie_sem_unlock(adapter, 2); | 992 | qlcnic_pcie_sem_unlock(adapter, 2); |
944 | } | 993 | } |
945 | 994 | ||
995 | static int | ||
996 | qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter) | ||
997 | { | ||
998 | u32 heartbeat, ret = -EIO; | ||
999 | int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT; | ||
1000 | |||
1001 | adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | ||
1002 | |||
1003 | do { | ||
1004 | msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS); | ||
1005 | heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | ||
1006 | if (heartbeat != adapter->heartbeat) { | ||
1007 | ret = QLCNIC_RCODE_SUCCESS; | ||
1008 | break; | ||
1009 | } | ||
1010 | } while (--retries); | ||
1011 | |||
1012 | return ret; | ||
1013 | } | ||
1014 | |||
946 | int | 1015 | int |
947 | qlcnic_need_fw_reset(struct qlcnic_adapter *adapter) | 1016 | qlcnic_need_fw_reset(struct qlcnic_adapter *adapter) |
948 | { | 1017 | { |
949 | u32 val, version, major, minor, build; | 1018 | u32 val, version, major, minor, build; |
950 | 1019 | ||
951 | if (qlcnic_check_fw_status(adapter)) { | 1020 | if (qlcnic_check_fw_hearbeat(adapter)) { |
952 | qlcnic_rom_lock_recovery(adapter); | 1021 | qlcnic_rom_lock_recovery(adapter); |
953 | return 1; | 1022 | return 1; |
954 | } | 1023 | } |