pci: Export bus numbers for bridge devices in struct pci_conf

This exports bus information about bridges to userspace via the
less-privileged PCIOCGETCONF ioctl.  Previously if userspace wished to
query this information, it had to use direct PCI config register
access which requires higher privilege.

Reviewed by:	imp
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D55771
This commit is contained in:
John Baldwin
2026-03-10 12:49:21 -04:00
parent c3ac5f14c8
commit 7e7a1b6153
4 changed files with 43 additions and 2 deletions
+6
View File
@@ -244,6 +244,12 @@ structure.
This should always be equivalent to the offset of the
.Va pc_spare
member.
.It pc_secbus
Secondary PCI bus number.
.Pq Only valid for bridge devices
.It pc_subbus
Subordinate PCI bus number.
.Pq Only valid for bridge devices
.It pc_spare
Reserved for future use.
.El
+3
View File
@@ -798,6 +798,9 @@ pci_fill_devinfo(device_t pcib, device_t bus, int d, int b, int s, int f,
devlist_entry->conf.pc_progif = cfg->progif;
devlist_entry->conf.pc_revid = cfg->revid;
devlist_entry->conf.pc_secbus = cfg->bridge.br_secbus;
devlist_entry->conf.pc_subbus = cfg->bridge.br_subbus;
pci_numdevs++;
pci_generation++;
+31 -1
View File
@@ -81,7 +81,9 @@ struct pci_conf32 {
u_int32_t pd_unit; /* device unit number */
int pd_numa_domain; /* device NUMA domain */
u_int32_t pc_reported_len;/* length of PCI data reported */
char pc_spare[64]; /* space for future fields */
uint8_t pc_secbus; /* secondary bus number */
uint8_t pc_subbus; /* subordinate bus number */
char pc_spare[62]; /* space for future fields */
};
struct pci_match_conf32 {
@@ -889,6 +891,8 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit;
if (cmd == PCIOCGETCONF32) {
pcup->pc32.pd_numa_domain = pcp->pd_numa_domain;
pcup->pc32.pc_secbus = pcp->pc_secbus;
pcup->pc32.pc_subbus = pcp->pc_subbus;
pcup->pc32.pc_reported_len =
(uint32_t)offsetof(struct pci_conf32, pc_spare);
}
@@ -1315,6 +1319,32 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
else
dinfo->conf.pd_numa_domain = 0;
if (dinfo->cfg.dev != NULL) {
/*
* Re-read the values in case a driver
* changed them after the device was
* initially scanned.
*/
switch (dinfo->conf.pc_hdr) {
case PCIM_HDRTYPE_BRIDGE:
dinfo->conf.pc_secbus =
pci_read_config(dinfo->cfg.dev,
PCIR_SECBUS_1, 1);
dinfo->conf.pc_subbus =
pci_read_config(dinfo->cfg.dev,
PCIR_SUBBUS_1, 1);
break;
case PCIM_HDRTYPE_CARDBUS:
dinfo->conf.pc_secbus =
pci_read_config(dinfo->cfg.dev,
PCIR_SECBUS_2, 1);
dinfo->conf.pc_subbus =
pci_read_config(dinfo->cfg.dev,
PCIR_SUBBUS_2, 1);
break;
}
}
if (pattern_buf == NULL ||
pci_conf_match(cmd, pattern_buf, num_patterns,
&dinfo->conf) == 0) {
+3 -1
View File
@@ -79,7 +79,9 @@ struct pci_conf {
u_long pd_unit; /* device unit number */
int pd_numa_domain; /* device NUMA domain */
size_t pc_reported_len;/* length of PCI data reported */
char pc_spare[64]; /* space for future fields */
uint8_t pc_secbus; /* secondary bus number */
uint8_t pc_subbus; /* subordinate bus number */
char pc_spare[62]; /* space for future fields */
};
struct pci_match_conf {