Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 05 Jan 2015 15:01 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        arch@freebsd.org
Subject:   devctl(8): A device control utility
Message-ID:  <3200196.9ZgXApgRdA@ralph.baldwin.cx>

next in thread | raw e-mail | index | archive | help
For a long time I've wanted a way to administratively manipulate the state of 
new-bus devices from userland.  I think the first use case I wanted was a way 
to power off the sound controller (and anything else I wasn't using) on my 
first laptop (a Dell Inspiron 5000e I got back in 2000).  Similarly, it would 
be nice to have a way to handle "ejectable" devices (ACPI has a provision for 
this, and said laptop had _EJx methods to allow one to swap a CD drive out for 
a battery in a bay while the laptop was in S3).  There are some other use 
cases that would also be nice such as detaching a driver from a PCI device to 
decide at runtime that it should be passed through to a bhyve guest (and 
possibly undoing that to allow a host driver to take it back over).  Forcing a 
rescan of a PCI device can be useful if you are using an FPGA and would like 
to alter BAR layout/sizes without having to reboot the OS.  A way to force 
resets at runtime might also be useful (e.g. a FLR for a PCI device).  A few 
weeks ago I finally sat down and started on an implementation.  It can be 
found here:

   https://github.com/bsdjhb/freebsd/compare/devctl

Sample commands look like:

 % devctl disable virtio_pci2

 # detaches the driver, but leaves the device's name intact similar to
 # specifying hint.virtio_pci.2.disabled=1 at boot

 % devctl enable virtio_pci2

 # enables a disabled device, including attaching it

 % devctl detach uart1

 # does a full detach, which means the device is now unnamed

 % devctl attach \_SB_.PCI0.LPC.UAR1

 # attaches an unattached device.  A provision is made for recognizing
 # device addresses via an EVENTHANDLER hook that a bus driver can
 # install.  Currently ACPI handles and pci selectors (ala pciconf)
 # are recognized via hooks in the ACPI and PCI bus drivers.

 % devctl set driver foo0 bar

 # forces the 'foo0' device to use the 'bar' device class and thus
 # only attach to a driver named 'bar' (assuming that 'bar' will
 # probe it, this doesn't override device_probe).  With some changes
 # to ppt.c, this would allow one to do 'devctl set driver foo0 ppt'
 # to detach a host driver and mark a device for PCI passthrough at
 # runtime.  I have not yet implemented a "clear driver" to reset
 # back to an empty device class.

The current version also includes 'suspend' and 'resume' commands which
use bus_suspend_child() (recently added by Justin Hibbits) to suspend
(and possibly power down) individual devices.

Implementation notes:

For the kernel <-> userland interface, I chose to use ioctls.  The ioctls
use a 'struct devreq' structure that is modeled on 'struct ifreq' used
for network interface ioctls in that there are a set of common fields and
a union of request-specific fields.

I would have liked to reuse /dev/devctl for this, but it is a single
purpose device intended for use by devd.  If I had my druthers, I would
probably like to rename /dev/devctl to /dev/devevents or /dev/devnotify
or some such and create a new /dev/devctl for these control ioctls.  Instead
what I've done for now is create a /dev/devctl2 for the new ioctls.

There is a thin library (libdevctl) that wraps the /dev/devctl2 ioctls and
provides methods like devctl_detach(), etc.  The thin library even has a
manpage already.

The devctl(8) utility is then a thin wrapper around libdevctl (and does not
yet have a manpage).

Do folks have any feedback?

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3200196.9ZgXApgRdA>