diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -112,6 +112,7 @@ static void acpi_lookup(void *arg, const char *name, device_t *dev); static int acpi_modevent(struct module *mod, int event, void *junk); +static int acpi_parse_pxm(device_t dev); static device_probe_t acpi_probe; static device_attach_t acpi_attach; @@ -142,6 +143,7 @@ static bus_hint_device_unit_t acpi_hint_device_unit; static bus_get_property_t acpi_bus_get_prop; static bus_get_device_path_t acpi_get_device_path; +static bus_get_domain_t acpibus_get_domain_method; static acpi_id_probe_t acpi_device_id_probe; static acpi_evaluate_object_t acpi_device_eval_obj; @@ -219,7 +221,7 @@ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_hint_device_unit, acpi_hint_device_unit), DEVMETHOD(bus_get_cpus, acpi_get_cpus), - DEVMETHOD(bus_get_domain, acpi_get_domain), + DEVMETHOD(bus_get_domain, acpibus_get_domain_method), DEVMETHOD(bus_get_property, acpi_bus_get_prop), DEVMETHOD(bus_get_device_path, acpi_get_device_path), @@ -819,6 +821,7 @@ if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL) return (NULL); + ad->ad_domain = ACPI_DEV_DOMAIN_UNKNOWN; resource_list_init(&ad->ad_rl); child = device_add_child_ordered(bus, order, name, unit); @@ -1055,6 +1058,9 @@ case ACPI_IVAR_FLAGS: *(int *)result = ad->ad_flags; break; + case ACPI_IVAR_DOMAIN: + *(int *)result = ad->ad_domain; + break; case ISA_IVAR_VENDORID: case ISA_IVAR_SERIAL: case ISA_IVAR_COMPATID: @@ -1099,6 +1105,9 @@ case ACPI_IVAR_FLAGS: ad->ad_flags = (int)value; break; + case ACPI_IVAR_DOMAIN: + ad->ad_domain = (int)value; + break; default: panic("bad ivar write request (%d)", index); return (ENOENT); @@ -1306,7 +1315,7 @@ * determined, return ENOENT. */ int -acpi_get_domain(device_t dev, device_t child, int *domain) +acpi_get_domain_method(device_t dev, device_t child, int *domain) { int d; @@ -1322,6 +1331,25 @@ return (bus_generic_get_domain(dev, child, domain)); } +static int +acpibus_get_domain_method(device_t dev, device_t child, int *domain) +{ + int error, d; + + error = acpi_read_ivar(dev, child, ACPI_IVAR_DOMAIN, + (uintptr_t *)domain); + if (error == 0 && *domain != ACPI_DEV_DOMAIN_UNKNOWN) + return (0); + + d = acpi_parse_pxm(child); + if (d >= 0) { + *domain = d; + acpi_write_ivar(dev, child, ACPI_IVAR_DOMAIN, d); + return (0); + } + return (ENOENT); +} + static struct rman * acpi_get_rman(device_t bus, int type, u_int flags) { diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -108,7 +108,7 @@ DEVMETHOD(bus_get_device_path, acpi_pci_get_device_path), DEVMETHOD(bus_get_cpus, acpi_get_cpus), DEVMETHOD(bus_get_dma_tag, acpi_pci_get_dma_tag), - DEVMETHOD(bus_get_domain, acpi_get_domain), + DEVMETHOD(bus_get_domain, acpi_get_domain_method), /* PCI interface */ DEVMETHOD(pci_alloc_devinfo, acpi_pci_alloc_devinfo), diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -89,6 +89,7 @@ void *ad_private; int ad_flags; int ad_cls_class; + int ad_domain; ACPI_BUFFER dsd; /* Device Specific Data */ const ACPI_OBJECT *dsd_pkg; @@ -269,6 +270,12 @@ #define ACPI_IVAR_UNUSED 0x101 /* Unused/reserved. */ #define ACPI_IVAR_PRIVATE 0x102 #define ACPI_IVAR_FLAGS 0x103 +#define ACPI_IVAR_DOMAIN 0x104 + +/* + * ad_domain NUMA domain special value. + */ +#define ACPI_DEV_DOMAIN_UNKNOWN (-1) /* * Accessor functions for our ivars. Default value for BUS_READ_IVAR is @@ -294,6 +301,7 @@ __ACPI_BUS_ACCESSOR(acpi, handle, ACPI, HANDLE, ACPI_HANDLE) __ACPI_BUS_ACCESSOR(acpi, private, ACPI, PRIVATE, void *) __ACPI_BUS_ACCESSOR(acpi, flags, ACPI, FLAGS, int) +__ACPI_BUS_ACCESSOR(acpi, domain, ACPI, DOMAIN, int) void acpi_fake_objhandler(ACPI_HANDLE h, void *data); static __inline device_t @@ -590,7 +598,7 @@ */ int acpi_map_pxm_to_vm_domainid(int pxm); bus_get_cpus_t acpi_get_cpus; -bus_get_domain_t acpi_get_domain; +bus_get_domain_t acpi_get_domain_method; #ifdef __aarch64__ /* diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -266,6 +266,7 @@ DEVICE_SYSCTL_PNPINFO, DEVICE_SYSCTL_PARENT, DEVICE_SYSCTL_IOMMU, + DEVICE_SYSCTL_DOMAIN, }; static int @@ -324,11 +325,32 @@ return (error); } +static int +device_sysctl_handler_int(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + int domain, error; + + bus_topo_lock(); + switch (arg2) { + case DEVICE_SYSCTL_DOMAIN: + error = bus_get_domain(dev, &domain); + if (error != 0) + domain = -1; + error = sysctl_handle_int(oidp, &domain, 0, req); + break; + default: + error = EINVAL; + break; + } + bus_topo_unlock(); + return (error); +} + static void device_sysctl_init(device_t dev) { devclass_t dc = dev->devclass; - int domain; if (dev->sysctl_tree != NULL) return; @@ -367,10 +389,11 @@ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, DEVICE_SYSCTL_IOMMU, device_sysctl_handler, "A", "iommu unit handling the device requests"); - if (bus_get_domain(dev, &domain) == 0) - SYSCTL_ADD_INT(&dev->sysctl_ctx, - SYSCTL_CHILDREN(dev->sysctl_tree), OID_AUTO, "%domain", - CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, domain, "NUMA domain"); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%domain", + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, DEVICE_SYSCTL_DOMAIN, device_sysctl_handler_int, "I", + "NUMA domain"); } static void diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -160,6 +160,27 @@ return (1); } +/* Remapping Hardware Static Affinity Structure lookup */ +struct rhsa_iter_arg { + uint64_t base; + u_int proxim_dom; +}; + +static int +dmar_rhsa_iter(ACPI_DMAR_HEADER *dmarh, void *arg) +{ + struct rhsa_iter_arg *ria; + ACPI_DMAR_RHSA *adr; + + if (dmarh->Type == ACPI_DMAR_TYPE_HARDWARE_AFFINITY) { + ria = arg; + adr = (ACPI_DMAR_RHSA *)dmarh; + if (adr->BaseAddress == ria->base) + ria->proxim_dom = adr->ProximityDomain; + } + return (1); +} + int dmar_rmrr_enable = 1; static int dmar_enable = 0; @@ -168,6 +189,7 @@ { ACPI_TABLE_DMAR *dmartbl; ACPI_DMAR_HARDWARE_UNIT *dmarh; + struct rhsa_iter_arg ria; ACPI_STATUS status; int i, error; @@ -217,7 +239,15 @@ i, (uintmax_t)dmarh->Address, error); device_delete_child(parent, dmar_devs[i]); dmar_devs[i] = NULL; + continue; } + + ria.base = dmarh->Address; + ria.proxim_dom = -1; + dmar_iterate_tbl(dmar_rhsa_iter, &ria); + acpi_set_domain(dmar_devs[i], ria.proxim_dom == -1 ? + ACPI_DEV_DOMAIN_UNKNOWN : + acpi_map_pxm_to_vm_domainid(ria.proxim_dom)); } } @@ -326,34 +356,12 @@ DMAR_ECAP_IRO(unit->hw_ecap)); } -/* Remapping Hardware Static Affinity Structure lookup */ -struct rhsa_iter_arg { - uint64_t base; - u_int proxim_dom; -}; - -static int -dmar_rhsa_iter(ACPI_DMAR_HEADER *dmarh, void *arg) -{ - struct rhsa_iter_arg *ria; - ACPI_DMAR_RHSA *adr; - - if (dmarh->Type == ACPI_DMAR_TYPE_HARDWARE_AFFINITY) { - ria = arg; - adr = (ACPI_DMAR_RHSA *)dmarh; - if (adr->BaseAddress == ria->base) - ria->proxim_dom = adr->ProximityDomain; - } - return (1); -} - static int dmar_attach(device_t dev) { struct dmar_unit *unit; ACPI_DMAR_HARDWARE_UNIT *dmaru; struct iommu_msi_data *dmd; - struct rhsa_iter_arg ria; uint64_t timeout; int disable_pmr; int i, error; @@ -381,13 +389,7 @@ if (bootverbose) dmar_print_caps(dev, unit, dmaru); dmar_quirks_post_ident(unit); - unit->memdomain = -1; - ria.base = unit->base; - ria.proxim_dom = -1; - dmar_iterate_tbl(dmar_rhsa_iter, &ria); - if (ria.proxim_dom != -1) - unit->memdomain = acpi_map_pxm_to_vm_domainid(ria.proxim_dom); - + unit->memdomain = acpi_get_domain(dev); timeout = dmar_get_timeout(); TUNABLE_UINT64_FETCH("hw.iommu.dmar.timeout", &timeout); dmar_update_timeout(timeout);