Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Mar 2026 16:53:53 +0000
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 9eb035ff8439 - main - pciconf: Factor out fetching of matching devices from list_devs
Message-ID:  <69b04ca1.454f4.3db1a766@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=9eb035ff8439195f565b9e3180b727333a4e7170

commit 9eb035ff8439195f565b9e3180b727333a4e7170
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-03-10 16:48:04 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-03-10 16:48:04 +0000

    pciconf: Factor out fetching of matching devices from list_devs
    
    The new fetch_devs function fetches the entire list of PCI devices
    into a single list, retrying if the list changes while it is being
    fetched.
    
    Reviewed by:    imp
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D55768
---
 usr.sbin/pciconf/pciconf.c | 168 ++++++++++++++++++++++++++-------------------
 1 file changed, 96 insertions(+), 72 deletions(-)

diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index 4d3941131858..6aa33d332c08 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -200,23 +200,13 @@ main(int argc, char **argv)
 	return (exitstatus);
 }
 
-static void
-list_devs(const char *name, int verbose, int bars, int bridge, int caps,
-    int errors, int vpd, int listmode)
+static bool
+fetch_devs(int fd, const char *name, struct pci_conf **confp, size_t *countp)
 {
-	int fd;
 	struct pci_conf_io pc;
 	struct pci_conf conf[255], *p;
 	struct pci_match_conf patterns[1];
-	int none_count = 0;
-
-	if (verbose)
-		load_vendors();
-
-	fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY,
-	    0);
-	if (fd < 0)
-		err(1, "%s", _PATH_DEVPCI);
+	size_t count;
 
 	bzero(&pc, sizeof(struct pci_conf_io));
 	pc.match_buf_len = sizeof(conf);
@@ -232,75 +222,109 @@ list_devs(const char *name, int verbose, int bars, int bridge, int caps,
 		pc.patterns = patterns;
 	}
 
+	p = NULL;
+	count = 0;
 	do {
 		if (ioctl(fd, PCIOCGETCONF, &pc) == -1)
 			err(1, "ioctl(PCIOCGETCONF)");
 
-		/*
-		 * 255 entries should be more than enough for most people,
-		 * but if someone has more devices, and then changes things
-		 * around between ioctls, we'll do the cheesy thing and
-		 * just bail.  The alternative would be to go back to the
-		 * beginning of the list, and print things twice, which may
-		 * not be desirable.
-		 */
 		if (pc.status == PCI_GETCONF_LIST_CHANGED) {
-			warnx("PCI device list changed, please try again");
-			exitstatus = 1;
-			close(fd);
-			return;
-		} else if (pc.status ==  PCI_GETCONF_ERROR) {
+			free(p);
+			p = NULL;
+			count = 0;
+			pc.offset = 0;
+			continue;
+		}
+
+		if (pc.status == PCI_GETCONF_ERROR) {
 			warnx("error returned from PCIOCGETCONF ioctl");
-			exitstatus = 1;
-			close(fd);
-			return;
+			return (false);
 		}
-		if (listmode == 2)
-			printf("drv\tselector\tclass    rev  hdr  "
-			    "vendor device subven subdev\n");
-		for (p = conf; p < &conf[pc.num_matches]; p++) {
-			if (listmode == 2)
-				printf("%s%d@pci%d:%d:%d:%d:"
-				    "\t%06x   %02x   %02x   "
-				    "%04x   %04x   %04x   %04x\n",
-				    *p->pd_name ? p->pd_name : "none",
-				    *p->pd_name ? (int)p->pd_unit :
-				    none_count++, p->pc_sel.pc_domain,
-				    p->pc_sel.pc_bus, p->pc_sel.pc_dev,
-				    p->pc_sel.pc_func, (p->pc_class << 16) |
-				    (p->pc_subclass << 8) | p->pc_progif,
-				    p->pc_revid, p->pc_hdr,
-				    p->pc_vendor, p->pc_device,
-				    p->pc_subvendor, p->pc_subdevice);
-			else
-				printf("%s%d@pci%d:%d:%d:%d:"
-				    "\tclass=0x%06x rev=0x%02x hdr=0x%02x "
-				    "vendor=0x%04x device=0x%04x "
-				    "subvendor=0x%04x subdevice=0x%04x\n",
-				    *p->pd_name ? p->pd_name : "none",
-				    *p->pd_name ? (int)p->pd_unit :
-				    none_count++, p->pc_sel.pc_domain,
-				    p->pc_sel.pc_bus, p->pc_sel.pc_dev,
-				    p->pc_sel.pc_func, (p->pc_class << 16) |
-				    (p->pc_subclass << 8) | p->pc_progif,
-				    p->pc_revid, p->pc_hdr,
-				    p->pc_vendor, p->pc_device,
-				    p->pc_subvendor, p->pc_subdevice);
-			if (verbose)
-				list_verbose(p);
-			if (bars)
-				list_bars(fd, p);
-			if (bridge)
-				list_bridge(fd, p);
-			if (caps)
-				list_caps(fd, p, caps);
-			if (errors)
-				list_errors(fd, p);
-			if (vpd)
-				list_vpd(fd, p);
+
+		p = reallocf(p, (count + pc.num_matches) * sizeof(*p));
+		if (p == NULL) {
+			warnx("failed to allocate buffer for PCIOCGETCONF results");
+			return (false);
 		}
+
+		memcpy(p + count, conf, pc.num_matches * sizeof(*p));
+		count += pc.num_matches;
 	} while (pc.status == PCI_GETCONF_MORE_DEVS);
 
+	*confp = p;
+	*countp = count;
+	return (true);
+}
+
+static void
+list_devs(const char *name, int verbose, int bars, int bridge, int caps,
+    int errors, int vpd, int listmode)
+{
+	int fd;
+	struct pci_conf *conf, *p;
+	size_t count;
+	int none_count = 0;
+
+	if (verbose)
+		load_vendors();
+
+	fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY,
+	    0);
+	if (fd < 0)
+		err(1, "%s", _PATH_DEVPCI);
+
+	if (!fetch_devs(fd, name, &conf, &count)) {
+		exitstatus = 1;
+		close(fd);
+		return;
+	}
+
+	if (listmode == 2)
+		printf("drv\tselector\tclass    rev  hdr  "
+		    "vendor device subven subdev\n");
+	for (p = conf; p < conf + count; p++) {
+		if (listmode == 2)
+			printf("%s%d@pci%d:%d:%d:%d:"
+			    "\t%06x   %02x   %02x   "
+			    "%04x   %04x   %04x   %04x\n",
+			    *p->pd_name ? p->pd_name : "none",
+			    *p->pd_name ? (int)p->pd_unit :
+			    none_count++, p->pc_sel.pc_domain,
+			    p->pc_sel.pc_bus, p->pc_sel.pc_dev,
+			    p->pc_sel.pc_func, (p->pc_class << 16) |
+			    (p->pc_subclass << 8) | p->pc_progif,
+			    p->pc_revid, p->pc_hdr,
+			    p->pc_vendor, p->pc_device,
+			    p->pc_subvendor, p->pc_subdevice);
+		else
+			printf("%s%d@pci%d:%d:%d:%d:"
+			    "\tclass=0x%06x rev=0x%02x hdr=0x%02x "
+			    "vendor=0x%04x device=0x%04x "
+			    "subvendor=0x%04x subdevice=0x%04x\n",
+			    *p->pd_name ? p->pd_name : "none",
+			    *p->pd_name ? (int)p->pd_unit :
+			    none_count++, p->pc_sel.pc_domain,
+			    p->pc_sel.pc_bus, p->pc_sel.pc_dev,
+			    p->pc_sel.pc_func, (p->pc_class << 16) |
+			    (p->pc_subclass << 8) | p->pc_progif,
+			    p->pc_revid, p->pc_hdr,
+			    p->pc_vendor, p->pc_device,
+			    p->pc_subvendor, p->pc_subdevice);
+		if (verbose)
+			list_verbose(p);
+		if (bars)
+			list_bars(fd, p);
+		if (bridge)
+			list_bridge(fd, p);
+		if (caps)
+			list_caps(fd, p, caps);
+		if (errors)
+			list_errors(fd, p);
+		if (vpd)
+			list_vpd(fd, p);
+	}
+
+	free(conf);
 	close(fd);
 }
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69b04ca1.454f4.3db1a766>