diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -164,10 +164,18 @@ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_delete_resource, pci_delete_resource), DEVMETHOD(bus_alloc_resource, pci_alloc_resource), +#ifdef PCI_IOV + DEVMETHOD(bus_adjust_resource, pci_adjust_resource), +#else DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), +#endif DEVMETHOD(bus_release_resource, pci_release_resource), DEVMETHOD(bus_activate_resource, pci_activate_resource), DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), +#ifdef PCI_IOV + DEVMETHOD(bus_map_resource, pci_map_resource), + DEVMETHOD(bus_unmap_resource, pci_unmap_resource), +#endif DEVMETHOD(bus_child_deleted, pci_child_deleted), DEVMETHOD(bus_child_detached, pci_child_detached), DEVMETHOD(bus_child_pnpinfo, pci_child_pnpinfo_method), @@ -5687,14 +5695,30 @@ struct pci_devinfo *dinfo; int error, rid, type; - error = bus_generic_activate_resource(dev, child, r); + dinfo = device_get_ivars(child); +#ifdef PCI_IOV + if (dinfo->cfg.flags & PCICFG_VF) { + switch (rman_get_type(r)) { + /* VFs can't have I/O BARs. */ + case SYS_RES_IOPORT: + error = EINVAL; + break; + case SYS_RES_MEMORY: + error = pci_vf_activate_mem_resource(dev, child, r); + break; + default: + error = bus_generic_activate_resource(dev, child, r); + break; + } + } else +#endif + error = bus_generic_activate_resource(dev, child, r); if (error) return (error); /* Enable decoding in the command register when activating BARs. */ if (device_get_parent(child) == dev) { /* Device ROMs need their decoding explicitly enabled. */ - dinfo = device_get_ivars(child); rid = rman_get_rid(r); type = rman_get_type(r); if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid)) @@ -5716,13 +5740,29 @@ struct pci_devinfo *dinfo; int error, rid, type; - error = bus_generic_deactivate_resource(dev, child, r); + dinfo = device_get_ivars(child); +#ifdef PCI_IOV + if (dinfo->cfg.flags & PCICFG_VF) { + switch (rman_get_type(r)) { + /* VFs can't have I/O BARs. */ + case SYS_RES_IOPORT: + error = EINVAL; + break; + case SYS_RES_MEMORY: + error = pci_vf_deactivate_mem_resource(dev, child, r); + break; + default: + error = bus_generic_deactivate_resource(dev, child, r); + break; + } + } else +#endif + error = bus_generic_deactivate_resource(dev, child, r); if (error) return (error); /* Disable decoding for device ROMs. */ if (device_get_parent(child) == dev) { - dinfo = device_get_ivars(child); rid = rman_get_rid(r); type = rman_get_type(r); if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid)) @@ -5732,6 +5772,76 @@ return (0); } +#ifdef PCI_IOV +int +pci_adjust_resource(device_t dev, device_t child, struct resource *r, + rman_res_t start, rman_res_t end) +{ + struct pci_devinfo *dinfo; + + dinfo = device_get_ivars(child); + if (dinfo->cfg.flags & PCICFG_VF) { + switch (rman_get_type(r)) { + /* VFs can't have I/O BARs. */ + case SYS_RES_IOPORT: + return (EINVAL); + case SYS_RES_MEMORY: + return (pci_vf_adjust_mem_resource(dev, child, r, + start, end)); + } + + /* Fall through for other types of resource allocations. */ + } + + return (bus_generic_adjust_resource(dev, child, r, start, end)); +} + +int +pci_map_resource(device_t dev, device_t child, struct resource *r, + struct resource_map_request *argsp, struct resource_map *map) +{ + struct pci_devinfo *dinfo; + + dinfo = device_get_ivars(child); + if (dinfo->cfg.flags & PCICFG_VF) { + switch (rman_get_type(r)) { + /* VFs can't have I/O BARs. */ + case SYS_RES_IOPORT: + return (EINVAL); + case SYS_RES_MEMORY: + return (pci_vf_map_mem_resource(dev, child, r, argsp, + map)); + } + + /* Fall through for other types of resource allocations. */ + } + + return (bus_generic_map_resource(dev, child, r, argsp, map)); +} + +int +pci_unmap_resource(device_t dev, device_t child, struct resource *r, + struct resource_map *map) +{ + struct pci_devinfo *dinfo; + + dinfo = device_get_ivars(child); + if (dinfo->cfg.flags & PCICFG_VF) { + switch (rman_get_type(r)) { + /* VFs can't have I/O BARs. */ + case SYS_RES_IOPORT: + return (EINVAL); + case SYS_RES_MEMORY: + return (pci_vf_unmap_mem_resource(dev, child, r, map)); + } + + /* Fall through for other types of resource allocations. */ + } + + return (bus_generic_unmap_resource(dev, child, r, map)); +} +#endif + void pci_child_deleted(device_t dev, device_t child) { diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c --- a/sys/dev/pci/pci_iov.c +++ b/sys/dev/pci/pci_iov.c @@ -1070,6 +1070,12 @@ 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 +1092,147 @@ 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_generic_map_resource(dev, 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; + + 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)); + + r = pci_vf_find_parent_resource(iov, r); + if (r == NULL) + return (ENOENT); + return (bus_generic_unmap_resource(dev, iov->iov_pf, r, map)); +} diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -65,9 +65,16 @@ bus_get_resource_list_t pci_get_resource_list; bus_delete_resource_t pci_delete_resource; bus_alloc_resource_t pci_alloc_resource; +#ifdef PCI_IOV +bus_adjust_resource_t pci_adjust_resource; +#endif bus_release_resource_t pci_release_resource; bus_activate_resource_t pci_activate_resource; bus_deactivate_resource_t pci_deactivate_resource; +#ifdef PCI_IOV +bus_map_resource_t pci_map_resource; +bus_unmap_resource_t pci_unmap_resource; +#endif bus_child_deleted_t pci_child_deleted; bus_child_detached_t pci_child_detached; bus_child_pnpinfo_t pci_child_pnpinfo_method; @@ -158,4 +165,16 @@ rman_res_t count, u_int flags); int pci_vf_release_mem_resource(device_t dev, device_t child, struct resource *r); +int pci_vf_activate_mem_resource(device_t dev, device_t child, + struct resource *r); +int pci_vf_deactivate_mem_resource(device_t dev, device_t child, + struct resource *r); +int pci_vf_adjust_mem_resource(device_t dev, device_t child, + struct resource *r, rman_res_t start, rman_res_t end); +int pci_vf_map_mem_resource(device_t dev, device_t child, + struct resource *r, struct resource_map_request *argsp, + struct resource_map *map); +int pci_vf_unmap_mem_resource(device_t dev, device_t child, + struct resource *r, struct resource_map *map); + #endif /* _PCI_PRIVATE_H_ */