From b7f87c9a8754df61d1a8ea31d106c4340dbc14c2 Mon Sep 17 00:00:00 2001 From: Szymon Durawa Date: Mon, 7 Oct 2024 15:02:50 +0200 Subject: [PATCH 1/7] PCI: vmd: Clean up vmd_enable_domain function This function is too long and needs to be shortened to make it more readable. Certain VMD devices like 0xAD0B has two bus ranges, current implementation supports only one range. This clean up is a prework for enablement additional VMD bus range. Signed-off-by: Szymon Durawa Suggested-by: Nirmal Patel --- drivers/pci/controller/vmd.c | 220 ++++++++++++++++++++--------------- 1 file changed, 128 insertions(+), 92 deletions(-) mode change 100644 => 100755 drivers/pci/controller/vmd.c diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c old mode 100644 new mode 100755 index 264a180403a0ec..46167378e372ed --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -767,17 +767,137 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) return 0; } -static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) +static void vmd_configure_cfgbar(struct vmd_dev *vmd) +{ + struct resource *res; + + res = &vmd->dev->resource[VMD_CFGBAR]; + vmd->resources[0] = (struct resource){ + .name = "VMD CFGBAR", + .start = vmd->busn_start, + .end = vmd->busn_start + (resource_size(res) >> 20) - 1, + .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, + }; +} + +/* + * If the window is below 4GB, clear IORESOURCE_MEM_64 so we can + * put 32-bit resources in the window. + * + * There's no hardware reason why a 64-bit window *couldn't* + * contain a 32-bit resource, but pbus_size_mem() computes the + * bridge window size assuming a 64-bit window will contain no + * 32-bit resources. __pci_assign_resource() enforces that + * artificial restriction to make sure everything will fit. + * + * The only way we could use a 64-bit non-prefetchable MEMBAR is + * if its address is <4GB so that we can convert it to a 32-bit + * resource. To be visible to the host OS, all VMD endpoints must + * be initially configured by platform BIOS, which includes setting + * up these resources. We can assume the device is configured + * according to the platform needs. + */ +static void vmd_configure_membar1(struct vmd_dev *vmd) +{ + struct resource *res; + u32 upper_bits; + unsigned long flags; + + res = &vmd->dev->resource[VMD_MEMBAR1]; + upper_bits = upper_32_bits(res->end); + flags = res->flags & ~IORESOURCE_SIZEALIGN; + if (!upper_bits) + flags &= ~IORESOURCE_MEM_64; + vmd->resources[1] = (struct resource){ + .name = "VMD MEMBAR1", + .start = res->start, + .end = res->end, + .flags = flags, + .parent = res, + }; +} + +/* + * Align resource information the same as for vmd_configure_membar1 + * function. + */ +static void vmd_configure_membar2(struct vmd_dev *vmd, + resource_size_t membar2_offset) { - struct pci_sysdata *sd = &vmd->sysdata; struct resource *res; u32 upper_bits; unsigned long flags; + + res = &vmd->dev->resource[VMD_MEMBAR2]; + upper_bits = upper_32_bits(res->end); + flags = res->flags & ~IORESOURCE_SIZEALIGN; + + if (!upper_bits) + flags &= ~IORESOURCE_MEM_64; + + vmd->resources[2] = (struct resource){ + .name = "VMD MEMBAR2", + .start = res->start + membar2_offset, + .end = res->end, + .flags = flags, + .parent = res, + }; +} + +static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) +{ + struct pci_bus *child; + struct pci_dev *dev; + int ret; + + vmd_acpi_begin(); + + pci_scan_child_bus(bus); + vmd_domain_reset(vmd_from_bus(bus)); + + /* + * When Intel VMD is enabled, the OS does not discover the Root Ports + * owned by Intel VMD within the MMCFG space. pci_reset_bus() applies + * a reset to the parent of the PCI device supplied as argument. This + * is why we pass a child device, so the reset can be triggered at + * the Intel bridge level and propagated to all the children in the + * hierarchy. + */ + list_for_each_entry(child, &bus->children, node) { + if (!list_empty(&child->devices)) { + dev = list_first_entry(&child->devices, struct pci_dev, + bus_list); + ret = pci_reset_bus(dev); + if (ret) + pci_warn(dev, "can't reset device: %d\n", ret); + + break; + } + } + + pci_assign_unassigned_bus_resources(bus); + + pci_walk_bus(bus, vmd_pm_enable_quirk, &features); + + /* + * VMD root buses are virtual and don't return true on pci_is_pcie() + * and will fail pcie_bus_configure_settings() early. It can instead be + * run on each of the real root ports. + */ + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + + pci_bus_add_devices(bus); + + vmd_acpi_end(); +} + +static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) +{ + struct pci_sysdata *sd = &vmd->sysdata; LIST_HEAD(resources); resource_size_t offset[2] = {0}; resource_size_t membar2_offset = 0x2000; - struct pci_bus *child; - struct pci_dev *dev; int ret; /* @@ -807,56 +927,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) return ret; } - res = &vmd->dev->resource[VMD_CFGBAR]; - vmd->resources[0] = (struct resource) { - .name = "VMD CFGBAR", - .start = vmd->busn_start, - .end = vmd->busn_start + (resource_size(res) >> 20) - 1, - .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, - }; - - /* - * If the window is below 4GB, clear IORESOURCE_MEM_64 so we can - * put 32-bit resources in the window. - * - * There's no hardware reason why a 64-bit window *couldn't* - * contain a 32-bit resource, but pbus_size_mem() computes the - * bridge window size assuming a 64-bit window will contain no - * 32-bit resources. __pci_assign_resource() enforces that - * artificial restriction to make sure everything will fit. - * - * The only way we could use a 64-bit non-prefetchable MEMBAR is - * if its address is <4GB so that we can convert it to a 32-bit - * resource. To be visible to the host OS, all VMD endpoints must - * be initially configured by platform BIOS, which includes setting - * up these resources. We can assume the device is configured - * according to the platform needs. - */ - res = &vmd->dev->resource[VMD_MEMBAR1]; - upper_bits = upper_32_bits(res->end); - flags = res->flags & ~IORESOURCE_SIZEALIGN; - if (!upper_bits) - flags &= ~IORESOURCE_MEM_64; - vmd->resources[1] = (struct resource) { - .name = "VMD MEMBAR1", - .start = res->start, - .end = res->end, - .flags = flags, - .parent = res, - }; - - res = &vmd->dev->resource[VMD_MEMBAR2]; - upper_bits = upper_32_bits(res->end); - flags = res->flags & ~IORESOURCE_SIZEALIGN; - if (!upper_bits) - flags &= ~IORESOURCE_MEM_64; - vmd->resources[2] = (struct resource) { - .name = "VMD MEMBAR2", - .start = res->start + membar2_offset, - .end = res->end, - .flags = flags, - .parent = res, - }; + vmd_configure_cfgbar(vmd); + vmd_configure_membar1(vmd); + vmd_configure_membar2(vmd, membar2_offset); sd->vmd_dev = vmd->dev; sd->domain = vmd_find_free_domain(); @@ -917,45 +990,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, "domain"), "Can't create symlink to domain\n"); - vmd_acpi_begin(); - - pci_scan_child_bus(vmd->bus); - vmd_domain_reset(vmd); + vmd_bus_enumeration(vmd->bus, features); - /* When Intel VMD is enabled, the OS does not discover the Root Ports - * owned by Intel VMD within the MMCFG space. pci_reset_bus() applies - * a reset to the parent of the PCI device supplied as argument. This - * is why we pass a child device, so the reset can be triggered at - * the Intel bridge level and propagated to all the children in the - * hierarchy. - */ - list_for_each_entry(child, &vmd->bus->children, node) { - if (!list_empty(&child->devices)) { - dev = list_first_entry(&child->devices, - struct pci_dev, bus_list); - ret = pci_reset_bus(dev); - if (ret) - pci_warn(dev, "can't reset device: %d\n", ret); - - break; - } - } - - pci_assign_unassigned_bus_resources(vmd->bus); - - pci_walk_bus(vmd->bus, vmd_pm_enable_quirk, &features); - - /* - * VMD root buses are virtual and don't return true on pci_is_pcie() - * and will fail pcie_bus_configure_settings() early. It can instead be - * run on each of the real root ports. - */ - list_for_each_entry(child, &vmd->bus->children, node) - pcie_bus_configure_settings(child); - - pci_bus_add_devices(vmd->bus); - - vmd_acpi_end(); return 0; } From fd2ed9dbe4dc85c80757b4809ad827c8918b9212 Mon Sep 17 00:00:00 2001 From: Szymon Durawa Date: Tue, 8 Oct 2024 14:40:53 +0200 Subject: [PATCH 2/7] PCI: vmd: Add VMD PCH rootbus support Starting from 0xAD0B VMD enhacement introduces separate rootbus for PCH. It means that all 3 MMIO BARs exposed by VMD are shared now between CPU IOC and PCH. This patch adds PCH bus enumeration and MMIO management for devices with VMD enhancement support. Signed-off-by: Szymon Durawa Suggested-by: Nirmal Patel --- drivers/pci/controller/vmd.c | 188 +++++++++++++++++++++++++++++++++-- 1 file changed, 182 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 46167378e372ed..c2706e49db8205 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -31,6 +31,15 @@ #define PCI_REG_VMLOCK 0x70 #define MB2_SHADOW_EN(vmlock) (vmlock & 0x2) +#define PCI_VMD_PRIMARY_PCH_BUS 0x80 +#define PCI_REG_BUSRANGE0 0xC8 +#define PCI_REG_BUSRANGE1 0xCC +#define PCI_MEMBAR1_OFFSET 0xD0 +#define PCI_MEMBAR2_OFFSET1 0xD8 +#define PCI_MEMBAR2_OFFSET2 0xDC +#define VMD_ROOTBUS_RANGE_END(busr) ((busr >> 8) & 0xff) +#define VMD_ROOTBUS_RANGE_START(busr) (busr & 0x00ff) + #define MB2_SHADOW_OFFSET 0x2000 #define MB2_SHADOW_SIZE 16 @@ -74,6 +83,12 @@ enum vmd_features { * proper power management of the SoC. */ VMD_FEAT_BIOS_PM_QUIRK = (1 << 5), + + /* + * Some client VMD devices have their VMD rootports connected to both + * IOC and PCH rootbus. + */ + VMD_FEAT_HAS_PCH_ROOTBUS = (1 << 6) }; #define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */ @@ -81,7 +96,8 @@ enum vmd_features { #define VMD_FEATS_CLIENT (VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | \ VMD_FEAT_HAS_BUS_RESTRICTIONS | \ VMD_FEAT_OFFSET_FIRST_VECTOR | \ - VMD_FEAT_BIOS_PM_QUIRK) + VMD_FEAT_BIOS_PM_QUIRK | \ + VMD_FEAT_HAS_PCH_ROOTBUS) static DEFINE_IDA(vmd_instance_ida); @@ -132,13 +148,15 @@ struct vmd_dev { struct vmd_irq_list *irqs; struct pci_sysdata sysdata; - struct resource resources[3]; + struct resource resources[6]; struct irq_domain *irq_domain; struct pci_bus *bus; + struct pci_bus *bus_pch; u8 busn_start; u8 first_vec; char *name; int instance; + u8 busn_start_pch; }; static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) @@ -364,10 +382,26 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) } } +static inline u8 vmd_has_pch_rootbus(struct vmd_dev *vmd) +{ + return vmd->busn_start_pch != 0; +} + static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, unsigned int devfn, int reg, int len) { - unsigned int busnr_ecam = bus->number - vmd->busn_start; + unsigned int busnr_ecam = 0; + + /* + * VMD enhacement specific: for PCH rootbus, bus number is set to + * PCI_VMD_PRIMARY_PCH_BUS but original value is 0xE1 which is stored + * in vmd->busn_start_pch. + */ + if (vmd_has_pch_rootbus(vmd) && bus->number == PCI_VMD_PRIMARY_PCH_BUS) + busnr_ecam = vmd->busn_start_pch - vmd->busn_start; + else + busnr_ecam = bus->number - vmd->busn_start; + u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR])) @@ -633,7 +667,7 @@ static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint, return 0; } -static int vmd_get_bus_number_start(struct vmd_dev *vmd) +static int vmd_get_bus_number_start(struct vmd_dev *vmd, unsigned long features) { struct pci_dev *dev = vmd->dev; u16 reg; @@ -652,6 +686,19 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) case 2: vmd->busn_start = 224; break; + case 3: + if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { + /* IOC start bus */ + vmd->busn_start = 224; + /* PCH start bus */ + vmd->busn_start_pch = 225; + } else { + pci_err(dev, + "Unknown Bus Offset Setting (%d)\n", + BUS_RESTRICT_CFG(reg)); + return -ENODEV; + } + break; default: pci_err(dev, "Unknown Bus Offset Setting (%d)\n", BUS_RESTRICT_CFG(reg)); @@ -770,6 +817,8 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) static void vmd_configure_cfgbar(struct vmd_dev *vmd) { struct resource *res; + u16 pch_bus_range = 0; + u16 ioc_bus_range = 0; res = &vmd->dev->resource[VMD_CFGBAR]; vmd->resources[0] = (struct resource){ @@ -778,6 +827,29 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd) .end = vmd->busn_start + (resource_size(res) >> 20) - 1, .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, }; + + if (vmd_has_pch_rootbus(vmd)) { + pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE0, + &ioc_bus_range); + pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE1, + &pch_bus_range); + + vmd->resources[3] = (struct resource){ + .name = "VMD CFGBAR PCH", + .start = VMD_ROOTBUS_RANGE_START(pch_bus_range), + .end = VMD_ROOTBUS_RANGE_END(pch_bus_range), + .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, + .parent = &vmd->resources[0], + }; + + /* + * Update first cfgbar range (IOC) with value stored + * in PCI_REG_BUSRANGE0 + */ + vmd->resources[0].start = + VMD_ROOTBUS_RANGE_START(ioc_bus_range); + vmd->resources[0].end = VMD_ROOTBUS_RANGE_END(ioc_bus_range); + } } /* @@ -802,6 +874,7 @@ static void vmd_configure_membar1(struct vmd_dev *vmd) struct resource *res; u32 upper_bits; unsigned long flags; + u32 vmd_enh_membar1_offset = 0; res = &vmd->dev->resource[VMD_MEMBAR1]; upper_bits = upper_32_bits(res->end); @@ -815,6 +888,26 @@ static void vmd_configure_membar1(struct vmd_dev *vmd) .flags = flags, .parent = res, }; + + if (vmd_has_pch_rootbus(vmd)) { + pci_read_config_dword(vmd->dev, PCI_MEMBAR1_OFFSET, + &vmd_enh_membar1_offset); + + vmd->resources[4] = (struct resource){ + .name = "VMD MEMBAR1 PCH", + .start = res->start + vmd_enh_membar1_offset, + .end = res->end, + .flags = flags, + .parent = &vmd->resources[1], + }; + + /* + * Update first MEMBAR1 range (IOC), memory start does not + * change, memory end is one less than the offset stored + * in PCI_MEMBAR1_OFFSET. + */ + vmd->resources[1].end = res->start + vmd_enh_membar1_offset - 1; + } } /* @@ -825,8 +918,9 @@ static void vmd_configure_membar2(struct vmd_dev *vmd, resource_size_t membar2_offset) { struct resource *res; - u32 upper_bits; + u32 upper_bits, reg; unsigned long flags; + u64 vmd_enh_membar2_offset = 0; res = &vmd->dev->resource[VMD_MEMBAR2]; upper_bits = upper_32_bits(res->end); @@ -842,6 +936,31 @@ static void vmd_configure_membar2(struct vmd_dev *vmd, .flags = flags, .parent = res, }; + + if (vmd_has_pch_rootbus(vmd)) { + pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET1, ®); + vmd_enh_membar2_offset = reg; + pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET2, ®); + vmd_enh_membar2_offset |= (u64)reg << 32; + + vmd->resources[5] = (struct resource){ + .name = "VMD MEMBAR2 PCH", + .start = res->start + membar2_offset + + vmd_enh_membar2_offset, + .end = res->end, + .flags = flags, + .parent = &vmd->resources[2], + }; + + /* + * Update first MEMBAR2 range (IOC), memory start does not + * change, memory end is one less than the offset stored + * as a 64 bit value in PCI_MEMBAR2_OFFSET1 and + * PCI_MEMBAR2_OFFSET2 registers. + */ + vmd->resources[2].end = res->start + vmd_enh_membar2_offset + + membar2_offset - 1; + } } static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) @@ -892,6 +1011,50 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_end(); } +static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, + resource_size_t *offset) +{ + LIST_HEAD(resources_pch); + + pci_add_resource(&resources_pch, &vmd->resources[3]); + pci_add_resource_offset(&resources_pch, &vmd->resources[4], + offset[0]); + pci_add_resource_offset(&resources_pch, &vmd->resources[5], + offset[1]); + + vmd->bus_pch = + pci_create_root_bus(&vmd->dev->dev, vmd->busn_start_pch, + &vmd_ops, sd, &resources_pch); + + if (!vmd->bus_pch) { + pci_free_resource_list(&resources_pch); + vmd_remove_irq_domain(vmd); + return -ENODEV; + } + + /* + * VMD enhacement specific: pci_scan_bridge_extend() in probe.c + * assigns setup as broken when primary != bus->number. + * For PCH rootbus primary is 0x80 and bus->number is 0xE1, + * bus number needs to be overwritten to the same value + * as primary to pass pci_scan_bridge_extend() + */ + vmd->bus_pch->primary = PCI_VMD_PRIMARY_PCH_BUS; + vmd->bus_pch->number = PCI_VMD_PRIMARY_PCH_BUS; + + vmd_copy_host_bridge_flags( + pci_find_host_bridge(vmd->dev->bus), + to_pci_host_bridge(vmd->bus_pch->bridge)); + + if (vmd->irq_domain) + dev_set_msi_domain(&vmd->bus_pch->dev, vmd->irq_domain); + else + dev_set_msi_domain(&vmd->bus_pch->dev, + dev_get_msi_domain(&vmd->dev->dev)); + + return 0; +} + static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -922,7 +1085,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) * limits the bus range to between 0-127, 128-255, or 224-255 */ if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) { - ret = vmd_get_bus_number_start(vmd); + ret = vmd_get_bus_number_start(vmd, features); if (ret) return ret; } @@ -990,6 +1153,15 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, "domain"), "Can't create symlink to domain\n"); + if (vmd_has_pch_rootbus(vmd)) { + ret = vmd_create_pch_bus(vmd, sd, offset); + if (ret) { + pci_err(vmd->dev, "Can't create PCH bus: %d\n", ret); + return ret; + } + + } + vmd_bus_enumeration(vmd->bus, features); return 0; @@ -1070,6 +1242,10 @@ static void vmd_remove(struct pci_dev *dev) pci_stop_root_bus(vmd->bus); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_remove_root_bus(vmd->bus); + if (vmd_has_pch_rootbus(vmd)) { + pci_stop_root_bus(vmd->bus_pch); + pci_remove_root_bus(vmd->bus_pch); + } vmd_cleanup_srcu(vmd); vmd_detach_resources(vmd); vmd_remove_irq_domain(vmd); From 3cf1f20e8633802e9051e9b4b68822d363c99c62 Mon Sep 17 00:00:00 2001 From: sdurawa Date: Tue, 15 Oct 2024 13:34:20 +0200 Subject: [PATCH 3/7] PCI: vmd: Add VMD PCH rootbus support Starting from 0xAD0B VMD enhacement introduces separate rootbus for PCH. It means that all 3 MMIO BARs exposed by VMD are shared now between CPU IOC and PCH. This patch adds PCH bus enumeration and MMIO management for devices with VMD enhancement support. Signed-off-by: Szymon Durawa Suggested-by: Nirmal Patel --- drivers/pci/controller/vmd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index c2706e49db8205..118b3507835010 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -972,7 +972,9 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_begin(); pci_scan_child_bus(bus); - vmd_domain_reset(vmd_from_bus(bus)); + + if (bus->primary == 0) + vmd_domain_reset(vmd_from_bus(bus)); /* * When Intel VMD is enabled, the OS does not discover the Root Ports @@ -1163,6 +1165,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) } vmd_bus_enumeration(vmd->bus, features); + vmd_bus_enumeration(vmd->bus_pch, features); return 0; } From d7f2ef2a6dacb2ce2331b817ca053468bae73715 Mon Sep 17 00:00:00 2001 From: sdurawa Date: Wed, 16 Oct 2024 12:49:07 +0200 Subject: [PATCH 4/7] PCI: vmd: Clean up vmd_enable_domain function This function is too long and needs to be shortened to make it more readable. Certain VMD devices like 0xAD0B has two bus ranges, current implementation supports only one range. This clean up is a prework for enablement additional VMD bus range. Signed-off-by: Szymon Durawa Suggested-by: Nirmal Patel --- drivers/pci/controller/vmd.c | 219 +++++++---------------------------- 1 file changed, 41 insertions(+), 178 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 118b3507835010..e84d1550e53a46 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -817,8 +817,6 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) static void vmd_configure_cfgbar(struct vmd_dev *vmd) { struct resource *res; - u16 pch_bus_range = 0; - u16 ioc_bus_range = 0; res = &vmd->dev->resource[VMD_CFGBAR]; vmd->resources[0] = (struct resource){ @@ -827,140 +825,44 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd) .end = vmd->busn_start + (resource_size(res) >> 20) - 1, .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, }; - - if (vmd_has_pch_rootbus(vmd)) { - pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE0, - &ioc_bus_range); - pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE1, - &pch_bus_range); - - vmd->resources[3] = (struct resource){ - .name = "VMD CFGBAR PCH", - .start = VMD_ROOTBUS_RANGE_START(pch_bus_range), - .end = VMD_ROOTBUS_RANGE_END(pch_bus_range), - .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, - .parent = &vmd->resources[0], - }; - - /* - * Update first cfgbar range (IOC) with value stored - * in PCI_REG_BUSRANGE0 - */ - vmd->resources[0].start = - VMD_ROOTBUS_RANGE_START(ioc_bus_range); - vmd->resources[0].end = VMD_ROOTBUS_RANGE_END(ioc_bus_range); - } } -/* - * If the window is below 4GB, clear IORESOURCE_MEM_64 so we can - * put 32-bit resources in the window. - * - * There's no hardware reason why a 64-bit window *couldn't* - * contain a 32-bit resource, but pbus_size_mem() computes the - * bridge window size assuming a 64-bit window will contain no - * 32-bit resources. __pci_assign_resource() enforces that - * artificial restriction to make sure everything will fit. - * - * The only way we could use a 64-bit non-prefetchable MEMBAR is - * if its address is <4GB so that we can convert it to a 32-bit - * resource. To be visible to the host OS, all VMD endpoints must - * be initially configured by platform BIOS, which includes setting - * up these resources. We can assume the device is configured - * according to the platform needs. - */ -static void vmd_configure_membar1(struct vmd_dev *vmd) +static void vmd_configure_membar(struct vmd_dev *vmd, + u8 membar_number, u8 resource_number, + resource_size_t start_offset, + resource_size_t end_offset, + struct resource *parent) { struct resource *res; u32 upper_bits; unsigned long flags; - u32 vmd_enh_membar1_offset = 0; + char name[16]; - res = &vmd->dev->resource[VMD_MEMBAR1]; + res = &vmd->dev->resource[membar_number]; upper_bits = upper_32_bits(res->end); flags = res->flags & ~IORESOURCE_SIZEALIGN; if (!upper_bits) flags &= ~IORESOURCE_MEM_64; - vmd->resources[1] = (struct resource){ - .name = "VMD MEMBAR1", - .start = res->start, - .end = res->end, - .flags = flags, - .parent = res, - }; - if (vmd_has_pch_rootbus(vmd)) { - pci_read_config_dword(vmd->dev, PCI_MEMBAR1_OFFSET, - &vmd_enh_membar1_offset); + snprintf(name, sizeof(name), "VMD MEMBAR%d", membar_number/2); - vmd->resources[4] = (struct resource){ - .name = "VMD MEMBAR1 PCH", - .start = res->start + vmd_enh_membar1_offset, - .end = res->end, - .flags = flags, - .parent = &vmd->resources[1], - }; + if (!parent) + parent = res; - /* - * Update first MEMBAR1 range (IOC), memory start does not - * change, memory end is one less than the offset stored - * in PCI_MEMBAR1_OFFSET. - */ - vmd->resources[1].end = res->start + vmd_enh_membar1_offset - 1; - } -} - -/* - * Align resource information the same as for vmd_configure_membar1 - * function. - */ -static void vmd_configure_membar2(struct vmd_dev *vmd, - resource_size_t membar2_offset) -{ - struct resource *res; - u32 upper_bits, reg; - unsigned long flags; - u64 vmd_enh_membar2_offset = 0; - - res = &vmd->dev->resource[VMD_MEMBAR2]; - upper_bits = upper_32_bits(res->end); - flags = res->flags & ~IORESOURCE_SIZEALIGN; - - if (!upper_bits) - flags &= ~IORESOURCE_MEM_64; - - vmd->resources[2] = (struct resource){ - .name = "VMD MEMBAR2", - .start = res->start + membar2_offset, - .end = res->end, + vmd->resources[resource_number] = (struct resource){ + .name = name, + .start = res->start + start_offset, + .end = res->end - end_offset, .flags = flags, - .parent = res, + .parent = parent, }; +} - if (vmd_has_pch_rootbus(vmd)) { - pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET1, ®); - vmd_enh_membar2_offset = reg; - pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET2, ®); - vmd_enh_membar2_offset |= (u64)reg << 32; - - vmd->resources[5] = (struct resource){ - .name = "VMD MEMBAR2 PCH", - .start = res->start + membar2_offset + - vmd_enh_membar2_offset, - .end = res->end, - .flags = flags, - .parent = &vmd->resources[2], - }; - - /* - * Update first MEMBAR2 range (IOC), memory start does not - * change, memory end is one less than the offset stored - * as a 64 bit value in PCI_MEMBAR2_OFFSET1 and - * PCI_MEMBAR2_OFFSET2 registers. - */ - vmd->resources[2].end = res->start + vmd_enh_membar2_offset + - membar2_offset - 1; - } +static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, + resource_size_t membar2_offset) +{ + vmd_configure_membar(vmd, VMD_MEMBAR1, 1, 0, 0, NULL); + vmd_configure_membar(vmd, VMD_MEMBAR2, 2, membar2_offset, 0, NULL); } static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) @@ -972,9 +874,7 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_begin(); pci_scan_child_bus(bus); - - if (bus->primary == 0) - vmd_domain_reset(vmd_from_bus(bus)); + vmd_domain_reset(vmd_from_bus(bus)); /* * When Intel VMD is enabled, the OS does not discover the Root Ports @@ -1013,50 +913,6 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_end(); } -static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, - resource_size_t *offset) -{ - LIST_HEAD(resources_pch); - - pci_add_resource(&resources_pch, &vmd->resources[3]); - pci_add_resource_offset(&resources_pch, &vmd->resources[4], - offset[0]); - pci_add_resource_offset(&resources_pch, &vmd->resources[5], - offset[1]); - - vmd->bus_pch = - pci_create_root_bus(&vmd->dev->dev, vmd->busn_start_pch, - &vmd_ops, sd, &resources_pch); - - if (!vmd->bus_pch) { - pci_free_resource_list(&resources_pch); - vmd_remove_irq_domain(vmd); - return -ENODEV; - } - - /* - * VMD enhacement specific: pci_scan_bridge_extend() in probe.c - * assigns setup as broken when primary != bus->number. - * For PCH rootbus primary is 0x80 and bus->number is 0xE1, - * bus number needs to be overwritten to the same value - * as primary to pass pci_scan_bridge_extend() - */ - vmd->bus_pch->primary = PCI_VMD_PRIMARY_PCH_BUS; - vmd->bus_pch->number = PCI_VMD_PRIMARY_PCH_BUS; - - vmd_copy_host_bridge_flags( - pci_find_host_bridge(vmd->dev->bus), - to_pci_host_bridge(vmd->bus_pch->bridge)); - - if (vmd->irq_domain) - dev_set_msi_domain(&vmd->bus_pch->dev, vmd->irq_domain); - else - dev_set_msi_domain(&vmd->bus_pch->dev, - dev_get_msi_domain(&vmd->dev->dev)); - - return 0; -} - static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -1093,8 +949,25 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) } vmd_configure_cfgbar(vmd); - vmd_configure_membar1(vmd); - vmd_configure_membar2(vmd, membar2_offset); + + /* + * If the window is below 4GB, clear IORESOURCE_MEM_64 so we can + * put 32-bit resources in the window. + * + * There's no hardware reason why a 64-bit window *couldn't* + * contain a 32-bit resource, but pbus_size_mem() computes the + * bridge window size assuming a 64-bit window will contain no + * 32-bit resources. __pci_assign_resource() enforces that + * artificial restriction to make sure everything will fit. + * + * The only way we could use a 64-bit non-prefetchable MEMBAR is + * if its address is <4GB so that we can convert it to a 32-bit + * resource. To be visible to the host OS, all VMD endpoints must + * be initially configured by platform BIOS, which includes setting + * up these resources. We can assume the device is configured + * according to the platform needs. + */ + vmd_configure_membar1_membar2(vmd, membar2_offset); sd->vmd_dev = vmd->dev; sd->domain = vmd_find_free_domain(); @@ -1155,17 +1028,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, "domain"), "Can't create symlink to domain\n"); - if (vmd_has_pch_rootbus(vmd)) { - ret = vmd_create_pch_bus(vmd, sd, offset); - if (ret) { - pci_err(vmd->dev, "Can't create PCH bus: %d\n", ret); - return ret; - } - - } - vmd_bus_enumeration(vmd->bus, features); - vmd_bus_enumeration(vmd->bus_pch, features); return 0; } From 2a3c56bda235d0bc00a02f3178fa1c9deaa89c2c Mon Sep 17 00:00:00 2001 From: sdurawa Date: Wed, 16 Oct 2024 13:52:22 +0200 Subject: [PATCH 5/7] Starting from Intel Arrow Lake VMD enhacement introduces separate rootbus for PCH. It means that all 3 MMIO BARs exposed by VMD are shared now between CPU IOC and PCH. This patch adds PCH bus enumeration and MMIO management for devices with VMD enhancement support. Signed-off-by: Szymon Durawa Suggested-by: Nirmal Patel --- drivers/pci/controller/vmd.c | 232 +++++++++++++++++++++++++++++------ 1 file changed, 196 insertions(+), 36 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index e84d1550e53a46..6112f6cfbf490b 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -23,6 +23,8 @@ #define VMD_MEMBAR1 2 #define VMD_MEMBAR2 4 +#define VMD_ROOTBUS_SIZE 2 + #define PCI_REG_VMCAP 0x40 #define BUS_RESTRICT_CAP(vmcap) (vmcap & 0x1) #define PCI_REG_VMCONFIG 0x44 @@ -43,6 +45,20 @@ #define MB2_SHADOW_OFFSET 0x2000 #define MB2_SHADOW_SIZE 16 +enum vmd_resources { + VMD_RESOURCE_CFGBAR, + VMD_RESOURCE_MEMBAR1, + VMD_RESOURCE_MEMBAR2, + VMD_RESOURCE_PCH_CFGBAR, + VMD_RESOURCE_PCH_MEMBAR1, + VMD_RESOURCE_PCH_MEMBAR2 +}; + +enum vmd_rootbus { + VMD_ROOTBUS0, + VMD_ROOTBUS1 +}; + enum vmd_features { /* * Device may contain registers which hint the physical location of the @@ -85,8 +101,8 @@ enum vmd_features { VMD_FEAT_BIOS_PM_QUIRK = (1 << 5), /* - * Some client VMD devices have their VMD rootports connected to both - * IOC and PCH rootbus. + * Starting from Intel Arrow Lake, VMD devices have their VMD rootports + * connected to CPU IOC and PCH rootbuses. */ VMD_FEAT_HAS_PCH_ROOTBUS = (1 << 6) }; @@ -150,9 +166,8 @@ struct vmd_dev { struct pci_sysdata sysdata; struct resource resources[6]; struct irq_domain *irq_domain; - struct pci_bus *bus; - struct pci_bus *bus_pch; - u8 busn_start; + struct pci_bus *bus[VMD_ROOTBUS_SIZE]; + u8 busn_start[VMD_ROOTBUS_SIZE]; u8 first_vec; char *name; int instance; @@ -384,24 +399,25 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) static inline u8 vmd_has_pch_rootbus(struct vmd_dev *vmd) { - return vmd->busn_start_pch != 0; + return vmd->busn_start[VMD_ROOTBUS1] != 0; } static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, unsigned int devfn, int reg, int len) { - unsigned int busnr_ecam = 0; + unsigned char bus_number = 0; /* * VMD enhacement specific: for PCH rootbus, bus number is set to * PCI_VMD_PRIMARY_PCH_BUS but original value is 0xE1 which is stored - * in vmd->busn_start_pch. + * in vmd->busn_start[VMD_ROOTBUS1]. */ if (vmd_has_pch_rootbus(vmd) && bus->number == PCI_VMD_PRIMARY_PCH_BUS) - busnr_ecam = vmd->busn_start_pch - vmd->busn_start; + bus_number = vmd->busn_start[VMD_ROOTBUS1]; else - busnr_ecam = bus->number - vmd->busn_start; + bus_number = bus->number; + unsigned int busnr_ecam = bus_number - vmd->busn_start[VMD_ROOTBUS0]; u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR])) @@ -678,13 +694,26 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd, unsigned long features) switch (BUS_RESTRICT_CFG(reg)) { case 0: - vmd->busn_start = 0; + vmd->busn_start[VMD_ROOTBUS0] = 0; break; case 1: - vmd->busn_start = 128; + vmd->busn_start[VMD_ROOTBUS0] = 128; break; case 2: - vmd->busn_start = 224; + vmd->busn_start[VMD_ROOTBUS0] = 224; + break; + case 3: + if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { + /* IOC start bus */ + vmd->busn_start[VMD_ROOTBUS0] = 224; + /* PCH start bus */ + vmd->busn_start[VMD_ROOTBUS1] = 225; + } else { + pci_err(dev, + "Unknown Bus Offset Setting (%d)\n", + BUS_RESTRICT_CFG(reg)); + return -ENODEV; + } break; case 3: if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { @@ -817,14 +846,42 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) static void vmd_configure_cfgbar(struct vmd_dev *vmd) { struct resource *res; + u16 ioc_bus_range = 0; + u16 pch_bus_range = 0; res = &vmd->dev->resource[VMD_CFGBAR]; - vmd->resources[0] = (struct resource){ + vmd->resources[VMD_RESOURCE_CFGBAR] = (struct resource){ .name = "VMD CFGBAR", - .start = vmd->busn_start, - .end = vmd->busn_start + (resource_size(res) >> 20) - 1, + .start = vmd->busn_start[VMD_ROOTBUS0], + .end = vmd->busn_start[VMD_ROOTBUS0] + + (resource_size(res) >> 20) - 1, .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, }; + + if (vmd_has_pch_rootbus(vmd)) { + pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE0, + &ioc_bus_range); + pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE1, + &pch_bus_range); + + /* + * Resize CPU IOC CFGBAR range to make space for PCH owned + * devices by adjusting range end with value stored in + * PCI_REG_BUSRANGE0 register. + */ + vmd->resources[VMD_RESOURCE_CFGBAR].start = + VMD_ROOTBUS_RANGE_START(ioc_bus_range); + vmd->resources[VMD_RESOURCE_CFGBAR].end = + VMD_ROOTBUS_RANGE_END(ioc_bus_range); + + vmd->resources[VMD_RESOURCE_PCH_CFGBAR] = (struct resource){ + .name = "VMD CFGBAR PCH", + .start = VMD_ROOTBUS_RANGE_START(pch_bus_range), + .end = VMD_ROOTBUS_RANGE_END(pch_bus_range), + .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, + .parent = &vmd->resources[VMD_RESOURCE_CFGBAR], + }; + } } static void vmd_configure_membar(struct vmd_dev *vmd, @@ -849,6 +906,9 @@ static void vmd_configure_membar(struct vmd_dev *vmd, if (!parent) parent = res; + if (resource_number > VMD_RESOURCE_MEMBAR2) + strncat(name, " PCH", 4); + vmd->resources[resource_number] = (struct resource){ .name = name, .start = res->start + start_offset, @@ -861,8 +921,43 @@ static void vmd_configure_membar(struct vmd_dev *vmd, static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, resource_size_t membar2_offset) { - vmd_configure_membar(vmd, VMD_MEMBAR1, 1, 0, 0, NULL); - vmd_configure_membar(vmd, VMD_MEMBAR2, 2, membar2_offset, 0, NULL); + vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_MEMBAR1, 0, 0, + NULL); + vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_MEMBAR2, + membar2_offset, 0, NULL); + + if (vmd_has_pch_rootbus(vmd)) { + u32 pch_membar1_offset = 0; + u64 pch_membar2_offset = 0; + u32 reg; + + pci_read_config_dword(vmd->dev, PCI_MEMBAR1_OFFSET, + &pch_membar1_offset); + + pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET1, ®); + pch_membar2_offset = reg; + + pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET2, ®); + pch_membar2_offset |= (u64)reg << 32; + + /* + * Resize CPU IOC MEMBAR1 and MEMBAR2 ranges to make space + * for PCH owned devices by adjusting range end with values + * stored in PCI_MEMBAR1_OFFSET and PCI_MEMBAR2_OFFSET registers + */ + vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_MEMBAR1, 0, + pch_membar1_offset, NULL); + vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_MEMBAR2, + membar2_offset, + pch_membar2_offset - membar2_offset, NULL); + + vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_PCH_MEMBAR1, + pch_membar1_offset, 0, + &vmd->resources[VMD_RESOURCE_MEMBAR1]); + vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_PCH_MEMBAR2, + membar2_offset + pch_membar2_offset, 0, + &vmd->resources[VMD_RESOURCE_MEMBAR2]); + } } static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) @@ -874,7 +969,9 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_begin(); pci_scan_child_bus(bus); - vmd_domain_reset(vmd_from_bus(bus)); + + if (bus->primary == 0) + vmd_domain_reset(vmd_from_bus(bus)); /* * When Intel VMD is enabled, the OS does not discover the Root Ports @@ -913,6 +1010,53 @@ static void vmd_bus_enumeration(struct pci_bus *bus, unsigned long features) vmd_acpi_end(); } +static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, + resource_size_t *offset) +{ + LIST_HEAD(resources_pch); + + pci_add_resource(&resources_pch, + &vmd->resources[VMD_RESOURCE_PCH_CFGBAR]); + pci_add_resource_offset(&resources_pch, + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR1], + offset[0]); + pci_add_resource_offset(&resources_pch, + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR2], + offset[1]); + + vmd->bus[VMD_ROOTBUS1] = + pci_create_root_bus(&vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS1], + &vmd_ops, sd, &resources_pch); + + if (!vmd->bus[VMD_ROOTBUS1]) { + pci_free_resource_list(&resources_pch); + vmd_remove_irq_domain(vmd); + return -ENODEV; + } + + /* + * This is a workaround for pci_scan_bridge_extend() code. + * It assigns setup as broken when primary != bus->number and + * for PCH rootbus primary is not "hard-wired to 0". + * To avoid this, vmd->bus[VMD_ROOTBUS1]->number and + * vmd->bus[VMD_ROOTBUS1]->primary are updated to same value. + */ + vmd->bus[VMD_ROOTBUS1]->primary = PCI_VMD_PRIMARY_PCH_BUS; + vmd->bus[VMD_ROOTBUS1]->number = PCI_VMD_PRIMARY_PCH_BUS; + + vmd_copy_host_bridge_flags( + pci_find_host_bridge(vmd->dev->bus), + to_pci_host_bridge(vmd->bus[VMD_ROOTBUS1]->bridge)); + + if (vmd->irq_domain) + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS1]->dev, vmd->irq_domain); + else + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS1]->dev, + dev_get_msi_domain(&vmd->dev->dev)); + + return 0; +} + static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -1003,32 +1147,48 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) vmd_set_msi_remapping(vmd, false); } - pci_add_resource(&resources, &vmd->resources[0]); - pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]); - pci_add_resource_offset(&resources, &vmd->resources[2], offset[1]); + pci_add_resource(&resources, &vmd->resources[VMD_RESOURCE_CFGBAR]); + pci_add_resource_offset( + &resources, &vmd->resources[VMD_RESOURCE_MEMBAR1], offset[0]); + pci_add_resource_offset( + &resources, &vmd->resources[VMD_RESOURCE_MEMBAR2], offset[1]); - vmd->bus = pci_create_root_bus(&vmd->dev->dev, vmd->busn_start, - &vmd_ops, sd, &resources); - if (!vmd->bus) { + vmd->bus[VMD_ROOTBUS0] = pci_create_root_bus( + &vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS0], &vmd_ops, sd, + &resources); + if (!vmd->bus[VMD_ROOTBUS0]) { pci_free_resource_list(&resources); vmd_remove_irq_domain(vmd); return -ENODEV; } - vmd_copy_host_bridge_flags(pci_find_host_bridge(vmd->dev->bus), - to_pci_host_bridge(vmd->bus->bridge)); + vmd_copy_host_bridge_flags( + pci_find_host_bridge(vmd->dev->bus), + to_pci_host_bridge(vmd->bus[VMD_ROOTBUS0]->bridge)); vmd_attach_resources(vmd); if (vmd->irq_domain) - dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain); + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS0]->dev, + vmd->irq_domain); else - dev_set_msi_domain(&vmd->bus->dev, + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS0]->dev, dev_get_msi_domain(&vmd->dev->dev)); - WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, - "domain"), "Can't create symlink to domain\n"); + WARN(sysfs_create_link(&vmd->dev->dev.kobj, + &vmd->bus[VMD_ROOTBUS0]->dev.kobj, "domain"), + "Can't create symlink to domain\n"); - vmd_bus_enumeration(vmd->bus, features); + vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS0], features); + + if (vmd_has_pch_rootbus(vmd)) { + ret = vmd_create_pch_bus(vmd, sd, offset); + if (ret) { + pci_err(vmd->dev, "Can't create PCH bus: %d\n", ret); + return ret; + } + + vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS1], features); + } return 0; } @@ -1105,12 +1265,12 @@ static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); - pci_stop_root_bus(vmd->bus); + pci_stop_root_bus(vmd->bus[VMD_ROOTBUS0]); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); - pci_remove_root_bus(vmd->bus); + pci_remove_root_bus(vmd->bus[VMD_ROOTBUS0]); if (vmd_has_pch_rootbus(vmd)) { - pci_stop_root_bus(vmd->bus_pch); - pci_remove_root_bus(vmd->bus_pch); + pci_stop_root_bus(vmd->bus[VMD_ROOTBUS1]); + pci_remove_root_bus(vmd->bus[VMD_ROOTBUS1]); } vmd_cleanup_srcu(vmd); vmd_detach_resources(vmd); From 0955c0175fdb80d65591335bf31658634c464139 Mon Sep 17 00:00:00 2001 From: sdurawa Date: Thu, 17 Oct 2024 16:36:54 +0200 Subject: [PATCH 6/7] Source code modifications according to review remarks. --- drivers/pci/controller/vmd.c | 171 ++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 6112f6cfbf490b..5acf925231967e 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -23,8 +23,6 @@ #define VMD_MEMBAR1 2 #define VMD_MEMBAR2 4 -#define VMD_ROOTBUS_SIZE 2 - #define PCI_REG_VMCAP 0x40 #define BUS_RESTRICT_CAP(vmcap) (vmcap & 0x1) #define PCI_REG_VMCONFIG 0x44 @@ -45,18 +43,20 @@ #define MB2_SHADOW_OFFSET 0x2000 #define MB2_SHADOW_SIZE 16 -enum vmd_resources { +enum vmd_resource { VMD_RESOURCE_CFGBAR, - VMD_RESOURCE_MEMBAR1, - VMD_RESOURCE_MEMBAR2, + VMD_RESOURCE_MEMBAR_1, + VMD_RESOURCE_MEMBAR_2, VMD_RESOURCE_PCH_CFGBAR, - VMD_RESOURCE_PCH_MEMBAR1, - VMD_RESOURCE_PCH_MEMBAR2 + VMD_RESOURCE_PCH_MEMBAR_1, + VMD_RESOURCE_PCH_MEMBAR_2, + VMD_RESOURCE_COUNT }; enum vmd_rootbus { - VMD_ROOTBUS0, - VMD_ROOTBUS1 + VMD_ROOTBUS_0, + VMD_ROOTBUS_1, + VMD_ROOTBUS_COUNT }; enum vmd_features { @@ -164,14 +164,13 @@ struct vmd_dev { struct vmd_irq_list *irqs; struct pci_sysdata sysdata; - struct resource resources[6]; + struct resource resources[VMD_RESOURCE_COUNT]; struct irq_domain *irq_domain; - struct pci_bus *bus[VMD_ROOTBUS_SIZE]; - u8 busn_start[VMD_ROOTBUS_SIZE]; + struct pci_bus *bus[VMD_ROOTBUS_COUNT]; + u8 busn_start[VMD_ROOTBUS_COUNT]; u8 first_vec; char *name; int instance; - u8 busn_start_pch; }; static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) @@ -399,26 +398,26 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) static inline u8 vmd_has_pch_rootbus(struct vmd_dev *vmd) { - return vmd->busn_start[VMD_ROOTBUS1] != 0; + return vmd->busn_start[VMD_ROOTBUS_1] != 0; } static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, unsigned int devfn, int reg, int len) { - unsigned char bus_number = 0; + unsigned char bus_number; + unsigned int busnr_ecam; + u32 offset; /* - * VMD enhacement specific: for PCH rootbus, bus number is set to - * PCI_VMD_PRIMARY_PCH_BUS but original value is 0xE1 which is stored - * in vmd->busn_start[VMD_ROOTBUS1]. + * VMD WA: for PCH rootbus, bus number is set to PCI_VMD_PRIMARY_PCH_BUS + * (see comment in vmd_create_pch_bus()) but original value is 0xE1 + * which is stored in vmd->busn_start[VMD_ROOTBUS_1]. */ - if (vmd_has_pch_rootbus(vmd) && bus->number == PCI_VMD_PRIMARY_PCH_BUS) - bus_number = vmd->busn_start[VMD_ROOTBUS1]; - else - bus_number = bus->number; + bus_number = (bus->number == PCI_VMD_PRIMARY_PCH_BUS) ? + vmd->busn_start[VMD_ROOTBUS_1] : bus->number; - unsigned int busnr_ecam = bus_number - vmd->busn_start[VMD_ROOTBUS0]; - u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); + busnr_ecam = bus_number - vmd->busn_start[VMD_ROOTBUS_0]; + offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR])) return NULL; @@ -694,38 +693,27 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd, unsigned long features) switch (BUS_RESTRICT_CFG(reg)) { case 0: - vmd->busn_start[VMD_ROOTBUS0] = 0; + vmd->busn_start[VMD_ROOTBUS_0] = 0; break; case 1: - vmd->busn_start[VMD_ROOTBUS0] = 128; + vmd->busn_start[VMD_ROOTBUS_0] = 128; break; case 2: - vmd->busn_start[VMD_ROOTBUS0] = 224; + vmd->busn_start[VMD_ROOTBUS_0] = 224; break; case 3: if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { /* IOC start bus */ - vmd->busn_start[VMD_ROOTBUS0] = 224; + vmd->busn_start[VMD_ROOTBUS_0] = 224; /* PCH start bus */ - vmd->busn_start[VMD_ROOTBUS1] = 225; + vmd->busn_start[VMD_ROOTBUS_1] = 225; } else { pci_err(dev, - "Unknown Bus Offset Setting (%d)\n", + "VMD Bus Restriction detected type %d,", BUS_RESTRICT_CFG(reg)); - return -ENODEV; - } - break; - case 3: - if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { - /* IOC start bus */ - vmd->busn_start = 224; - /* PCH start bus */ - vmd->busn_start_pch = 225; - } else { pci_err(dev, - "Unknown Bus Offset Setting (%d)\n", - BUS_RESTRICT_CFG(reg)); - return -ENODEV; + "but PCH Rootbus is not supported, aborting.\n"); + return -ENXIO; } break; default: @@ -852,8 +840,8 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd) res = &vmd->dev->resource[VMD_CFGBAR]; vmd->resources[VMD_RESOURCE_CFGBAR] = (struct resource){ .name = "VMD CFGBAR", - .start = vmd->busn_start[VMD_ROOTBUS0], - .end = vmd->busn_start[VMD_ROOTBUS0] + + .start = vmd->busn_start[VMD_ROOTBUS_0], + .end = vmd->busn_start[VMD_ROOTBUS_0] + (resource_size(res) >> 20) - 1, .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, }; @@ -884,9 +872,21 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd) } } +/** + * vmd_configure_membar - Configure VMD MemBAR register, which points + * to MMIO address assigned by the OS or BIOS. + * @vmd: the VMD device + * @resource_number: resource buffer number to be filled in + * @membar_number: type of the MemBAR + * @start_offset: 4K aligned offset applied to start of VMD’s MEMBAR MMIO space + * @end_offset: 4K aligned offset applied to end of VMD’s MEMBAR MMIO space + * @parent: parent resource assigned to resource to be filled in + * + * Function fills resource buffer inside the VMD structure. + */ static void vmd_configure_membar(struct vmd_dev *vmd, - u8 membar_number, u8 resource_number, - resource_size_t start_offset, + enum vmd_resource resource_number, + u8 membar_number, resource_size_t start_offset, resource_size_t end_offset, struct resource *parent) { @@ -906,7 +906,7 @@ static void vmd_configure_membar(struct vmd_dev *vmd, if (!parent) parent = res; - if (resource_number > VMD_RESOURCE_MEMBAR2) + if (resource_number > VMD_RESOURCE_MEMBAR_2) strncat(name, " PCH", 4); vmd->resources[resource_number] = (struct resource){ @@ -921,11 +921,6 @@ static void vmd_configure_membar(struct vmd_dev *vmd, static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, resource_size_t membar2_offset) { - vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_MEMBAR1, 0, 0, - NULL); - vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_MEMBAR2, - membar2_offset, 0, NULL); - if (vmd_has_pch_rootbus(vmd)) { u32 pch_membar1_offset = 0; u64 pch_membar2_offset = 0; @@ -945,18 +940,24 @@ static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, * for PCH owned devices by adjusting range end with values * stored in PCI_MEMBAR1_OFFSET and PCI_MEMBAR2_OFFSET registers */ - vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_MEMBAR1, 0, + vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_1, VMD_MEMBAR1, 0, pch_membar1_offset, NULL); - vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_MEMBAR2, + vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_2, VMD_MEMBAR2, membar2_offset, pch_membar2_offset - membar2_offset, NULL); - vmd_configure_membar(vmd, VMD_MEMBAR1, VMD_RESOURCE_PCH_MEMBAR1, - pch_membar1_offset, 0, - &vmd->resources[VMD_RESOURCE_MEMBAR1]); - vmd_configure_membar(vmd, VMD_MEMBAR2, VMD_RESOURCE_PCH_MEMBAR2, + vmd_configure_membar(vmd, VMD_RESOURCE_PCH_MEMBAR_1, + VMD_MEMBAR1, pch_membar1_offset, 0, + &vmd->resources[VMD_RESOURCE_MEMBAR_1]); + vmd_configure_membar(vmd, VMD_RESOURCE_PCH_MEMBAR_2, + VMD_MEMBAR2, membar2_offset + pch_membar2_offset, 0, - &vmd->resources[VMD_RESOURCE_MEMBAR2]); + &vmd->resources[VMD_RESOURCE_MEMBAR_2]); + } else { + vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_1, VMD_MEMBAR1, 0, + 0, NULL); + vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_2, VMD_MEMBAR2, + membar2_offset, 0, NULL); } } @@ -1018,17 +1019,17 @@ static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, pci_add_resource(&resources_pch, &vmd->resources[VMD_RESOURCE_PCH_CFGBAR]); pci_add_resource_offset(&resources_pch, - &vmd->resources[VMD_RESOURCE_PCH_MEMBAR1], + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_1], offset[0]); pci_add_resource_offset(&resources_pch, - &vmd->resources[VMD_RESOURCE_PCH_MEMBAR2], + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_2], offset[1]); - vmd->bus[VMD_ROOTBUS1] = - pci_create_root_bus(&vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS1], + vmd->bus[VMD_ROOTBUS_1] = + pci_create_root_bus(&vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS_1], &vmd_ops, sd, &resources_pch); - if (!vmd->bus[VMD_ROOTBUS1]) { + if (!vmd->bus[VMD_ROOTBUS_1]) { pci_free_resource_list(&resources_pch); vmd_remove_irq_domain(vmd); return -ENODEV; @@ -1041,17 +1042,17 @@ static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, * To avoid this, vmd->bus[VMD_ROOTBUS1]->number and * vmd->bus[VMD_ROOTBUS1]->primary are updated to same value. */ - vmd->bus[VMD_ROOTBUS1]->primary = PCI_VMD_PRIMARY_PCH_BUS; - vmd->bus[VMD_ROOTBUS1]->number = PCI_VMD_PRIMARY_PCH_BUS; + vmd->bus[VMD_ROOTBUS_1]->primary = PCI_VMD_PRIMARY_PCH_BUS; + vmd->bus[VMD_ROOTBUS_1]->number = PCI_VMD_PRIMARY_PCH_BUS; vmd_copy_host_bridge_flags( pci_find_host_bridge(vmd->dev->bus), - to_pci_host_bridge(vmd->bus[VMD_ROOTBUS1]->bridge)); + to_pci_host_bridge(vmd->bus[VMD_ROOTBUS_1]->bridge)); if (vmd->irq_domain) - dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS1]->dev, vmd->irq_domain); + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS_1]->dev, vmd->irq_domain); else - dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS1]->dev, + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS_1]->dev, dev_get_msi_domain(&vmd->dev->dev)); return 0; @@ -1149,14 +1150,14 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) pci_add_resource(&resources, &vmd->resources[VMD_RESOURCE_CFGBAR]); pci_add_resource_offset( - &resources, &vmd->resources[VMD_RESOURCE_MEMBAR1], offset[0]); + &resources, &vmd->resources[VMD_RESOURCE_MEMBAR_1], offset[0]); pci_add_resource_offset( - &resources, &vmd->resources[VMD_RESOURCE_MEMBAR2], offset[1]); + &resources, &vmd->resources[VMD_RESOURCE_MEMBAR_2], offset[1]); - vmd->bus[VMD_ROOTBUS0] = pci_create_root_bus( - &vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS0], &vmd_ops, sd, + vmd->bus[VMD_ROOTBUS_0] = pci_create_root_bus( + &vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS_0], &vmd_ops, sd, &resources); - if (!vmd->bus[VMD_ROOTBUS0]) { + if (!vmd->bus[VMD_ROOTBUS_0]) { pci_free_resource_list(&resources); vmd_remove_irq_domain(vmd); return -ENODEV; @@ -1164,21 +1165,21 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) vmd_copy_host_bridge_flags( pci_find_host_bridge(vmd->dev->bus), - to_pci_host_bridge(vmd->bus[VMD_ROOTBUS0]->bridge)); + to_pci_host_bridge(vmd->bus[VMD_ROOTBUS_0]->bridge)); vmd_attach_resources(vmd); if (vmd->irq_domain) - dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS0]->dev, + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS_0]->dev, vmd->irq_domain); else - dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS0]->dev, + dev_set_msi_domain(&vmd->bus[VMD_ROOTBUS_0]->dev, dev_get_msi_domain(&vmd->dev->dev)); WARN(sysfs_create_link(&vmd->dev->dev.kobj, - &vmd->bus[VMD_ROOTBUS0]->dev.kobj, "domain"), + &vmd->bus[VMD_ROOTBUS_0]->dev.kobj, "domain"), "Can't create symlink to domain\n"); - vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS0], features); + vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS_0], features); if (vmd_has_pch_rootbus(vmd)) { ret = vmd_create_pch_bus(vmd, sd, offset); @@ -1187,7 +1188,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) return ret; } - vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS1], features); + vmd_bus_enumeration(vmd->bus[VMD_ROOTBUS_1], features); } return 0; @@ -1265,12 +1266,12 @@ static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); - pci_stop_root_bus(vmd->bus[VMD_ROOTBUS0]); + pci_stop_root_bus(vmd->bus[VMD_ROOTBUS_0]); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); - pci_remove_root_bus(vmd->bus[VMD_ROOTBUS0]); + pci_remove_root_bus(vmd->bus[VMD_ROOTBUS_0]); if (vmd_has_pch_rootbus(vmd)) { - pci_stop_root_bus(vmd->bus[VMD_ROOTBUS1]); - pci_remove_root_bus(vmd->bus[VMD_ROOTBUS1]); + pci_stop_root_bus(vmd->bus[VMD_ROOTBUS_1]); + pci_remove_root_bus(vmd->bus[VMD_ROOTBUS_1]); } vmd_cleanup_srcu(vmd); vmd_detach_resources(vmd); From 40a649712bc9fea678039898e72c429e5ff37fcb Mon Sep 17 00:00:00 2001 From: sdurawa Date: Mon, 21 Oct 2024 13:17:58 +0200 Subject: [PATCH 7/7] Replace PCI with VMD prefix for variables, align code indentation. --- drivers/pci/controller/vmd.c | 95 +++++++++++++++++------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 5acf925231967e..8d50dbe9095e37 100755 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -31,12 +31,12 @@ #define PCI_REG_VMLOCK 0x70 #define MB2_SHADOW_EN(vmlock) (vmlock & 0x2) -#define PCI_VMD_PRIMARY_PCH_BUS 0x80 -#define PCI_REG_BUSRANGE0 0xC8 -#define PCI_REG_BUSRANGE1 0xCC -#define PCI_MEMBAR1_OFFSET 0xD0 -#define PCI_MEMBAR2_OFFSET1 0xD8 -#define PCI_MEMBAR2_OFFSET2 0xDC +#define VMD_PRIMARY_PCH_BUS 0x80 +#define VMD_REG_BUSRANGE0 0xC8 +#define VMD_REG_BUSRANGE1 0xCC +#define VMD_MEMBAR1_OFFSET 0xD0 +#define VMD_MEMBAR2_OFFSET1 0xD8 +#define VMD_MEMBAR2_OFFSET2 0xDC #define VMD_ROOTBUS_RANGE_END(busr) ((busr >> 8) & 0xff) #define VMD_ROOTBUS_RANGE_START(busr) (busr & 0x00ff) @@ -44,7 +44,7 @@ #define MB2_SHADOW_SIZE 16 enum vmd_resource { - VMD_RESOURCE_CFGBAR, + VMD_RESOURCE_CFGBAR = 0, VMD_RESOURCE_MEMBAR_1, VMD_RESOURCE_MEMBAR_2, VMD_RESOURCE_PCH_CFGBAR, @@ -54,7 +54,7 @@ enum vmd_resource { }; enum vmd_rootbus { - VMD_ROOTBUS_0, + VMD_ROOTBUS_0 = 0, VMD_ROOTBUS_1, VMD_ROOTBUS_COUNT }; @@ -112,7 +112,7 @@ enum vmd_features { #define VMD_FEATS_CLIENT (VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | \ VMD_FEAT_HAS_BUS_RESTRICTIONS | \ VMD_FEAT_OFFSET_FIRST_VECTOR | \ - VMD_FEAT_BIOS_PM_QUIRK | \ + VMD_FEAT_BIOS_PM_QUIRK | \ VMD_FEAT_HAS_PCH_ROOTBUS) static DEFINE_IDA(vmd_instance_ida); @@ -413,7 +413,7 @@ static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, * (see comment in vmd_create_pch_bus()) but original value is 0xE1 * which is stored in vmd->busn_start[VMD_ROOTBUS_1]. */ - bus_number = (bus->number == PCI_VMD_PRIMARY_PCH_BUS) ? + bus_number = (bus->number == VMD_PRIMARY_PCH_BUS) ? vmd->busn_start[VMD_ROOTBUS_1] : bus->number; busnr_ecam = bus_number - vmd->busn_start[VMD_ROOTBUS_0]; @@ -702,19 +702,17 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd, unsigned long features) vmd->busn_start[VMD_ROOTBUS_0] = 224; break; case 3: - if (features & VMD_FEAT_HAS_PCH_ROOTBUS) { - /* IOC start bus */ - vmd->busn_start[VMD_ROOTBUS_0] = 224; - /* PCH start bus */ - vmd->busn_start[VMD_ROOTBUS_1] = 225; - } else { + if (!(features & VMD_FEAT_HAS_PCH_ROOTBUS)) { pci_err(dev, - "VMD Bus Restriction detected type %d,", + "VMD Bus Restriction detected type %d, but PCH Rootbus is not supported, aborting.\n", BUS_RESTRICT_CFG(reg)); - pci_err(dev, - "but PCH Rootbus is not supported, aborting.\n"); return -ENXIO; } + + /* IOC start bus */ + vmd->busn_start[VMD_ROOTBUS_0] = 224; + /* PCH start bus */ + vmd->busn_start[VMD_ROOTBUS_1] = 225; break; default: pci_err(dev, "Unknown Bus Offset Setting (%d)\n", @@ -847,9 +845,9 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd) }; if (vmd_has_pch_rootbus(vmd)) { - pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE0, + pci_read_config_word(vmd->dev, VMD_REG_BUSRANGE0, &ioc_bus_range); - pci_read_config_word(vmd->dev, PCI_REG_BUSRANGE1, + pci_read_config_word(vmd->dev, VMD_REG_BUSRANGE1, &pch_bus_range); /* @@ -901,14 +899,12 @@ static void vmd_configure_membar(struct vmd_dev *vmd, if (!upper_bits) flags &= ~IORESOURCE_MEM_64; - snprintf(name, sizeof(name), "VMD MEMBAR%d", membar_number/2); + snprintf(name, sizeof(name), "VMD MEMBAR%d %s", membar_number / 2, + resource_number > VMD_RESOURCE_MEMBAR_2 ? "PCH" : ""); if (!parent) parent = res; - if (resource_number > VMD_RESOURCE_MEMBAR_2) - strncat(name, " PCH", 4); - vmd->resources[resource_number] = (struct resource){ .name = name, .start = res->start + start_offset, @@ -926,13 +922,13 @@ static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, u64 pch_membar2_offset = 0; u32 reg; - pci_read_config_dword(vmd->dev, PCI_MEMBAR1_OFFSET, - &pch_membar1_offset); + pci_read_config_dword(vmd->dev, VMD_MEMBAR1_OFFSET, + &pch_membar1_offset); - pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET1, ®); + pci_read_config_dword(vmd->dev, VMD_MEMBAR2_OFFSET1, ®); pch_membar2_offset = reg; - pci_read_config_dword(vmd->dev, PCI_MEMBAR2_OFFSET2, ®); + pci_read_config_dword(vmd->dev, VMD_MEMBAR2_OFFSET2, ®); pch_membar2_offset |= (u64)reg << 32; /* @@ -941,23 +937,23 @@ static void vmd_configure_membar1_membar2(struct vmd_dev *vmd, * stored in PCI_MEMBAR1_OFFSET and PCI_MEMBAR2_OFFSET registers */ vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_1, VMD_MEMBAR1, 0, - pch_membar1_offset, NULL); + pch_membar1_offset, NULL); vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_2, VMD_MEMBAR2, - membar2_offset, - pch_membar2_offset - membar2_offset, NULL); + membar2_offset, + pch_membar2_offset - membar2_offset, NULL); vmd_configure_membar(vmd, VMD_RESOURCE_PCH_MEMBAR_1, - VMD_MEMBAR1, pch_membar1_offset, 0, - &vmd->resources[VMD_RESOURCE_MEMBAR_1]); + VMD_MEMBAR1, pch_membar1_offset, 0, + &vmd->resources[VMD_RESOURCE_MEMBAR_1]); vmd_configure_membar(vmd, VMD_RESOURCE_PCH_MEMBAR_2, - VMD_MEMBAR2, - membar2_offset + pch_membar2_offset, 0, - &vmd->resources[VMD_RESOURCE_MEMBAR_2]); + VMD_MEMBAR2, + membar2_offset + pch_membar2_offset, 0, + &vmd->resources[VMD_RESOURCE_MEMBAR_2]); } else { vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_1, VMD_MEMBAR1, 0, - 0, NULL); + 0, NULL); vmd_configure_membar(vmd, VMD_RESOURCE_MEMBAR_2, VMD_MEMBAR2, - membar2_offset, 0, NULL); + membar2_offset, 0, NULL); } } @@ -1017,21 +1013,22 @@ static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, LIST_HEAD(resources_pch); pci_add_resource(&resources_pch, - &vmd->resources[VMD_RESOURCE_PCH_CFGBAR]); + &vmd->resources[VMD_RESOURCE_PCH_CFGBAR]); pci_add_resource_offset(&resources_pch, - &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_1], - offset[0]); + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_1], + offset[0]); pci_add_resource_offset(&resources_pch, - &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_2], - offset[1]); + &vmd->resources[VMD_RESOURCE_PCH_MEMBAR_2], + offset[1]); vmd->bus[VMD_ROOTBUS_1] = pci_create_root_bus(&vmd->dev->dev, vmd->busn_start[VMD_ROOTBUS_1], - &vmd_ops, sd, &resources_pch); + &vmd_ops, sd, &resources_pch); if (!vmd->bus[VMD_ROOTBUS_1]) { pci_free_resource_list(&resources_pch); - vmd_remove_irq_domain(vmd); + pci_stop_root_bus(vmd->bus[VMD_ROOTBUS_1]); + pci_remove_root_bus(vmd->bus[VMD_ROOTBUS_1]); return -ENODEV; } @@ -1042,8 +1039,8 @@ static int vmd_create_pch_bus(struct vmd_dev *vmd, struct pci_sysdata *sd, * To avoid this, vmd->bus[VMD_ROOTBUS1]->number and * vmd->bus[VMD_ROOTBUS1]->primary are updated to same value. */ - vmd->bus[VMD_ROOTBUS_1]->primary = PCI_VMD_PRIMARY_PCH_BUS; - vmd->bus[VMD_ROOTBUS_1]->number = PCI_VMD_PRIMARY_PCH_BUS; + vmd->bus[VMD_ROOTBUS_1]->primary = VMD_PRIMARY_PCH_BUS; + vmd->bus[VMD_ROOTBUS_1]->number = VMD_PRIMARY_PCH_BUS; vmd_copy_host_bridge_flags( pci_find_host_bridge(vmd->dev->bus), @@ -1358,4 +1355,4 @@ module_pci_driver(vmd_drv); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Volume Management Device driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.6"); +MODULE_VERSION("0.7");