devinfo: Support PCI DBSF and ACPI handles for -p

When matching on a name of a device, match on ACPI handles and PCI
selectors in addition to device names.  This can be useful for
matching on devices without an attached driver.

For example: devinfo -p pci0:0:31:0

Reviewed by:	imp
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D55673
This commit is contained in:
John Baldwin
2026-03-06 15:36:05 -05:00
parent 95dd8736f8
commit ca25b1b263
2 changed files with 78 additions and 2 deletions
+21 -1
View File
@@ -26,7 +26,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd August 28, 2025
.Dd March 6, 2026
.Dt DEVINFO 8
.Os
.Sh NAME
@@ -53,6 +53,26 @@ The following options are accepted:
Display the path of
.Ar dev
back to the root of the device tree.
.Ar dev
can either be a device name,
the absolute path of an ACPI handle
.Po must begin with a
.Dq \e
.Pc ,
or a PCI selector
.Po
either
.Sy pci Ns Fa domain Ns : Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
or
.Sy pci Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
.Pc .
.Pp
If
.Fl v
is specified,
each device is output on a separate line including the device name and
additional verbose information;
otherwise, a space-separated list of device names is output.
.It Fl r
Causes hardware resource information
.Pq such as IRQ, I/O ports, I/O memory addresses
+57 -1
View File
@@ -275,13 +275,69 @@ print_device_path_entry(struct devinfo_dev *dev)
printf("\n");
}
/*
* This assumes the string to be compared in *cp is either space or
* nul terminated.
*/
static bool
match_value(const char *cp, const char *name)
{
const char *end;
size_t len;
end = strchr(cp, ' ');
if (end == NULL)
return (strcmp(cp, name) == 0);
if (end == cp)
return (false);
/* NB: strncmp(3) would return zero if name matches a prefix. */
len = end - cp;
return (strlen(name) == len && memcmp(name, cp, len) == 0);
}
static bool
device_matches_name(struct devinfo_dev *dev, const char *name)
{
const char *cp, *val;
if (strcmp(dev->dd_name, name) == 0)
return (true);
if (*dev->dd_location) {
/* Permit matches on the ACPI handle stored in location. */
if (name[0] == '\\' && (cp = strstr(dev->dd_location,
"handle=\\")) != NULL) {
if (match_value(cp + strlen("handle="), name))
return (true);
}
/* Permit matches on the PCI dbsf stored in location. */
if (strncmp(name, "pci", strlen("pci")) == 0 &&
(cp = strstr(dev->dd_location, "dbsf=pci")) != NULL) {
cp += strlen("dbsf=pci");
val = name + strlen("pci");
if (match_value(cp, val))
return (true);
/* Also match on pci<b>:<s>:<f> for domain 0. */
if (strncmp(cp, "0:", strlen("0:")) == 0 &&
match_value(cp + strlen("0:"), val))
return (true);
}
}
return (false);
}
static int
print_device_path(struct devinfo_dev *dev, void *xname)
{
const char *name = xname;
int rv;
if (strcmp(dev->dd_name, name) == 0) {
if (device_matches_name(dev, name)) {
print_device_path_entry(dev);
return (1);
}