aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pci/pci_iov.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/pci_iov.c')
-rw-r--r--sys/dev/pci/pci_iov.c156
1 files changed, 154 insertions, 2 deletions
diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c
index c8e139f043c9..1f72391fb6b4 100644
--- a/sys/dev/pci/pci_iov.c
+++ b/sys/dev/pci/pci_iov.c
@@ -43,10 +43,10 @@
#include <sys/pciio.h>
#include <sys/queue.h>
#include <sys/rman.h>
+#include <sys/stdarg.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
-#include <machine/stdarg.h>
#include <sys/nv.h>
#include <sys/iov_schema.h>
@@ -670,7 +670,7 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
}
}
- bus_generic_attach(bus);
+ bus_attach_children(bus);
}
static int
@@ -736,6 +736,7 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg)
/* We don't yet support allocating extra bus numbers for VFs. */
if (pci_get_bus(dev) != PCI_RID2BUS(last_rid)) {
+ device_printf(dev, "not enough PCIe bus numbers for VFs\n");
error = ENOSPC;
goto out;
}
@@ -1070,6 +1071,12 @@ pci_vf_release_mem_resource(device_t dev, device_t child, struct resource *r)
dinfo = device_get_ivars(child);
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &dinfo->cfg.iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
if (rman_get_flags(r) & RF_ACTIVE) {
error = bus_deactivate_resource(child, r);
if (error != 0)
@@ -1086,3 +1093,148 @@ pci_vf_release_mem_resource(device_t dev, device_t child, struct resource *r)
return (rman_release_resource(r));
}
+
+int
+pci_vf_activate_mem_resource(device_t dev, device_t child, struct resource *r)
+{
+#ifdef INVARIANTS
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+#endif
+ struct resource_map map;
+ int error;
+
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &dinfo->cfg.iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
+ error = rman_activate_resource(r);
+ if (error != 0)
+ return (error);
+
+ if ((rman_get_flags(r) & RF_UNMAPPED) == 0) {
+ error = BUS_MAP_RESOURCE(dev, child, r, NULL, &map);
+ if (error != 0) {
+ rman_deactivate_resource(r);
+ return (error);
+ }
+
+ rman_set_mapping(r, &map);
+ }
+ return (0);
+}
+
+int
+pci_vf_deactivate_mem_resource(device_t dev, device_t child, struct resource *r)
+{
+#ifdef INVARIANTS
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+#endif
+ struct resource_map map;
+ int error;
+
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &dinfo->cfg.iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
+ error = rman_deactivate_resource(r);
+ if (error != 0)
+ return (error);
+
+ if ((rman_get_flags(r) & RF_UNMAPPED) == 0) {
+ rman_get_mapping(r, &map);
+ BUS_UNMAP_RESOURCE(dev, child, r, &map);
+ }
+ return (0);
+}
+
+int
+pci_vf_adjust_mem_resource(device_t dev, device_t child, struct resource *r,
+ rman_res_t start, rman_res_t end)
+{
+#ifdef INVARIANTS
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+#endif
+
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &dinfo->cfg.iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
+ return (rman_adjust_resource(r, start, end));
+}
+
+static struct resource *
+pci_vf_find_parent_resource(struct pcicfg_iov *iov, struct resource *r)
+{
+ struct resource *pres;
+
+ for (u_int i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ pres = iov->iov_bar[i].res;
+ if (pres != NULL) {
+ if (rman_get_start(pres) <= rman_get_start(r) &&
+ rman_get_end(pres) >= rman_get_end(r))
+ return (pres);
+ }
+ }
+ return (NULL);
+}
+
+int
+pci_vf_map_mem_resource(device_t dev, device_t child, struct resource *r,
+ struct resource_map_request *argsp, struct resource_map *map)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ struct pcicfg_iov *iov = dinfo->cfg.iov;
+ struct resource_map_request args;
+ struct resource *pres;
+ rman_res_t length, start;
+ int error;
+
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
+ /* Resources must be active to be mapped. */
+ if (!(rman_get_flags(r) & RF_ACTIVE))
+ return (ENXIO);
+
+ resource_init_map_request(&args);
+ error = resource_validate_map_request(r, argsp, &args, &start, &length);
+ if (error)
+ return (error);
+
+ pres = pci_vf_find_parent_resource(dinfo->cfg.iov, r);
+ if (pres == NULL)
+ return (ENOENT);
+
+ args.offset = start - rman_get_start(pres);
+ args.length = length;
+ return (bus_map_resource(iov->iov_pf, pres, &args, map));
+}
+
+int
+pci_vf_unmap_mem_resource(device_t dev, device_t child, struct resource *r,
+ struct resource_map *map)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ struct pcicfg_iov *iov = dinfo->cfg.iov;
+ struct resource *pres;
+
+ KASSERT(rman_get_type(r) == SYS_RES_MEMORY,
+ ("%s: invalid resource %p", __func__, r));
+ KASSERT(rman_is_region_manager(r, &iov->rman),
+ ("%s: rman %p doesn't match for resource %p", __func__,
+ &dinfo->cfg.iov->rman, r));
+
+ pres = pci_vf_find_parent_resource(iov, r);
+ if (pres == NULL)
+ return (ENOENT);
+ return (bus_unmap_resource(iov->iov_pf, pres, map));
+}