diff options
Diffstat (limited to 'drivers/ntb/ntb_hw.c')
-rw-r--r-- | drivers/ntb/ntb_hw.c | 262 |
1 files changed, 160 insertions, 102 deletions
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 97b18eec3d39..2f3ff73b1d1b 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c | |||
@@ -69,7 +69,7 @@ module_param(xeon_errata_workaround, bool, 0644); | |||
69 | MODULE_PARM_DESC(xeon_errata_workaround, "Workaround for the Xeon Errata"); | 69 | MODULE_PARM_DESC(xeon_errata_workaround, "Workaround for the Xeon Errata"); |
70 | 70 | ||
71 | enum { | 71 | enum { |
72 | NTB_CONN_CLASSIC = 0, | 72 | NTB_CONN_TRANSPARENT = 0, |
73 | NTB_CONN_B2B, | 73 | NTB_CONN_B2B, |
74 | NTB_CONN_RP, | 74 | NTB_CONN_RP, |
75 | }; | 75 | }; |
@@ -509,7 +509,8 @@ static void ntb_link_event(struct ntb_device *ndev, int link_state) | |||
509 | ndev->link_status = NTB_LINK_UP; | 509 | ndev->link_status = NTB_LINK_UP; |
510 | event = NTB_EVENT_HW_LINK_UP; | 510 | event = NTB_EVENT_HW_LINK_UP; |
511 | 511 | ||
512 | if (ndev->hw_type == BWD_HW) | 512 | if (ndev->hw_type == BWD_HW || |
513 | ndev->conn_type == NTB_CONN_TRANSPARENT) | ||
513 | status = readw(ndev->reg_ofs.lnk_stat); | 514 | status = readw(ndev->reg_ofs.lnk_stat); |
514 | else { | 515 | else { |
515 | int rc = pci_read_config_word(ndev->pdev, | 516 | int rc = pci_read_config_word(ndev->pdev, |
@@ -649,119 +650,174 @@ static int ntb_xeon_setup(struct ntb_device *ndev) | |||
649 | if (rc) | 650 | if (rc) |
650 | return rc; | 651 | return rc; |
651 | 652 | ||
652 | switch (val & SNB_PPD_CONN_TYPE) { | ||
653 | case NTB_CONN_B2B: | ||
654 | ndev->conn_type = NTB_CONN_B2B; | ||
655 | break; | ||
656 | case NTB_CONN_CLASSIC: | ||
657 | case NTB_CONN_RP: | ||
658 | default: | ||
659 | dev_err(&ndev->pdev->dev, "Only B2B supported at this time\n"); | ||
660 | return -EINVAL; | ||
661 | } | ||
662 | |||
663 | if (val & SNB_PPD_DEV_TYPE) | 653 | if (val & SNB_PPD_DEV_TYPE) |
664 | ndev->dev_type = NTB_DEV_USD; | 654 | ndev->dev_type = NTB_DEV_USD; |
665 | else | 655 | else |
666 | ndev->dev_type = NTB_DEV_DSD; | 656 | ndev->dev_type = NTB_DEV_DSD; |
667 | 657 | ||
668 | ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; | 658 | switch (val & SNB_PPD_CONN_TYPE) { |
669 | ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; | 659 | case NTB_CONN_B2B: |
670 | ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; | 660 | dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); |
671 | ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; | 661 | ndev->conn_type = NTB_CONN_B2B; |
672 | ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; | 662 | ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; |
673 | ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_LINK_STATUS_OFFSET; | 663 | ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; |
674 | ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; | 664 | ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; |
675 | ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; | 665 | ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; |
676 | 666 | ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; | |
677 | /* There is a Xeon hardware errata related to writes to | 667 | ndev->limits.max_spads = SNB_MAX_B2B_SPADS; |
678 | * SDOORBELL or B2BDOORBELL in conjunction with inbound access | 668 | |
679 | * to NTB MMIO Space, which may hang the system. To workaround | 669 | /* There is a Xeon hardware errata related to writes to |
680 | * this use the second memory window to access the interrupt and | 670 | * SDOORBELL or B2BDOORBELL in conjunction with inbound access |
681 | * scratch pad registers on the remote system. | 671 | * to NTB MMIO Space, which may hang the system. To workaround |
682 | */ | 672 | * this use the second memory window to access the interrupt and |
683 | if (xeon_errata_workaround) { | 673 | * scratch pad registers on the remote system. |
684 | if (!ndev->mw[1].bar_sz) | ||
685 | return -EINVAL; | ||
686 | |||
687 | ndev->limits.max_mw = SNB_ERRATA_MAX_MW; | ||
688 | ndev->reg_ofs.spad_write = ndev->mw[1].vbase + | ||
689 | SNB_SPAD_OFFSET; | ||
690 | ndev->reg_ofs.rdb = ndev->mw[1].vbase + | ||
691 | SNB_PDOORBELL_OFFSET; | ||
692 | |||
693 | /* Set the Limit register to 4k, the minimum size, to | ||
694 | * prevent an illegal access | ||
695 | */ | 674 | */ |
696 | writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + | 675 | if (xeon_errata_workaround) { |
697 | SNB_PBAR4LMT_OFFSET); | 676 | if (!ndev->mw[1].bar_sz) |
698 | } else { | 677 | return -EINVAL; |
699 | ndev->limits.max_mw = SNB_MAX_MW; | 678 | |
700 | ndev->reg_ofs.spad_write = ndev->reg_base + | 679 | ndev->limits.max_mw = SNB_ERRATA_MAX_MW; |
701 | SNB_B2B_SPAD_OFFSET; | 680 | ndev->reg_ofs.spad_write = ndev->mw[1].vbase + |
702 | ndev->reg_ofs.rdb = ndev->reg_base + | 681 | SNB_SPAD_OFFSET; |
703 | SNB_B2B_DOORBELL_OFFSET; | 682 | ndev->reg_ofs.rdb = ndev->mw[1].vbase + |
683 | SNB_PDOORBELL_OFFSET; | ||
684 | |||
685 | /* Set the Limit register to 4k, the minimum size, to | ||
686 | * prevent an illegal access | ||
687 | */ | ||
688 | writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + | ||
689 | SNB_PBAR4LMT_OFFSET); | ||
690 | } else { | ||
691 | ndev->limits.max_mw = SNB_MAX_MW; | ||
692 | ndev->reg_ofs.spad_write = ndev->reg_base + | ||
693 | SNB_B2B_SPAD_OFFSET; | ||
694 | ndev->reg_ofs.rdb = ndev->reg_base + | ||
695 | SNB_B2B_DOORBELL_OFFSET; | ||
696 | |||
697 | /* Disable the Limit register, just incase it is set to | ||
698 | * something silly | ||
699 | */ | ||
700 | writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); | ||
701 | } | ||
704 | 702 | ||
705 | /* Disable the Limit register, just incase it is set to | 703 | /* The Xeon errata workaround requires setting SBAR Base |
706 | * something silly | 704 | * addresses to known values, so that the PBAR XLAT can be |
705 | * pointed at SBAR0 of the remote system. | ||
707 | */ | 706 | */ |
708 | writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); | 707 | if (ndev->dev_type == NTB_DEV_USD) { |
709 | } | 708 | writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + |
709 | SNB_PBAR2XLAT_OFFSET); | ||
710 | if (xeon_errata_workaround) | ||
711 | writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + | ||
712 | SNB_PBAR4XLAT_OFFSET); | ||
713 | else { | ||
714 | writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base + | ||
715 | SNB_PBAR4XLAT_OFFSET); | ||
716 | /* B2B_XLAT_OFFSET is a 64bit register, but can | ||
717 | * only take 32bit writes | ||
718 | */ | ||
719 | writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, | ||
720 | ndev->reg_base + SNB_B2B_XLAT_OFFSETL); | ||
721 | writel(SNB_MBAR01_DSD_ADDR >> 32, | ||
722 | ndev->reg_base + SNB_B2B_XLAT_OFFSETU); | ||
723 | } | ||
710 | 724 | ||
711 | /* The Xeon errata workaround requires setting SBAR Base | 725 | writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + |
712 | * addresses to known values, so that the PBAR XLAT can be | 726 | SNB_SBAR0BASE_OFFSET); |
713 | * pointed at SBAR0 of the remote system. | 727 | writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + |
714 | */ | 728 | SNB_SBAR2BASE_OFFSET); |
715 | if (ndev->dev_type == NTB_DEV_USD) { | 729 | writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base + |
716 | writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + | 730 | SNB_SBAR4BASE_OFFSET); |
717 | SNB_PBAR2XLAT_OFFSET); | 731 | } else { |
718 | if (xeon_errata_workaround) | 732 | writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + |
733 | SNB_PBAR2XLAT_OFFSET); | ||
734 | if (xeon_errata_workaround) | ||
735 | writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + | ||
736 | SNB_PBAR4XLAT_OFFSET); | ||
737 | else { | ||
738 | writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base + | ||
739 | SNB_PBAR4XLAT_OFFSET); | ||
740 | /* B2B_XLAT_OFFSET is a 64bit register, but can | ||
741 | * only take 32bit writes | ||
742 | */ | ||
743 | writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, | ||
744 | ndev->reg_base + SNB_B2B_XLAT_OFFSETL); | ||
745 | writel(SNB_MBAR01_USD_ADDR >> 32, | ||
746 | ndev->reg_base + SNB_B2B_XLAT_OFFSETU); | ||
747 | } | ||
719 | writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + | 748 | writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + |
720 | SNB_PBAR4XLAT_OFFSET); | 749 | SNB_SBAR0BASE_OFFSET); |
721 | else { | 750 | writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + |
751 | SNB_SBAR2BASE_OFFSET); | ||
722 | writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base + | 752 | writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base + |
723 | SNB_PBAR4XLAT_OFFSET); | 753 | SNB_SBAR4BASE_OFFSET); |
724 | /* B2B_XLAT_OFFSET is a 64bit register, but can | ||
725 | * only take 32bit writes | ||
726 | */ | ||
727 | writel(SNB_MBAR01_USD_ADDR & 0xffffffff, | ||
728 | ndev->reg_base + SNB_B2B_XLAT_OFFSETL); | ||
729 | writel(SNB_MBAR01_DSD_ADDR >> 32, | ||
730 | ndev->reg_base + SNB_B2B_XLAT_OFFSETU); | ||
731 | } | 754 | } |
755 | break; | ||
756 | case NTB_CONN_RP: | ||
757 | dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); | ||
758 | ndev->conn_type = NTB_CONN_RP; | ||
732 | 759 | ||
733 | writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + | 760 | if (xeon_errata_workaround) { |
734 | SNB_SBAR0BASE_OFFSET); | 761 | dev_err(&ndev->pdev->dev, |
735 | writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + | 762 | "NTB-RP disabled due to hardware errata. To disregard this warning and potentially lock-up the system, add the parameter 'xeon_errata_workaround=0'.\n"); |
736 | SNB_SBAR2BASE_OFFSET); | 763 | return -EINVAL; |
737 | writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base + | ||
738 | SNB_SBAR4BASE_OFFSET); | ||
739 | } else { | ||
740 | writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + | ||
741 | SNB_PBAR2XLAT_OFFSET); | ||
742 | if (xeon_errata_workaround) | ||
743 | writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + | ||
744 | SNB_PBAR4XLAT_OFFSET); | ||
745 | else { | ||
746 | writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base + | ||
747 | SNB_PBAR4XLAT_OFFSET); | ||
748 | /* B2B_XLAT_OFFSET is a 64bit register, but can | ||
749 | * only take 32bit writes | ||
750 | */ | ||
751 | writel(SNB_MBAR01_USD_ADDR & 0xffffffff, | ||
752 | ndev->reg_base + SNB_B2B_XLAT_OFFSETL); | ||
753 | writel(SNB_MBAR01_USD_ADDR >> 32, | ||
754 | ndev->reg_base + SNB_B2B_XLAT_OFFSETU); | ||
755 | } | 764 | } |
756 | writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + | 765 | |
757 | SNB_SBAR0BASE_OFFSET); | 766 | /* Scratch pads need to have exclusive access from the primary |
758 | writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + | 767 | * or secondary side. Halve the num spads so that each side can |
759 | SNB_SBAR2BASE_OFFSET); | 768 | * have an equal amount. |
760 | writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base + | 769 | */ |
761 | SNB_SBAR4BASE_OFFSET); | 770 | ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; |
771 | /* Note: The SDOORBELL is the cause of the errata. You REALLY | ||
772 | * don't want to touch it. | ||
773 | */ | ||
774 | ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; | ||
775 | ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; | ||
776 | ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; | ||
777 | /* Offset the start of the spads to correspond to whether it is | ||
778 | * primary or secondary | ||
779 | */ | ||
780 | ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + | ||
781 | ndev->limits.max_spads * 4; | ||
782 | ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; | ||
783 | ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; | ||
784 | ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; | ||
785 | ndev->limits.max_mw = SNB_MAX_MW; | ||
786 | break; | ||
787 | case NTB_CONN_TRANSPARENT: | ||
788 | dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); | ||
789 | ndev->conn_type = NTB_CONN_TRANSPARENT; | ||
790 | /* Scratch pads need to have exclusive access from the primary | ||
791 | * or secondary side. Halve the num spads so that each side can | ||
792 | * have an equal amount. | ||
793 | */ | ||
794 | ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; | ||
795 | ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; | ||
796 | ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; | ||
797 | ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; | ||
798 | ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; | ||
799 | /* Offset the start of the spads to correspond to whether it is | ||
800 | * primary or secondary | ||
801 | */ | ||
802 | ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + | ||
803 | ndev->limits.max_spads * 4; | ||
804 | ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; | ||
805 | ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; | ||
806 | |||
807 | ndev->limits.max_mw = SNB_MAX_MW; | ||
808 | break; | ||
809 | default: | ||
810 | /* Most likely caused by the remote NTB-RP device not being | ||
811 | * configured | ||
812 | */ | ||
813 | dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", val); | ||
814 | return -EINVAL; | ||
762 | } | 815 | } |
763 | 816 | ||
764 | ndev->limits.max_spads = SNB_MAX_B2B_SPADS; | 817 | ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; |
818 | ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; | ||
819 | ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; | ||
820 | |||
765 | ndev->limits.max_db_bits = SNB_MAX_DB_BITS; | 821 | ndev->limits.max_db_bits = SNB_MAX_DB_BITS; |
766 | ndev->limits.msix_cnt = SNB_MSIX_CNT; | 822 | ndev->limits.msix_cnt = SNB_MSIX_CNT; |
767 | ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; | 823 | ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; |
@@ -865,8 +921,10 @@ static int ntb_device_setup(struct ntb_device *ndev) | |||
865 | dev_info(&ndev->pdev->dev, "Device Type = %s\n", | 921 | dev_info(&ndev->pdev->dev, "Device Type = %s\n", |
866 | ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); | 922 | ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); |
867 | 923 | ||
868 | /* Enable Bus Master and Memory Space on the secondary side */ | 924 | if (ndev->conn_type == NTB_CONN_B2B) |
869 | writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, ndev->reg_ofs.spci_cmd); | 925 | /* Enable Bus Master and Memory Space on the secondary side */ |
926 | writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, | ||
927 | ndev->reg_ofs.spci_cmd); | ||
870 | 928 | ||
871 | return 0; | 929 | return 0; |
872 | } | 930 | } |
@@ -1360,7 +1418,7 @@ static void ntb_pci_remove(struct pci_dev *pdev) | |||
1360 | 1418 | ||
1361 | /* Bring NTB link down */ | 1419 | /* Bring NTB link down */ |
1362 | ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); | 1420 | ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); |
1363 | ntb_cntl |= NTB_LINK_DISABLE; | 1421 | ntb_cntl |= NTB_CNTL_LINK_DISABLE; |
1364 | writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); | 1422 | writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); |
1365 | 1423 | ||
1366 | ntb_transport_free(ndev->ntb_transport); | 1424 | ntb_transport_free(ndev->ntb_transport); |