Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 26 Feb 2009 18:54:25 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r189080 - in stable/7: sys sys/contrib/pf sys/dev/ath/ath_hal sys/dev/cardbus sys/dev/cxgb sys/dev/pci sys/sys usr.sbin/pciconf
Message-ID:  <200902261854.n1QIsPLP035420@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Thu Feb 26 18:54:24 2009
New Revision: 189080
URL: http://svn.freebsd.org/changeset/base/189080

Log:
  MFC: Add a new ioctl to fetch details about an individual BAR of a device
  and add support for displaying BAR details via a new pciconf flag.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cardbus/cardbus.c
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/dev/pci/pci_user.c
  stable/7/sys/dev/pci/pcireg.h
  stable/7/sys/sys/pciio.h
  stable/7/usr.sbin/pciconf/   (props changed)
  stable/7/usr.sbin/pciconf/pciconf.8
  stable/7/usr.sbin/pciconf/pciconf.c

Modified: stable/7/sys/dev/cardbus/cardbus.c
==============================================================================
--- stable/7/sys/dev/cardbus/cardbus.c	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/sys/dev/cardbus/cardbus.c	Thu Feb 26 18:54:24 2009	(r189080)
@@ -145,7 +145,7 @@ cardbus_device_setup_regs(pcicfgregs *cf
 	 * Some cards power up with garbage in their BARs.  This
 	 * code clears all that junk out.
 	 */
-	for (i = 0; i < PCI_MAX_BAR_0; i++)
+	for (i = 0; i < PCIR_MAX_BAR_0; i++)
 		pci_write_config(dev, PCIR_BAR(i), 0, 4);
 
 	cfg->intline =

Modified: stable/7/sys/dev/pci/pci_user.c
==============================================================================
--- stable/7/sys/dev/pci/pci_user.c	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/sys/dev/pci/pci_user.c	Thu Feb 26 18:54:24 2009	(r189080)
@@ -307,7 +307,10 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
 	struct pci_conf_io *cio;
 	struct pci_devinfo *dinfo;
 	struct pci_io *io;
+	struct pci_bar_io *bio;
 	struct pci_match_conf *pattern_buf;
+	struct resource_list_entry *rle;
+	uint32_t value;
 	size_t confsz, iolen, pbufsz;
 	int error, ionum, i, num_patterns;
 #ifdef PRE7_COMPAT
@@ -319,11 +322,11 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
 	io_old = NULL;
 	pattern_buf_old = NULL;
 
-	if (!(flag & FWRITE) &&
-	    (cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD))
+	if (!(flag & FWRITE) && cmd != PCIOCGETBAR &&
+	    cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD)
 		return EPERM;
 #else
-	if (!(flag & FWRITE) && cmd != PCIOCGETCONF)
+	if (!(flag & FWRITE) && cmd != PCIOCGETBAR && cmd != PCIOCGETCONF)
 		return EPERM;
 #endif
 
@@ -669,6 +672,70 @@ getconfexit:
 		}
 		break;
 
+	case PCIOCGETBAR:
+		bio = (struct pci_bar_io *)data;
+
+		/*
+		 * Assume that the user-level bus number is
+		 * in fact the physical PCI bus number.
+		 */
+		pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
+		    bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
+		    bio->pbi_sel.pc_func);
+		if (pcidev == NULL) {
+			error = ENODEV;
+			break;
+		}
+		dinfo = device_get_ivars(pcidev);
+		
+		/*
+		 * Look for a resource list entry matching the requested BAR.
+		 *
+		 * XXX: This will not find BARs that are not initialized, but
+		 * maybe that is ok?
+		 */
+		rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
+		    bio->pbi_reg);
+		if (rle == NULL)
+			rle = resource_list_find(&dinfo->resources,
+			    SYS_RES_IOPORT, bio->pbi_reg);
+		if (rle == NULL || rle->res == NULL) {
+			error = EINVAL;
+			break;
+		}
+
+		/*
+		 * Ok, we have a resource for this BAR.  Read the lower
+		 * 32 bits to get any flags.
+		 */
+		value = pci_read_config(pcidev, bio->pbi_reg, 4);
+		if (PCI_BAR_MEM(value)) {
+			if (rle->type != SYS_RES_MEMORY) {
+				error = EINVAL;
+				break;
+			}
+			value &= ~PCIM_BAR_MEM_BASE;
+		} else {
+			if (rle->type != SYS_RES_IOPORT) {
+				error = EINVAL;
+				break;
+			}
+			value &= ~PCIM_BAR_IO_BASE;
+		}
+		bio->pbi_base = rman_get_start(rle->res) | value;
+		bio->pbi_length = rman_get_size(rle->res);
+
+		/*
+		 * Check the command register to determine if this BAR
+		 * is enabled.
+		 */
+		value = pci_read_config(pcidev, PCIR_COMMAND, 2);
+		if (rle->type == SYS_RES_MEMORY)
+			bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0;
+		else
+			bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0;
+		error = 0;
+		break;
 	default:
 		error = ENOTTY;
 		break;

Modified: stable/7/sys/dev/pci/pcireg.h
==============================================================================
--- stable/7/sys/dev/pci/pcireg.h	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/sys/dev/pci/pcireg.h	Thu Feb 26 18:54:24 2009	(r189080)
@@ -117,7 +117,7 @@
 
 #define	PCIR_BARS	0x10
 #define	PCIR_BAR(x)		(PCIR_BARS + (x) * 4)
-#define	PCI_MAX_BAR_0		5	/* Number of standard bars */
+#define	PCIR_MAX_BAR_0		5
 #define	PCI_RID2BAR(rid)	(((rid) - PCIR_BARS) / 4)
 #define	PCI_BAR_IO(x)		(((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE)
 #define	PCI_BAR_MEM(x)		(((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE)
@@ -158,6 +158,7 @@
 
 /* config registers for header type 1 (PCI-to-PCI bridge) devices */
 
+#define	PCIR_MAX_BAR_1	1
 #define	PCIR_SECSTAT_1	0x1e
 
 #define	PCIR_PRIBUS_1	0x18
@@ -188,6 +189,7 @@
 
 /* config registers for header type 2 (CardBus) devices */
 
+#define	PCIR_MAX_BAR_2	0
 #define	PCIR_CAP_PTR_2	0x14
 #define	PCIR_SECSTAT_2	0x16
 

Modified: stable/7/sys/sys/pciio.h
==============================================================================
--- stable/7/sys/sys/pciio.h	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/sys/sys/pciio.h	Thu Feb 26 18:54:24 2009	(r189080)
@@ -108,9 +108,18 @@ struct pci_io {
 	u_int32_t	pi_data;	/* data to write or result of read */
 };
 
+struct pci_bar_io {
+	struct pcisel	pbi_sel;	/* device to operate on */
+	int		pbi_reg;	/* starting address of BAR */
+	int		pbi_enabled;	/* decoding enabled */
+	uint64_t	pbi_base;	/* current value of BAR */
+	uint64_t	pbi_length;	/* length of BAR */
+};
+
 #define	PCIOCGETCONF	_IOWR('p', 5, struct pci_conf_io)
 #define	PCIOCREAD	_IOWR('p', 2, struct pci_io)
 #define	PCIOCWRITE	_IOWR('p', 3, struct pci_io)
 #define	PCIOCATTACHED	_IOWR('p', 4, struct pci_io)
+#define	PCIOCGETBAR	_IOWR('p', 6, struct pci_bar_io)
 
 #endif /* !_SYS_PCIIO_H_ */

Modified: stable/7/usr.sbin/pciconf/pciconf.8
==============================================================================
--- stable/7/usr.sbin/pciconf/pciconf.8	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/usr.sbin/pciconf/pciconf.8	Thu Feb 26 18:54:24 2009	(r189080)
@@ -33,7 +33,7 @@
 .Nd diagnostic utility for the PCI bus
 .Sh SYNOPSIS
 .Nm
-.Fl l Op Fl cv
+.Fl l Op Fl bcv
 .Nm
 .Fl a Ar selector
 .Nm
@@ -112,6 +112,32 @@ device, which contains several (similar 
 one chip.
 .Pp
 If the
+.Fl b
+option is supplied,
+.Nm
+will list any base address registers
+.Pq BARs
+that are assigned resources for each device.
+Each BAR will be enumerated via a line in the following format:
+.Bd -literal
+    bar   [10] = type Memory, range 32, base 0xda060000, size 131072, enabled
+.Ed
+.Pp
+The first value after the
+.Dq Li bar
+prefix in the square brackets is the offset of the BAR in config space in
+hexadecimal.
+The type of a BAR is one of
+.Dq Memory ,
+.Dq Prefetchable Memory ,
+or
+.Dq I/O Port .
+The range indicates the maximum address the BAR decodes.
+The base and size indicate the start and length of the BAR's address window,
+respectively.
+Finally, the last flag indicates if the BAR is enabled or disabled.
+.Pp
+If the
 .Fl c
 option is supplied,
 .Nm

Modified: stable/7/usr.sbin/pciconf/pciconf.c
==============================================================================
--- stable/7/usr.sbin/pciconf/pciconf.c	Thu Feb 26 18:46:22 2009	(r189079)
+++ stable/7/usr.sbin/pciconf/pciconf.c	Thu Feb 26 18:54:24 2009	(r189080)
@@ -37,6 +37,7 @@ static const char rcsid[] =
 
 #include <ctype.h>
 #include <err.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -66,7 +67,8 @@ struct pci_vendor_info
 
 TAILQ_HEAD(,pci_vendor_info)	pci_vendors;
 
-static void list_devs(int verbose, int caps);
+static void list_bars(int fd, struct pci_conf *p);
+static void list_devs(int verbose, int bars, int caps);
 static void list_verbose(struct pci_conf *p);
 static const char *guess_class(struct pci_conf *p);
 static const char *guess_subclass(struct pci_conf *p);
@@ -81,7 +83,7 @@ static void
 usage(void)
 {
 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
-		"usage: pciconf -l [-cv]",
+		"usage: pciconf -l [-bcv]",
 		"       pciconf -a selector",
 		"       pciconf -r [-b | -h] selector addr[:addr2]",
 		"       pciconf -w [-b | -h] selector addr value");
@@ -92,10 +94,10 @@ int
 main(int argc, char **argv)
 {
 	int c;
-	int listmode, readmode, writemode, attachedmode, caps, verbose;
+	int listmode, readmode, writemode, attachedmode, bars, caps, verbose;
 	int byte, isshort;
 
-	listmode = readmode = writemode = attachedmode = caps = verbose = byte = isshort = 0;
+	listmode = readmode = writemode = attachedmode = bars = caps = verbose = byte = isshort = 0;
 
 	while ((c = getopt(argc, argv, "abchlrwv")) != -1) {
 		switch(c) {
@@ -104,6 +106,7 @@ main(int argc, char **argv)
 			break;
 
 		case 'b':
+			bars = 1;
 			byte = 1;
 			break;
 
@@ -143,7 +146,7 @@ main(int argc, char **argv)
 		usage();
 
 	if (listmode) {
-		list_devs(verbose, caps);
+		list_devs(verbose, bars, caps);
 	} else if (attachedmode) {
 		chkattached(argv[optind],
 		       byte ? 1 : isshort ? 2 : 4);
@@ -161,7 +164,7 @@ main(int argc, char **argv)
 }
 
 static void
-list_devs(int verbose, int caps)
+list_devs(int verbose, int bars, int caps)
 {
 	int fd;
 	struct pci_conf_io pc;
@@ -217,6 +220,8 @@ list_devs(int verbose, int caps)
 			       p->pc_revid, p->pc_hdr);
 			if (verbose)
 				list_verbose(p);
+			if (bars)
+				list_bars(fd, p);
 			if (caps)
 				list_caps(fd, p);
 		}
@@ -226,6 +231,64 @@ list_devs(int verbose, int caps)
 }
 
 static void
+list_bars(int fd, struct pci_conf *p)
+{
+	struct pci_bar_io bar;
+	uint64_t base;
+	const char *type;
+	int i, range, max;
+
+	switch (p->pc_hdr & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_NORMAL:
+		max = PCIR_MAX_BAR_0;
+		break;
+	case PCIM_HDRTYPE_BRIDGE:
+		max = PCIR_MAX_BAR_1;
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		max = PCIR_MAX_BAR_2;
+		break;
+	default:
+		return;
+	}
+
+	for (i = 0; i <= max; i++) {
+		bar.pbi_sel = p->pc_sel;
+		bar.pbi_reg = PCIR_BAR(i);
+		if (ioctl(fd, PCIOCGETBAR, &bar) < 0)
+			continue;
+		if (PCI_BAR_IO(bar.pbi_base)) {
+			type = "I/O Port";
+			range = 32;
+			base = bar.pbi_base & PCIM_BAR_IO_BASE;
+		} else {
+			if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
+				type = "Prefetchable Memory";
+			else
+				type = "Memory";
+			switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
+			case PCIM_BAR_MEM_32:
+				range = 32;
+				break;
+			case PCIM_BAR_MEM_1MB:
+				range = 20;
+				break;
+			case PCIM_BAR_MEM_64:
+				range = 64;
+				break;
+			default:
+				range = -1;
+			}
+			base = bar.pbi_base & ~((uint64_t)0xf);
+		}
+		printf("    bar   [%02x] = type %s, range %2d, base %#jx, ",
+		    PCIR_BAR(i), type, range, (uintmax_t)base);
+		printf("size %2d, %s\n", (int)bar.pbi_length,
+		    bar.pbi_enabled ? "enabled" : "disabled");
+	}
+}
+
+static void
 list_verbose(struct pci_conf *p)
 {
 	struct pci_vendor_info	*vi;



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