diff options
Diffstat (limited to 'sys/powerpc/ofw/ofw_pcibus.c')
| -rw-r--r-- | sys/powerpc/ofw/ofw_pcibus.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c index ed4e66dde207..9c4f45d1c1df 100644 --- a/sys/powerpc/ofw/ofw_pcibus.c +++ b/sys/powerpc/ofw/ofw_pcibus.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/libkern.h> #include <sys/module.h> #include <sys/pciio.h> +#include <sys/smp.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> @@ -80,6 +81,8 @@ static device_method_t ofw_pcibus_methods[] = { DEVMETHOD(bus_child_deleted, ofw_pcibus_child_deleted), DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method), DEVMETHOD(bus_rescan, bus_null_rescan), + DEVMETHOD(bus_get_cpus, ofw_pcibus_get_cpus), + DEVMETHOD(bus_get_domain, ofw_pcibus_get_domain), /* PCI interface */ DEVMETHOD(pci_alloc_devinfo, ofw_pcibus_alloc_devinfo), @@ -382,3 +385,77 @@ ofw_pcibus_get_devinfo(device_t bus, device_t dev) return (&dinfo->opd_obdinfo); } +static int +ofw_pcibus_parse_associativity(device_t dev, int *domain) +{ + phandle_t node; + cell_t associativity[5]; + int res; + + if ((node = ofw_bus_get_node(dev)) == -1) { + if (bootverbose) + device_printf(dev, "no ofw node found\n"); + return (ENXIO); + } + res = OF_getproplen(node, "ibm,associativity"); + if (res <= 0) + return (ENXIO); + OF_getencprop(node, "ibm,associativity", + associativity, res); + + *domain = associativity[3] - 1; + if (bootverbose) + device_printf(dev, "domain(%d)\n", *domain); + return (0); +} + +int +ofw_pcibus_get_cpus(device_t dev, device_t child, enum cpu_sets op, size_t setsize, + cpuset_t *cpuset) +{ + int d, error; + + error = ofw_pcibus_parse_associativity(child, &d); + if (error) + return (bus_generic_get_cpus(dev, child, op, setsize, cpuset)); + + switch (op) { + case LOCAL_CPUS: + if (setsize != sizeof(cpuset_t)) + return (EINVAL); + *cpuset = cpuset_domain[d]; + return (0); + case INTR_CPUS: + error = bus_generic_get_cpus(dev, child, op, setsize, cpuset); + if (error != 0) + return (error); + if (setsize != sizeof(cpuset_t)) + return (EINVAL); + CPU_AND(cpuset, &cpuset_domain[d]); + return (0); + default: + return (bus_generic_get_cpus(dev, child, op, setsize, cpuset)); + } + return (0); +} + +/* + * Fetch the NUMA domain for the given device 'dev'. + * + * If a device has a _PXM method, map that to a NUMA domain. + * Otherwise, pass the request up to the parent. + * If there's no matching domain or the domain cannot be + * determined, return ENOENT. + */ +int +ofw_pcibus_get_domain(device_t dev, device_t child, int *domain) +{ + int d, error; + + error = ofw_pcibus_parse_associativity(child, &d); + /* No ofw node; go up a level */ + if (error) + return (bus_generic_get_domain(dev, child, domain)); + *domain = d; + return (0); +} |
