Re: [PATCH v3 7/8] PCI: vmd: Add support for second rootbus under VMD

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 22, 2024 at 09:52:14AM +0100, Szymon Durawa wrote:
> Starting from Intel Arrow Lake VMD enhancement introduces second rootbus
> support with fixed root bus number (0x80). It means that all 3 MMIO BARs
> exposed by VMD are shared now between both buses (current BUS0 and
> new BUS1).
> 
> Add new BUS1 enumeration and divide MMIO space to be shared between
> both rootbuses. Due to enumeration issues with rootbus hardwired to a
> fixed non-zero value, this patch will work with a workaround proposed
> in next patch. Without workaround user won't see attached devices for BUS1
> rootbus.
> 

Series mostly looks good to me. But I'm not comfortable with patches 7 and 8 due
to the dependency. Patch 7 is adding the second root bus, but the devices will
only be detected after applying patch 8, which will break bisecting.

Can you try moving patch 8 before 7? Or merge both of them?

- Mani

> Suggested-by: Nirmal Patel <nirmal.patel@xxxxxxxxxxxxxxx>
> Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@xxxxxxxxxxxxxxx>
> Signed-off-by: Szymon Durawa <szymon.durawa@xxxxxxxxxxxxxxx>
> ---
>  drivers/pci/controller/vmd.c | 208 ++++++++++++++++++++++++++++++-----
>  1 file changed, 180 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
> index 6d8397b5ebee..6cd14c28fd4e 100755
> --- a/drivers/pci/controller/vmd.c
> +++ b/drivers/pci/controller/vmd.c
> @@ -26,6 +26,7 @@
>  #define VMD_RESTRICT_0_BUS_START 0
>  #define VMD_RESTRICT_1_BUS_START 128
>  #define VMD_RESTRICT_2_BUS_START 224
> +#define VMD_RESTRICT_3_BUS_START 225
>  
>  #define PCI_REG_VMCAP		0x40
>  #define BUS_RESTRICT_CAP(vmcap)	(vmcap & 0x1)
> @@ -38,15 +39,33 @@
>  #define MB2_SHADOW_OFFSET	0x2000
>  #define MB2_SHADOW_SIZE		16
>  
> +#define VMD_PRIMARY_BUS0 0x00
> +#define VMD_PRIMARY_BUS1 0x80
> +#define VMD_BUSRANGE0 0xc8
> +#define VMD_BUSRANGE1 0xcc
> +#define VMD_MEMBAR1_OFFSET 0xd0
> +#define VMD_MEMBAR2_OFFSET1 0xd8
> +#define VMD_MEMBAR2_OFFSET2 0xdc
> +#define VMD_BUS_END(busr) ((busr >> 8) & 0xff)
> +#define VMD_BUS_START(busr) (busr & 0x00ff)
> +
> +/*
> + * Add VMD resources for BUS1, it will share the same MMIO space with
> + * previous VMD resources.
> + */
>  enum vmd_resource {
>  	VMD_RES_CFGBAR = 0, /* VMD Bus0 Config BAR */
>  	VMD_RES_MBAR_1, /* VMD Bus0 Resource MemBAR 1 */
>  	VMD_RES_MBAR_2, /* VMD Bus0 Resource MemBAR 2 */
> +	VMD_RES_BUS1_CFGBAR, /* VMD Bus1 Config BAR */
> +	VMD_RES_BUS1_MBAR_1, /* VMD Bus1 Resource MemBAR 1 */
> +	VMD_RES_BUS1_MBAR_2, /* VMD Bus1 Resource MemBAR 2 */
>  	VMD_RES_COUNT
>  };
>  
>  enum vmd_rootbus {
>  	VMD_BUS_0 = 0,
> +	VMD_BUS_1,
>  	VMD_BUS_COUNT
>  };
>  
> @@ -90,6 +109,12 @@ enum vmd_features {
>  	 * proper power management of the SoC.
>  	 */
>  	VMD_FEAT_BIOS_PM_QUIRK		= (1 << 5),
> +
> +	/*
> +	 * Starting from Intel Arrow Lake, VMD devices have their VMD rootports
> +	 * connected to additional BUS1 rootport.
> +	 */
> +	VMD_FEAT_HAS_BUS1_ROOTBUS	= (1 << 6)
>  };
>  
>  #define VMD_BIOS_PM_QUIRK_LTR	0x1003	/* 3145728 ns */
> @@ -97,7 +122,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_BUS1_ROOTBUS)
>  
>  static DEFINE_IDA(vmd_instance_ida);
>  
> @@ -155,6 +181,7 @@ struct vmd_dev {
>  	u8			first_vec;
>  	char			*name;
>  	int			instance;
> +	bool			bus1_rootbus;
>  };
>  
>  static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
> @@ -532,11 +559,16 @@ static inline void vmd_acpi_end(void) { }
>  
>  static void vmd_domain_reset(struct vmd_dev *vmd)
>  {
> -	u16 bus, max_buses = resource_size(&vmd->resources[VMD_RES_CFGBAR]);
> +	u16 bus, bus_cnt = resource_size(&vmd->resources[VMD_RES_CFGBAR]);
>  	u8 dev, functions, fn, hdr_type;
>  	char __iomem *base;
>  
> -	for (bus = 0; bus < max_buses; bus++) {
> +	if (vmd->bus1_rootbus) {
> +		bus_cnt += resource_size(&vmd->resources[VMD_RES_BUS1_CFGBAR]);
> +		bus_cnt += 2;
> +	}
> +
> +	for (bus = 0; bus < bus_cnt; bus++) {
>  		for (dev = 0; dev < 32; dev++) {
>  			base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,
>  						PCI_DEVFN(dev, 0), 0);
> @@ -582,12 +614,24 @@ static void vmd_attach_resources(struct vmd_dev *vmd)
>  {
>  	vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[VMD_RES_MBAR_1];
>  	vmd->dev->resource[VMD_MEMBAR2].child = &vmd->resources[VMD_RES_MBAR_2];
> +
> +	if (vmd->bus1_rootbus) {
> +		vmd->resources[VMD_RES_MBAR_1].sibling =
> +			&vmd->resources[VMD_RES_BUS1_MBAR_1];
> +		vmd->resources[VMD_RES_MBAR_2].sibling =
> +			&vmd->resources[VMD_RES_BUS1_MBAR_2];
> +	}
>  }
>  
>  static void vmd_detach_resources(struct vmd_dev *vmd)
>  {
>  	vmd->dev->resource[VMD_MEMBAR1].child = NULL;
>  	vmd->dev->resource[VMD_MEMBAR2].child = NULL;
> +
> +	if (vmd->bus1_rootbus) {
> +		vmd->resources[VMD_RES_MBAR_1].sibling = NULL;
> +		vmd->resources[VMD_RES_MBAR_2].sibling = NULL;
> +	}
>  }
>  
>  /*
> @@ -660,7 +704,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;
> @@ -679,6 +723,19 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd)
>  		case 2:
>  			vmd->busn_start[VMD_BUS_0] = VMD_RESTRICT_2_BUS_START;
>  			break;
> +		case 3:
> +			if (!(features & VMD_FEAT_HAS_BUS1_ROOTBUS)) {
> +				pci_err(dev, "VMD Bus Restriction detected type %d, but BUS1 Rootbus is not supported, aborting.\n",
> +					BUS_RESTRICT_CFG(reg));
> +				return -ENODEV;
> +			}
> +
> +			/* BUS0 start number */
> +			vmd->busn_start[VMD_BUS_0] = VMD_RESTRICT_2_BUS_START;
> +			/* BUS1 start number */
> +			vmd->busn_start[VMD_BUS_1] = VMD_RESTRICT_3_BUS_START;
> +			vmd->bus1_rootbus = true;
> +			break;
>  		default:
>  			pci_err(dev, "Unknown Bus Offset Setting (%d)\n",
>  				BUS_RESTRICT_CFG(reg));
> @@ -805,6 +862,30 @@ static void vmd_configure_cfgbar(struct vmd_dev *vmd)
>  		       (resource_size(res) >> 20) - 1,
>  		.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED,
>  	};
> +
> +	if (vmd->bus1_rootbus) {
> +		u16 bus0_range = 0;
> +		u16 bus1_range = 0;
> +
> +		pci_read_config_word(vmd->dev, VMD_BUSRANGE0, &bus0_range);
> +		pci_read_config_word(vmd->dev, VMD_BUSRANGE1, &bus1_range);
> +
> +		/*
> +		 * Resize BUS0 CFGBAR range to make space for BUS1
> +		 * owned devices by adjusting range end with value stored in
> +		 * VMD_BUSRANGE0 register.
> +		 */
> +		vmd->resources[VMD_RES_CFGBAR].start = VMD_BUS_START(bus0_range);
> +		vmd->resources[VMD_RES_CFGBAR].end = VMD_BUS_END(bus0_range);
> +
> +		vmd->resources[VMD_RES_BUS1_CFGBAR] = (struct resource){
> +			.name = "VMD CFGBAR BUS1",
> +			.start = VMD_BUS_START(bus1_range),
> +			.end = VMD_BUS_END(bus1_range),
> +			.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED,
> +			.parent = res,
> +		};
> +	}
>  }
>  
>  /*
> @@ -834,8 +915,9 @@ static void vmd_configure_membar(struct vmd_dev *vmd,
>  		flags &= ~IORESOURCE_MEM_64;
>  
>  	vmd->resources[resource_number] = (struct resource){
> -		.name = kasprintf(GFP_KERNEL, "VMD MEMBAR%d",
> -				  membar_number / 2),
> +		.name = kasprintf(
> +			GFP_KERNEL, "VMD MEMBAR%d %s", membar_number / 2,
> +			resource_number > VMD_RES_MBAR_2 ? "BUS1" : ""),
>  		.start = res->start + start_offset,
>  		.end = res->end - end_offset,
>  		.flags = flags,
> @@ -846,41 +928,80 @@ static void vmd_configure_membar(struct vmd_dev *vmd,
>  static void vmd_configure_membar1_membar2(struct vmd_dev *vmd,
>  					  resource_size_t mbar2_ofs)
>  {
> -	vmd_configure_membar(vmd, 1, VMD_MEMBAR1, 0, 0);
> -	vmd_configure_membar(vmd, 2, VMD_MEMBAR2, mbar2_ofs, 0);
> +	if (vmd->bus1_rootbus) {
> +		u32 bus1_mbar1_ofs = 0;
> +		u64 bus1_mbar2_ofs = 0;
> +		u32 reg;
> +
> +		pci_read_config_dword(vmd->dev, VMD_MEMBAR1_OFFSET,
> +				      &bus1_mbar1_ofs);
> +
> +		pci_read_config_dword(vmd->dev, VMD_MEMBAR2_OFFSET1, &reg);
> +		bus1_mbar2_ofs = reg;
> +
> +		pci_read_config_dword(vmd->dev, VMD_MEMBAR2_OFFSET2, &reg);
> +		bus1_mbar2_ofs |= (u64)reg << 32;
> +
> +		/*
> +		 * Resize BUS MEMBAR1 and MEMBAR2 ranges to make space
> +		 * for BUS1 owned devices by adjusting range end with values
> +		 * stored in VMD_MEMBAR1_OFFSET and VMD_MEMBAR2_OFFSET registers
> +		 */
> +		vmd_configure_membar(vmd, VMD_RES_MBAR_1, VMD_MEMBAR1, 0,
> +				     bus1_mbar1_ofs);
> +		vmd_configure_membar(vmd, VMD_RES_MBAR_2, VMD_MEMBAR2,
> +				     mbar2_ofs, bus1_mbar2_ofs - mbar2_ofs);
> +
> +		vmd_configure_membar(vmd, VMD_RES_BUS1_MBAR_1, VMD_MEMBAR1,
> +				     bus1_mbar1_ofs, 0);
> +		vmd_configure_membar(vmd, VMD_RES_BUS1_MBAR_2, VMD_MEMBAR2,
> +				     mbar2_ofs + bus1_mbar2_ofs, 0);
> +	} else {
> +		vmd_configure_membar(vmd, VMD_RES_MBAR_1, VMD_MEMBAR1, 0, 0);
> +		vmd_configure_membar(vmd, VMD_RES_MBAR_2, VMD_MEMBAR2,
> +				     mbar2_ofs, 0);
> +	}
>  }
>  
> -static int vmd_create_bus(struct vmd_dev *vmd, struct pci_sysdata *sd,
> -			  resource_size_t *offset)
> +static int vmd_create_bus(struct vmd_dev *vmd, enum vmd_rootbus bus_number,
> +			  struct pci_sysdata *sd, resource_size_t *offset)
>  {
> +	u8 cfgbar = bus_number * 3;
> +	u8 membar1 = cfgbar + 1;
> +	u8 membar2 = cfgbar + 2;
> +	struct pci_bus *vmd_bus;
>  	LIST_HEAD(resources);
>  
> -	pci_add_resource(&resources, &vmd->resources[VMD_RES_CFGBAR]);
> -	pci_add_resource_offset(&resources, &vmd->resources[VMD_RES_MBAR_1],
> +	pci_add_resource(&resources, &vmd->resources[cfgbar]);
> +	pci_add_resource_offset(&resources, &vmd->resources[membar1],
>  				offset[0]);
> -	pci_add_resource_offset(&resources, &vmd->resources[VMD_RES_MBAR_2],
> +	pci_add_resource_offset(&resources, &vmd->resources[membar2],
>  				offset[1]);
>  
> -	vmd->bus[VMD_BUS_0] = pci_create_root_bus(&vmd->dev->dev,
> -						  vmd->busn_start[VMD_BUS_0],
> -						  &vmd_ops, sd, &resources);
> -	if (!vmd->bus[VMD_BUS_0]) {
> +	vmd_bus = pci_create_root_bus(&vmd->dev->dev,
> +				      vmd->busn_start[bus_number], &vmd_ops, sd,
> +				      &resources);
> +
> +	if (!vmd_bus) {
>  		pci_free_resource_list(&resources);
> -		vmd_remove_irq_domain(vmd);
> +
> +		if (bus_number == VMD_PRIMARY_BUS0)
> +			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[VMD_BUS_0]->bridge));
> +	vmd_copy_host_bridge_flags(pci_find_host_bridge(vmd->dev->bus),
> +				   to_pci_host_bridge(vmd_bus->bridge));
>  
>  	vmd_attach_resources(vmd);
>  	if (vmd->irq_domain)
> -		dev_set_msi_domain(&vmd->bus[VMD_BUS_0]->dev, vmd->irq_domain);
> +		dev_set_msi_domain(&vmd_bus->dev, vmd->irq_domain);
>  	else
> -		dev_set_msi_domain(&vmd->bus[VMD_BUS_0]->dev,
> +		dev_set_msi_domain(&vmd_bus->dev,
>  				   dev_get_msi_domain(&vmd->dev->dev));
>  
> +	vmd->bus[bus_number] = vmd_bus;
> +
>  	return 0;
>  }
>  
> @@ -893,7 +1014,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 == VMD_PRIMARY_BUS0)
> +		vmd_domain_reset(vmd_from_bus(bus));
>  
>  	/*
>  	 * When Intel VMD is enabled, the OS does not discover the Root Ports
> @@ -961,7 +1084,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;
>  	}
> @@ -1021,7 +1144,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
>  		vmd_set_msi_remapping(vmd, false);
>  	}
>  
> -	ret = vmd_create_bus(vmd, sd, offset);
> +	ret = vmd_create_bus(vmd, VMD_BUS_0, sd, offset);
>  
>  	if (ret) {
>  		pci_err(vmd->dev, "Can't create bus: %d\n", ret);
> @@ -1034,6 +1157,27 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
>  
>  	vmd_bus_enumeration(vmd->bus[VMD_BUS_0], features);
>  
> +	if (vmd->bus1_rootbus) {
> +		ret = vmd_create_bus(vmd, VMD_BUS_1, sd, offset);
> +		if (ret) {
> +			pci_err(vmd->dev, "Can't create BUS1: %d\n", ret);
> +			return ret;
> +		}
> +
> +		/*
> +		 * Primary bus is not set by pci_create_root_bus(), it is
> +		 * updated here
> +		 */
> +		vmd->bus[VMD_BUS_1]->primary = VMD_PRIMARY_BUS1;
> +
> +		WARN(sysfs_create_link(&vmd->dev->dev.kobj,
> +				       &vmd->bus[VMD_BUS_1]->dev.kobj,
> +				       "domain1"),
> +		     "Can't create symlink to domain1\n");
> +
> +		vmd_bus_enumeration(vmd->bus[VMD_BUS_1], features);
> +	}
> +
>  	return 0;
>  }
>  
> @@ -1113,10 +1257,18 @@ static void vmd_remove(struct pci_dev *dev)
>  	sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
>  	pci_remove_root_bus(vmd->bus[VMD_BUS_0]);
>  
> -	/* CFGBAR is static, does not require releasing memory */
> +	/* CFGBARs are static, do not require releasing memory */
>  	kfree(vmd->resources[VMD_RES_MBAR_1].name);
>  	kfree(vmd->resources[VMD_RES_MBAR_2].name);
>  
> +	if (vmd->bus1_rootbus) {
> +		pci_stop_root_bus(vmd->bus[VMD_BUS_1]);
> +		sysfs_remove_link(&vmd->dev->dev.kobj, "domain1");
> +		pci_remove_root_bus(vmd->bus[VMD_BUS_1]);
> +		kfree(vmd->resources[VMD_RES_BUS1_MBAR_1].name);
> +		kfree(vmd->resources[VMD_RES_BUS1_MBAR_2].name);
> +	}
> +
>  	vmd_cleanup_srcu(vmd);
>  	vmd_detach_resources(vmd);
>  	vmd_remove_irq_domain(vmd);
> @@ -1202,4 +1354,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");
> -- 
> 2.39.3
> 
> 

-- 
மணிவண்ணன் சதாசிவம்




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux