diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -355,7 +355,6 @@ TAILQ_HEAD(, pci_mmio_region) mmio; }; -int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name); int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv, unsigned int flags); bool pci_device_is_present(struct pci_dev *pdev); @@ -369,7 +368,9 @@ void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res); int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *name); +int linuxkpi_pci_request_region(struct pci_dev *, int, const char *); int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name); +int linuxkpi_pcim_request_all_regions(struct pci_dev *, const char *); void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar); void linuxkpi_pci_release_regions(struct pci_dev *pdev); int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, @@ -562,12 +563,16 @@ return (pdev->bus->self); } +#define pci_request_region(pdev, bar, res_name) \ + linuxkpi_pci_request_region(pdev, bar, res_name) #define pci_release_region(pdev, bar) \ linuxkpi_pci_release_region(pdev, bar) -#define pci_release_regions(pdev) \ - linuxkpi_pci_release_regions(pdev) #define pci_request_regions(pdev, res_name) \ linuxkpi_pci_request_regions(pdev, res_name) +#define pci_release_regions(pdev) \ + linuxkpi_pci_release_regions(pdev) +#define pcim_request_all_regions(pdev, name) \ + linuxkpi_pcim_request_all_regions(pdev, name) static inline void lkpi_pci_disable_msix(struct pci_dev *pdev) diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -1159,8 +1159,9 @@ return (rle->count); } -int -pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) +static int +lkpi_pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, + bool managed) { struct resource *res; struct pci_devres *dr; @@ -1168,9 +1169,20 @@ int rid; int type; + if (!lkpi_pci_bar_id_valid(bar)) + return (-EINVAL); + + /* + * If the bar is not valid, return success without adding the BAR; + * otherwise linuxkpi_pcim_request_all_regions() will error. + */ + if (pci_resource_len(pdev, bar) == 0) + return (0); + /* Likewise if it is neither IO nor MEM, nothing to do for us. */ type = pci_resource_type(pdev, bar); if (type < 0) - return (-ENODEV); + return (0); + rid = PCIR_BAR(bar); res = bus_alloc_resource_any(pdev->dev.bsddev, type, &rid, RF_ACTIVE|RF_SHAREABLE); @@ -1183,11 +1195,16 @@ /* * It seems there is an implicit devres tracking on these if the device - * is managed; otherwise the resources are not automatiaclly freed on - * FreeBSD/LinuxKPI tough they should be/are expected to be by Linux - * drivers. + * is managed (lkpi_pci_devres_find() case); otherwise the resources are + * not automatically freed on FreeBSD/LinuxKPI though they should be/are + * expected to be by Linux drivers. + * Otherwise if we are called from a pcim-function with the managed + * argument set, we need to track devres independent of pdev->managed. */ - dr = lkpi_pci_devres_find(pdev); + if (managed) + dr = lkpi_pci_devres_get_alloc(pdev); + else + dr = lkpi_pci_devres_find(pdev); if (dr != NULL) { dr->region_mask |= (1 << bar); dr->region_table[bar] = res; @@ -1203,6 +1220,12 @@ return (0); } +int +linuxkpi_pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) +{ + return (lkpi_pci_request_region(pdev, bar, res_name, false)); +} + int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name) { @@ -1219,6 +1242,24 @@ return (0); } +int +linuxkpi_pcim_request_all_regions(struct pci_dev *pdev, const char *res_name) +{ + int bar, error; + + for (bar = 0; bar <= PCIR_MAX_BAR_0; bar++) { + error = lkpi_pci_request_region(pdev, bar, res_name, true); + if (error != 0) { + device_printf(pdev->dev.bsddev, "%s: bar %d res_name '%s': " + "lkpi_pci_request_region returned %d\n", __func__, + bar, res_name, error); + pci_release_regions(pdev); + return (error); + } + } + return (0); +} + void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar) {