mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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
This commit is contained in:
committed by
Manivannan Sadhasivam
parent
483768846d
commit
f71e2b67b5
@@ -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);
|
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
|
* pci_epf_free_space() - free the allocated PCI EPF register space
|
||||||
* @epf: the EPF device from whom to free the memory
|
* @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,
|
const struct pci_epc_features *epc_features,
|
||||||
enum pci_epc_interface_type type)
|
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;
|
struct pci_epf_bar *epf_bar;
|
||||||
dma_addr_t phys_addr;
|
dma_addr_t phys_addr;
|
||||||
struct pci_epc *epc;
|
struct pci_epc *epc;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
size_t mem_size;
|
||||||
void *space;
|
void *space;
|
||||||
|
|
||||||
if (size < 128)
|
if (pci_epf_get_required_bar_size(epf, &size, &mem_size, bar,
|
||||||
size = 128;
|
epc_features, type))
|
||||||
|
return NULL;
|
||||||
/* 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 (type == PRIMARY_INTERFACE) {
|
if (type == PRIMARY_INTERFACE) {
|
||||||
epc = epf->epc;
|
epc = epf->epc;
|
||||||
|
|||||||
Reference in New Issue
Block a user