PCI: endpoint: Add pci_epf_align_inbound_addr() helper for inbound address alignment

Add pci_epf_align_inbound_addr() to align the inbound addresses according
to PCI BAR alignment requirements. The aligned base address and offset are
returned via 'base' and 'off' parameters.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
[mani: reworded kernel-doc and commit message]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20250710-ep-msi-v21-5-57683fc7fb25@nxp.com
pull/1320/head
Frank Li 2025-07-10 15:13:51 -04:00 committed by Bjorn Helgaas
parent c822392280
commit 4ff4252a23
2 changed files with 41 additions and 0 deletions

View File

@ -477,6 +477,44 @@ struct pci_epf *pci_epf_create(const char *name)
}
EXPORT_SYMBOL_GPL(pci_epf_create);
/**
* pci_epf_align_inbound_addr() - Align the given address based on the BAR
* alignment requirement
* @epf: the EPF device
* @addr: inbound address to be aligned
* @bar: the BAR number corresponding to the given addr
* @base: base address matching the @bar alignment requirement
* @off: offset to be added to the @base address
*
* Helper function to align input @addr based on BAR's alignment requirement.
* The aligned base address and offset are returned via @base and @off.
*
* NOTE: The pci_epf_alloc_space() function already accounts for alignment.
* This API is primarily intended for use with other memory regions not
* allocated by pci_epf_alloc_space(), such as peripheral register spaces or
* the message address of a platform MSI controller.
*
* Return: 0 on success, errno otherwise.
*/
int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
u64 addr, dma_addr_t *base, size_t *off)
{
/*
* Most EP controllers require the BAR start address to be aligned to
* the BAR size, because they mask off the lower bits.
*
* Alignment to BAR size also works for controllers that support
* unaligned addresses.
*/
u64 align = epf->bar[bar].size;
*base = round_down(addr, align);
*off = addr & (align - 1);
return 0;
}
EXPORT_SYMBOL_GPL(pci_epf_align_inbound_addr);
static void pci_epf_dev_release(struct device *dev)
{
struct pci_epf *epf = to_pci_epf(dev);

View File

@ -241,6 +241,9 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
enum pci_epc_interface_type type);
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
u64 addr, dma_addr_t *base, size_t *off);
int pci_epf_bind(struct pci_epf *epf);
void pci_epf_unbind(struct pci_epf *epf);
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);