diff options
Diffstat (limited to 'drivers/net/ethernet/cavium/thunder/thunder_bgx.c')
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 108 |
1 files changed, 96 insertions, 12 deletions
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 2f85b64f01fa..1e4695270da6 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c | |||
@@ -31,6 +31,7 @@ struct lmac { | |||
31 | u8 lmac_type; | 31 | u8 lmac_type; |
32 | u8 lane_to_sds; | 32 | u8 lane_to_sds; |
33 | bool use_training; | 33 | bool use_training; |
34 | bool autoneg; | ||
34 | bool link_up; | 35 | bool link_up; |
35 | int lmacid; /* ID within BGX */ | 36 | int lmacid; /* ID within BGX */ |
36 | int lmacid_bd; /* ID on board */ | 37 | int lmacid_bd; /* ID on board */ |
@@ -461,7 +462,17 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) | |||
461 | /* power down, reset autoneg, autoneg enable */ | 462 | /* power down, reset autoneg, autoneg enable */ |
462 | cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL); | 463 | cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL); |
463 | cfg &= ~PCS_MRX_CTL_PWR_DN; | 464 | cfg &= ~PCS_MRX_CTL_PWR_DN; |
464 | cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN); | 465 | cfg |= PCS_MRX_CTL_RST_AN; |
466 | if (lmac->phydev) { | ||
467 | cfg |= PCS_MRX_CTL_AN_EN; | ||
468 | } else { | ||
469 | /* In scenarios where PHY driver is not present or it's a | ||
470 | * non-standard PHY, FW sets AN_EN to inform Linux driver | ||
471 | * to do auto-neg and link polling or not. | ||
472 | */ | ||
473 | if (cfg & PCS_MRX_CTL_AN_EN) | ||
474 | lmac->autoneg = true; | ||
475 | } | ||
465 | bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg); | 476 | bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg); |
466 | 477 | ||
467 | if (lmac->lmac_type == BGX_MODE_QSGMII) { | 478 | if (lmac->lmac_type == BGX_MODE_QSGMII) { |
@@ -472,7 +483,7 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) | |||
472 | return 0; | 483 | return 0; |
473 | } | 484 | } |
474 | 485 | ||
475 | if (lmac->lmac_type == BGX_MODE_SGMII) { | 486 | if ((lmac->lmac_type == BGX_MODE_SGMII) && lmac->phydev) { |
476 | if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS, | 487 | if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS, |
477 | PCS_MRX_STATUS_AN_CPT, false)) { | 488 | PCS_MRX_STATUS_AN_CPT, false)) { |
478 | dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n"); | 489 | dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n"); |
@@ -678,12 +689,71 @@ static int bgx_xaui_check_link(struct lmac *lmac) | |||
678 | return -1; | 689 | return -1; |
679 | } | 690 | } |
680 | 691 | ||
692 | static void bgx_poll_for_sgmii_link(struct lmac *lmac) | ||
693 | { | ||
694 | u64 pcs_link, an_result; | ||
695 | u8 speed; | ||
696 | |||
697 | pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid, | ||
698 | BGX_GMP_PCS_MRX_STATUS); | ||
699 | |||
700 | /*Link state bit is sticky, read it again*/ | ||
701 | if (!(pcs_link & PCS_MRX_STATUS_LINK)) | ||
702 | pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid, | ||
703 | BGX_GMP_PCS_MRX_STATUS); | ||
704 | |||
705 | if (bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_GMP_PCS_MRX_STATUS, | ||
706 | PCS_MRX_STATUS_AN_CPT, false)) { | ||
707 | lmac->link_up = false; | ||
708 | lmac->last_speed = SPEED_UNKNOWN; | ||
709 | lmac->last_duplex = DUPLEX_UNKNOWN; | ||
710 | goto next_poll; | ||
711 | } | ||
712 | |||
713 | lmac->link_up = ((pcs_link & PCS_MRX_STATUS_LINK) != 0) ? true : false; | ||
714 | an_result = bgx_reg_read(lmac->bgx, lmac->lmacid, | ||
715 | BGX_GMP_PCS_ANX_AN_RESULTS); | ||
716 | |||
717 | speed = (an_result >> 3) & 0x3; | ||
718 | lmac->last_duplex = (an_result >> 1) & 0x1; | ||
719 | switch (speed) { | ||
720 | case 0: | ||
721 | lmac->last_speed = 10; | ||
722 | break; | ||
723 | case 1: | ||
724 | lmac->last_speed = 100; | ||
725 | break; | ||
726 | case 2: | ||
727 | lmac->last_speed = 1000; | ||
728 | break; | ||
729 | default: | ||
730 | lmac->link_up = false; | ||
731 | lmac->last_speed = SPEED_UNKNOWN; | ||
732 | lmac->last_duplex = DUPLEX_UNKNOWN; | ||
733 | break; | ||
734 | } | ||
735 | |||
736 | next_poll: | ||
737 | |||
738 | if (lmac->last_link != lmac->link_up) { | ||
739 | if (lmac->link_up) | ||
740 | bgx_sgmii_change_link_state(lmac); | ||
741 | lmac->last_link = lmac->link_up; | ||
742 | } | ||
743 | |||
744 | queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 3); | ||
745 | } | ||
746 | |||
681 | static void bgx_poll_for_link(struct work_struct *work) | 747 | static void bgx_poll_for_link(struct work_struct *work) |
682 | { | 748 | { |
683 | struct lmac *lmac; | 749 | struct lmac *lmac; |
684 | u64 spu_link, smu_link; | 750 | u64 spu_link, smu_link; |
685 | 751 | ||
686 | lmac = container_of(work, struct lmac, dwork.work); | 752 | lmac = container_of(work, struct lmac, dwork.work); |
753 | if (lmac->is_sgmii) { | ||
754 | bgx_poll_for_sgmii_link(lmac); | ||
755 | return; | ||
756 | } | ||
687 | 757 | ||
688 | /* Receive link is latching low. Force it high and verify it */ | 758 | /* Receive link is latching low. Force it high and verify it */ |
689 | bgx_reg_modify(lmac->bgx, lmac->lmacid, | 759 | bgx_reg_modify(lmac->bgx, lmac->lmacid, |
@@ -775,9 +845,21 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) | |||
775 | (lmac->lmac_type != BGX_MODE_XLAUI) && | 845 | (lmac->lmac_type != BGX_MODE_XLAUI) && |
776 | (lmac->lmac_type != BGX_MODE_40G_KR) && | 846 | (lmac->lmac_type != BGX_MODE_40G_KR) && |
777 | (lmac->lmac_type != BGX_MODE_10G_KR)) { | 847 | (lmac->lmac_type != BGX_MODE_10G_KR)) { |
778 | if (!lmac->phydev) | 848 | if (!lmac->phydev) { |
779 | return -ENODEV; | 849 | if (lmac->autoneg) { |
780 | 850 | bgx_reg_write(bgx, lmacid, | |
851 | BGX_GMP_PCS_LINKX_TIMER, | ||
852 | PCS_LINKX_TIMER_COUNT); | ||
853 | goto poll; | ||
854 | } else { | ||
855 | /* Default to below link speed and duplex */ | ||
856 | lmac->link_up = true; | ||
857 | lmac->last_speed = 1000; | ||
858 | lmac->last_duplex = 1; | ||
859 | bgx_sgmii_change_link_state(lmac); | ||
860 | return 0; | ||
861 | } | ||
862 | } | ||
781 | lmac->phydev->dev_flags = 0; | 863 | lmac->phydev->dev_flags = 0; |
782 | 864 | ||
783 | if (phy_connect_direct(&lmac->netdev, lmac->phydev, | 865 | if (phy_connect_direct(&lmac->netdev, lmac->phydev, |
@@ -786,15 +868,17 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) | |||
786 | return -ENODEV; | 868 | return -ENODEV; |
787 | 869 | ||
788 | phy_start_aneg(lmac->phydev); | 870 | phy_start_aneg(lmac->phydev); |
789 | } else { | 871 | return 0; |
790 | lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND | | ||
791 | WQ_MEM_RECLAIM, 1); | ||
792 | if (!lmac->check_link) | ||
793 | return -ENOMEM; | ||
794 | INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link); | ||
795 | queue_delayed_work(lmac->check_link, &lmac->dwork, 0); | ||
796 | } | 872 | } |
797 | 873 | ||
874 | poll: | ||
875 | lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND | | ||
876 | WQ_MEM_RECLAIM, 1); | ||
877 | if (!lmac->check_link) | ||
878 | return -ENOMEM; | ||
879 | INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link); | ||
880 | queue_delayed_work(lmac->check_link, &lmac->dwork, 0); | ||
881 | |||
798 | return 0; | 882 | return 0; |
799 | } | 883 | } |
800 | 884 | ||