Skip to content

Commit 0bfc675

Browse files
nxpfrankliMani-Sadhasivam
authored andcommitted
PCI: endpoint: Add pci_epf_assign_bar_space() API
Add pci_epf_assign_bar_space() API to allow setting any MMIO address as the BAR memory space, such as an MSI message base address. This API also conforms to the BAR base address and size alignment restrictions enforced by the PCI spec r6.0, sec 7.5.1.2.1. Signed-off-by: Frank Li <Frank.Li@nxp.com> [mani: removed unused epc var, reworded kdoc, comments and description] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Link: https://patch.msgid.link/20251015-vntb_msi_doorbell-v6-3-9230298b1910@nxp.com
1 parent f71e2b6 commit 0bfc675

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

drivers/pci/endpoint/pci-epf-core.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,83 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
346346
}
347347
EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
348348

349+
/**
350+
* pci_epf_assign_bar_space() - Assign PCI EPF BAR space
351+
* @epf: EPF device to assign the BAR memory
352+
* @size: Size of the memory that has to be assigned
353+
* @bar: BAR number for which the memory is assigned
354+
* @epc_features: Features provided by the EPC specific to this EPF
355+
* @type: Identifies if the assignment is for primary EPC or secondary EPC
356+
* @bar_addr: Address to be assigned for the @bar
357+
*
358+
* Invoke to assign memory for the PCI EPF BAR.
359+
* Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR
360+
* can only be a 64-bit BAR, or if the requested size is larger than 2 GB.
361+
*/
362+
int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size,
363+
enum pci_barno bar,
364+
const struct pci_epc_features *epc_features,
365+
enum pci_epc_interface_type type,
366+
dma_addr_t bar_addr)
367+
{
368+
size_t bar_size, aligned_mem_size;
369+
struct pci_epf_bar *epf_bar;
370+
dma_addr_t limit;
371+
int pos;
372+
373+
if (!size)
374+
return -EINVAL;
375+
376+
limit = bar_addr + size - 1;
377+
378+
/*
379+
* Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
380+
* bar_addr: U U U U U U 0 X X X X X X X X X
381+
* limit: U U U U U U 1 X X X X X X X X X
382+
*
383+
* bar_addr^limit 0 0 0 0 0 0 1 X X X X X X X X X
384+
*
385+
* U: unchanged address bits in range [bar_addr, limit]
386+
* X: bit 0 or 1
387+
*
388+
* (bar_addr^limit) & BIT_ULL(pos) will find the first set bit from MSB
389+
* (pos). And value of (2 ^ pos) should be able to cover the BAR range.
390+
*/
391+
for (pos = 8 * sizeof(dma_addr_t) - 1; pos > 0; pos--)
392+
if ((limit ^ bar_addr) & BIT_ULL(pos))
393+
break;
394+
395+
if (pos == 8 * sizeof(dma_addr_t) - 1)
396+
return -EINVAL;
397+
398+
bar_size = BIT_ULL(pos + 1);
399+
if (pci_epf_get_required_bar_size(epf, &bar_size, &aligned_mem_size,
400+
bar, epc_features, type))
401+
return -ENOMEM;
402+
403+
if (type == PRIMARY_INTERFACE)
404+
epf_bar = epf->bar;
405+
else
406+
epf_bar = epf->sec_epc_bar;
407+
408+
epf_bar[bar].phys_addr = ALIGN_DOWN(bar_addr, aligned_mem_size);
409+
410+
if (epf_bar[bar].phys_addr + bar_size < limit)
411+
return -ENOMEM;
412+
413+
epf_bar[bar].addr = NULL;
414+
epf_bar[bar].size = bar_size;
415+
epf_bar[bar].mem_size = aligned_mem_size;
416+
epf_bar[bar].barno = bar;
417+
if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
418+
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
419+
else
420+
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32;
421+
422+
return 0;
423+
}
424+
EXPORT_SYMBOL_GPL(pci_epf_assign_bar_space);
425+
349426
static void pci_epf_remove_cfs(struct pci_epf_driver *driver)
350427
{
351428
struct config_group *group, *tmp;

include/linux/pci-epf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
242242
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
243243
enum pci_epc_interface_type type);
244244

245+
int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size,
246+
enum pci_barno bar,
247+
const struct pci_epc_features *epc_features,
248+
enum pci_epc_interface_type type,
249+
dma_addr_t bar_addr);
250+
245251
int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
246252
u64 addr, dma_addr_t *base, size_t *off);
247253
int pci_epf_bind(struct pci_epf *epf);

0 commit comments

Comments
 (0)