Re: acpidmar(4): Store PCI domain in softc for segment mapping

Mark Kettenis <[email protected]> Wed, 29 Jul 2026 23:12:52 +0200
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
> Date: Tue, 28 Jul 2026 15:39:46 +0200
> From: hshoexer <[email protected]>
> 
> Hi,
> 
> with this change I store the PCI domain in the softc.  Later I use
> that value when mapping domain to segment.  Instead of counting.

The way acpipci(4) works we already have a 1:1 mapping between PCI
segments and PCI domains.  Technically that isn't necessarily correct,
but in practice that seems to be the only workable approach.

> Also fall back to segment 0, when ACPI did not provide a segment.

If APCI doesn't provide a segment, we already set it to 0.  This is
required by the standard.  So...

> This actually enforces use of the IOMMU.
>     
> While there:
>  - tweak printf to use segment instead of PCI domain
>  - use ACPI provided segment instead of hardcoded 0 in ivhd_showpage()
> 
> ok?
> 
> Take care,
> HJ.
> 
> -----------------------------------------------------------------------------
> diff --git a/sys/arch/amd64/pci/acpipci.c b/sys/arch/amd64/pci/acpipci.c
> index e3121987654..e5e861662d7 100644
> --- a/sys/arch/amd64/pci/acpipci.c
> +++ b/sys/arch/amd64/pci/acpipci.c
> @@ -66,6 +66,7 @@ struct acpipci_softc {
>  	char		sc_memex_name[32];
>  	int		sc_bus;
>  	uint32_t	sc_seg;
> +	int		sc_domain;
>  };
>  
>  int	acpipci_match(struct device *, void *, void *);
> @@ -97,15 +98,14 @@ int
>  acpipci_domain_to_seg(int domain)
>  {
>  	struct acpipci_softc *sc;
> -	int i, d = 0;
> +	int i;
>  
>  	for (i = 0; i < acpipci_cd.cd_ndevs; i++) {
>  		sc = (struct acpipci_softc *)acpipci_cd.cd_devs[i];
>  		if (sc == NULL)
>  			continue;
> -		if (d == domain)
> +		if (sc->sc_domain == domain)
>  			return sc->sc_seg;
> -		d++;
>  	}
>  
>  	return -1;
> @@ -147,6 +147,9 @@ acpipci_attach(struct device *parent, struct device *self, void *aux)
>  	aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg);
>  	sc->sc_seg = seg;
>  
> +	/* Assigned when the PCI bus attaches. */
> +	sc->sc_domain = -1;
> +
>  	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
>  		printf(": can't find resources\n");
>  
> @@ -210,6 +213,7 @@ acpipci_attach_bus(struct device *parent, struct acpipci_softc *sc)
>  	pba.pba_pmemex = sc->sc_memex;
>  	pba.pba_domain = pci_ndomains++;
>  	pba.pba_bus = sc->sc_bus;
> +	sc->sc_domain = pba.pba_domain;
>  
>  	/* Enable MSI in ACPI 2.0 and above, unless we're told not to. */
>  	if (sc->sc_acpi->sc_fadt->hdr.revision >= 2 &&
> diff --git a/sys/dev/acpi/acpidmar.c b/sys/dev/acpi/acpidmar.c
> index 57b90ddb193..cf18265fd09 100644
> --- a/sys/dev/acpi/acpidmar.c
> +++ b/sys/dev/acpi/acpidmar.c
> @@ -2581,9 +2581,8 @@ acpidmar_pci_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa)
>  
>  	segment = acpipci_domain_to_seg(pa->pa_domain);
>  	if (segment < 0) {
> -		DPRINTF(1, "acpidmar: no ACPI segment for pci domain %d\n",
> -		    pa->pa_domain);
> -		return;
> +		/* Fall back to segment 0. */
> +		segment = 0;
>  	}

So it we ever get a -1 here, somethings is really wrong.  So I'd
probably turn this into:

        KASSERT(segment >= 0);

Otherwise this looks good.

I'm still curious to see any x86 AML that actually uses non-zero _SEG
numbers.

>  	/* Record PCI-PCI bridge forwarding windows */
> @@ -2608,7 +2607,7 @@ acpidmar_pci_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa)
>  	    PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_ISA) {
>  		/* For ISA Bridges, map 0-16Mb as 1:1 */
>  		printf("dmar: %.4x:%.2x:%.2x.%x mapping ISA\n",
> -		    pa->pa_domain, bus, dev, fun);
> +		    segment, bus, dev, fun);
>  		domain_map_pthru(dom, 0x00, 16*1024*1024);
>  
>  		/* Keep the identity mapped IOVA range out of the allocator */
> @@ -2917,7 +2916,7 @@ ivhd_showpage(struct iommu_softc *iommu, int sid, paddr_t paddr)
>  	if (show > 10)
>  		return;
>  	show++;
> -	dom = acpidmar_pci_attach(acpidmar_sc, 0, sid, 0);
> +	dom = acpidmar_pci_attach(acpidmar_sc, iommu->segment, sid, 0);
>  	if (!dom)
>  		return;
>  	printf("DTE: %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
> 
>