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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to