summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/pci_user.c73
-rw-r--r--sys/dev/pci/pcireg.h4
2 files changed, 73 insertions, 4 deletions
diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c
index b7ae55a..ed75353 100644
--- a/sys/dev/pci/pci_user.c
+++ b/sys/dev/pci/pci_user.c
@@ -307,7 +307,10 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
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, caddr_t data, int flag, struct thread *t
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;
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index e9ba5e7..0b69ca4 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -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
OpenPOWER on IntegriCloud