Index: sys/amd64/include/intr_machdep.h =================================================================== --- sys/amd64/include/intr_machdep.h +++ sys/amd64/include/intr_machdep.h @@ -143,6 +143,9 @@ register_t __padding; /* pad to 16 bytes */ }; +#ifdef SMP +extern cpuset_t intr_cpus; +#endif extern struct mtx icu_lock; extern int elcr_found; Index: sys/dev/acpica/acpi.c =================================================================== --- sys/dev/acpica/acpi.c +++ sys/dev/acpica/acpi.c @@ -209,6 +209,7 @@ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 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), /* ACPI bus */ @@ -1072,6 +1073,28 @@ } } +int +acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, cpuset_t *cpuset, int size) +{ + int rc, d, error; + + if ((rc = acpi_get_domain(dev, child, &d)) != 0) + return (rc); + + switch (op) { + case LOCAL_CPUS: + *cpuset = cpuset_domain[d]; + return (0); + case INTR_CPUS: + if ((error = bus_generic_get_cpus(dev, child, op, cpuset, size))) + return (error); + CPU_AND(cpuset, &cpuset_domain[d]); + return (0); + default: + return (bus_generic_get_cpus(dev, child, op, cpuset, size)); + } +} + /* * Fetch the VM domain for the given device 'dev'. * @@ -1085,9 +1108,10 @@ ACPI_HANDLE h; int d, pxm; - h = acpi_get_handle(dev); - if ((h != NULL) && - ACPI_SUCCESS(acpi_GetInteger(h, "_PXM", &pxm))) { + if ((h = acpi_get_handle(dev)) == NULL) + return (ENOENT); + + if (ACPI_SUCCESS(acpi_GetInteger(h, "_PXM", &pxm))) { d = acpi_map_pxm_to_vm_domainid(pxm); if (d < 0) return (-1); @@ -1095,7 +1119,6 @@ return (1); } #endif - return (0); } Index: sys/dev/acpica/acpi_pci.c =================================================================== --- sys/dev/acpica/acpi_pci.c +++ sys/dev/acpica/acpi_pci.c @@ -98,6 +98,7 @@ DEVMETHOD(bus_read_ivar, acpi_pci_read_ivar), DEVMETHOD(bus_write_ivar, acpi_pci_write_ivar), DEVMETHOD(bus_child_location_str, acpi_pci_child_location_str_method), + DEVMETHOD(bus_get_cpus, acpi_get_cpus), DEVMETHOD(bus_get_dma_tag, acpi_pci_get_dma_tag), DEVMETHOD(bus_get_domain, acpi_get_domain), Index: sys/dev/acpica/acpivar.h =================================================================== --- sys/dev/acpica/acpivar.h +++ sys/dev/acpica/acpivar.h @@ -503,6 +503,9 @@ #if MAXMEMDOM > 1 extern int acpi_map_pxm_to_vm_domainid(int pxm); #endif + +extern int acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, + cpuset_t *cpuset, int size); extern int acpi_get_domain(device_t dev, device_t child, int *domain); extern int acpi_parse_pxm(device_t dev, int *domain); Index: sys/kern/bus_if.m =================================================================== --- sys/kern/bus_if.m +++ sys/kern/bus_if.m @@ -707,3 +707,21 @@ device_t _child; int *_domain; } DEFAULT bus_generic_get_domain; + +/** + * @brief Request a set of CPUs + * + * @param _dev the bus device + * @param _child the child device + * @param _op type of CPUs to request + * @param _cpuset a pointer to a cpuset to receive the requested set of CPUs + * @param _size size of cpuset + * + */ +METHOD int get_cpus { + device_t _dev; + device_t _child; + enum cpu_sets _op; + cpuset_t *_cpuset; + int _size; +} DEFAULT bus_generic_get_cpus; Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -4079,6 +4080,23 @@ } /** + * @brief Helper function for implementing BUS_GET_CPUS(). + * + * This simple implementation of BUS_GET_CPUS() simply calls the + * BUS_GET_CPUS() method of the parent of @p dev. + */ +int +bus_generic_get_cpus(device_t dev, device_t child, enum cpu_sets op, + cpuset_t *cpuset, int size) +{ + + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent != NULL) + return (BUS_GET_CPUS(dev->parent, child, op, cpuset, size)); + return (EINVAL); +} + +/** * @brief Helper function for implementing BUS_GET_DMA_TAG(). * * This simple implementation of BUS_GET_DMA_TAG() simply calls the @@ -4559,6 +4577,28 @@ } /** + * @brief Wrapper function for BUS_GET_CPUS(). + * + * This function simply calls the BUS_GET_CPUS() method of the + * parent of @p dev. + */ +int +bus_get_cpus(device_t dev, enum cpu_sets op, cpuset_t *cpuset, int size) +{ + device_t parent; + + /* + * How should we handle size mismatch? + */ + if (size < sizeof(cpuset_t)) + return (ENXIO); + parent = device_get_parent(dev); + if (parent == NULL) + return (EINVAL); + return (BUS_GET_CPUS(parent, dev, op, cpuset, size)); +} + +/** * @brief Wrapper function for BUS_GET_DMA_TAG(). * * This function simply calls the BUS_GET_DMA_TAG() method of the @@ -4633,6 +4673,20 @@ return (-1); } +static int +root_get_cpus(device_t dev, device_t child, enum cpu_sets op, cpuset_t *cpuset, int size) +{ + + switch (op) { + case INTR_CPUS: + /* Default to returning the set of all CPUs. */ + *cpuset = all_cpus; + return (0); + default: + return (EINVAL); + } +} + static kobj_method_t root_methods[] = { /* Device interface */ KOBJMETHOD(device_shutdown, bus_generic_shutdown), @@ -4645,6 +4699,7 @@ KOBJMETHOD(bus_write_ivar, bus_generic_write_ivar), KOBJMETHOD(bus_setup_intr, root_setup_intr), KOBJMETHOD(bus_child_present, root_child_present), + KOBJMETHOD(bus_get_cpus, root_get_cpus), KOBJMETHOD_END }; Index: sys/sys/_cpuset.h =================================================================== --- sys/sys/_cpuset.h +++ sys/sys/_cpuset.h @@ -32,6 +32,7 @@ #ifndef _SYS__CPUSET_H_ #define _SYS__CPUSET_H_ +#include #include #ifdef _KERNEL Index: sys/sys/bus.h =================================================================== --- sys/sys/bus.h +++ sys/sys/bus.h @@ -31,6 +31,7 @@ #include #include +#include #include /** @@ -265,6 +266,16 @@ INTR_POLARITY_LOW = 2 }; +/** + * CPU sets supported by bus_get_cpus(). Note that not all sets may be + * supported for a given device. If a request is not supported by a + * device (or its parents), then bus_get_cpus() will fail with EINVAL. + */ +enum cpu_sets { + LOCAL_CPUS = 0, + INTR_CPUS +}; + typedef int (*devop_t)(void); /** @@ -381,6 +392,8 @@ int rid, struct resource *r); int bus_generic_detach(device_t dev); void bus_generic_driver_added(device_t dev, driver_t *driver); +int bus_generic_get_cpus(device_t dev, device_t child, enum cpu_sets op, + cpuset_t *cpuset, int size); bus_dma_tag_t bus_generic_get_dma_tag(device_t dev, device_t child); int bus_generic_get_domain(device_t dev, device_t child, int *domain); @@ -447,6 +460,7 @@ struct resource *r); int bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r); +int bus_get_cpus(device_t dev, enum cpu_sets op, cpuset_t *cpuset, int size); bus_dma_tag_t bus_get_dma_tag(device_t dev); int bus_get_domain(device_t dev, int *domain); int bus_release_resource(device_t dev, int type, int rid, Index: sys/x86/x86/intr_machdep.c =================================================================== --- sys/x86/x86/intr_machdep.c +++ sys/x86/x86/intr_machdep.c @@ -475,7 +475,7 @@ * allocate CPUs round-robin. */ -static cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1); +cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1); static int current_cpu; /* Index: sys/x86/x86/nexus.c =================================================================== --- sys/x86/x86/nexus.c +++ sys/x86/x86/nexus.c @@ -128,6 +128,7 @@ static int nexus_get_resource(device_t, device_t, int, int, rman_res_t *, rman_res_t *); static void nexus_delete_resource(device_t, device_t, int, int); +static int nexus_get_cpus(device_t, device_t, enum cpu_sets, cpuset_t *, int size); #ifdef DEV_APIC static int nexus_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs); static int nexus_release_msi(device_t pcib, device_t dev, int count, int *irqs); @@ -164,6 +165,7 @@ DEVMETHOD(bus_set_resource, nexus_set_resource), DEVMETHOD(bus_get_resource, nexus_get_resource), DEVMETHOD(bus_delete_resource, nexus_delete_resource), + DEVMETHOD(bus_get_cpus, nexus_get_cpus), /* pcib interface */ #ifdef DEV_APIC @@ -616,6 +618,21 @@ resource_list_delete(rl, type, rid); } +static int +nexus_get_cpus(device_t dev, device_t child, enum cpu_sets op, cpuset_t *cpuset, int size) +{ + + switch (op) { +#ifdef SMP + case INTR_CPUS: + *cpuset = intr_cpus; + return (0); +#endif + default: + return (bus_generic_get_cpus(dev, child, op, cpuset, size)); + } +} + /* Called from the MSI code to add new IRQs to the IRQ rman. */ void nexus_add_irq(u_long irq)