From: Damien Le Moal <dlemoal@kernel.org> To: "Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>, "Kishon Vijay Abraham I" <kishon@kernel.org>, "Shawn Lin" <shawn.lin@rock-chips.com>, "Krzysztof Wilczyński" <kw@linux.com>, "Bjorn Helgaas" <bhelgaas@google.com>, "Heiko Stuebner" <heiko@sntech.de>, linux-pci@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Subject: [PATCH 03/19] PCI: endpoint: Introduce pci_epc_map_align() Date: Fri, 29 Mar 2024 18:09:29 +0900 [thread overview] Message-ID: <20240329090945.1097609-4-dlemoal@kernel.org> (raw) In-Reply-To: <20240329090945.1097609-1-dlemoal@kernel.org> 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 rockchip endpoint controller uses at most the lower 20 bits of a physical memory address region as the lower bits of an RC PCI address. 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 a PCI EP function driver is not possible with the current EPC API as it only provides the ->align field in struct pci_epc_features. Furthermore, this alignment is static and does not depend on a mapping pci address and size. Solve this by introducing the function pci_epc_map_align() and the endpoint controller operation ->map_align to allow endpoint function drivers to obtain the size and the offset into a controller address region that must be used to map an RC PCI address region. The size of the physical address region provided by pci_epc_map_align() can then be used as the size argument for the function pci_epc_mem_alloc_addr(). The offset into the allocated controller memory can be used to correctly handle data transfers. Of note is that pci_epc_map_align() may indicate upon return a mapping size that is smaller (but not 0) than the requested PCI address region size. For such case, an endpoint function driver must handle data transfers in fragments. The controller operation ->map_align is optional: controllers that do not have any address alignment constraints for mapping a RC PCI address region do not need to implement this operation. For such controllers, pci_epc_map_align() always returns the mapping size as equal to the requested size and an offset equal to 0. The structure pci_epc_map is introduced to represent a mapping start PCI address, size and the size and offset into the controller memory needed for mapping the PCI address region. Signed-off-by: Damien Le Moal <dlemoal@kernel.org> --- drivers/pci/endpoint/pci-epc-core.c | 66 +++++++++++++++++++++++++++++ include/linux/pci-epc.h | 33 +++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 26fe2c255fc9..f558b333f842 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -432,6 +432,72 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, } EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); +/** + * pci_epc_map_align() - Get the offset into and the size of a controller memory + * address region needed to map a RC PCI address region + * @epc: the EPC device on which address is allocated + * @func_no: the physical endpoint function number in the EPC device + * @vfunc_no: the virtual endpoint function number in the physical function + * @pci_addr: PCI address to which the physical address should be mapped + * @size: the size of the mapping starting from @pci_addr + * @map: populate here the actual size and offset into the controller memory + * that must be allocated for the mapping + * + * Invoke the controller map_align operation to obtain the size and the offset + * into a controller address region that must be allocated to map @size + * bytes of the RC PCI address space starting from @pci_addr. + * + * The size of the mapping that can be handled by the controller is indicated + * using the pci_size field of @map. This size may be smaller than the requested + * @size. In such case, the function driver must handle the mapping using + * several fragments. The offset into the controller memory for the effective + * mapping of the @pci_addr..@pci_addr+@map->pci_size address range is indicated + * using the map_ofst field of @map. + */ +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u64 pci_addr, size_t size, struct pci_epc_map *map) +{ + const struct pci_epc_features *features; + size_t mask; + int ret; + + if (!pci_epc_check_func(epc, func_no, vfunc_no)) + return -EINVAL; + + if (!size || !map) + return -EINVAL; + + memset(map, 0, sizeof(*map)); + map->pci_addr = pci_addr; + map->pci_size = size; + + if (epc->ops->map_align) { + mutex_lock(&epc->lock); + ret = epc->ops->map_align(epc, func_no, vfunc_no, map); + mutex_unlock(&epc->lock); + return ret; + } + + /* + * Assume a fixed alignment constraint as specified by the controller + * features. + */ + features = pci_epc_get_features(epc, func_no, vfunc_no); + if (!features || !features->align) { + map->map_pci_addr = pci_addr; + map->map_size = size; + map->map_ofst = 0; + } + + mask = features->align - 1; + map->map_pci_addr = map->pci_addr & ~mask; + map->map_ofst = map->pci_addr & mask; + map->map_size = ALIGN(map->map_ofst + map->pci_size, features->align); + + return 0; +} +EXPORT_SYMBOL_GPL(pci_epc_map_align); + /** * pci_epc_map_addr() - map CPU address to PCI address * @epc: the EPC device on which address is allocated diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index cc2f70d061c8..8cfb4aaf2628 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -32,11 +32,40 @@ pci_epc_interface_string(enum pci_epc_interface_type type) } } +/** + * struct pci_epc_map - information about EPC memory for mapping a RC PCI + * address range + * @pci_addr: start address of the RC PCI address range to map + * @pci_size: size of the RC PCI address range to map + * @map_pci_addr: RC PCI address used as the first address mapped + * @map_size: size of the controller memory needed for the mapping + * @map_ofst: offset into the controller memory needed for the mapping + * @phys_base: base physical address of the allocated EPC memory + * @phys_addr: physical address at which @pci_addr is mapped + * @virt_base: base virtual address of the allocated EPC memory + * @virt_addr: virtual address at which @pci_addr is mapped + */ +struct pci_epc_map { + phys_addr_t pci_addr; + size_t pci_size; + + phys_addr_t map_pci_addr; + size_t map_size; + phys_addr_t map_ofst; + + phys_addr_t phys_base; + phys_addr_t phys_addr; + void __iomem *virt_base; + void __iomem *virt_addr; +}; + /** * struct pci_epc_ops - set of function pointers for performing EPC operations * @write_header: ops to populate configuration space header * @set_bar: ops to configure the BAR * @clear_bar: ops to reset the BAR + * @map_align: operation to get the size and offset into a controller memory + * window needed to map an RC PCI address region * @map_addr: ops to map CPU address to PCI address * @unmap_addr: ops to unmap CPU address and PCI address * @set_msi: ops to set the requested number of MSI interrupts in the MSI @@ -61,6 +90,8 @@ struct pci_epc_ops { struct pci_epf_bar *epf_bar); void (*clear_bar)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); + int (*map_align)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct pci_epc_map *map); int (*map_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t addr, u64 pci_addr, size_t size); void (*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, @@ -234,6 +265,8 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u64 pci_addr, size_t size, struct pci_epc_map *map); int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr, u64 pci_addr, size_t size); -- 2.44.0
WARNING: multiple messages have this Message-ID (diff)
From: Damien Le Moal <dlemoal@kernel.org> To: "Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>, "Kishon Vijay Abraham I" <kishon@kernel.org>, "Shawn Lin" <shawn.lin@rock-chips.com>, "Krzysztof Wilczyński" <kw@linux.com>, "Bjorn Helgaas" <bhelgaas@google.com>, "Heiko Stuebner" <heiko@sntech.de>, linux-pci@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Subject: [PATCH 03/19] PCI: endpoint: Introduce pci_epc_map_align() Date: Fri, 29 Mar 2024 18:09:29 +0900 [thread overview] Message-ID: <20240329090945.1097609-4-dlemoal@kernel.org> (raw) In-Reply-To: <20240329090945.1097609-1-dlemoal@kernel.org> 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 rockchip endpoint controller uses at most the lower 20 bits of a physical memory address region as the lower bits of an RC PCI address. 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 a PCI EP function driver is not possible with the current EPC API as it only provides the ->align field in struct pci_epc_features. Furthermore, this alignment is static and does not depend on a mapping pci address and size. Solve this by introducing the function pci_epc_map_align() and the endpoint controller operation ->map_align to allow endpoint function drivers to obtain the size and the offset into a controller address region that must be used to map an RC PCI address region. The size of the physical address region provided by pci_epc_map_align() can then be used as the size argument for the function pci_epc_mem_alloc_addr(). The offset into the allocated controller memory can be used to correctly handle data transfers. Of note is that pci_epc_map_align() may indicate upon return a mapping size that is smaller (but not 0) than the requested PCI address region size. For such case, an endpoint function driver must handle data transfers in fragments. The controller operation ->map_align is optional: controllers that do not have any address alignment constraints for mapping a RC PCI address region do not need to implement this operation. For such controllers, pci_epc_map_align() always returns the mapping size as equal to the requested size and an offset equal to 0. The structure pci_epc_map is introduced to represent a mapping start PCI address, size and the size and offset into the controller memory needed for mapping the PCI address region. Signed-off-by: Damien Le Moal <dlemoal@kernel.org> --- drivers/pci/endpoint/pci-epc-core.c | 66 +++++++++++++++++++++++++++++ include/linux/pci-epc.h | 33 +++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 26fe2c255fc9..f558b333f842 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -432,6 +432,72 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, } EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); +/** + * pci_epc_map_align() - Get the offset into and the size of a controller memory + * address region needed to map a RC PCI address region + * @epc: the EPC device on which address is allocated + * @func_no: the physical endpoint function number in the EPC device + * @vfunc_no: the virtual endpoint function number in the physical function + * @pci_addr: PCI address to which the physical address should be mapped + * @size: the size of the mapping starting from @pci_addr + * @map: populate here the actual size and offset into the controller memory + * that must be allocated for the mapping + * + * Invoke the controller map_align operation to obtain the size and the offset + * into a controller address region that must be allocated to map @size + * bytes of the RC PCI address space starting from @pci_addr. + * + * The size of the mapping that can be handled by the controller is indicated + * using the pci_size field of @map. This size may be smaller than the requested + * @size. In such case, the function driver must handle the mapping using + * several fragments. The offset into the controller memory for the effective + * mapping of the @pci_addr..@pci_addr+@map->pci_size address range is indicated + * using the map_ofst field of @map. + */ +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u64 pci_addr, size_t size, struct pci_epc_map *map) +{ + const struct pci_epc_features *features; + size_t mask; + int ret; + + if (!pci_epc_check_func(epc, func_no, vfunc_no)) + return -EINVAL; + + if (!size || !map) + return -EINVAL; + + memset(map, 0, sizeof(*map)); + map->pci_addr = pci_addr; + map->pci_size = size; + + if (epc->ops->map_align) { + mutex_lock(&epc->lock); + ret = epc->ops->map_align(epc, func_no, vfunc_no, map); + mutex_unlock(&epc->lock); + return ret; + } + + /* + * Assume a fixed alignment constraint as specified by the controller + * features. + */ + features = pci_epc_get_features(epc, func_no, vfunc_no); + if (!features || !features->align) { + map->map_pci_addr = pci_addr; + map->map_size = size; + map->map_ofst = 0; + } + + mask = features->align - 1; + map->map_pci_addr = map->pci_addr & ~mask; + map->map_ofst = map->pci_addr & mask; + map->map_size = ALIGN(map->map_ofst + map->pci_size, features->align); + + return 0; +} +EXPORT_SYMBOL_GPL(pci_epc_map_align); + /** * pci_epc_map_addr() - map CPU address to PCI address * @epc: the EPC device on which address is allocated diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index cc2f70d061c8..8cfb4aaf2628 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -32,11 +32,40 @@ pci_epc_interface_string(enum pci_epc_interface_type type) } } +/** + * struct pci_epc_map - information about EPC memory for mapping a RC PCI + * address range + * @pci_addr: start address of the RC PCI address range to map + * @pci_size: size of the RC PCI address range to map + * @map_pci_addr: RC PCI address used as the first address mapped + * @map_size: size of the controller memory needed for the mapping + * @map_ofst: offset into the controller memory needed for the mapping + * @phys_base: base physical address of the allocated EPC memory + * @phys_addr: physical address at which @pci_addr is mapped + * @virt_base: base virtual address of the allocated EPC memory + * @virt_addr: virtual address at which @pci_addr is mapped + */ +struct pci_epc_map { + phys_addr_t pci_addr; + size_t pci_size; + + phys_addr_t map_pci_addr; + size_t map_size; + phys_addr_t map_ofst; + + phys_addr_t phys_base; + phys_addr_t phys_addr; + void __iomem *virt_base; + void __iomem *virt_addr; +}; + /** * struct pci_epc_ops - set of function pointers for performing EPC operations * @write_header: ops to populate configuration space header * @set_bar: ops to configure the BAR * @clear_bar: ops to reset the BAR + * @map_align: operation to get the size and offset into a controller memory + * window needed to map an RC PCI address region * @map_addr: ops to map CPU address to PCI address * @unmap_addr: ops to unmap CPU address and PCI address * @set_msi: ops to set the requested number of MSI interrupts in the MSI @@ -61,6 +90,8 @@ struct pci_epc_ops { struct pci_epf_bar *epf_bar); void (*clear_bar)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); + int (*map_align)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct pci_epc_map *map); int (*map_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t addr, u64 pci_addr, size_t size); void (*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, @@ -234,6 +265,8 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar); +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u64 pci_addr, size_t size, struct pci_epc_map *map); int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr, u64 pci_addr, size_t size); -- 2.44.0 _______________________________________________ Linux-rockchip mailing list Linux-rockchip@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip
next prev parent reply other threads:[~2024-03-29 9:09 UTC|newest] Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-03-29 9:09 [PATCH 00/19] Improve PCI memory mapping API Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 01/19] PCI: endpoint: Introduce pci_epc_check_func() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 12:33 ` Bjorn Helgaas 2024-03-29 12:33 ` Bjorn Helgaas 2024-03-29 9:09 ` [PATCH 02/19] PCI: endpoint: Improve pci_epc_mem_alloc_addr() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 15:32 ` Frank Li 2024-03-29 15:32 ` Frank Li 2024-03-29 9:09 ` Damien Le Moal [this message] 2024-03-29 9:09 ` [PATCH 03/19] PCI: endpoint: Introduce pci_epc_map_align() Damien Le Moal 2024-03-29 9:09 ` [PATCH 04/19] PCI: endpoint: Introduce pci_epc_mem_map()/unmap() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 05/19] PCI: endpoint: test: Use pci_epc_mem_map/unmap() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 06/19] PCI: endpoint: test: Synchronously cancel command handler work Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 15:36 ` Frank Li 2024-03-29 15:36 ` Frank Li 2024-03-29 9:09 ` [PATCH 07/19] PCI: endpoint: test: Implement link_down event operation Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 15:37 ` Frank Li 2024-03-29 15:37 ` Frank Li 2024-03-29 9:09 ` [PATCH 08/19] PCI: rockchip-ep: Fix address translation unit programming Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 09/19] PCI: rockchip-ep: use macro to define EP controller .align feature Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 10/19] PCI: rockchip-ep: Improve rockchip_pcie_ep_unmap_addr() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 11/19] PCI: rockchip-ep: Improve rockchip_pcie_ep_map_addr() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 12/19] PCI: rockchip-ep: Implement the map_info endpoint controller operation Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 13/19] PCI: rockchip-ep: Refactor rockchip_pcie_ep_probe() memory allocations Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 14/19] PCI: rockchip-ep: Refactor rockchip_pcie_ep_probe() MSIX hiding Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 15/19] PCI: rockchip-ep: Refactor endpoint link training enable Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 16/19] PCI: rockship-ep: Introduce rockchip_pcie_ep_stop() Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 9:09 ` [PATCH 17/19] PCI: rockchip-ep: Improve link training Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-31 2:03 ` kernel test robot 2024-03-31 2:03 ` kernel test robot 2024-03-29 9:09 ` [PATCH 18/19] dt-bindings: pci: rockchip,rk3399-pcie-ep: Add ep-gpios property Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-29 12:28 ` Krzysztof Kozlowski 2024-03-29 12:28 ` Krzysztof Kozlowski 2024-03-29 9:09 ` [PATCH 19/19] PCI: rockchip-ep: Handle PERST signal in endpoint mode Damien Le Moal 2024-03-29 9:09 ` Damien Le Moal 2024-03-30 10:31 ` kernel test robot 2024-03-30 10:31 ` kernel test robot 2024-03-31 5:40 ` kernel test robot 2024-03-31 5:40 ` kernel test robot 2024-03-29 12:41 ` [PATCH 00/19] Improve PCI memory mapping API Bjorn Helgaas 2024-03-29 12:41 ` Bjorn Helgaas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240329090945.1097609-4-dlemoal@kernel.org \ --to=dlemoal@kernel.org \ --cc=bhelgaas@google.com \ --cc=heiko@sntech.de \ --cc=kishon@kernel.org \ --cc=kw@linux.com \ --cc=linux-pci@vger.kernel.org \ --cc=linux-rockchip@lists.infradead.org \ --cc=manivannan.sadhasivam@linaro.org \ --cc=shawn.lin@rock-chips.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.