diff options
| author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2025-07-31 18:28:22 +0000 |
|---|---|---|
| committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-01-16 19:37:47 +0000 |
| commit | c017775775ee7548a071806042b0294e94824991 (patch) | |
| tree | 8ab0d99d7a9682f80c4dcdad0ecab3b9869da847 | |
| parent | 008b9c7db5b28ed38f30e05f9c0bfb6e30156a35 (diff) | |
LinuxKPI: pci: implement [linuxkpi_]pcim_request_all_regions()
Factor out the pci_request_region() implementation into an internal
function and make pci_request_region() a simple wrapperaround it.
Likewise implement pcim_request_all_regions() as a loop calling
pci_request_region() for each entry.
In two cases which we returned an error before (bar index is valid but
bar is not (no len), and neither IO nor MEM) we now reutrn success
(nothing to do for us). Otherwise callers, especially
pcim_request_all_regions() would error out for the wrong reasons.
This seems to also match the expected behaviour of pci_request_region().
Sponsored by: The FreeBSD Foundation (intially)
Reviewed by: dumbbell
Differential Revision: https://reviews.freebsd.org/D52068
LinuxKPI: pci: undo the pci_resource_len() check in lkpi_pci_request_region()
Creating non-passthru SR-IOV interfaces on a mlx5en(4) failed.
The problem lies in the pci_resource_len() call but not that the BAR length
is tmeporary 0 but in that we call lkpi_pci_get_bar() with a true argument
which will create the BAR resource for us and report the approriate length
back. However, the later call to bus_alloc_resource_any() will then fail
given the resource already exists.
Restore the previous behaviour and let bus_alloc_resource_any() do the
work. Adjust the return values from -ENODEV to -EBUSY to match callers
expectations.
In linuxkpi_pcim_request_all_regions(), like in linuxkpi_pci_request_regions(),
filter out the -EBUSY errors as "not an error" and try the next bar.
This also seems to be consistent with the expectations of the callers.
PR: 290793
Reported by: David BOYER (jcduss13 gmail.com)
Tested on: mlx5en, iwlwifi, mt7921
Reviewed by: kib
Fixes: 7e21158d44cd "implement [linuxkpi_]pcim_request_all_regions()"
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D53902
(cherry picked from commit 7e21158d44cd46e720395604ca6f00f2fa36b20c)
(cherry picked from commit ff31767e530abb4a54131af199fed6ec946a5fa4)
(cherry picked from commit ed29ffd396e522a45ab1980c12a75b3409b51712)
(cherry picked from commit 2032abb31cbe067d41067a81e529d91f1bace4c9)
| -rw-r--r-- | sys/compat/linuxkpi/common/include/linux/pci.h | 11 | ||||
| -rw-r--r-- | sys/compat/linuxkpi/common/src/linux_pci.c | 52 |
2 files changed, 51 insertions, 12 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index 20bd399b6170..c22a4403a823 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -347,7 +347,6 @@ struct pci_dev { spinlock_t pcie_cap_lock; }; -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); @@ -361,7 +360,9 @@ void *linuxkpi_pcim_iomap(struct pci_dev *, int, unsigned long); 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, @@ -541,12 +542,16 @@ done: 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 index 0d8cfdeb576d..deea5df06c4a 100644 --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -1140,8 +1140,9 @@ pci_resource_len(struct pci_dev *pdev, int bar) 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; @@ -1149,9 +1150,13 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) int rid; int type; + if (!lkpi_pci_bar_id_valid(bar)) + return (-EINVAL); + 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); @@ -1159,16 +1164,21 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) device_printf(pdev->dev.bsddev, "%s: failed to alloc " "bar %d type %d rid %d\n", __func__, bar, type, PCIR_BAR(bar)); - return (-ENODEV); + return (-EBUSY); } /* * 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; @@ -1185,6 +1195,12 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) } 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) { int error; @@ -1192,7 +1208,25 @@ linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name) for (i = 0; i <= PCIR_MAX_BAR_0; i++) { error = pci_request_region(pdev, i, res_name); - if (error && error != -ENODEV) { + if (error && error != -EBUSY) { + pci_release_regions(pdev); + return (error); + } + } + 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 && error != -EBUSY) { + 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); } |
