diff options
author | jhb <jhb@FreeBSD.org> | 2016-02-01 23:07:31 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2016-02-01 23:07:31 +0000 |
commit | 05de7f15435827d273d924fd9d03c09d36bb19b6 (patch) | |
tree | 8ea3c2613bb0dac29850ab9ba9b462ff3ca84571 /sys/dev | |
parent | 90b6006f8d6ccaaaa6ebef08c2fa902a3b796e21 (diff) | |
download | FreeBSD-src-05de7f15435827d273d924fd9d03c09d36bb19b6.zip FreeBSD-src-05de7f15435827d273d924fd9d03c09d36bb19b6.tar.gz |
MFC 278320,278336,278830,285621:
Add devctl(8): a utility for manipulating new-bus devices. Note that
this version does not include the 'suspend' and 'resume' commands
present in HEAD as those depend on larger changes to the suspend and
resume code in the kernel.
278320:
Add a new device control utility for new-bus devices called devctl. This
allows the user to request administrative changes to individual devices
such as attach or detaching drivers or disabling and re-enabling devices.
- Add a new /dev/devctl2 character device which uses ioctls for device
requests. The ioctls use a common 'struct devreq' which is somewhat
similar to 'struct ifreq'.
- The ioctls identify the device to operate on via a string. This
string can either by the device's name, or it can be a bus-specific
address. (For unattached devices, a bus address is the only way to
locate a device.) Bus drivers register an eventhandler to claim
unrecognized device names that the driver recognizes as a valid address.
Two buses currently support addresses: ACPI recognizes any device
in the ACPI namespace via its full path starting with "\" and
the PCI bus driver recognizes an address specification of
'pci[<domain>:]<bus>:<slot>:<func>' (identical to the PCI selector
strings supported by pciconf).
- To make it easier to cut and paste, change the PnP location string
in the PCI bus driver to output a full PCI selector string rather
than 'slot=<slot> function=<func>'.
- Add a devctl(3) interface in libdevctl which provides a wrapper around
the ioctls and is the preferred interface for other userland code.
- Add a devctl(8) program which is a simple wrapper around the requests
supported by devctl(3).
- Add a resource_unset_value() function that can be used to remove a
hint from the kernel environment. This is used to clear a
hint.<driver>.<unit>.disabled hint when re-enabling a boot-time
disabled device.
278336:
Unbreak the build (memchr is explicitly required by devctl(9) after r278320)
278830:
install the man page...
285621:
Fix formatting.
Approved by: re (marius)
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpica/acpi.c | 30 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 59 |
2 files changed, 86 insertions, 3 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 55b0dd2..08a967f 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -100,6 +100,7 @@ int acpi_quirks; /* Supported sleep states. */ static BOOLEAN acpi_sleep_states[ACPI_S_STATE_COUNT]; +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_probe(device_t dev); static int acpi_attach(device_t dev); @@ -670,8 +671,10 @@ acpi_attach(device_t dev) /* Register ACPI again to pass the correct argument of pm_func. */ power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc); - if (!acpi_disabled("bus")) + if (!acpi_disabled("bus")) { + EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000); acpi_probe_children(dev); + } /* Update all GPEs and enable runtime GPEs. */ status = AcpiUpdateAllGpes(); @@ -3404,6 +3407,31 @@ acpi_disabled(char *subsys) return (0); } +static void +acpi_lookup(void *arg, const char *name, device_t *dev) +{ + ACPI_HANDLE handle; + + if (*dev != NULL) + return; + + /* + * Allow any handle name that is specified as an absolute path and + * starts with '\'. We could restrict this to \_SB and friends, + * but see acpi_probe_children() for notes on why we scan the entire + * namespace for devices. + * + * XXX: The pathname argument to AcpiGetHandle() should be fixed to + * be const. + */ + if (name[0] != '\\') + return; + if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name), + &handle))) + return; + *dev = acpi_get_device(handle); +} + /* * Control interface. * diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index cef2db4..bf41b8e 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/malloc.h> #include <sys/module.h> +#include <sys/limits.h> #include <sys/linker.h> #include <sys/fcntl.h> #include <sys/conf.h> @@ -4924,8 +4925,8 @@ pci_child_location_str_method(device_t dev, device_t child, char *buf, size_t buflen) { - snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child), - pci_get_function(child)); + snprintf(buf, buflen, "pci%d:%d:%d:%d", pci_get_domain(child), + pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); return (0); } @@ -4955,10 +4956,60 @@ pci_assign_interrupt_method(device_t dev, device_t child) cfg->intpin)); } +static void +pci_lookup(void *arg, const char *name, device_t *dev) +{ + long val; + char *end; + int domain, bus, slot, func; + + if (*dev != NULL) + return; + + /* + * Accept pciconf-style selectors of either pciD:B:S:F or + * pciB:S:F. In the latter case, the domain is assumed to + * be zero. + */ + if (strncmp(name, "pci", 3) != 0) + return; + val = strtol(name + 3, &end, 10); + if (val < 0 || val > INT_MAX || *end != ':') + return; + domain = val; + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX || *end != ':') + return; + bus = val; + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX) + return; + slot = val; + if (*end == ':') { + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX || *end != '\0') + return; + func = val; + } else if (*end == '\0') { + func = slot; + slot = bus; + bus = domain; + domain = 0; + } else + return; + + if (domain > PCI_DOMAINMAX || bus > PCI_BUSMAX || slot > PCI_SLOTMAX || + func > PCIE_ARI_FUNCMAX || (slot != 0 && func > PCI_FUNCMAX)) + return; + + *dev = pci_find_dbsf(domain, bus, slot, func); +} + static int pci_modevent(module_t mod, int what, void *arg) { static struct cdev *pci_cdev; + static eventhandler_tag tag; switch (what) { case MOD_LOAD: @@ -4967,9 +5018,13 @@ pci_modevent(module_t mod, int what, void *arg) pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644, "pci"); pci_load_vendor_data(); + tag = EVENTHANDLER_REGISTER(dev_lookup, pci_lookup, NULL, + 1000); break; case MOD_UNLOAD: + if (tag != NULL) + EVENTHANDLER_DEREGISTER(dev_lookup, tag); destroy_dev(pci_cdev); break; } |