Skip to content

Commit ce1dfe6

Browse files
damien-lemoalMani-Sadhasivam
authored andcommitted
PCI: endpoint: Introduce pci_epc_mem_map()/unmap()
Some endpoint controllers have requirements on the alignment of the controller physical memory address that must be used to map a RC PCI address region. For instance, the endpoint controller of the RK3399 SoC uses at most the lower 20 bits of a physical memory address region as the lower bits of a RC PCI address region. For mapping a PCI address region of size bytes starting from pci_addr, the exact number of address bits used is the number of address bits changing in the address range [pci_addr..pci_addr + size - 1]. For this example, this creates the following constraints: 1) The offset into the controller physical memory allocated for a mapping depends on the mapping size *and* the starting PCI address for the mapping. 2) A mapping size cannot exceed the controller windows size (1MB) minus the offset needed into the allocated physical memory, which can end up being a smaller size than the desired mapping size. Handling these constraints independently of the controller being used in an endpoint function driver is not possible with the current EPC API as only the ->align field in struct pci_epc_features is provided but used for BAR (inbound ATU mappings) mapping only. A new API is needed for function drivers to discover mapping constraints and handle non-static requirements based on the RC PCI address range to access. Introduce the endpoint controller operation ->align_addr() to allow the EPC core functions to obtain the size and the offset into a controller address region that must be allocated and mapped to access a RC PCI address region. The size of the mapping provided by the align_addr() operation can then be used as the size argument for the function pci_epc_mem_alloc_addr() and the offset into the allocated controller memory provided can be used to correctly handle data transfers. For endpoint controllers that have PCI address alignment constraints, the align_addr() operation may indicate upon return an effective PCI address mapping size that is smaller (but not 0) than the requested PCI address region size. The controller ->align_addr() operation is optional: controllers that do not have any alignment constraints for mapping RC PCI address regions do not need to implement this operation. For such controllers, it is always assumed that the mapping size is equal to the requested size of the PCI region and that the mapping offset is 0. The function pci_epc_mem_map() is introduced to use this new controller operation (if it is defined) to handle controller memory allocation and mapping to a RC PCI address region in endpoint function drivers. This function first uses the ->align_addr() controller operation to determine the controller memory address size (and offset into) needed for mapping an RC PCI address region. The result of this operation is used to allocate a controller physical memory region using pci_epc_mem_alloc_addr() and then to map that memory to the RC PCI address space with pci_epc_map_addr(). Since ->align_addr() () may indicate that not all of a RC PCI address region can be mapped, pci_epc_mem_map() may only partially map the RC PCI address region specified. It is the responsibility of the caller (an endpoint function driver) to handle such smaller mapping by repeatedly using pci_epc_mem_map() over the desried PCI address range. The counterpart of pci_epc_mem_map() to unmap and free a mapped controller memory address region is pci_epc_mem_unmap(). Both functions operate using the new struct pci_epc_map data structure. This new structure represents a mapping PCI address, mapping effective size, the size of the controller memory needed for the mapping as well as the physical and virtual CPU addresses of the mapping (phys_base and virt_base fields). For convenience, the physical and virtual CPU addresses within that mapping to use to access the target RC PCI address region are also provided (phys_addr and virt_addr fields). Endpoint function drivers can use struct pci_epc_map to access the mapped RC PCI address region using the ->virt_addr and ->pci_size fields. Co-developed-by: Rick Wertenbroek <rick.wertenbroek@gmail.com> Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com> Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Link: https://lore.kernel.org/r/20241012113246.95634-4-dlemoal@kernel.org [mani: squashed the patch that changed phy_addr_t to u64] Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
1 parent 2314c6f commit ce1dfe6

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

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

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,109 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
466466
}
467467
EXPORT_SYMBOL_GPL(pci_epc_map_addr);
468468

469+
/**
470+
* pci_epc_mem_map() - allocate and map a PCI address to a CPU address
471+
* @epc: the EPC device on which the CPU address is to be allocated and mapped
472+
* @func_no: the physical endpoint function number in the EPC device
473+
* @vfunc_no: the virtual endpoint function number in the physical function
474+
* @pci_addr: PCI address to which the CPU address should be mapped
475+
* @pci_size: the number of bytes to map starting from @pci_addr
476+
* @map: where to return the mapping information
477+
*
478+
* Allocate a controller memory address region and map it to a RC PCI address
479+
* region, taking into account the controller physical address mapping
480+
* constraints using the controller operation align_addr(). If this operation is
481+
* not defined, we assume that there are no alignment constraints for the
482+
* mapping.
483+
*
484+
* The effective size of the PCI address range mapped from @pci_addr is
485+
* indicated by @map->pci_size. This size may be less than the requested
486+
* @pci_size. The local virtual CPU address for the mapping is indicated by
487+
* @map->virt_addr (@map->phys_addr indicates the physical address).
488+
* The size and CPU address of the controller memory allocated and mapped are
489+
* respectively indicated by @map->map_size and @map->virt_base (and
490+
* @map->phys_base for the physical address of @map->virt_base).
491+
*
492+
* Returns 0 on success and a negative error code in case of error.
493+
*/
494+
int pci_epc_mem_map(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
495+
u64 pci_addr, size_t pci_size, struct pci_epc_map *map)
496+
{
497+
size_t map_size = pci_size;
498+
size_t map_offset = 0;
499+
int ret;
500+
501+
if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
502+
return -EINVAL;
503+
504+
if (!pci_size || !map)
505+
return -EINVAL;
506+
507+
/*
508+
* Align the PCI address to map. If the controller defines the
509+
* .align_addr() operation, use it to determine the PCI address to map
510+
* and the size of the mapping. Otherwise, assume that the controller
511+
* has no alignment constraint.
512+
*/
513+
memset(map, 0, sizeof(*map));
514+
map->pci_addr = pci_addr;
515+
if (epc->ops->align_addr)
516+
map->map_pci_addr =
517+
epc->ops->align_addr(epc, pci_addr,
518+
&map_size, &map_offset);
519+
else
520+
map->map_pci_addr = pci_addr;
521+
map->map_size = map_size;
522+
if (map->map_pci_addr + map->map_size < pci_addr + pci_size)
523+
map->pci_size = map->map_pci_addr + map->map_size - pci_addr;
524+
else
525+
map->pci_size = pci_size;
526+
527+
map->virt_base = pci_epc_mem_alloc_addr(epc, &map->phys_base,
528+
map->map_size);
529+
if (!map->virt_base)
530+
return -ENOMEM;
531+
532+
map->phys_addr = map->phys_base + map_offset;
533+
map->virt_addr = map->virt_base + map_offset;
534+
535+
ret = pci_epc_map_addr(epc, func_no, vfunc_no, map->phys_base,
536+
map->map_pci_addr, map->map_size);
537+
if (ret) {
538+
pci_epc_mem_free_addr(epc, map->phys_base, map->virt_base,
539+
map->map_size);
540+
return ret;
541+
}
542+
543+
return 0;
544+
}
545+
EXPORT_SYMBOL_GPL(pci_epc_mem_map);
546+
547+
/**
548+
* pci_epc_mem_unmap() - unmap and free a CPU address region
549+
* @epc: the EPC device on which the CPU address is allocated and mapped
550+
* @func_no: the physical endpoint function number in the EPC device
551+
* @vfunc_no: the virtual endpoint function number in the physical function
552+
* @map: the mapping information
553+
*
554+
* Unmap and free a CPU address region that was allocated and mapped with
555+
* pci_epc_mem_map().
556+
*/
557+
void pci_epc_mem_unmap(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
558+
struct pci_epc_map *map)
559+
{
560+
if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
561+
return;
562+
563+
if (!map || !map->virt_base)
564+
return;
565+
566+
pci_epc_unmap_addr(epc, func_no, vfunc_no, map->phys_base);
567+
pci_epc_mem_free_addr(epc, map->phys_base, map->virt_base,
568+
map->map_size);
569+
}
570+
EXPORT_SYMBOL_GPL(pci_epc_mem_unmap);
571+
469572
/**
470573
* pci_epc_clear_bar() - reset the BAR
471574
* @epc: the EPC device for which the BAR has to be cleared

include/linux/pci-epc.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,43 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
3232
}
3333
}
3434

35+
/**
36+
* struct pci_epc_map - information about EPC memory for mapping a RC PCI
37+
* address range
38+
* @pci_addr: start address of the RC PCI address range to map
39+
* @pci_size: size of the RC PCI address range mapped from @pci_addr
40+
* @map_pci_addr: RC PCI address used as the first address mapped (may be lower
41+
* than @pci_addr)
42+
* @map_size: size of the controller memory needed for mapping the RC PCI address
43+
* range @pci_addr..@pci_addr+@pci_size
44+
* @phys_base: base physical address of the allocated EPC memory for mapping the
45+
* RC PCI address range
46+
* @phys_addr: physical address at which @pci_addr is mapped
47+
* @virt_base: base virtual address of the allocated EPC memory for mapping the
48+
* RC PCI address range
49+
* @virt_addr: virtual address at which @pci_addr is mapped
50+
*/
51+
struct pci_epc_map {
52+
u64 pci_addr;
53+
size_t pci_size;
54+
55+
u64 map_pci_addr;
56+
size_t map_size;
57+
58+
phys_addr_t phys_base;
59+
phys_addr_t phys_addr;
60+
void __iomem *virt_base;
61+
void __iomem *virt_addr;
62+
};
63+
3564
/**
3665
* struct pci_epc_ops - set of function pointers for performing EPC operations
3766
* @write_header: ops to populate configuration space header
3867
* @set_bar: ops to configure the BAR
3968
* @clear_bar: ops to reset the BAR
69+
* @align_addr: operation to get the mapping address, mapping size and offset
70+
* into a controller memory window needed to map an RC PCI address
71+
* region
4072
* @map_addr: ops to map CPU address to PCI address
4173
* @unmap_addr: ops to unmap CPU address and PCI address
4274
* @set_msi: ops to set the requested number of MSI interrupts in the MSI
@@ -61,6 +93,8 @@ struct pci_epc_ops {
6193
struct pci_epf_bar *epf_bar);
6294
void (*clear_bar)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
6395
struct pci_epf_bar *epf_bar);
96+
u64 (*align_addr)(struct pci_epc *epc, u64 pci_addr, size_t *size,
97+
size_t *offset);
6498
int (*map_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
6599
phys_addr_t addr, u64 pci_addr, size_t size);
66100
void (*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
@@ -278,6 +312,10 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
278312
phys_addr_t *phys_addr, size_t size);
279313
void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
280314
void __iomem *virt_addr, size_t size);
315+
int pci_epc_mem_map(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
316+
u64 pci_addr, size_t pci_size, struct pci_epc_map *map);
317+
void pci_epc_mem_unmap(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
318+
struct pci_epc_map *map);
281319

282320
#else
283321
static inline void pci_epc_init_notify(struct pci_epc *epc)

0 commit comments

Comments
 (0)