[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250815-vntb_msi_doorbell-v1-1-32df6c4bf96c@nxp.com>
Date: Fri, 15 Aug 2025 18:20:53 -0400
From: Frank Li <Frank.Li@....com>
To: Manivannan Sadhasivam <mani@...nel.org>,
Krzysztof WilczyĆski <kwilczynski@...nel.org>,
Kishon Vijay Abraham I <kishon@...nel.org>,
Bjorn Helgaas <bhelgaas@...gle.com>, Jon Mason <jdmason@...zu.us>,
Dave Jiang <dave.jiang@...el.com>, Allen Hubbe <allenbh@...il.com>
Cc: linux-pci@...r.kernel.org, linux-kernel@...r.kernel.org,
ntb@...ts.linux.dev, Frank Li <Frank.Li@....com>
Subject: [PATCH 1/2] PCI: endpoint: Enhance pci_epf_alloc_space() and
rename to pci_epf_set_inbound_space()
Enhance pci_epf_alloc_space() to handle setting any physical address as
inbound memory space, such as an MSI message base address. The function
already accounts for different alignment requirements for different BARs,
so reuse this logic and rename the function to pci_epf_set_inbound_space().
Make pci_epf_alloc_space() inline and call pci_epf_set_inbound_space() with
from_space set to true to maintain compatibility.
Signed-off-by: Frank Li <Frank.Li@....com>
---
---
drivers/pci/endpoint/pci-epf-core.c | 69 ++++++++++++++++++++++++++++++-------
include/linux/pci-epc.h | 5 ---
include/linux/pci-epf.h | 35 ++++++++++++++++---
3 files changed, 87 insertions(+), 22 deletions(-)
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index d54e18872aefc07c655c94c104a347328ff7a432..5b802b1ea3e28a32e38f4ab6a649cb97a2f29b95 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -249,20 +249,26 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
EXPORT_SYMBOL_GPL(pci_epf_free_space);
/**
- * pci_epf_alloc_space() - allocate memory for the PCI EPF register space
+ * pci_epf_set_inbound_space() - set memory for the PCI EPF inbound address space
* @epf: the EPF device to whom allocate the memory
* @size: the size of the memory that has to be allocated
* @bar: the BAR number corresponding to the allocated register space
* @epc_features: the features provided by the EPC specific to this EPF
* @type: Identifies if the allocation is for primary EPC or secondary EPC
+ * @from_memory: allocate from system memory
+ * @inbound_addr: Any physical address space such as MSI message address that
+ * work as inbound address space. from_memory need be false.
*
* Invoke to allocate memory for the PCI EPF register space.
* Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR
* can only be a 64-bit BAR, or if the requested size is larger than 2 GB.
*/
-void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
- const struct pci_epc_features *epc_features,
- enum pci_epc_interface_type type)
+int pci_epf_set_inbound_space(struct pci_epf *epf, size_t size,
+ enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type,
+ bool from_memory,
+ dma_addr_t inbound_addr)
{
u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
size_t aligned_size, align = epc_features->align;
@@ -270,7 +276,32 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
dma_addr_t phys_addr;
struct pci_epc *epc;
struct device *dev;
- void *space;
+ void *space = NULL;
+ dma_addr_t up;
+
+ up = inbound_addr + size - 1;
+
+ /*
+ * Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ * Inbound_addr: U U U U U U 0 X X X X X X X X X
+ * Up: U U U U U U 1 X X X X X X X X X
+ *
+ * U means address bits have not change in Range [Inbound_Addr, Up]
+ * X means bit 0 or 1.
+ *
+ * Inbound_addr^Up 0 0 0 0 0 0 1 X X X X X X X X X
+ * Find first bit 1 pos from MSB, 2 ^ pos windows will cover
+ * [Inbound_Addr, Up] range.
+ */
+ if (!from_memory) {
+ int pos;
+
+ for (pos = sizeof(dma_addr_t) - 1; pos > 0; pos--)
+ if ((up ^ inbound_addr) & BIT_ULL(pos))
+ break;
+
+ size = 1 << pos;
+ }
if (size < 128)
size = 128;
@@ -283,7 +314,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
if (size > bar_fixed_size) {
dev_err(&epf->dev,
"requested BAR size is larger than fixed size\n");
- return NULL;
+ return -EINVAL;
}
size = bar_fixed_size;
} else {
@@ -308,13 +339,25 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
}
dev = epc->dev.parent;
- space = dma_alloc_coherent(dev, aligned_size, &phys_addr, GFP_KERNEL);
- if (!space) {
- dev_err(dev, "failed to allocate mem space\n");
- return NULL;
+
+ if (from_memory) {
+ space = dma_alloc_coherent(dev, aligned_size,
+ &phys_addr, GFP_KERNEL);
+ if (!space) {
+ dev_err(dev, "failed to allocate mem space\n");
+ return -ENOMEM;
+ }
+ }
+
+ epf_bar[bar].phys_addr = from_memory ?
+ phys_addr : ALIGN_DOWN(inbound_addr, aligned_size);
+
+ if (!from_memory && (epf_bar[bar].phys_addr + size < up)) {
+ dev_err(&epf->dev,
+ "Given bar can't fit required inbound memory region\n");
+ return -EINVAL;
}
- epf_bar[bar].phys_addr = phys_addr;
epf_bar[bar].addr = space;
epf_bar[bar].size = size;
epf_bar[bar].aligned_size = aligned_size;
@@ -324,9 +367,9 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
else
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32;
- return space;
+ return 0;
}
-EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
+EXPORT_SYMBOL_GPL(pci_epf_set_inbound_space);
static void pci_epf_remove_cfs(struct pci_epf_driver *driver)
{
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 4286bfdbfdfad2754d763be2b8474e5d2d403a1f..5f1d8787c3bb7a6130adb54c079a48c82d5afcf4 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -13,11 +13,6 @@
struct pci_epc;
-enum pci_epc_interface_type {
- UNKNOWN_INTERFACE = -1,
- PRIMARY_INTERFACE,
- SECONDARY_INTERFACE,
-};
static inline const char *
pci_epc_interface_string(enum pci_epc_interface_type type)
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 2e85504ba2baf93827224884ca19ae2bd0e6906b..4311a8ba1081b8a8aa327c8ed10f9c5d9af2feba 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -17,7 +17,12 @@
struct pci_epf;
struct pci_epc_features;
-enum pci_epc_interface_type;
+
+enum pci_epc_interface_type {
+ UNKNOWN_INTERFACE = -1,
+ PRIMARY_INTERFACE,
+ SECONDARY_INTERFACE,
+};
enum pci_barno {
NO_BAR = -1,
@@ -236,9 +241,31 @@ void pci_epf_destroy(struct pci_epf *epf);
int __pci_epf_register_driver(struct pci_epf_driver *driver,
struct module *owner);
void pci_epf_unregister_driver(struct pci_epf_driver *driver);
-void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
- const struct pci_epc_features *epc_features,
- enum pci_epc_interface_type type);
+
+int pci_epf_set_inbound_space(struct pci_epf *epf, size_t size,
+ enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type,
+ bool from_memory,
+ dma_addr_t inbound_addr);
+
+static inline void *
+pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type)
+{
+ int ret;
+
+ ret = pci_epf_set_inbound_space(epf, size, bar, epc_features, type,
+ true, 0);
+
+ if (ret)
+ return NULL;
+
+ return type == PRIMARY_INTERFACE ? epf->bar[bar].addr :
+ epf->sec_epc_bar[bar].addr;
+}
+
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
--
2.34.1
Powered by blists - more mailing lists