History

Merge branch 'pci/controller/vmd'

- Support device ID 0x28C1 and assume that BIOS has already enumerated the hierarchy below VMD and stored bus range info for OS to use (Nirmal Patel) - Add support for VMCONFIG BUS_RESTRICT_CFG=3, which makes it possible to enumerate downstream devices on Intel Arrow Lake-HX systems and probably others (Ali Alaei) - Observe _OSC negotiation for VMD hierarchy only when running on bare metal, not when running in a VM (Nirmal Patel) - Add Nova Lake (NVL) and Dunlow (DNL) Device IDs (Szymon Durawa) * pci/controller/vmd: PCI: vmd: Add Nova Lake (NVL) and Dunlow (DNL) Device IDs PCI: vmd: Only copy root bridge _OSC control flags in bare metal OS PCI: vmd: Handle BUS_RESTRICT_CFG value 3 for Arrow Lake-HX PCI: vmd: Add feature to scan BIOS-enumerated devices

Bjorn Helgaas committed 2 months ago

Commit e0aba452 parents b130a2c 55aa4512 files · +169 −35Browse files

Unified · Split

2 files
  1. drivers/pci/controller/vmd.c +168 −35
  2. include/linux/pci_ids.h +1 −0
drivers/pci/controller/vmd.c+168−35
@@ -37,6 +37,12 @@ · 36 unmodified lines
37#define MB2_SHADOW_OFFSET 0x200037#define MB2_SHADOW_OFFSET 0x2000
38#define MB2_SHADOW_SIZE 1638#define MB2_SHADOW_SIZE 16
39 39
40/* DMR BAR4 register offsets */
41#define SHADOW_MEMBAR1_28C1 0x2818 /* MEMBAR1 physical address */
42#define SHADOW_MEMBAR2_28C1 0x2820 /* MEMBAR2 physical address */
43#define BASE_ID_REG_28C1 0x2840
44#define MEMBAR2_OFFSET_28C1 0x30d0
45
40enum vmd_features {46enum vmd_features {
41 /*47 /*
42 * Device may contain registers which hint the physical location of the48 * Device may contain registers which hint the physical location of the
@@ -77,6 +83,15 @@ enum vmd_features { · 34 unmodified lines
77 * proper power management of the SoC.83 * proper power management of the SoC.
78 */84 */
79 VMD_FEAT_BIOS_PM_QUIRK = (1 << 5),85 VMD_FEAT_BIOS_PM_QUIRK = (1 << 5),
86
87 /*
88 * Newer VMD with device ID 0x28C1 has unique settings compared to its
89 * predecessor where BIOS enumerates the entire VMD device tree and
90 * stores respective configurations including bus start range and
91 * shadow registers in VMD MMIO space in VMD BAR4/BAR5, otherwise
92 * referred to as MEMBAR2 or MSI-X BAR.
93 */
94 VMD_FEAT_USE_BIOS_INFO = (1 << 6),
80};95};
81 96
82#define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */97#define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */
@@ -142,6 +157,7 @@ struct vmd_dev { · 59 unmodified lines
142 u8 first_vec;157 u8 first_vec;
143 char *name;158 char *name;
144 int instance;159 int instance;
160 unsigned long features;
145};161};
146 162
147static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)163static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
@@ -366,6 +382,9 @@ static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable) · 218 unmodified lines
366{382{
367 u16 reg;383 u16 reg;
368 384
385 if (!!(vmd->features & VMD_FEAT_USE_BIOS_INFO))
386 return;
387
369 pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);388 pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, &reg);
370 reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :389 reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) :
371 (reg | VMCONFIG_MSI_REMAP);390 (reg | VMCONFIG_MSI_REMAP);
@@ -389,11 +408,22 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) · 17 unmodified lines
389 }408 }
390}409}
391 410
411static unsigned int vmd_bus_to_ecam(struct vmd_dev *vmd, unsigned int busnr)
412{
413 if (!!(vmd->features & VMD_FEAT_USE_BIOS_INFO))
414 return busnr;
415
416 return busnr - vmd->busn_start;
417}
418
392static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,419static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
393 unsigned int devfn, int reg, int len)420 unsigned int devfn, int reg, int len)
394{421{
395 unsigned int busnr_ecam = bus->number - vmd->busn_start;422 unsigned int busnr_ecam;
396 u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);423 u32 offset;
424
425 busnr_ecam = vmd_bus_to_ecam(vmd, bus->number);
426 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
397 427
398 if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))428 if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))
399 return NULL;429 return NULL;
@@ -518,22 +548,37 @@ static inline void vmd_acpi_begin(void) { } · 118 unmodified lines
518static inline void vmd_acpi_end(void) { }548static inline void vmd_acpi_end(void) { }
519#endif /* CONFIG_ACPI */549#endif /* CONFIG_ACPI */
520 550
551static resource_size_t vmd_cfgbar_ecam_space(struct vmd_dev *vmd)
552{
553 resource_size_t cfgbar_buses;
554 unsigned int ecam_start;
555
556 cfgbar_buses = resource_size(&vmd->dev->resource[VMD_CFGBAR]) >> 20;
557 ecam_start = vmd_bus_to_ecam(vmd, vmd->resources[0].start);
558 if (ecam_start >= cfgbar_buses)
559 return 0;
560
561 return cfgbar_buses - ecam_start;
562}
521static void vmd_domain_reset(struct vmd_dev *vmd)563static void vmd_domain_reset(struct vmd_dev *vmd)
522{564{
523 u16 bus, max_buses = resource_size(&vmd->resources[0]);565 u16 bus, max_buses = resource_size(&vmd->resources[0]);
524 u8 dev, functions, fn, hdr_type;566 u8 dev, functions, fn, hdr_type;
567 unsigned int ecam_bus;
525 char __iomem *base;568 char __iomem *base;
526 569
570 max_buses = min_t(u16, max_buses, vmd_cfgbar_ecam_space(vmd));
527 for (bus = 0; bus < max_buses; bus++) {571 for (bus = 0; bus < max_buses; bus++) {
572 ecam_bus = vmd_bus_to_ecam(vmd, vmd->resources[0].start + bus);
528 for (dev = 0; dev < 32; dev++) {573 for (dev = 0; dev < 32; dev++) {
529 base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,574 base = vmd->cfgbar + PCIE_ECAM_OFFSET(ecam_bus,
530 PCI_DEVFN(dev, 0), 0);575 PCI_DEVFN(dev, 0), 0);
531 576
532 hdr_type = readb(base + PCI_HEADER_TYPE);577 hdr_type = readb(base + PCI_HEADER_TYPE);
533 578
534 functions = (hdr_type & PCI_HEADER_TYPE_MFD) ? 8 : 1;579 functions = (hdr_type & PCI_HEADER_TYPE_MFD) ? 8 : 1;
535 for (fn = 0; fn < functions; fn++) {580 for (fn = 0; fn < functions; fn++) {
536 base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,581 base = vmd->cfgbar + PCIE_ECAM_OFFSET(ecam_bus,
537 PCI_DEVFN(dev, fn), 0);582 PCI_DEVFN(dev, fn), 0);
538 583
539 hdr_type = readb(base + PCI_HEADER_TYPE) &584 hdr_type = readb(base + PCI_HEADER_TYPE) &
@@ -640,6 +685,8 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) · 100 unmodified lines
640 pci_read_config_word(dev, PCI_REG_VMCAP, &reg);685 pci_read_config_word(dev, PCI_REG_VMCAP, &reg);
641 if (BUS_RESTRICT_CAP(reg)) {686 if (BUS_RESTRICT_CAP(reg)) {
642 pci_read_config_word(dev, PCI_REG_VMCONFIG, &reg);687 pci_read_config_word(dev, PCI_REG_VMCONFIG, &reg);
688 if (PCI_POSSIBLE_ERROR(reg))
689 return -ENODEV;
643 690
644 switch (BUS_RESTRICT_CFG(reg)) {691 switch (BUS_RESTRICT_CFG(reg)) {
645 case 0:692 case 0:
@@ -648,6 +695,7 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) · 2 unmodified lines
648 case 1:695 case 1:
649 vmd->busn_start = 128;696 vmd->busn_start = 128;
650 break;697 break;
698 case 3:
651 case 2:699 case 2:
652 vmd->busn_start = 224;700 vmd->busn_start = 224;
653 break;701 break;
@@ -661,6 +709,46 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) · 7 unmodified lines
661 return 0;709 return 0;
662}710}
663 711
712static int vmd_get_bus_info_from_bar4(struct vmd_dev *vmd,
713 resource_size_t *offset1,
714 resource_size_t *offset2)
715{
716 u64 phys1, phys2, bar4_2840;
717 void __iomem *bar4;
718 u32 base_id;
719 u8 base_bus;
720
721 bar4 = pci_ioremap_bar(vmd->dev, 4);
722 if (!bar4)
723 return -ENOMEM;
724
725 /* Read shadow registers for MEMBAR1 and MEMBAR2 physical addresses */
726 phys1 = readq(bar4 + SHADOW_MEMBAR1_28C1);
727 phys2 = readq(bar4 + SHADOW_MEMBAR2_28C1);
728
729 /*
730 * Read and set bus start number from Base ID register. 24-bit Base ID
731 * register is part of 64-bit shadowed reqid hide range register and
732 * holds segment, bus, device and function.
733 */
734 bar4_2840 = readq(bar4 + BASE_ID_REG_28C1);
735 base_id = bar4_2840 & 0xFFFFFF;
736 base_bus = base_id >> 8;
737 vmd->busn_start = base_bus;
738
739 /* Calculate offsets like vmd_get_phys_offsets() does */
740 if (phys1)
741 *offset1 = vmd->dev->resource[VMD_MEMBAR1].start -
742 (phys1 & PCI_BASE_ADDRESS_MEM_MASK);
743 if (phys2)
744 *offset2 = vmd->dev->resource[VMD_MEMBAR2].start -
745 (phys2 & PCI_BASE_ADDRESS_MEM_MASK);
746
747 pci_iounmap(vmd->dev, bar4);
748
749 return 0;
750}
751
664static irqreturn_t vmd_irq(int irq, void *data)752static irqreturn_t vmd_irq(int irq, void *data)
665{753{
666 struct vmd_irq_list *irqs = data;754 struct vmd_irq_list *irqs = data;
@@ -711,6 +799,52 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd) · 44 unmodified lines
711 return 0;799 return 0;
712}800}
713 801
802static int vmd_prepare_offsets_and_bus(struct vmd_dev *vmd,
803 unsigned long features,
804 resource_size_t *membar2_offset,
805 resource_size_t *offset1,
806 resource_size_t *offset2)
807{
808 int ret;
809
810 /*
811 * Shadow registers may exist in certain VMD device IDs which allow
812 * guests to correctly assign host physical addresses to the root ports
813 * and child devices. These registers will either return the host value
814 * or 0, depending on an enable bit in the VMD device.
815 *
816 * For certain VMD devices (i.e. 0x28C1), BIOS places device info
817 * in BAR4 shadow registers to determine the base bus number and memory
818 * offsets.
819 */
820 if (features & VMD_FEAT_USE_BIOS_INFO) {
821 *membar2_offset = MEMBAR2_OFFSET_28C1;
822 ret = vmd_get_bus_info_from_bar4(vmd, offset1, offset2);
823 if (ret)
824 return ret;
825 } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) {
826 *membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE;
827 ret = vmd_get_phys_offsets(vmd, true, offset1, offset2);
828 if (ret)
829 return ret;
830 } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
831 ret = vmd_get_phys_offsets(vmd, false, offset1, offset2);
832 if (ret)
833 return ret;
834 }
835
836 /*
837 * Certain VMD devices may have a root port configuration option which
838 * limits the bus range to between 0-127, 128-255, or 224-255.
839 */
840 if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) {
841 ret = vmd_get_bus_number_start(vmd);
842 if (ret)
843 return ret;
844 }
845 return 0;
846}
847
714/*848/*
715 * Since VMD is an aperture to regular PCIe root ports, only allow it to849 * Since VMD is an aperture to regular PCIe root ports, only allow it to
716 * control features that the OS is allowed to control on the physical PCI bus.850 * control features that the OS is allowed to control on the physical PCI bus.
@@ -780,42 +914,25 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) · 63 unmodified lines
780 LIST_HEAD(resources);914 LIST_HEAD(resources);
781 resource_size_t offset[2] = {0};915 resource_size_t offset[2] = {0};
782 resource_size_t membar2_offset = 0x2000;916 resource_size_t membar2_offset = 0x2000;
917 resource_size_t busn_end;
783 struct pci_bus *child;918 struct pci_bus *child;
784 struct pci_dev *dev;919 struct pci_dev *dev;
920 bool vmd_in_guest;
785 int ret;921 int ret;
786 922
787 /*923 ret = vmd_prepare_offsets_and_bus(vmd, features, &membar2_offset,
788 * Shadow registers may exist in certain VMD device ids which allow924 &offset[0], &offset[1]);
789 * guests to correctly assign host physical addresses to the root ports925 if (ret)
790 * and child devices. These registers will either return the host value926 return ret;
791 * or 0, depending on an enable bit in the VMD device.
792 */
793 if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) {
794 membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE;
795 ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]);
796 if (ret)
797 return ret;
798 } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {
799 ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]);
800 if (ret)
801 return ret;
802 }
803
804 /*
805 * Certain VMD devices may have a root port configuration option which
806 * limits the bus range to between 0-127, 128-255, or 224-255
807 */
808 if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) {
809 ret = vmd_get_bus_number_start(vmd);
810 if (ret)
811 return ret;
812 }
813 927
928 /* Do not let resource[0] end go out of bounds */
814 res = &vmd->dev->resource[VMD_CFGBAR];929 res = &vmd->dev->resource[VMD_CFGBAR];
930 busn_end = vmd->busn_start + (resource_size(res) >> 20) - 1;
931 busn_end = min_t(resource_size_t, busn_end, 0xff);
815 vmd->resources[0] = (struct resource) {932 vmd->resources[0] = (struct resource) {
816 .name = "VMD CFGBAR",933 .name = "VMD CFGBAR",
817 .start = vmd->busn_start,934 .start = vmd->busn_start,
818 .end = vmd->busn_start + (resource_size(res) >> 20) - 1,935 .end = busn_end,
819 .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED,936 .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED,
820 };937 };
821 938
@@ -862,14 +979,16 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) · 40 unmodified lines
862 .parent = res,979 .parent = res,
863 };980 };
864 981
982 /* Non-zero offset means guest/direct assign view. */
983 vmd_in_guest = offset[0] || offset[1];
984
865 /*985 /*
866 * Currently MSI remapping must be enabled in guest passthrough mode986 * Currently MSI remapping must be enabled in guest passthrough mode
867 * due to some missing interrupt remapping plumbing. This is probably987 * due to some missing interrupt remapping plumbing. This is probably
868 * acceptable because the guest is usually CPU-limited and MSI988 * acceptable because the guest is usually CPU-limited and MSI
869 * remapping doesn't become a performance bottleneck.989 * remapping doesn't become a performance bottleneck.
870 */990 */
871 if (!(features & VMD_FEAT_CAN_BYPASS_MSI_REMAP) ||991 if (!(features & VMD_FEAT_CAN_BYPASS_MSI_REMAP) || vmd_in_guest) {
872 offset[0] || offset[1]) {
873 ret = vmd_alloc_irqs(vmd);992 ret = vmd_alloc_irqs(vmd);
874 if (ret)993 if (ret)
875 return ret;994 return ret;
@@ -910,8 +1029,13 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) · 34 unmodified lines
910 return -ENODEV;1029 return -ENODEV;
911 }1030 }
912 1031
913 vmd_copy_host_bridge_flags(pci_find_host_bridge(vmd->dev->bus),1032 /*
914 to_pci_host_bridge(vmd->bus->bridge));1033 * Don't copy _OSC control flags from root bridge if running in a VM, as
1034 * they don't reflect the physical root bridge capabilities.
1035 */
1036 if (!vmd_in_guest)
1037 vmd_copy_host_bridge_flags(pci_find_host_bridge(vmd->dev->bus),
1038 to_pci_host_bridge(vmd->bus->bridge));
915 1039
916 vmd_attach_resources(vmd);1040 vmd_attach_resources(vmd);
917 if (vmd->irq_domain)1041 if (vmd->irq_domain)
@@ -998,6 +1122,7 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) · 80 unmodified lines
998 1122
999 vmd->dev = dev;1123 vmd->dev = dev;
1000 vmd->sysdata.domain = PCI_DOMAIN_NR_NOT_SET;1124 vmd->sysdata.domain = PCI_DOMAIN_NR_NOT_SET;
1125 vmd->features = features;
1001 vmd->instance = ida_alloc(&vmd_instance_ida, GFP_KERNEL);1126 vmd->instance = ida_alloc(&vmd_instance_ida, GFP_KERNEL);
1002 if (vmd->instance < 0)1127 if (vmd->instance < 0)
1003 return vmd->instance;1128 return vmd->instance;
@@ -1114,6 +1239,10 @@ static const struct pci_device_id vmd_ids[] = { · 110 unmodified lines
1114 .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |1239 .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
1115 VMD_FEAT_HAS_BUS_RESTRICTIONS |1240 VMD_FEAT_HAS_BUS_RESTRICTIONS |
1116 VMD_FEAT_CAN_BYPASS_MSI_REMAP,},1241 VMD_FEAT_CAN_BYPASS_MSI_REMAP,},
1242 {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_28C1),
1243 .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
1244 VMD_FEAT_CAN_BYPASS_MSI_REMAP |
1245 VMD_FEAT_USE_BIOS_INFO,},
1117 {PCI_VDEVICE(INTEL, 0x467f),1246 {PCI_VDEVICE(INTEL, 0x467f),
1118 .driver_data = VMD_FEATS_CLIENT,},1247 .driver_data = VMD_FEATS_CLIENT,},
1119 {PCI_VDEVICE(INTEL, 0x4c3d),1248 {PCI_VDEVICE(INTEL, 0x4c3d),
@@ -1132,6 +1261,10 @@ static const struct pci_device_id vmd_ids[] = { · 12 unmodified lines
1132 .driver_data = VMD_FEATS_CLIENT,},1261 .driver_data = VMD_FEATS_CLIENT,},
1133 {PCI_VDEVICE(INTEL, 0xb07f),1262 {PCI_VDEVICE(INTEL, 0xb07f),
1134 .driver_data = VMD_FEATS_CLIENT,},1263 .driver_data = VMD_FEATS_CLIENT,},
1264 {PCI_VDEVICE(INTEL, 0xd70b),
1265 .driver_data = VMD_FEATS_CLIENT,},
1266 {PCI_VDEVICE(INTEL, 0xd73b),
1267 .driver_data = VMD_FEATS_CLIENT,},
1135 {0,}1268 {0,}
1136};1269};
1137MODULE_DEVICE_TABLE(pci, vmd_ids);1270MODULE_DEVICE_TABLE(pci, vmd_ids);
include/linux/pci_ids.h+1−0
@@ -2892,6 +2892,7 @@ · 2891 unmodified lines
2892#define PCI_DEVICE_ID_INTEL_HDA_ICH8 0x284b2892#define PCI_DEVICE_ID_INTEL_HDA_ICH8 0x284b
2893#define PCI_DEVICE_ID_INTEL_ICH8_6 0x28502893#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850
2894#define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c02894#define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c0
2895#define PCI_DEVICE_ID_INTEL_VMD_28C1 0x28c1
2895#define PCI_DEVICE_ID_INTEL_ICH9_0 0x29102896#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
2896#define PCI_DEVICE_ID_INTEL_ICH9_2 0x29122897#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
2897#define PCI_DEVICE_ID_INTEL_ICH9_3 0x29132898#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913