PCI: endpoint: Retain fixed-size BAR size as well as aligned size
authorJerome Brunet <jbrunet@baylibre.com>
Thu, 24 Apr 2025 08:34:04 +0000 (10:34 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 28 May 2025 21:15:40 +0000 (16:15 -0500)
When allocating space for an endpoint function on a BAR with a fixed size,
the size saved in 'struct pci_epf_bar.size' should be the fixed size as
expected by pci_epc_set_bar().

However, if pci_epf_alloc_space() increased the allocation size to
accommodate iATU alignment requirements, it previously saved the larger
aligned size in .size, which broke pci_epc_set_bar().

To solve this, keep the fixed BAR size in .size and save the aligned size
in a new .aligned_size for use when deallocating it.

Fixes: 2a9a801620ef ("PCI: endpoint: Add support to specify alignment for buffers allocated to BARs")
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
[mani: commit message fixup]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[bhelgaas: more specific subject, commit log, wrap comment to match file]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20250424-pci-ep-size-alignment-v5-1-2d4ec2af23f5@baylibre.com
drivers/pci/endpoint/pci-epf-core.c
include/linux/pci-epf.h

index 394395c7f8decfa2010469655a4bd58a002993fd..577a9e490115c9dd5d7fb624c4a3001f39b97e78 100644 (file)
@@ -236,12 +236,13 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
        }
 
        dev = epc->dev.parent;
-       dma_free_coherent(dev, epf_bar[bar].size, addr,
+       dma_free_coherent(dev, epf_bar[bar].aligned_size, addr,
                          epf_bar[bar].phys_addr);
 
        epf_bar[bar].phys_addr = 0;
        epf_bar[bar].addr = NULL;
        epf_bar[bar].size = 0;
+       epf_bar[bar].aligned_size = 0;
        epf_bar[bar].barno = 0;
        epf_bar[bar].flags = 0;
 }
@@ -264,7 +265,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
                          enum pci_epc_interface_type type)
 {
        u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
-       size_t align = epc_features->align;
+       size_t aligned_size, align = epc_features->align;
        struct pci_epf_bar *epf_bar;
        dma_addr_t phys_addr;
        struct pci_epc *epc;
@@ -285,12 +286,18 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
                        return NULL;
                }
                size = bar_fixed_size;
+       } else {
+               /* BAR size must be power of two */
+               size = roundup_pow_of_two(size);
        }
 
-       if (align)
-               size = ALIGN(size, align);
-       else
-               size = roundup_pow_of_two(size);
+       /*
+        * Allocate enough memory to accommodate the iATU alignment
+        * requirement.  In most cases, this will be the same as .size but
+        * it might be different if, for example, the fixed size of a BAR
+        * is smaller than align.
+        */
+       aligned_size = align ? ALIGN(size, align) : size;
 
        if (type == PRIMARY_INTERFACE) {
                epc = epf->epc;
@@ -301,7 +308,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
        }
 
        dev = epc->dev.parent;
-       space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
+       space = dma_alloc_coherent(dev, aligned_size, &phys_addr, GFP_KERNEL);
        if (!space) {
                dev_err(dev, "failed to allocate mem space\n");
                return NULL;
@@ -310,6 +317,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
        epf_bar[bar].phys_addr = phys_addr;
        epf_bar[bar].addr = space;
        epf_bar[bar].size = size;
+       epf_bar[bar].aligned_size = aligned_size;
        epf_bar[bar].barno = bar;
        if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
                epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
index 879d19cebd4fc6d8df9d724e3a52fa7fbd61e535..749cee0bcf2cc0600ad3be1582b0c497c5a21bed 100644 (file)
@@ -114,6 +114,8 @@ struct pci_epf_driver {
  * @phys_addr: physical address that should be mapped to the BAR
  * @addr: virtual address corresponding to the @phys_addr
  * @size: the size of the address space present in BAR
+ * @aligned_size: the size actually allocated to accommodate the iATU alignment
+ *                requirement
  * @barno: BAR number
  * @flags: flags that are set for the BAR
  */
@@ -121,6 +123,7 @@ struct pci_epf_bar {
        dma_addr_t      phys_addr;
        void            *addr;
        size_t          size;
+       size_t          aligned_size;
        enum pci_barno  barno;
        int             flags;
 };