Hi Jean On 6/29/22 11:14, Jean-Philippe Brucker wrote: > 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). Yes that's what I saw too > 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? sure > >> --- >> 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. OK > >> +} >> + >> /** >> * 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 OK Thanks Eric > > Thanks, > Jean > > >> static inline int viot_iommu_configure(struct device *dev) >> { >> return -ENODEV; >> -- >> 2.35.3 >>