aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/cxl/Kconfig8
-rw-r--r--drivers/misc/cxl/pci.c236
-rw-r--r--include/misc/cxl.h25
3 files changed, 18 insertions, 251 deletions
diff --git a/drivers/misc/cxl/Kconfig b/drivers/misc/cxl/Kconfig
index 93397cb05b15..3ce933707828 100644
--- a/drivers/misc/cxl/Kconfig
+++ b/drivers/misc/cxl/Kconfig
@@ -33,11 +33,3 @@ config CXL
33 CAPI adapters are found in POWER8 based systems. 33 CAPI adapters are found in POWER8 based systems.
34 34
35 If unsure, say N. 35 If unsure, say N.
36
37config CXL_BIMODAL
38 bool "Support for bi-modal CAPI cards"
39 depends on HOTPLUG_PCI_POWERNV = y && CXL || HOTPLUG_PCI_POWERNV = m && CXL = m
40 default y
41 help
42 Select this option to enable support for bi-modal CAPI cards, such as
43 the Mellanox CX-4.
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 429d6de1dde7..9c5a21fee835 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -55,8 +55,6 @@
55 pci_read_config_byte(dev, vsec + 0xa, dest) 55 pci_read_config_byte(dev, vsec + 0xa, dest)
56#define CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val) \ 56#define CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val) \
57 pci_write_config_byte(dev, vsec + 0xa, val) 57 pci_write_config_byte(dev, vsec + 0xa, val)
58#define CXL_WRITE_VSEC_MODE_CONTROL_BUS(bus, devfn, vsec, val) \
59 pci_bus_write_config_byte(bus, devfn, vsec + 0xa, val)
60#define CXL_VSEC_PROTOCOL_MASK 0xe0 58#define CXL_VSEC_PROTOCOL_MASK 0xe0
61#define CXL_VSEC_PROTOCOL_1024TB 0x80 59#define CXL_VSEC_PROTOCOL_1024TB 0x80
62#define CXL_VSEC_PROTOCOL_512TB 0x40 60#define CXL_VSEC_PROTOCOL_512TB 0x40
@@ -800,234 +798,36 @@ static int setup_cxl_bars(struct pci_dev *dev)
800 return 0; 798 return 0;
801} 799}
802 800
803#ifdef CONFIG_CXL_BIMODAL 801/* pciex node: ibm,opal-m64-window = <0x3d058 0x0 0x3d058 0x0 0x8 0x0>; */
804 802static int switch_card_to_cxl(struct pci_dev *dev)
805struct cxl_switch_work {
806 struct pci_dev *dev;
807 struct work_struct work;
808 int vsec;
809 int mode;
810};
811
812static void switch_card_to_cxl(struct work_struct *work)
813{ 803{
814 struct cxl_switch_work *switch_work = 804 int vsec;
815 container_of(work, struct cxl_switch_work, work);
816 struct pci_dev *dev = switch_work->dev;
817 struct pci_bus *bus = dev->bus;
818 struct pci_controller *hose = pci_bus_to_host(bus);
819 struct pci_dev *bridge;
820 struct pnv_php_slot *php_slot;
821 unsigned int devfn;
822 u8 val; 805 u8 val;
823 int rc; 806 int rc;
824 807
825 dev_info(&bus->dev, "cxl: Preparing for mode switch...\n"); 808 dev_info(&dev->dev, "switch card to CXL\n");
826 bridge = list_first_entry_or_null(&hose->bus->devices, struct pci_dev,
827 bus_list);
828 if (!bridge) {
829 dev_WARN(&bus->dev, "cxl: Couldn't find root port!\n");
830 goto err_dev_put;
831 }
832 809
833 php_slot = pnv_php_find_slot(pci_device_to_OF_node(bridge)); 810 if (!(vsec = find_cxl_vsec(dev))) {
834 if (!php_slot) { 811 dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
835 dev_err(&bus->dev, "cxl: Failed to find slot hotplug "
836 "information. You may need to upgrade "
837 "skiboot. Aborting.\n");
838 goto err_dev_put;
839 }
840
841 rc = CXL_READ_VSEC_MODE_CONTROL(dev, switch_work->vsec, &val);
842 if (rc) {
843 dev_err(&bus->dev, "cxl: Failed to read CAPI mode control: %i\n", rc);
844 goto err_dev_put;
845 }
846 devfn = dev->devfn;
847
848 /* Release the reference obtained in cxl_check_and_switch_mode() */
849 pci_dev_put(dev);
850
851 dev_dbg(&bus->dev, "cxl: Removing PCI devices from kernel\n");
852 pci_lock_rescan_remove();
853 pci_hp_remove_devices(bridge->subordinate);
854 pci_unlock_rescan_remove();
855
856 /* Switch the CXL protocol on the card */
857 if (switch_work->mode == CXL_BIMODE_CXL) {
858 dev_info(&bus->dev, "cxl: Switching card to CXL mode\n");
859 val &= ~CXL_VSEC_PROTOCOL_MASK;
860 val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE;
861 rc = pnv_cxl_enable_phb_kernel_api(hose, true);
862 if (rc) {
863 dev_err(&bus->dev, "cxl: Failed to enable kernel API"
864 " on real PHB, aborting\n");
865 goto err_free_work;
866 }
867 } else {
868 dev_WARN(&bus->dev, "cxl: Switching card to PCI mode not supported!\n");
869 goto err_free_work;
870 }
871
872 rc = CXL_WRITE_VSEC_MODE_CONTROL_BUS(bus, devfn, switch_work->vsec, val);
873 if (rc) {
874 dev_err(&bus->dev, "cxl: Failed to configure CXL protocol: %i\n", rc);
875 goto err_free_work;
876 }
877
878 /*
879 * The CAIA spec (v1.1, Section 10.6 Bi-modal Device Support) states
880 * we must wait 100ms after this mode switch before touching PCIe config
881 * space.
882 */
883 msleep(100);
884
885 /*
886 * Hot reset to cause the card to come back in cxl mode. A
887 * OPAL_RESET_PCI_LINK would be sufficient, but currently lacks support
888 * in skiboot, so we use a hot reset instead.
889 *
890 * We call pci_set_pcie_reset_state() on the bridge, as a CAPI card is
891 * guaranteed to sit directly under the root port, and setting the reset
892 * state on a device directly under the root port is equivalent to doing
893 * it on the root port iself.
894 */
895 dev_info(&bus->dev, "cxl: Configuration write complete, resetting card\n");
896 pci_set_pcie_reset_state(bridge, pcie_hot_reset);
897 pci_set_pcie_reset_state(bridge, pcie_deassert_reset);
898
899 dev_dbg(&bus->dev, "cxl: Offlining slot\n");
900 rc = pnv_php_set_slot_power_state(&php_slot->slot, OPAL_PCI_SLOT_OFFLINE);
901 if (rc) {
902 dev_err(&bus->dev, "cxl: OPAL offlining call failed: %i\n", rc);
903 goto err_free_work;
904 }
905
906 dev_dbg(&bus->dev, "cxl: Onlining and probing slot\n");
907 rc = pnv_php_set_slot_power_state(&php_slot->slot, OPAL_PCI_SLOT_ONLINE);
908 if (rc) {
909 dev_err(&bus->dev, "cxl: OPAL onlining call failed: %i\n", rc);
910 goto err_free_work;
911 }
912
913 pci_lock_rescan_remove();
914 pci_hp_add_devices(bridge->subordinate);
915 pci_unlock_rescan_remove();
916
917 dev_info(&bus->dev, "cxl: CAPI mode switch completed\n");
918 kfree(switch_work);
919 return;
920
921err_dev_put:
922 /* Release the reference obtained in cxl_check_and_switch_mode() */
923 pci_dev_put(dev);
924err_free_work:
925 kfree(switch_work);
926}
927
928int cxl_check_and_switch_mode(struct pci_dev *dev, int mode, int vsec)
929{
930 struct cxl_switch_work *work;
931 u8 val;
932 int rc;
933
934 if (!cpu_has_feature(CPU_FTR_HVMODE))
935 return -ENODEV; 812 return -ENODEV;
936
937 if (!vsec) {
938 vsec = find_cxl_vsec(dev);
939 if (!vsec) {
940 dev_info(&dev->dev, "CXL VSEC not found\n");
941 return -ENODEV;
942 }
943 } 813 }
944 814
945 rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val); 815 if ((rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val))) {
946 if (rc) { 816 dev_err(&dev->dev, "failed to read current mode control: %i", rc);
947 dev_err(&dev->dev, "Failed to read current mode control: %i", rc);
948 return rc; 817 return rc;
949 } 818 }
950 819 val &= ~CXL_VSEC_PROTOCOL_MASK;
951 if (mode == CXL_BIMODE_PCI) { 820 val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE;
952 if (!(val & CXL_VSEC_PROTOCOL_ENABLE)) { 821 if ((rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val))) {
953 dev_info(&dev->dev, "Card is already in PCI mode\n"); 822 dev_err(&dev->dev, "failed to enable CXL protocol: %i", rc);
954 return 0; 823 return rc;
955 }
956 /*
957 * TODO: Before it's safe to switch the card back to PCI mode
958 * we need to disable the CAPP and make sure any cachelines the
959 * card holds have been flushed out. Needs skiboot support.
960 */
961 dev_WARN(&dev->dev, "CXL mode switch to PCI unsupported!\n");
962 return -EIO;
963 }
964
965 if (val & CXL_VSEC_PROTOCOL_ENABLE) {
966 dev_info(&dev->dev, "Card is already in CXL mode\n");
967 return 0;
968 } 824 }
969
970 dev_info(&dev->dev, "Card is in PCI mode, scheduling kernel thread "
971 "to switch to CXL mode\n");
972
973 work = kmalloc(sizeof(struct cxl_switch_work), GFP_KERNEL);
974 if (!work)
975 return -ENOMEM;
976
977 pci_dev_get(dev);
978 work->dev = dev;
979 work->vsec = vsec;
980 work->mode = mode;
981 INIT_WORK(&work->work, switch_card_to_cxl);
982
983 schedule_work(&work->work);
984
985 /* 825 /*
986 * We return a failure now to abort the driver init. Once the 826 * The CAIA spec (v0.12 11.6 Bi-modal Device Support) states
987 * link has been cycled and the card is in cxl mode we will 827 * we must wait 100ms after this mode switch before touching
988 * come back (possibly using the generic cxl driver), but 828 * PCIe config space.
989 * return success as the card should then be in cxl mode.
990 *
991 * TODO: What if the card comes back in PCI mode even after
992 * the switch? Don't want to spin endlessly.
993 */ 829 */
994 return -EBUSY; 830 msleep(100);
995}
996EXPORT_SYMBOL_GPL(cxl_check_and_switch_mode);
997
998#endif /* CONFIG_CXL_BIMODAL */
999
1000static int setup_cxl_protocol_area(struct pci_dev *dev)
1001{
1002 u8 val;
1003 int rc;
1004 int vsec = find_cxl_vsec(dev);
1005
1006 if (!vsec) {
1007 dev_info(&dev->dev, "CXL VSEC not found\n");
1008 return -ENODEV;
1009 }
1010
1011 rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val);
1012 if (rc) {
1013 dev_err(&dev->dev, "Failed to read current mode control: %i\n", rc);
1014 return rc;
1015 }
1016
1017 if (!(val & CXL_VSEC_PROTOCOL_ENABLE)) {
1018 dev_err(&dev->dev, "Card not in CAPI mode!\n");
1019 return -EIO;
1020 }
1021
1022 if ((val & CXL_VSEC_PROTOCOL_MASK) != CXL_VSEC_PROTOCOL_256TB) {
1023 val &= ~CXL_VSEC_PROTOCOL_MASK;
1024 val |= CXL_VSEC_PROTOCOL_256TB;
1025 rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val);
1026 if (rc) {
1027 dev_err(&dev->dev, "Failed to set CXL protocol area: %i\n", rc);
1028 return rc;
1029 }
1030 }
1031 831
1032 return 0; 832 return 0;
1033} 833}
@@ -1724,7 +1524,7 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev)
1724 if ((rc = setup_cxl_bars(dev))) 1524 if ((rc = setup_cxl_bars(dev)))
1725 return rc; 1525 return rc;
1726 1526
1727 if ((rc = setup_cxl_protocol_area(dev))) 1527 if ((rc = switch_card_to_cxl(dev)))
1728 return rc; 1528 return rc;
1729 1529
1730 if ((rc = cxl_update_image_control(adapter))) 1530 if ((rc = cxl_update_image_control(adapter)))
diff --git a/include/misc/cxl.h b/include/misc/cxl.h
index 6a3711a2e217..74da2e440763 100644
--- a/include/misc/cxl.h
+++ b/include/misc/cxl.h
@@ -39,31 +39,6 @@
39bool cxl_slot_is_supported(struct pci_dev *dev, int flags); 39bool cxl_slot_is_supported(struct pci_dev *dev, int flags);
40 40
41 41
42#define CXL_BIMODE_CXL 1
43#define CXL_BIMODE_PCI 2
44
45/*
46 * Check the mode that the given bi-modal CXL adapter is currently in and
47 * change it if necessary. This does not apply to AFU drivers.
48 *
49 * If the mode matches the requested mode this function will return 0 - if the
50 * driver was expecting the generic CXL driver to have bound to the adapter and
51 * it gets this return value it should fail the probe function to give the CXL
52 * driver a chance to probe it.
53 *
54 * If the mode does not match it will start a background task to unplug the
55 * device from Linux and switch its mode, and will return -EBUSY. At this
56 * point the calling driver should make sure it has released the device and
57 * fail its probe function.
58 *
59 * The offset of the CXL VSEC can be provided to this function. If 0 is passed,
60 * this function will search for a CXL VSEC with ID 0x1280 and return -ENODEV
61 * if it is not found.
62 */
63#ifdef CONFIG_CXL_BIMODAL
64int cxl_check_and_switch_mode(struct pci_dev *dev, int mode, int vsec);
65#endif
66
67/* Get the AFU associated with a pci_dev */ 42/* Get the AFU associated with a pci_dev */
68struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev); 43struct cxl_afu *cxl_pci_to_afu(struct pci_dev *dev);
69 44