diff options
| author | Frank Li <Frank.Li@nxp.com> | 2025-10-15 11:27:29 -0400 |
|---|---|---|
| committer | Manivannan Sadhasivam <mani@kernel.org> | 2025-10-27 20:04:51 +0530 |
| commit | f71e2b67b51dcb2fd8c6d566230f17a735770bee (patch) | |
| tree | d918c9d94174e9cd9e48922818b6ee209a140813 | |
| parent | 483768846d66c04354898f00bcdaad58a3763be2 (diff) | |
PCI: endpoint: Add pci_epf_get_required_bar_size() helper
Introduce pci_epf_get_required_bar_size() helper to get the required BAR
size and backing memory size. This helper will be used to set a fixed MMIO
address as the backing memory for a BAR.
Since this helper returns both BAR size and the aligned memory size, use
two parameters, 'bar_size' and 'aligned_mem_size' to avoid confusion.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
[mani: renamed helper to pci_epf_get_required_bar_size(), reworded description]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20251015-vntb_msi_doorbell-v6-2-9230298b1910@nxp.com
| -rw-r--r-- | drivers/pci/endpoint/pci-epf-core.c | 74 |
1 files changed, 46 insertions, 28 deletions
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 214e3f6e6d0d..ec20aabb7f75 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -208,6 +208,48 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf) } EXPORT_SYMBOL_GPL(pci_epf_remove_vepf); +static int pci_epf_get_required_bar_size(struct pci_epf *epf, size_t *bar_size, + size_t *aligned_mem_size, + enum pci_barno bar, + const struct pci_epc_features *epc_features, + enum pci_epc_interface_type type) +{ + u64 bar_fixed_size = epc_features->bar[bar].fixed_size; + size_t align = epc_features->align; + size_t size = *bar_size; + + if (size < 128) + size = 128; + + /* According to PCIe base spec, min size for a resizable BAR is 1 MB. */ + if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M) + size = SZ_1M; + + if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) { + if (size > bar_fixed_size) { + dev_err(&epf->dev, + "requested BAR size is larger than fixed size\n"); + return -ENOMEM; + } + size = bar_fixed_size; + } else { + /* BAR size must be power of two */ + size = roundup_pow_of_two(size); + } + + *bar_size = size; + + /* + * The EPC's BAR start address must meet alignment requirements. In most + * cases, the alignment will match the BAR size. However, differences + * can occur—for example, when the fixed BAR size (e.g., 128 bytes) is + * smaller than the required alignment (e.g., 4 KB). + */ + *aligned_mem_size = align ? ALIGN(size, align) : size; + + return 0; +} + /** * pci_epf_free_space() - free the allocated PCI EPF register space * @epf: the EPF device from whom to free the memory @@ -264,40 +306,16 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, const struct pci_epc_features *epc_features, enum pci_epc_interface_type type) { - u64 bar_fixed_size = epc_features->bar[bar].fixed_size; - size_t mem_size, align = epc_features->align; struct pci_epf_bar *epf_bar; dma_addr_t phys_addr; struct pci_epc *epc; struct device *dev; + size_t mem_size; void *space; - if (size < 128) - size = 128; - - /* According to PCIe base spec, min size for a resizable BAR is 1 MB. */ - if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M) - size = SZ_1M; - - if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) { - if (size > bar_fixed_size) { - dev_err(&epf->dev, - "requested BAR size is larger than fixed size\n"); - return NULL; - } - size = bar_fixed_size; - } else { - /* BAR size must be power of two */ - 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. - */ - mem_size = align ? ALIGN(size, align) : size; + if (pci_epf_get_required_bar_size(epf, &size, &mem_size, bar, + epc_features, type)) + return NULL; if (type == PRIMARY_INTERFACE) { epc = epf->epc; |