Hi Eric, On Mon, Jun 27, 2022 at 02:55:34PM +0200, Eric Auger wrote: > Currently acpi_viot_init() gets called after the pci > device has been scanned and pci_enable_acs() has been called. > So pci_request_acs() fails to be taken into account leading > to wrong single iommu group topologies when dealing with > multi-function root ports for instance. > > We cannot simply move the acpi_viot_init() earlier, similarly > as the IORT init because the VIOT parsing relies on the pci > scan. However we can detect VIOT is present earlier and in > such a case, request ACS. Introduce a new acpi_viot_early_init() > routine that allows to call pci_request_acs() before the scan. > > Fixes: 3cf485540e7b ("ACPI: Add driver for the VIOT table") > Signed-off-by: Eric Auger <eric.auger@xxxxxxxxxx> > Reported-by: Jin Liu <jinl@xxxxxxxxxx> Thanks for the fix, the patch makes sense and fixes the issue. I wondered whether we should keep the logic where we only request ACS if an IOMMU is found to manage a PCI range, but I can't see any harm in requesting it regardless (plus there is a precedent with AMD IOMMU). I could imagine some VMM wanting to only put an IOMMU in front of its MMIO devices and leave PCI to roam free, but that seems like a stretch. There is another issue with the existing code, though: we can't call pci_request_acs() when CONFIG_PCI is disabled because no stub is defined. Could you wrap the call in an #ifdef? > --- > drivers/acpi/bus.c | 1 + > drivers/acpi/viot.c | 23 +++++++++++++++++------ > include/linux/acpi_viot.h | 2 ++ > 3 files changed, 20 insertions(+), 6 deletions(-) > > diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c > index 86fa61a21826..906ad8153fd9 100644 > --- a/drivers/acpi/bus.c > +++ b/drivers/acpi/bus.c > @@ -1400,6 +1400,7 @@ static int __init acpi_init(void) > > pci_mmcfg_late_init(); > acpi_iort_init(); > + acpi_viot_early_init(); > acpi_hest_init(); > acpi_ghes_init(); > acpi_scan_init(); > diff --git a/drivers/acpi/viot.c b/drivers/acpi/viot.c > index d2256326c73a..3c1be123e4d6 100644 > --- a/drivers/acpi/viot.c > +++ b/drivers/acpi/viot.c > @@ -248,6 +248,23 @@ static int __init viot_parse_node(const struct acpi_viot_header *hdr) > return ret; > } > > +/** > + * acpi_viot_early_init - Test the presence of VIOT and enable ACS > + * > + * If the VIOT does exist, ACS must be enabled. This cannot be > + * done in acpi_viot_init() which is called after the bus scan > + */ > +void __init acpi_viot_early_init(void) > +{ > + acpi_status status; > + struct acpi_table_header *hdr; > + > + status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr); > + if (!ACPI_FAILURE(status)) > + pci_request_acs(); > + acpi_put_table(hdr); I'd rather not call acpi_put_table() in case of failure. I know it is handled but it looks fragile and I couldn't find any other user of acpi_get_table() doing this. > +} > + > /** > * acpi_viot_init - Parse the VIOT table > * > @@ -319,12 +336,6 @@ static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data) > epid = ((domain_nr - ep->segment_start) << 16) + > dev_id - ep->bdf_start + ep->endpoint_id; > > - /* > - * If we found a PCI range managed by the viommu, we're > - * the one that has to request ACS. > - */ > - pci_request_acs(); > - > return viot_dev_iommu_init(&pdev->dev, ep->viommu, > epid); > } > diff --git a/include/linux/acpi_viot.h b/include/linux/acpi_viot.h > index 1eb8ee5b0e5f..e58d60f8ff2e 100644 > --- a/include/linux/acpi_viot.h > +++ b/include/linux/acpi_viot.h > @@ -6,10 +6,12 @@ > #include <linux/acpi.h> > > #ifdef CONFIG_ACPI_VIOT > +void __init acpi_viot_early_init(void); > void __init acpi_viot_init(void); > int viot_iommu_configure(struct device *dev); > #else > static inline void acpi_viot_init(void) {} > +static inline void acpi_viot_early_init(void) {} nit: different declaration order Thanks, Jean > static inline int viot_iommu_configure(struct device *dev) > { > return -ENODEV; > -- > 2.35.3 >