summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pciconf/pciconf.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-02-02 19:54:16 +0000
committerjhb <jhb@FreeBSD.org>2009-02-02 19:54:16 +0000
commitfafb6ced88907b5b8a97eb1197547f7e88bb2b7c (patch)
treea62a7bd4e4111906cdc630730dbde725062184bd /usr.sbin/pciconf/pciconf.c
parent2660392853b1e799fc0aedf0753fdb1180f79b8b (diff)
downloadFreeBSD-src-fafb6ced88907b5b8a97eb1197547f7e88bb2b7c.zip
FreeBSD-src-fafb6ced88907b5b8a97eb1197547f7e88bb2b7c.tar.gz
- Add a new ioctl to /dev/pci to fetch details on an individual BAR of a
device. The details include the current value of the BAR (including all the flag bits and the current base address), its length, and whether or not it is enabled. Since this operation is not invasive, non-root users are allowed to use it (unlike manual config register access which requires root). The intention is that userland apps (such as Xorg) will use this interface rather than dangerously frobbing the BARs from userland to obtain this information. - Add a new sub-mode to the 'list' mode of pciconf. The -b flag when used with -l will now list all the active BARs for each device. MFC after: 1 month
Diffstat (limited to 'usr.sbin/pciconf/pciconf.c')
-rw-r--r--usr.sbin/pciconf/pciconf.c75
1 files changed, 69 insertions, 6 deletions
diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index 4234a84..7d1da2d 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -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;
OpenPOWER on IntegriCloud