PCI: endpoint: Retain fixed-size BAR size as well as aligned size
[ Upstream commit 793908d60b8745c386b9f4e29eb702f74ceb0886 ]
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: 2a9a801620 ("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
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9137bd312b
commit
0a3e2ec508
@@ -236,12 +236,13 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev = epc->dev.parent;
|
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);
|
||||||
|
|
||||||
epf_bar[bar].phys_addr = 0;
|
epf_bar[bar].phys_addr = 0;
|
||||||
epf_bar[bar].addr = NULL;
|
epf_bar[bar].addr = NULL;
|
||||||
epf_bar[bar].size = 0;
|
epf_bar[bar].size = 0;
|
||||||
|
epf_bar[bar].aligned_size = 0;
|
||||||
epf_bar[bar].barno = 0;
|
epf_bar[bar].barno = 0;
|
||||||
epf_bar[bar].flags = 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)
|
enum pci_epc_interface_type type)
|
||||||
{
|
{
|
||||||
u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
|
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;
|
struct pci_epf_bar *epf_bar;
|
||||||
dma_addr_t phys_addr;
|
dma_addr_t phys_addr;
|
||||||
struct pci_epc *epc;
|
struct pci_epc *epc;
|
||||||
@@ -281,12 +282,18 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
size = bar_fixed_size;
|
size = bar_fixed_size;
|
||||||
|
} else {
|
||||||
|
/* BAR size must be power of two */
|
||||||
|
size = roundup_pow_of_two(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (align)
|
/*
|
||||||
size = ALIGN(size, align);
|
* Allocate enough memory to accommodate the iATU alignment
|
||||||
else
|
* requirement. In most cases, this will be the same as .size but
|
||||||
size = roundup_pow_of_two(size);
|
* 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) {
|
if (type == PRIMARY_INTERFACE) {
|
||||||
epc = epf->epc;
|
epc = epf->epc;
|
||||||
@@ -297,7 +304,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev = epc->dev.parent;
|
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) {
|
if (!space) {
|
||||||
dev_err(dev, "failed to allocate mem space\n");
|
dev_err(dev, "failed to allocate mem space\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -306,6 +313,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].phys_addr = phys_addr;
|
||||||
epf_bar[bar].addr = space;
|
epf_bar[bar].addr = space;
|
||||||
epf_bar[bar].size = size;
|
epf_bar[bar].size = size;
|
||||||
|
epf_bar[bar].aligned_size = aligned_size;
|
||||||
epf_bar[bar].barno = bar;
|
epf_bar[bar].barno = bar;
|
||||||
if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
|
if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
|
||||||
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ struct pci_epf_driver {
|
|||||||
* @phys_addr: physical address that should be mapped to the BAR
|
* @phys_addr: physical address that should be mapped to the BAR
|
||||||
* @addr: virtual address corresponding to the @phys_addr
|
* @addr: virtual address corresponding to the @phys_addr
|
||||||
* @size: the size of the address space present in BAR
|
* @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
|
* @barno: BAR number
|
||||||
* @flags: flags that are set for the BAR
|
* @flags: flags that are set for the BAR
|
||||||
*/
|
*/
|
||||||
@@ -121,6 +123,7 @@ struct pci_epf_bar {
|
|||||||
dma_addr_t phys_addr;
|
dma_addr_t phys_addr;
|
||||||
void *addr;
|
void *addr;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
size_t aligned_size;
|
||||||
enum pci_barno barno;
|
enum pci_barno barno;
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user