public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
@ 2026-02-19  8:13 Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 1/7] PCI: endpoint: Add auxiliary resource query API Koichiro Den
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Hi,

Some endpoint platforms cannot use a GIC ITS-backed MSI domain for
EP-side doorbells. In those cases, endpoint function (EPF) drivers
cannot provide a doorbell to the root complex (RC), and features such as
vNTB may fall back to polling with significantly higher latency.

This series adds an alternate doorbell backend based on the DesignWare
PCIe controller's integrated eDMA interrupt-emulation feature. The RC
rings the doorbell by doing a single 32-bit MMIO write to an eDMA
doorbell location exposed in a BAR window. The EP side receives a Linux
IRQ that EPF drivers can use as a doorbell interrupt, without relying on
MSI message writes reaching the ITS.

To support this, the series:

  - Adds an EPC auxiliary resource query API so EPF drivers can discover
    controller-integrated resources (DMA MMIO, doorbell MMIO, and DMA LL
    memory).
  - Updates DesignWare EP controllers to report integrated eDMA
    resources via the new API.
  - Updates dw-edma to provide a dedicated virtual IRQ for interrupt
    emulation and to perform the core-specific deassert sequence.
  - Updates pci-epf-test and pci-epf-vntb to reuse a pre-exposed
    BAR/offset and to honor per-doorbell IRQ flags.

Many thanks to Frank and Niklas for their continued review and valuable
feedback throughout the development of this series. The Reviewed-by tags
for the last two patches are dropped due to the additional changes
following Niklas' review in the v8 threads. Since the diff is small, I'd
appreciate it if Frank could re-check them.


Dependencies
------------

The following three series are prerequisites for this series:

  (1). [PATCH v2 0/4] PCI: endpoint: Doorbell-related fixes
       https://lore.kernel.org/linux-pci/20260217063856.3759713-1-den@valinux.co.jp/
  (2). [PATCH 0/2] dmaengine: dw-edma: Interrupt-emulation doorbell support
       https://lore.kernel.org/dmaengine/20260215152216.3393561-1-den@valinux.co.jp/
  (3). [PATCH 0/9] PCI: endpoint differentiate between disabled and reserved BARs
       https://lore.kernel.org/linux-pci/20260217212707.2450423-11-cassel@kernel.org/

Regarding (3):
  - [PATCH 2/9] and [PATCH 3/9] are strictly the prerequisites for this v9 series.
    In fact, they are split out from v8 series.
  - With [PATCH 6/9], this v9 series should allow the embedded doorbell fallback
    path to pass on RK3588 from the beginning. Given that, picking up the whole
    (3) series earlier should be the most streamlined choice.


Tested on
---------

I re-tested the embedded (DMA) doorbell fallback path (via pci-epf-test)
on R-Car Spider boards (with this v9 series):

  $ ./pci_endpoint_test -t DOORBELL_TEST
  TAP version 13
  1..1
  # Starting 1 tests from 1 test cases.
  #  RUN           pcie_ep_doorbell.DOORBELL_TEST ...
  #            OK  pcie_ep_doorbell.DOORBELL_TEST
  ok 1 pcie_ep_doorbell.DOORBELL_TEST
  # PASSED: 1 / 1 tests passed.
  # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0

with the following message observed on the EP side:

  [   82.043715] pci_epf_test pci_epf_test.0: Can't find MSI domain for EPC
  [   82.044382] pci_epf_test pci_epf_test.0: Using embedded (DMA) doorbell fallback

(Note: for the test to pass on R-Car Spider, one of the following was required:
 - echo 1048576 > functions/pci_epf_test/func1/pci_epf_test.0/bar2_size
 - apply https://lore.kernel.org/linux-pci/20260210160315.2272930-1-den@valinux.co.jp/)


Performance test: vNTB ping latency
-----------------------------------

Setup:
  - configfs (R-Car Spider in EP mode):

      cd /sys/kernel/config/pci_ep/
      mkdir functions/pci_epf_vntb/func1
      echo 0x1912 >   functions/pci_epf_vntb/func1/vendorid
      echo 0x0030 >   functions/pci_epf_vntb/func1/deviceid
      echo 32 >       functions/pci_epf_vntb/func1/msi_interrupts
      echo 4 >        functions/pci_epf_vntb/func1/pci_epf_vntb.0/db_count
      echo 128 >      functions/pci_epf_vntb/func1/pci_epf_vntb.0/spad_count
      echo 1 >        functions/pci_epf_vntb/func1/pci_epf_vntb.0/num_mws
      echo 0x100000 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/mw1
      echo 0x1912 >   functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_vid
      echo 0x0030 >   functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid
      echo 0x10 >     functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number
      echo 0 >        functions/pci_epf_vntb/func1/pci_epf_vntb.0/ctrl_bar
      echo 4 >        functions/pci_epf_vntb/func1/pci_epf_vntb.0/db_bar [*]
      echo 2 >        functions/pci_epf_vntb/func1/pci_epf_vntb.0/mw1_bar
      ln -s controllers/e65d0000.pcie-ep functions/pci_epf_vntb/func1/primary/
      echo 1 > controllers/e65d0000.pcie-ep/start

      [*]: On R-Car Spider, a hack is currently needed to use BAR4 for
           the doorbell. I'll consider posting a patch for that
           separately.

  - ensure ntb_transport/ntb_netdev are loaded on both sides

Results:

  - Without this series (pci.git main)

    $ ping -c 10 10.0.0.11
    PING 10.0.0.11 (10.0.0.11) 56(84) bytes of data.
    64 bytes from 10.0.0.11: icmp_seq=1 ttl=64 time=6.04 ms
    64 bytes from 10.0.0.11: icmp_seq=2 ttl=64 time=12.6 ms
    64 bytes from 10.0.0.11: icmp_seq=3 ttl=64 time=7.40 ms
    64 bytes from 10.0.0.11: icmp_seq=4 ttl=64 time=5.38 ms
    64 bytes from 10.0.0.11: icmp_seq=5 ttl=64 time=11.4 ms
    64 bytes from 10.0.0.11: icmp_seq=6 ttl=64 time=9.42 ms
    64 bytes from 10.0.0.11: icmp_seq=7 ttl=64 time=3.36 ms
    64 bytes from 10.0.0.11: icmp_seq=8 ttl=64 time=9.48 ms
    64 bytes from 10.0.0.11: icmp_seq=9 ttl=64 time=4.24 ms
    64 bytes from 10.0.0.11: icmp_seq=10 ttl=64 time=10.4 ms

  - With this series (on top of pci.git main + Dependency (1), (2) and (3))

    $ ping -c 10 10.0.0.11
    PING 10.0.0.11 (10.0.0.11) 56(84) bytes of data.
    64 bytes from 10.0.0.11: icmp_seq=1 ttl=64 time=0.845 ms
    64 bytes from 10.0.0.11: icmp_seq=2 ttl=64 time=0.742 ms
    64 bytes from 10.0.0.11: icmp_seq=3 ttl=64 time=0.868 ms
    64 bytes from 10.0.0.11: icmp_seq=4 ttl=64 time=0.806 ms
    64 bytes from 10.0.0.11: icmp_seq=5 ttl=64 time=0.951 ms
    64 bytes from 10.0.0.11: icmp_seq=6 ttl=64 time=0.965 ms
    64 bytes from 10.0.0.11: icmp_seq=7 ttl=64 time=0.871 ms
    64 bytes from 10.0.0.11: icmp_seq=8 ttl=64 time=0.877 ms
    64 bytes from 10.0.0.11: icmp_seq=9 ttl=64 time=0.938 ms
    64 bytes from 10.0.0.11: icmp_seq=10 ttl=64 time=0.960 ms

---

Changelog
---------

* v8->v9 changes:
  - Add a new dependency series (3), which moved the BAR reserved-subregion
    framework + the RK3588 BAR4 example out of v8 (dropping the corresponding
    patches from this series).
  - pci-epf-vntb: rename the duplicate-IRQ helper and invert the return value,
    per Frank's review.
  - pci-epf-test: drop the extra size_add() doorbell-offset check, per Niklas'
    review.
  - pci-ep-msi: add a DWORD alignment check for DOORBELL_MMIO, per Niklas's
    review.
  - Carry over Reviewed-by tags for unchanged patches + drop Reviewed-by tags
    where code changed.
  - Rename the last patch subject (drop 'eDMA' word).

* v7->v8 changes:
  - Deduplicate request_irq()/free_irq() calls based on virq (shared
    IRQ) rather than doorbell type, as suggested during review of v7
    Patch #7.
  - Clean up the pci_epf_alloc_doorbell() error path, as suggested
    during review of v7 Patch #9.
  - Use range_end_overflows_t() instead of an open-coded overflow check,
    following discussion during review of v7 Patch #5.
  - Add a write-data field to the DOORBELL_MMIO aux-resource metadata
    and plumb it through to the embedded doorbell backend (DesignWare
    uses data=0).

* v6->v7 changes:
  - Split out preparatory patches to keep the series below 10 patches.
  - Add support for platforms where the eDMA register block is fixed
    within a reserved BAR window (e.g. RK3588 BAR4) and must be reused
    as-is.
  - Introduce a dedicated virtual IRQ and irq_chip (using
    handle_level_irq) for interrupt-emulation doorbells instead of
    reusing per-channel IRQs. This avoids delivery via different IRQs on
    platforms with chip->nr_irqs > 1.

* v5->v6 changes:
  - Fix a double-free in v5 Patch 8/8 caused by mixing __free(kfree) with
    an explicit kfree(). This is a functional bug (detectable by KASAN),
    hence the respin solely for this fix. Sorry for the noise. No other
    changes.

* v4->v5 changes:
  - Change the series subject now that the series has evolved into a
    consumer-driven set focused on the embedded doorbell fallback and its
    in-tree users (epf-test and epf-vntb).
  - Drop [PATCH v4 01/09] (dw-edma per-channel interrupt routing control)
    from this series for now, so the series focuses on what's needed by the
    current consumer (i.e. the doorbell fallback implementation).
  - Replace the v4 embedded-doorbell "test variant + host/kselftest
    plumbing" with a generic embedded-doorbell fallback in
    pci_epf_alloc_doorbell(), including exposing required IRQ request flags
    to EPF drivers.
  - Two preparatory fix patches (Patch 6/8 and 7/8) to clean up error
    handling and state management ahead of Patch 8/8.
  - Rename *_get_remote_resource() to *_get_aux_resources() and adjust
    relevant variable namings and kernel docs. Discussion may continue.
  - Rework dw-edma per-channel metadata exposure to cache the needed info
    in dw_edma_chip (IRQ number + emulation doorbell offset) and consume it
    from the DesignWare EPC auxiliary resource provider without calling back
    to dw-edma.

* v3->v4 changes:
  - Drop dma_slave_caps.hw_id and the dmaengine selfirq callback
    registration API. Instead, add a dw-edma specific dw_edma_chan_info()
    helper and extend the EPC remote resource metadata accordingly.
  - Add explicit acking for eDMA interrupt emulation and adjust the
    dw-edma IRQ path for embedded-doorbell usage.
  - Replace the previous EPC API smoke test with an embedded doorbell
    test variant (pci-epf-test + pci_endpoint_test/selftests).
  - Rebase onto pci.git controller/dwc commit 43d324eeb08c.

* v2->v3 changes:
  - Replace DWC-specific helpers with a generic EPC remote resource query API.
  - Add pci-epf-test smoke test and host/kselftest support for the new API.
  - Drop the dw-edma-specific notify-only channel and polling approach
    ([PATCH v2 4/7] and [PATCH v2 5/7]), and rework notification handling
    around a generic dmaengine_(un)register_selfirq() API implemented
    by dw-edma.

* v1->v2 changes:
  - Combine the two previously posted series into a single set (per Frank's
    suggestion). Order dmaengine/dw-edma patches first so hw_id support
    lands before the PCI LL-region helper, which assumes
    dma_slave_caps.hw_id availability.

v8: https://lore.kernel.org/linux-pci/20260217080601.3808847-1-den@valinux.co.jp/
v7: https://lore.kernel.org/linux-pci/20260215163847.3522572-1-den@valinux.co.jp/
v6: https://lore.kernel.org/all/20260209125316.2132589-1-den@valinux.co.jp/
v5: https://lore.kernel.org/all/20260209062952.2049053-1-den@valinux.co.jp/
v4: https://lore.kernel.org/all/20260206172646.1556847-1-den@valinux.co.jp/
v3: https://lore.kernel.org/all/20260204145440.950609-1-den@valinux.co.jp/
v2: https://lore.kernel.org/all/20260127033420.3460579-1-den@valinux.co.jp/
v1: https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
    +
    https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/


Thanks for reviewing.


Koichiro Den (7):
  PCI: endpoint: Add auxiliary resource query API
  PCI: dwc: Record integrated eDMA register window
  PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource
    API
  PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new
    backends
  PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets
  PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback

 .../pci/controller/dwc/pcie-designware-ep.c   | 151 ++++++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.c  |   4 +
 drivers/pci/controller/dwc/pcie-designware.h  |   2 +
 drivers/pci/endpoint/functions/pci-epf-test.c |  84 ++++++----
 drivers/pci/endpoint/functions/pci-epf-vntb.c |  61 ++++++-
 drivers/pci/endpoint/pci-ep-msi.c             | 149 +++++++++++++++--
 drivers/pci/endpoint/pci-epc-core.c           |  41 +++++
 include/linux/pci-epc.h                       |  52 ++++++
 include/linux/pci-epf.h                       |  23 ++-
 9 files changed, 520 insertions(+), 47 deletions(-)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v9 1/7] PCI: endpoint: Add auxiliary resource query API
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 2/7] PCI: dwc: Record integrated eDMA register window Koichiro Den
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Endpoint controller drivers may integrate auxiliary blocks (e.g. DMA
engines) whose register windows and descriptor memories metadata need to
be exposed to a remote peer. Endpoint function drivers need a generic
way to discover such resources without hard-coding controller-specific
helpers.

Add pci_epc_get_aux_resources() and the corresponding pci_epc_ops
get_aux_resources() callback. The API returns a list of resources
described by type, physical address and size, plus type-specific
metadata.

Passing resources == NULL (or num_resources == 0) returns the required
number of entries.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/endpoint/pci-epc-core.c | 41 +++++++++++++++++++++++
 include/linux/pci-epc.h             | 52 +++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 5045e22367cf..10bd392c4667 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -157,6 +157,47 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 }
 EXPORT_SYMBOL_GPL(pci_epc_get_features);
 
+/**
+ * pci_epc_get_aux_resources() - query EPC-provided auxiliary resources
+ * @epc: EPC device
+ * @func_no: function number
+ * @vfunc_no: virtual function number
+ * @resources: output array (may be NULL to query required count)
+ * @num_resources: size of @resources array in entries (0 when querying count)
+ *
+ * Some EPC backends integrate auxiliary blocks (e.g. DMA engines) whose control
+ * registers and/or descriptor memories can be exposed to the host by mapping
+ * them into BAR space. This helper queries the backend for such resources.
+ *
+ * Return:
+ *   * >= 0: number of resources returned (or required, if @resources is NULL)
+ *   * -EOPNOTSUPP: backend does not support auxiliary resource queries
+ *   * other -errno on failure
+ */
+int pci_epc_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			      struct pci_epc_aux_resource *resources,
+			      int num_resources)
+{
+	int ret;
+
+	if (!epc || !epc->ops)
+		return -EINVAL;
+
+	if (func_no >= epc->max_functions)
+		return -EINVAL;
+
+	if (!epc->ops->get_aux_resources)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&epc->lock);
+	ret = epc->ops->get_aux_resources(epc, func_no, vfunc_no, resources,
+					  num_resources);
+	mutex_unlock(&epc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_get_aux_resources);
+
 /**
  * pci_epc_stop() - stop the PCI link
  * @epc: the link of the EPC device that has to be stopped
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 8687b9c3462b..705026f64ef1 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -61,6 +61,51 @@ struct pci_epc_map {
 	void __iomem	*virt_addr;
 };
 
+/**
+ * enum pci_epc_aux_resource_type - auxiliary resource type identifiers
+ * @PCI_EPC_AUX_DMA_CTRL_MMIO: Integrated DMA controller register window (MMIO)
+ * @PCI_EPC_AUX_DMA_CHAN_DESC: Per-channel DMA descriptor
+ * @PCI_EPC_AUX_DOORBELL_MMIO: Doorbell MMIO, that might be outside the DMA
+ *                             controller register window
+ *
+ * EPC backends may expose auxiliary blocks (e.g. DMA engines) by mapping their
+ * register windows and descriptor memories into BAR space. This enum
+ * identifies the type of each exposable resource.
+ */
+enum pci_epc_aux_resource_type {
+	PCI_EPC_AUX_DMA_CTRL_MMIO,
+	PCI_EPC_AUX_DMA_CHAN_DESC,
+	PCI_EPC_AUX_DOORBELL_MMIO,
+};
+
+/**
+ * struct pci_epc_aux_resource - a physical auxiliary resource that may be
+ *                               exposed for peer use
+ * @type:       resource type, see enum pci_epc_aux_resource_type
+ * @phys_addr:  physical base address of the resource
+ * @size:       size of the resource in bytes
+ * @bar:        BAR number where this resource is already exposed to the RC
+ *              (NO_BAR if not)
+ * @bar_offset: offset within @bar where the resource starts (valid iff
+ *              @bar != NO_BAR)
+ * @u:          type-specific metadata
+ */
+struct pci_epc_aux_resource {
+	enum pci_epc_aux_resource_type type;
+	phys_addr_t phys_addr;
+	resource_size_t size;
+	enum pci_barno bar;
+	resource_size_t bar_offset;
+
+	union {
+		/* PCI_EPC_AUX_DOORBELL_MMIO */
+		struct {
+			int irq; /* IRQ number for the doorbell handler */
+			u32 data; /* write value to ring the doorbell */
+		} db_mmio;
+	} u;
+};
+
 /**
  * struct pci_epc_ops - set of function pointers for performing EPC operations
  * @write_header: ops to populate configuration space header
@@ -84,6 +129,7 @@ struct pci_epc_map {
  * @start: ops to start the PCI link
  * @stop: ops to stop the PCI link
  * @get_features: ops to get the features supported by the EPC
+ * @get_aux_resources: ops to retrieve controller-owned auxiliary resources
  * @owner: the module owner containing the ops
  */
 struct pci_epc_ops {
@@ -115,6 +161,9 @@ struct pci_epc_ops {
 	void	(*stop)(struct pci_epc *epc);
 	const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
 						       u8 func_no, u8 vfunc_no);
+	int	(*get_aux_resources)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+				     struct pci_epc_aux_resource *resources,
+				     int num_resources);
 	struct module *owner;
 };
 
@@ -348,6 +397,9 @@ int pci_epc_start(struct pci_epc *epc);
 void pci_epc_stop(struct pci_epc *epc);
 const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 						    u8 func_no, u8 vfunc_no);
+int pci_epc_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			      struct pci_epc_aux_resource *resources,
+			      int num_resources);
 enum pci_barno
 pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features);
 enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 2/7] PCI: dwc: Record integrated eDMA register window
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 1/7] PCI: endpoint: Add auxiliary resource query API Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 3/7] PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource API Koichiro Den
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Some DesignWare PCIe controllers integrate an eDMA block whose registers
are located in a dedicated register window. Endpoint function drivers
may need the physical base and size of this window to map/expose it to a
peer.

Record the physical base and size of the integrated eDMA register window
in struct dw_pcie.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/controller/dwc/pcie-designware.c | 4 ++++
 drivers/pci/controller/dwc/pcie-designware.h | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 5741c09dde7f..f82ed189f6ae 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -162,8 +162,12 @@ int dw_pcie_get_resources(struct dw_pcie *pci)
 			pci->edma.reg_base = devm_ioremap_resource(pci->dev, res);
 			if (IS_ERR(pci->edma.reg_base))
 				return PTR_ERR(pci->edma.reg_base);
+			pci->edma_reg_phys = res->start;
+			pci->edma_reg_size = resource_size(res);
 		} else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) {
 			pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET;
+			pci->edma_reg_phys = pci->atu_phys_addr + DEFAULT_DBI_DMA_OFFSET;
+			pci->edma_reg_size = pci->atu_size - DEFAULT_DBI_DMA_OFFSET;
 		}
 	}
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index ae6389dd9caa..52f26663e8b1 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -541,6 +541,8 @@ struct dw_pcie {
 	int			max_link_speed;
 	u8			n_fts[2];
 	struct dw_edma_chip	edma;
+	phys_addr_t		edma_reg_phys;
+	resource_size_t		edma_reg_size;
 	bool			l1ss_support;	/* L1 PM Substates support */
 	struct clk_bulk_data	app_clks[DW_PCIE_NUM_APP_CLKS];
 	struct clk_bulk_data	core_clks[DW_PCIE_NUM_CORE_CLKS];
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 3/7] PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource API
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 1/7] PCI: endpoint: Add auxiliary resource query API Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 2/7] PCI: dwc: Record integrated eDMA register window Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 4/7] PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends Koichiro Den
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Implement the EPC aux-resource API for DesignWare endpoint controllers
with integrated eDMA.

Report:
  - DMA controller MMIO window (PCI_EPC_AUX_DMA_CTRL_MMIO)
  - interrupt-emulation doorbell register (PCI_EPC_AUX_DOORBELL_MMIO),
    including its Linux IRQ and the data value to write to trigger the
    interrupt
  - per-channel LL descriptor regions (PCI_EPC_AUX_DMA_CHAN_DESC)

If the DMA controller MMIO window is already exposed via a
platform-owned fixed BAR subregion, also provide the BAR number and
offset so EPF drivers can reuse it without reprogramming the BAR.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 .../pci/controller/dwc/pcie-designware-ep.c   | 151 ++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 5e47517c757c..2408ce95c103 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -9,6 +9,7 @@
 #include <linux/align.h>
 #include <linux/bitfield.h>
 #include <linux/of.h>
+#include <linux/overflow.h>
 #include <linux/platform_device.h>
 
 #include "pcie-designware.h"
@@ -808,6 +809,155 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
 	return ep->ops->get_features(ep);
 }
 
+static const struct pci_epc_bar_rsvd_region *
+dw_pcie_ep_find_bar_rsvd_region(struct dw_pcie_ep *ep,
+				enum pci_epc_bar_rsvd_region_type type,
+				enum pci_barno *bar,
+				resource_size_t *bar_offset)
+{
+	const struct pci_epc_features *features;
+	const struct pci_epc_bar_desc *bar_desc;
+	const struct pci_epc_bar_rsvd_region *r;
+	int i, j;
+
+	if (!ep->ops->get_features)
+		return NULL;
+
+	features = ep->ops->get_features(ep);
+	if (!features)
+		return NULL;
+
+	for (i = BAR_0; i <= BAR_5; i++) {
+		bar_desc = &features->bar[i];
+
+		if (!bar_desc->nr_rsvd_regions || !bar_desc->rsvd_regions)
+			continue;
+
+		for (j = 0; j < bar_desc->nr_rsvd_regions; j++) {
+			r = &bar_desc->rsvd_regions[j];
+
+			if (r->type != type)
+				continue;
+
+			if (bar)
+				*bar = i;
+			if (bar_offset)
+				*bar_offset = r->offset;
+			return r;
+		}
+	}
+
+	return NULL;
+}
+
+static int
+dw_pcie_ep_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+			     struct pci_epc_aux_resource *resources,
+			     int num_resources)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	const struct pci_epc_bar_rsvd_region *rsvd;
+	struct dw_edma_chip *edma = &pci->edma;
+	enum pci_barno dma_ctrl_bar = NO_BAR;
+	int ll_cnt = 0, needed, idx = 0;
+	resource_size_t db_offset = edma->db_offset;
+	resource_size_t dma_ctrl_bar_offset = 0;
+	resource_size_t dma_reg_size;
+	unsigned int i;
+
+	if (!pci->edma_reg_size)
+		return 0;
+
+	dma_reg_size = pci->edma_reg_size;
+
+	for (i = 0; i < edma->ll_wr_cnt; i++)
+		if (edma->ll_region_wr[i].sz)
+			ll_cnt++;
+
+	for (i = 0; i < edma->ll_rd_cnt; i++)
+		if (edma->ll_region_rd[i].sz)
+			ll_cnt++;
+
+	needed = 1 + ll_cnt + (db_offset != ~0 ? 1 : 0);
+
+	/* Count query mode */
+	if (!resources || !num_resources)
+		return needed;
+
+	if (num_resources < needed)
+		return -ENOSPC;
+
+	rsvd = dw_pcie_ep_find_bar_rsvd_region(ep,
+					       PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO,
+					       &dma_ctrl_bar,
+					       &dma_ctrl_bar_offset);
+	if (rsvd && rsvd->size < dma_reg_size)
+		dma_reg_size = rsvd->size;
+
+	/* DMA register block */
+	resources[idx++] = (struct pci_epc_aux_resource) {
+		.type = PCI_EPC_AUX_DMA_CTRL_MMIO,
+		.phys_addr = pci->edma_reg_phys,
+		.size = dma_reg_size,
+		.bar = dma_ctrl_bar,
+		.bar_offset = dma_ctrl_bar_offset,
+	};
+
+	/*
+	 * For interrupt-emulation doorbells, report a standalone resource
+	 * instead of bundling it into the DMA controller MMIO resource.
+	 */
+	if (db_offset != ~0) {
+		if (range_end_overflows_t(resource_size_t, db_offset,
+					  sizeof(u32), dma_reg_size))
+			return -EINVAL;
+
+		resources[idx++] = (struct pci_epc_aux_resource) {
+			.type = PCI_EPC_AUX_DOORBELL_MMIO,
+			.phys_addr = pci->edma_reg_phys + db_offset,
+			.size = sizeof(u32),
+			.bar = dma_ctrl_bar,
+			.bar_offset = dma_ctrl_bar != NO_BAR ?
+					dma_ctrl_bar_offset + db_offset : 0,
+			.u.db_mmio = {
+				.irq = edma->db_irq,
+				.data = 0, /* write 0 to assert */
+			},
+		};
+	}
+
+	/* One LL region per write channel */
+	for (i = 0; i < edma->ll_wr_cnt; i++) {
+		if (!edma->ll_region_wr[i].sz)
+			continue;
+
+		resources[idx++] = (struct pci_epc_aux_resource) {
+			.type = PCI_EPC_AUX_DMA_CHAN_DESC,
+			.phys_addr = edma->ll_region_wr[i].paddr,
+			.size = edma->ll_region_wr[i].sz,
+			.bar = NO_BAR,
+			.bar_offset = 0,
+		};
+	}
+
+	/* One LL region per read channel */
+	for (i = 0; i < edma->ll_rd_cnt; i++) {
+		if (!edma->ll_region_rd[i].sz)
+			continue;
+
+		resources[idx++] = (struct pci_epc_aux_resource) {
+			.type = PCI_EPC_AUX_DMA_CHAN_DESC,
+			.phys_addr = edma->ll_region_rd[i].paddr,
+			.size = edma->ll_region_rd[i].sz,
+			.bar = NO_BAR,
+			.bar_offset = 0,
+		};
+	}
+
+	return idx;
+}
+
 static const struct pci_epc_ops epc_ops = {
 	.write_header		= dw_pcie_ep_write_header,
 	.set_bar		= dw_pcie_ep_set_bar,
@@ -823,6 +973,7 @@ static const struct pci_epc_ops epc_ops = {
 	.start			= dw_pcie_ep_start,
 	.stop			= dw_pcie_ep_stop,
 	.get_features		= dw_pcie_ep_get_features,
+	.get_aux_resources	= dw_pcie_ep_get_aux_resources,
 };
 
 /**
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 4/7] PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
                   ` (2 preceding siblings ...)
  2026-02-19  8:13 ` [PATCH v9 3/7] PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource API Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags Koichiro Den
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Prepare pci-ep-msi for non-MSI doorbell backends.

Factor MSI doorbell allocation into a helper and extend struct
pci_epf_doorbell_msg with:

  - irq_flags: required IRQ request flags (e.g. IRQF_SHARED for some
    backends)
  - type: doorbell backend type
  - bar/offset: pre-exposed doorbell target location, if any

Initialize these fields for the existing MSI-backed doorbell
implementation.

Also add PCI_EPF_DOORBELL_EMBEDDED type, which is to be implemented in a
follow-up patch.

No functional changes.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/endpoint/pci-ep-msi.c | 54 ++++++++++++++++++++++---------
 include/linux/pci-epf.h           | 23 +++++++++++--
 2 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index ad8a81d6ad77..50badffa9d72 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -8,6 +8,7 @@
 
 #include <linux/device.h>
 #include <linux/export.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/msi.h>
@@ -35,23 +36,13 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
 	pci_epc_put(epc);
 }
 
-int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
+static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
 {
-	struct pci_epc *epc = epf->epc;
+	struct pci_epf_doorbell_msg *msg;
 	struct device *dev = &epf->dev;
+	struct pci_epc *epc = epf->epc;
 	struct irq_domain *domain;
-	void *msg;
-	int ret;
-	int i;
-
-	/* TODO: Multi-EPF support */
-	if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
-		dev_err(dev, "MSI doorbell doesn't support multiple EPF\n");
-		return -EINVAL;
-	}
-
-	if (epf->db_msg)
-		return -EBUSY;
+	int ret, i;
 
 	domain = of_msi_map_get_device_domain(epc->dev.parent, 0,
 					      DOMAIN_BUS_PLATFORM_MSI);
@@ -74,6 +65,12 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
 	if (!msg)
 		return -ENOMEM;
 
+	for (i = 0; i < num_db; i++)
+		msg[i] = (struct pci_epf_doorbell_msg) {
+			.type = PCI_EPF_DOORBELL_MSI,
+			.bar = NO_BAR,
+		};
+
 	epf->num_db = num_db;
 	epf->db_msg = msg;
 
@@ -90,13 +87,40 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
 	for (i = 0; i < num_db; i++)
 		epf->db_msg[i].virq = msi_get_virq(epc->dev.parent, i);
 
+	return 0;
+}
+
+int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
+{
+	struct pci_epc *epc = epf->epc;
+	struct device *dev = &epf->dev;
+	int ret;
+
+	/* TODO: Multi-EPF support */
+	if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
+		dev_err(dev, "Doorbell doesn't support multiple EPF\n");
+		return -EINVAL;
+	}
+
+	if (epf->db_msg)
+		return -EBUSY;
+
+	ret = pci_epf_alloc_doorbell_msi(epf, num_db);
+	if (!ret)
+		return 0;
+
+	dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
 
 void pci_epf_free_doorbell(struct pci_epf *epf)
 {
-	platform_device_msi_free_irqs_all(epf->epc->dev.parent);
+	if (!epf->db_msg)
+		return;
+
+	if (epf->db_msg[0].type == PCI_EPF_DOORBELL_MSI)
+		platform_device_msi_free_irqs_all(epf->epc->dev.parent);
 
 	kfree(epf->db_msg);
 	epf->db_msg = NULL;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 7737a7c03260..cd747447a1ea 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -152,14 +152,33 @@ struct pci_epf_bar {
 	struct pci_epf_bar_submap	*submap;
 };
 
+enum pci_epf_doorbell_type {
+	PCI_EPF_DOORBELL_MSI = 0,
+	PCI_EPF_DOORBELL_EMBEDDED,
+};
+
 /**
  * struct pci_epf_doorbell_msg - represents doorbell message
- * @msg: MSI message
- * @virq: IRQ number of this doorbell MSI message
+ * @msg: Doorbell address/data pair to be mapped into BAR space.
+ *       For MSI-backed doorbells this is the MSI message, while for
+ *       "embedded" doorbells this represents an MMIO write that asserts
+ *       an interrupt on the EP side.
+ * @virq: IRQ number of this doorbell message
+ * @irq_flags: Required flags for request_irq()/request_threaded_irq().
+ *             Callers may OR-in additional flags (e.g. IRQF_ONESHOT).
+ * @type: Doorbell type.
+ * @bar: BAR number where the doorbell target is already exposed to the RC
+ *       (NO_BAR if not)
+ * @offset: offset within @bar for the doorbell target (valid iff
+ *          @bar != NO_BAR)
  */
 struct pci_epf_doorbell_msg {
 	struct msi_msg msg;
 	int virq;
+	unsigned long irq_flags;
+	enum pci_epf_doorbell_type type;
+	enum pci_barno bar;
+	resource_size_t offset;
 };
 
 /**
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
                   ` (3 preceding siblings ...)
  2026-02-19  8:13 ` [PATCH v9 4/7] PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19 16:30   ` ALOK TIWARI
  2026-02-19  8:13 ` [PATCH v9 6/7] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets Koichiro Den
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Support doorbell backends where the doorbell target is already exposed
via a platform-owned fixed BAR mapping and/or where the doorbell IRQ
must be requested with specific flags.

When pci_epf_alloc_doorbell() provides db_msg[].bar/offset, reuse the
pre-exposed BAR window and skip programming a new inbound mapping. Also
honor db_msg[].irq_flags when requesting the doorbell IRQ.

Multiple doorbells may share the same Linux IRQ. Avoid duplicate
request_irq() calls by requesting each unique virq once.

Make pci-epf-vntb work with platform-defined or embedded doorbell
backends without exposing backend-specific details to the consumer
layer.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes since v8:
  - Reword the last paragraph into imperative mood
  - Rename s/epf_ntb_db_irq_is_first/epf_ntb_db_irq_is_duplicated/ and
    invert the returned bool value

 drivers/pci/endpoint/functions/pci-epf-vntb.c | 61 ++++++++++++++++++-
 1 file changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 52cf442ca1d9..7a27e9343394 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -134,6 +134,11 @@ struct epf_ntb {
 	u16 vntb_vid;
 
 	bool linkup;
+
+	/*
+	 * True when doorbells are interrupt-driven (MSI or embedded), false
+	 * when polled.
+	 */
 	bool msi_doorbell;
 	u32 spad_size;
 
@@ -517,6 +522,17 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)
 	return 0;
 }
 
+static bool epf_ntb_db_irq_is_duplicated(const struct pci_epf *epf, unsigned int idx)
+{
+	unsigned int i;
+
+	for (i = 0; i < idx; i++)
+		if (epf->db_msg[i].virq == epf->db_msg[idx].virq)
+			return true;
+
+	return false;
+}
+
 static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 					    struct pci_epf_bar *db_bar,
 					    const struct pci_epc_features *epc_features,
@@ -533,9 +549,24 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 	if (ret)
 		return ret;
 
+	/*
+	 * The doorbell target may already be exposed by a platform-owned fixed
+	 * BAR. In that case, we must reuse it and the requested db_bar must
+	 * match.
+	 */
+	if (epf->db_msg[0].bar != NO_BAR && epf->db_msg[0].bar != barno) {
+		ret = -EINVAL;
+		goto err_free_doorbell;
+	}
+
 	for (req = 0; req < ntb->db_count; req++) {
+		/* Avoid requesting duplicate handlers */
+		if (epf_ntb_db_irq_is_duplicated(epf, req))
+			continue;
+
 		ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
-				  0, "pci_epf_vntb_db", ntb);
+				  epf->db_msg[req].irq_flags, "pci_epf_vntb_db",
+				  ntb);
 
 		if (ret) {
 			dev_err(&epf->dev,
@@ -545,6 +576,22 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 		}
 	}
 
+	if (epf->db_msg[0].bar != NO_BAR) {
+		for (i = 0; i < ntb->db_count; i++) {
+			msg = &epf->db_msg[i].msg;
+
+			if (epf->db_msg[i].bar != barno) {
+				ret = -EINVAL;
+				goto err_free_irq;
+			}
+
+			ntb->reg->db_data[i] = msg->data;
+			ntb->reg->db_offset[i] = epf->db_msg[i].offset;
+		}
+		goto out;
+	}
+
+	/* Program inbound mapping for the doorbell */
 	msg = &epf->db_msg[0].msg;
 
 	high = 0;
@@ -591,6 +638,7 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 		ntb->reg->db_offset[i] = offset;
 	}
 
+out:
 	ntb->reg->db_entry_size = 0;
 
 	ntb->msi_doorbell = true;
@@ -598,9 +646,13 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 	return 0;
 
 err_free_irq:
-	for (req--; req >= 0; req--)
+	for (req--; req >= 0; req--) {
+		if (epf_ntb_db_irq_is_duplicated(epf, req))
+			continue;
 		free_irq(epf->db_msg[req].virq, ntb);
+	}
 
+err_free_doorbell:
 	pci_epf_free_doorbell(ntb->epf);
 	return ret;
 }
@@ -666,8 +718,11 @@ static void epf_ntb_db_bar_clear(struct epf_ntb *ntb)
 	if (ntb->msi_doorbell) {
 		int i;
 
-		for (i = 0; i < ntb->db_count; i++)
+		for (i = 0; i < ntb->db_count; i++) {
+			if (epf_ntb_db_irq_is_duplicated(ntb->epf, i))
+				continue;
 			free_irq(ntb->epf->db_msg[i].virq, ntb);
+		}
 	}
 
 	if (ntb->epf->db_msg)
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 6/7] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
                   ` (4 preceding siblings ...)
  2026-02-19  8:13 ` [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-19  8:13 ` [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
  2026-02-27 15:06 ` [PATCH v9 0/7] " Niklas Cassel
  7 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

pci-epf-test advertises the doorbell target to the RC as a BAR number
and an offset, and the RC rings the doorbell with a single DWORD MMIO
write.

Some doorbell backends may report that the doorbell target is already
exposed via a platform-owned fixed BAR (db_msg[0].bar/offset). In that
case, reuse the pre-exposed window and do not reprogram the BAR with
pci_epc_set_bar().

Also honor db_msg[0].irq_flags when requesting the doorbell IRQ, and
only restore the original BAR mapping on disable if pci-epf-test
programmed it.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes since v8:
  - Drop the extra size_add() doorbell-offset check, which is generally
    unneeded when pci_epf_align_inbound_addr() runs. This fixes
    BAR_RESERVED cases where epf->bar[bar].size can be 0.

 drivers/pci/endpoint/functions/pci-epf-test.c | 84 +++++++++++++------
 1 file changed, 57 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 684f018ea242..4fc53edbceed 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -92,6 +92,7 @@ struct pci_epf_test {
 	bool			dma_private;
 	const struct pci_epc_features *epc_features;
 	struct pci_epf_bar	db_bar;
+	bool			db_bar_programmed;
 	size_t			bar_size[PCI_STD_NUM_BARS];
 };
 
@@ -731,7 +732,9 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
 {
 	u32 status = le32_to_cpu(reg->status);
 	struct pci_epf *epf = epf_test->epf;
+	struct pci_epf_doorbell_msg *db;
 	struct pci_epc *epc = epf->epc;
+	unsigned long irq_flags;
 	struct msi_msg *msg;
 	enum pci_barno bar;
 	size_t offset;
@@ -741,13 +744,28 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
 	if (ret)
 		goto set_status_err;
 
-	msg = &epf->db_msg[0].msg;
-	bar = pci_epc_get_next_free_bar(epf_test->epc_features, epf_test->test_reg_bar + 1);
-	if (bar < BAR_0)
-		goto err_doorbell_cleanup;
+	db = &epf->db_msg[0];
+	msg = &db->msg;
+	epf_test->db_bar_programmed = false;
+
+	if (db->bar != NO_BAR) {
+		/*
+		 * The doorbell target is already exposed via a platform-owned
+		 * fixed BAR
+		 */
+		bar = db->bar;
+		offset = db->offset;
+	} else {
+		bar = pci_epc_get_next_free_bar(epf_test->epc_features,
+						epf_test->test_reg_bar + 1);
+		if (bar < BAR_0)
+			goto err_doorbell_cleanup;
+	}
+
+	irq_flags = epf->db_msg[0].irq_flags | IRQF_ONESHOT;
 
 	ret = request_threaded_irq(epf->db_msg[0].virq, NULL,
-				   pci_epf_test_doorbell_handler, IRQF_ONESHOT,
+				   pci_epf_test_doorbell_handler, irq_flags,
 				   "pci-ep-test-doorbell", epf_test);
 	if (ret) {
 		dev_err(&epf->dev,
@@ -759,22 +777,30 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
 	reg->doorbell_data = cpu_to_le32(msg->data);
 	reg->doorbell_bar = cpu_to_le32(bar);
 
-	msg = &epf->db_msg[0].msg;
-	ret = pci_epf_align_inbound_addr(epf, bar, ((u64)msg->address_hi << 32) | msg->address_lo,
-					 &epf_test->db_bar.phys_addr, &offset);
+	if (db->bar == NO_BAR) {
+		ret = pci_epf_align_inbound_addr(epf, bar,
+						 ((u64)msg->address_hi << 32) |
+						 msg->address_lo,
+						 &epf_test->db_bar.phys_addr,
+						 &offset);
 
-	if (ret)
-		goto err_free_irq;
+		if (ret)
+			goto err_free_irq;
+	}
 
 	reg->doorbell_offset = cpu_to_le32(offset);
 
-	epf_test->db_bar.barno = bar;
-	epf_test->db_bar.size = epf->bar[bar].size;
-	epf_test->db_bar.flags = epf->bar[bar].flags;
+	if (db->bar == NO_BAR) {
+		epf_test->db_bar.barno = bar;
+		epf_test->db_bar.size = epf->bar[bar].size;
+		epf_test->db_bar.flags = epf->bar[bar].flags;
 
-	ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar);
-	if (ret)
-		goto err_free_irq;
+		ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar);
+		if (ret)
+			goto err_free_irq;
+
+		epf_test->db_bar_programmed = true;
+	}
 
 	status |= STATUS_DOORBELL_ENABLE_SUCCESS;
 	reg->status = cpu_to_le32(status);
@@ -804,17 +830,21 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test,
 	free_irq(epf->db_msg[0].virq, epf_test);
 	pci_epf_test_doorbell_cleanup(epf_test);
 
-	/*
-	 * The doorbell feature temporarily overrides the inbound translation
-	 * to point to the address stored in epf_test->db_bar.phys_addr, i.e.,
-	 * it calls set_bar() twice without ever calling clear_bar(), as
-	 * calling clear_bar() would clear the BAR's PCI address assigned by
-	 * the host. Thus, when disabling the doorbell, restore the inbound
-	 * translation to point to the memory allocated for the BAR.
-	 */
-	ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf->bar[bar]);
-	if (ret)
-		goto set_status_err;
+	if (epf_test->db_bar_programmed) {
+		/*
+		 * The doorbell feature temporarily overrides the inbound translation
+		 * to point to the address stored in epf_test->db_bar.phys_addr, i.e.,
+		 * it calls set_bar() twice without ever calling clear_bar(), as
+		 * calling clear_bar() would clear the BAR's PCI address assigned by
+		 * the host. Thus, when disabling the doorbell, restore the inbound
+		 * translation to point to the memory allocated for the BAR.
+		 */
+		ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf->bar[bar]);
+		if (ret)
+			goto set_status_err;
+
+		epf_test->db_bar_programmed = false;
+	}
 
 	status |= STATUS_DOORBELL_DISABLE_SUCCESS;
 	reg->status = cpu_to_le32(status);
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
                   ` (5 preceding siblings ...)
  2026-02-19  8:13 ` [PATCH v9 6/7] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets Koichiro Den
@ 2026-02-19  8:13 ` Koichiro Den
  2026-02-20 17:42   ` Koichiro Den
  2026-02-27 15:06 ` [PATCH v9 0/7] " Niklas Cassel
  7 siblings, 1 reply; 18+ messages in thread
From: Koichiro Den @ 2026-02-19  8:13 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

Some endpoint platforms cannot use platform MSI / GIC ITS to implement
EP-side doorbells. In those cases, EPF drivers cannot provide an
interrupt-driven doorbell and often fall back to polling.

Add an "embedded" doorbell backend that uses a controller-integrated
doorbell target (e.g. DesignWare integrated eDMA interrupt-emulation
doorbell).

The backend locates the doorbell register and a corresponding Linux IRQ
via the EPC aux-resource API. If the doorbell register is already
exposed via a fixed BAR mapping, provide BAR+offset. Otherwise provide
the physical address so EPF drivers can map it into BAR space.

When MSI doorbell allocation fails with -ENODEV,
pci_epf_alloc_doorbell() falls back to this embedded backend.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes since v8:
  - Add MMIO address alignment check
  - Drop 'eDMA' word from the subject

 drivers/pci/endpoint/pci-ep-msi.c | 99 ++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index 50badffa9d72..f287fbf684ca 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -6,6 +6,8 @@
  * Author: Frank Li <Frank.Li@nxp.com>
  */
 
+#include <linux/align.h>
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
@@ -36,6 +38,86 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
 	pci_epc_put(epc);
 }
 
+static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
+{
+	const struct pci_epc_aux_resource *doorbell = NULL;
+	struct pci_epf_doorbell_msg *msg;
+	struct pci_epc *epc = epf->epc;
+	struct device *dev = &epf->dev;
+	int count, ret, i;
+	u64 addr;
+
+	count = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
+					  NULL, 0);
+	if (count == -EOPNOTSUPP || count == 0)
+		return -ENODEV;
+	if (count < 0)
+		return count;
+
+	struct pci_epc_aux_resource *res __free(kfree) =
+				kcalloc(count, sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+
+	ret = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
+					res, count);
+	if (ret == -EOPNOTSUPP || ret == 0)
+		return -ENODEV;
+	if (ret < 0)
+		return ret;
+
+	count = ret;
+
+	for (i = 0; i < count; i++) {
+		if (res[i].type == PCI_EPC_AUX_DOORBELL_MMIO) {
+			if (doorbell) {
+				dev_warn(dev,
+					 "Duplicate DOORBELL_MMIO resource found\n");
+				continue;
+			}
+			doorbell = &res[i];
+		}
+	}
+	if (!doorbell)
+		return -ENODEV;
+
+	addr = doorbell->phys_addr;
+	if (!IS_ALIGNED(addr, sizeof(u32)))
+		return -EINVAL;
+
+	msg = kcalloc(num_db, sizeof(*msg), GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	/*
+	 * Embedded doorbell backends (e.g. DesignWare eDMA interrupt emulation)
+	 * typically provide a single IRQ and do not offer per-doorbell
+	 * distinguishable address/data pairs. The EPC aux resource therefore
+	 * exposes one DOORBELL_MMIO entry (u.db_mmio.irq).
+	 *
+	 * Still, pci_epf_alloc_doorbell() allows requesting multiple doorbells.
+	 * For such backends we replicate the same address/data for each entry
+	 * and mark the IRQ as shared (IRQF_SHARED). Consumers must treat them
+	 * as equivalent "kick" doorbells.
+	 */
+	for (i = 0; i < num_db; i++)
+		msg[i] = (struct pci_epf_doorbell_msg) {
+			.msg.address_lo = (u32)addr,
+			.msg.address_hi = (u32)(addr >> 32),
+			.msg.data = doorbell->u.db_mmio.data,
+			.virq = doorbell->u.db_mmio.irq,
+			.irq_flags = IRQF_SHARED,
+			.type = PCI_EPF_DOORBELL_EMBEDDED,
+			.bar = doorbell->bar,
+			.offset = (doorbell->bar == NO_BAR) ? 0 :
+				  doorbell->bar_offset,
+		};
+
+	epf->num_db = num_db;
+	epf->db_msg = msg;
+	return 0;
+}
+
 static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
 {
 	struct pci_epf_doorbell_msg *msg;
@@ -109,8 +191,21 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
 	if (!ret)
 		return 0;
 
-	dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
-	return ret;
+	/*
+	 * Fall back to embedded doorbell only when platform MSI is unavailable
+	 * for this EPC.
+	 */
+	if (ret != -ENODEV)
+		return ret;
+
+	ret = pci_epf_alloc_doorbell_embedded(epf, num_db);
+	if (ret) {
+		dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
+		return ret;
+	}
+
+	dev_info(dev, "Using embedded (DMA) doorbell fallback\n");
+	return 0;
 }
 EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-19  8:13 ` [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags Koichiro Den
@ 2026-02-19 16:30   ` ALOK TIWARI
  2026-02-20  3:35     ` Koichiro Den
  0 siblings, 1 reply; 18+ messages in thread
From: ALOK TIWARI @ 2026-02-19 16:30 UTC (permalink / raw)
  To: Koichiro Den, jingoohan1, mani, lpieralisi, kwilczynski, robh,
	bhelgaas, kishon, jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb



On 2/19/2026 1:43 PM, Koichiro Den wrote:
>   static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
>   					    struct pci_epf_bar *db_bar,
>   					    const struct pci_epc_features *epc_features,

The return value of pci_epc_get_features() seems to be used here
without checking for NULL.

Since this function can return NULL, and other EPF drivers
(pci-epf-test.c, pci-epf-ntb.c) handle that case,
is VNTB assuming that epc_features is always non-NULL,
or should a defensive NULL check be added for pci_epc_get_features()?

> @@ -533,9 +549,24 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
>   	if (ret)
>   		return ret;
>   
> +	/*
> +	 * The doorbell target may already be exposed by a platform-owned fixed
> +	 * BAR. In that case, we must reuse it and the requested db_bar must
> +	 * match.
> +	 */
> +	if (epf->db_msg[0].bar != NO_BAR && epf->db_msg[0].bar != barno) {
> +		ret = -EINVAL;
> +		goto err_free_doorbell;
> +	}
> +
>   	for (req = 0; req < ntb->db_count; req++) {
> +		/* Avoid requesting duplicate handlers */
> +		if (epf_ntb_db_irq_is_duplicated(epf, req))
> +			continue;
> +
>   		ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
> -				  0, "pci_epf_vntb_db", ntb);
> +		


Thanks,
Alok

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-19 16:30   ` ALOK TIWARI
@ 2026-02-20  3:35     ` Koichiro Den
  2026-02-20 10:27       ` Niklas Cassel
  2026-02-20 15:14       ` ALOK TIWARI
  0 siblings, 2 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-20  3:35 UTC (permalink / raw)
  To: ALOK TIWARI
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel, mmaddireddy, linux-pci,
	linux-kernel, ntb

On Thu, Feb 19, 2026 at 10:00:19PM +0530, ALOK TIWARI wrote:
> 
> 
> On 2/19/2026 1:43 PM, Koichiro Den wrote:
> >   static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
> >   					    struct pci_epf_bar *db_bar,
> >   					    const struct pci_epc_features *epc_features,
> 
> The return value of pci_epc_get_features() seems to be used here
> without checking for NULL.
> 
> Since this function can return NULL, and other EPF drivers
> (pci-epf-test.c, pci-epf-ntb.c) handle that case,
> is VNTB assuming that epc_features is always non-NULL,
> or should a defensive NULL check be added for pci_epc_get_features()?

Thanks for the comment, good catch.

AFAICT, this is a pre-existing issue (at least since the initial vNTB merge,
commit e35f56bb0330), and the same pattern can be found in a few other paths in
epf-vntb, such as:

  - epf_ntb_config_spad_bar_alloc()
  - epf_ntb_configure_interrupt()
  - epf_ntb_db_bar_init() (the one you pointed out)

From the current mainline state, all in-tree pci_epc_ops implementations provide
a .get_features callback and return a non-NULL pointer, and the same holds for
the in-tree dw_pcie_ep_ops implementations. So in practice this does not appear
to be triggering a NULL-dereference issue today.

That said, pci_epc_get_features() is documented to return NULL on failure, so
adding defensive checks would certainly imnprove robustness and align vNTB with
other EPF drivers.

Since this is independent of the doorbell rework in this series, I think it
would probably cleaner to address it in a separate patch.

If you are planning to send such a patch, I would be happy to test and/or review
it. Otherwise, I can prepare a small follow-up patch (with a Reported-by tag)
when I have a spare cycle. Given that this is pre-existing and does not seem to
cause observable issues today, I do not think it requires a Fixes: tag or stable
backporting.

Best regards,
Koichiro

> 
> > @@ -533,9 +549,24 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
> >   	if (ret)
> >   		return ret;
> > +	/*
> > +	 * The doorbell target may already be exposed by a platform-owned fixed
> > +	 * BAR. In that case, we must reuse it and the requested db_bar must
> > +	 * match.
> > +	 */
> > +	if (epf->db_msg[0].bar != NO_BAR && epf->db_msg[0].bar != barno) {
> > +		ret = -EINVAL;
> > +		goto err_free_doorbell;
> > +	}
> > +
> >   	for (req = 0; req < ntb->db_count; req++) {
> > +		/* Avoid requesting duplicate handlers */
> > +		if (epf_ntb_db_irq_is_duplicated(epf, req))
> > +			continue;
> > +
> >   		ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
> > -				  0, "pci_epf_vntb_db", ntb);
> > +		
> 
> 
> Thanks,
> Alok

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-20  3:35     ` Koichiro Den
@ 2026-02-20 10:27       ` Niklas Cassel
  2026-02-20 17:53         ` Koichiro Den
  2026-02-20 15:14       ` ALOK TIWARI
  1 sibling, 1 reply; 18+ messages in thread
From: Niklas Cassel @ 2026-02-20 10:27 UTC (permalink / raw)
  To: Koichiro Den
  Cc: ALOK TIWARI, jingoohan1, mani, lpieralisi, kwilczynski, robh,
	bhelgaas, kishon, jdmason, dave.jiang, allenbh, Frank.Li,
	shinichiro.kawasaki, christian.bruel, mmaddireddy, linux-pci,
	linux-kernel, ntb

On Fri, Feb 20, 2026 at 12:35:31PM +0900, Koichiro Den wrote:
> On Thu, Feb 19, 2026 at 10:00:19PM +0530, ALOK TIWARI wrote:
> > 
> > 
> > On 2/19/2026 1:43 PM, Koichiro Den wrote:
> > >   static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
> > >   					    struct pci_epf_bar *db_bar,
> > >   					    const struct pci_epc_features *epc_features,
> > 
> > The return value of pci_epc_get_features() seems to be used here
> > without checking for NULL.
> > 
> > Since this function can return NULL, and other EPF drivers
> > (pci-epf-test.c, pci-epf-ntb.c) handle that case,
> > is VNTB assuming that epc_features is always non-NULL,
> > or should a defensive NULL check be added for pci_epc_get_features()?
> 
> Thanks for the comment, good catch.
> 
> AFAICT, this is a pre-existing issue (at least since the initial vNTB merge,
> commit e35f56bb0330), and the same pattern can be found in a few other paths in
> epf-vntb, such as:
> 
>   - epf_ntb_config_spad_bar_alloc()
>   - epf_ntb_configure_interrupt()
>   - epf_ntb_db_bar_init() (the one you pointed out)
> 
> From the current mainline state, all in-tree pci_epc_ops implementations provide
> a .get_features callback and return a non-NULL pointer, and the same holds for
> the in-tree dw_pcie_ep_ops implementations. So in practice this does not appear
> to be triggering a NULL-dereference issue today.

We should really clean this up somehow.


The problems are:

1) A long time ago, not all EPC driver had a get_features callback.
   Now, EPC drivers do have such a callback.
   Ideally, we should probably add a check that an EPC driver implements
   epc->ops_get_features in __pci_epc_create(), and return failure if it
   doesn't.

This way we can remove the if (!epc->ops_get_features) check in e.g.
pci_epc_get_features().


2) DWC based glue drivers have their own get_features callback in
struct dw_pcie_ep
But here we should just have some check in dw_pcie_ep_init() that
returns failure if the glue driver has not implemented
(struct dw_pcie_ep *)->ops->get_features)

This way we can remove the
if (!ep->ops->get_features) checks in pcie-designware-ep.c.


3) Even if the get_features callback is implemented, EPF drivers call
   pci_epc_get_features(), which has this code:

        if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
                return NULL;

So, it will return NULL for invalid func_no / vfunc_no.

I think this currently makes it quite hard to remove the NULL checks on the
return value from a epc->ops_get_features() call in the EPF drivers.




How pci-epf-test has managed to "workaround" this the silliness of having

features = pci_epc_get_features(epc, func_no, vfunc_no);
if (!features)

checks everywhere (problem 3): It calls pci_epc_get_features() once in .bind()
and if it fails, it fails bind(), if it returns non-NULL, it caches the result:
https://github.com/torvalds/linux/blob/v6.19/drivers/pci/endpoint/functions/pci-epf-test.c#L1112-L1123

That way, all other places in pci-epf-test.c does not need to NULL check
pci_epc_get_features(). (Instead it uses the cached value in struct pci_epf_test *)

pci-epf-vntb.c should probably do something similar to avoid sprinkling
NULL checks all over pci-epf-vntb.c.


Kind regards,
Niklas

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-20  3:35     ` Koichiro Den
  2026-02-20 10:27       ` Niklas Cassel
@ 2026-02-20 15:14       ` ALOK TIWARI
  1 sibling, 0 replies; 18+ messages in thread
From: ALOK TIWARI @ 2026-02-20 15:14 UTC (permalink / raw)
  To: Koichiro Den
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel, mmaddireddy, linux-pci,
	linux-kernel, ntb



On 2/20/2026 9:05 AM, Koichiro Den wrote:
> Since this is independent of the doorbell rework in this series, I think it
> would probably cleaner to address it in a separate patch.

Yes, agreed this is independent of the doorbell rework.

> 
> If you are planning to send such a patch, I would be happy to test and/or review
> it. Otherwise, I can prepare a small follow-up patch (with a Reported-by tag)
> when I have a spare cycle. Given that this is pre-existing and does not seem to
> cause observable issues today, I do not think it requires a Fixes: tag or stable
> backporting.

I will send a separate patch for this.

> 
> Best regards,
> Koichiro


Thanks,
Alok

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-19  8:13 ` [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
@ 2026-02-20 17:42   ` Koichiro Den
  2026-02-20 17:59     ` Koichiro Den
  2026-02-27 15:34     ` Niklas Cassel
  0 siblings, 2 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-20 17:42 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

On Thu, Feb 19, 2026 at 05:13:18PM +0900, Koichiro Den wrote:
> Some endpoint platforms cannot use platform MSI / GIC ITS to implement
> EP-side doorbells. In those cases, EPF drivers cannot provide an
> interrupt-driven doorbell and often fall back to polling.
> 
> Add an "embedded" doorbell backend that uses a controller-integrated
> doorbell target (e.g. DesignWare integrated eDMA interrupt-emulation
> doorbell).
> 
> The backend locates the doorbell register and a corresponding Linux IRQ
> via the EPC aux-resource API. If the doorbell register is already
> exposed via a fixed BAR mapping, provide BAR+offset. Otherwise provide
> the physical address so EPF drivers can map it into BAR space.
> 
> When MSI doorbell allocation fails with -ENODEV,
> pci_epf_alloc_doorbell() falls back to this embedded backend.
> 
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> Changes since v8:
>   - Add MMIO address alignment check
>   - Drop 'eDMA' word from the subject
> 
>  drivers/pci/endpoint/pci-ep-msi.c | 99 ++++++++++++++++++++++++++++++-
>  1 file changed, 97 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
> index 50badffa9d72..f287fbf684ca 100644
> --- a/drivers/pci/endpoint/pci-ep-msi.c
> +++ b/drivers/pci/endpoint/pci-ep-msi.c
> @@ -6,6 +6,8 @@
>   * Author: Frank Li <Frank.Li@nxp.com>
>   */
>  
> +#include <linux/align.h>
> +#include <linux/cleanup.h>
>  #include <linux/device.h>
>  #include <linux/export.h>
>  #include <linux/interrupt.h>
> @@ -36,6 +38,86 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
>  	pci_epc_put(epc);
>  }
>  
> +static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
> +{
> +	const struct pci_epc_aux_resource *doorbell = NULL;
> +	struct pci_epf_doorbell_msg *msg;
> +	struct pci_epc *epc = epf->epc;
> +	struct device *dev = &epf->dev;
> +	int count, ret, i;
> +	u64 addr;
> +
> +	count = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
> +					  NULL, 0);
> +	if (count == -EOPNOTSUPP || count == 0)
> +		return -ENODEV;
> +	if (count < 0)
> +		return count;
> +
> +	struct pci_epc_aux_resource *res __free(kfree) =
> +				kcalloc(count, sizeof(*res), GFP_KERNEL);
> +	if (!res)
> +		return -ENOMEM;
> +
> +	ret = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
> +					res, count);
> +	if (ret == -EOPNOTSUPP || ret == 0)
> +		return -ENODEV;
> +	if (ret < 0)
> +		return ret;
> +
> +	count = ret;
> +
> +	for (i = 0; i < count; i++) {
> +		if (res[i].type == PCI_EPC_AUX_DOORBELL_MMIO) {
> +			if (doorbell) {
> +				dev_warn(dev,
> +					 "Duplicate DOORBELL_MMIO resource found\n");
> +				continue;
> +			}
> +			doorbell = &res[i];
> +		}
> +	}
> +	if (!doorbell)
> +		return -ENODEV;
> +
> +	addr = doorbell->phys_addr;
> +	if (!IS_ALIGNED(addr, sizeof(u32)))
> +		return -EINVAL;
> +
> +	msg = kcalloc(num_db, sizeof(*msg), GFP_KERNEL);
> +	if (!msg)
> +		return -ENOMEM;
> +
> +	/*
> +	 * Embedded doorbell backends (e.g. DesignWare eDMA interrupt emulation)
> +	 * typically provide a single IRQ and do not offer per-doorbell
> +	 * distinguishable address/data pairs. The EPC aux resource therefore
> +	 * exposes one DOORBELL_MMIO entry (u.db_mmio.irq).
> +	 *
> +	 * Still, pci_epf_alloc_doorbell() allows requesting multiple doorbells.
> +	 * For such backends we replicate the same address/data for each entry
> +	 * and mark the IRQ as shared (IRQF_SHARED). Consumers must treat them
> +	 * as equivalent "kick" doorbells.
> +	 */
> +	for (i = 0; i < num_db; i++)
> +		msg[i] = (struct pci_epf_doorbell_msg) {
> +			.msg.address_lo = (u32)addr,
> +			.msg.address_hi = (u32)(addr >> 32),

On second thought, I'm wondering whether it makes sense to handle the case where
the embedded doorbell target resides behind an IOMMU in this series.

In v9, we simply expose the raw physical address without establishing an IOMMU
mapping. When the EPC parent device is attached to an IOMMU domain, a Host->EP
MMIO write through the BAR window may result in an IOMMU fault.

Initially, I planned to submit IOMMU support separately as a follow-up series
once this series is accepted, to avoid making this series too large [1].

However, for consistency with the MSI doorbell case when CONFIG_IRQ_MSI_IOMMU=y,
it might be cleaner to handle the IOVA mapping as part of this series.

[1] Supporting such an IOMMU-backed case would likely require additional
    patches for vNTB + ntb_transport to demonstrate usability, such as:
    https://lore.kernel.org/all/20260118135440.1958279-12-den@valinux.co.jp/
    https://lore.kernel.org/all/20260118135440.1958279-16-den@valinux.co.jp/
    https://lore.kernel.org/all/20260118135440.1958279-19-den@valinux.co.jp/

Perhaps the cleanest option would be to submit these three as a prerequisite
series.

Conceptually, the change would look like the following (to be applied on top of
this v9 Patch 9/9):


diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index f287fbf684ca..05423c83ae45 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -44,6 +44,9 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
        struct pci_epf_doorbell_msg *msg;
        struct pci_epc *epc = epf->epc;
        struct device *dev = &epf->dev;
+       phys_addr_t phys_base;
+       size_t map_size, off;
+       dma_addr_t iova_base;
        int count, ret, i;
        u64 addr;

@@ -85,6 +88,17 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
        if (!IS_ALIGNED(addr, sizeof(u32)))
                return -EINVAL;

+       phys_base = addr & PAGE_MASK;
+       off = addr - phys_base;
+       map_size = PAGE_ALIGN(off + sizeof(u32));
+
+       iova_base = dma_map_resource(epc->dev.parent, phys_base, map_size,
+                                    DMA_FROM_DEVICE, 0);
+       if (dma_mapping_error(epc->dev.parent, iova_base))
+               return -EIO;
+
+       addr = iova_base + off;
+
        msg = kcalloc(num_db, sizeof(*msg), GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
@@ -111,6 +125,8 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
                        .bar = doorbell->bar,
                        .offset = (doorbell->bar == NO_BAR) ? 0 :
                                  doorbell->bar_offset,
+                       .iova_base = iova_base,
+                       .iova_size = map_size,
                };

        epf->num_db = num_db;
@@ -211,11 +227,18 @@ EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);

 void pci_epf_free_doorbell(struct pci_epf *epf)
 {
+       struct pci_epf_doorbell_msg *msg0;
+       struct pci_epc *epc = epf->epc;
+
        if (!epf->db_msg)
                return;

-       if (epf->db_msg[0].type == PCI_EPF_DOORBELL_MSI)
+       msg0 = &epf->db_msg[0];
+       if (msg0->type == PCI_EPF_DOORBELL_MSI)
                platform_device_msi_free_irqs_all(epf->epc->dev.parent);
+       else if (msg0->type == PCI_EPF_DOORBELL_EMBEDDED)
+               dma_unmap_resource(epc->dev.parent, msg0->iova_base,
+                                  msg0->iova_size, DMA_FROM_DEVICE, 0);

        kfree(epf->db_msg);
        epf->db_msg = NULL;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index cd747447a1ea..e39251a5a6f7 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -176,6 +176,8 @@ struct pci_epf_doorbell_msg {
        struct msi_msg msg;
        int virq;
        unsigned long irq_flags;
+       dma_addr_t iova_base;
+       size_t iova_size;
        enum pci_epf_doorbell_type type;
        enum pci_barno bar;
        resource_size_t offset;

----8<----

Note: pci_epc_aux_resource was intentionally designed to expose a common
'phys_addr' field (rather than a DMA address), because some use cases require a
raw physical address. For example, in the remote dw-edma scenario, the host side
programs the (EP-local) physical address directly into
dw_edma_chip->ll_region_*[i].paddr.

Frank, since this would affect Patch 9/9, I would appreciate it if you could
take another look and share your thoughts. I had to drop your Reviewed-by tag in
v9 due to a small change, so a re-review would be very helpful in any case.

Niklas, any comments would be appreciated.

Best regards,
Koichiro


> +			.msg.data = doorbell->u.db_mmio.data,
> +			.virq = doorbell->u.db_mmio.irq,
> +			.irq_flags = IRQF_SHARED,
> +			.type = PCI_EPF_DOORBELL_EMBEDDED,
> +			.bar = doorbell->bar,
> +			.offset = (doorbell->bar == NO_BAR) ? 0 :
> +				  doorbell->bar_offset,
> +		};
> +
> +	epf->num_db = num_db;
> +	epf->db_msg = msg;
> +	return 0;
> +}
> +
>  static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
>  {
>  	struct pci_epf_doorbell_msg *msg;
> @@ -109,8 +191,21 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
>  	if (!ret)
>  		return 0;
>  
> -	dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
> -	return ret;
> +	/*
> +	 * Fall back to embedded doorbell only when platform MSI is unavailable
> +	 * for this EPC.
> +	 */
> +	if (ret != -ENODEV)
> +		return ret;
> +
> +	ret = pci_epf_alloc_doorbell_embedded(epf, num_db);
> +	if (ret) {
> +		dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
> +		return ret;
> +	}
> +
> +	dev_info(dev, "Using embedded (DMA) doorbell fallback\n");
> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
>  
> -- 
> 2.51.0
> 
> 

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
  2026-02-20 10:27       ` Niklas Cassel
@ 2026-02-20 17:53         ` Koichiro Den
  0 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-20 17:53 UTC (permalink / raw)
  To: Niklas Cassel, ALOK TIWARI
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, Frank.Li, shinichiro.kawasaki,
	christian.bruel, mmaddireddy, linux-pci, linux-kernel, ntb

On Fri, Feb 20, 2026 at 11:27:05AM +0100, Niklas Cassel wrote:
> On Fri, Feb 20, 2026 at 12:35:31PM +0900, Koichiro Den wrote:
> > On Thu, Feb 19, 2026 at 10:00:19PM +0530, ALOK TIWARI wrote:
> > > 
> > > 
> > > On 2/19/2026 1:43 PM, Koichiro Den wrote:
> > > >   static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
> > > >   					    struct pci_epf_bar *db_bar,
> > > >   					    const struct pci_epc_features *epc_features,
> > > 
> > > The return value of pci_epc_get_features() seems to be used here
> > > without checking for NULL.
> > > 
> > > Since this function can return NULL, and other EPF drivers
> > > (pci-epf-test.c, pci-epf-ntb.c) handle that case,
> > > is VNTB assuming that epc_features is always non-NULL,
> > > or should a defensive NULL check be added for pci_epc_get_features()?
> > 
> > Thanks for the comment, good catch.
> > 
> > AFAICT, this is a pre-existing issue (at least since the initial vNTB merge,
> > commit e35f56bb0330), and the same pattern can be found in a few other paths in
> > epf-vntb, such as:
> > 
> >   - epf_ntb_config_spad_bar_alloc()
> >   - epf_ntb_configure_interrupt()
> >   - epf_ntb_db_bar_init() (the one you pointed out)
> > 
> > From the current mainline state, all in-tree pci_epc_ops implementations provide
> > a .get_features callback and return a non-NULL pointer, and the same holds for
> > the in-tree dw_pcie_ep_ops implementations. So in practice this does not appear
> > to be triggering a NULL-dereference issue today.
> 
> We should really clean this up somehow.
> 
> 
> The problems are:
> 
> 1) A long time ago, not all EPC driver had a get_features callback.
>    Now, EPC drivers do have such a callback.
>    Ideally, we should probably add a check that an EPC driver implements
>    epc->ops_get_features in __pci_epc_create(), and return failure if it
>    doesn't.
> 
> This way we can remove the if (!epc->ops_get_features) check in e.g.
> pci_epc_get_features().
> 
> 
> 2) DWC based glue drivers have their own get_features callback in
> struct dw_pcie_ep
> But here we should just have some check in dw_pcie_ep_init() that
> returns failure if the glue driver has not implemented
> (struct dw_pcie_ep *)->ops->get_features)
> 
> This way we can remove the
> if (!ep->ops->get_features) checks in pcie-designware-ep.c.
> 
> 
> 3) Even if the get_features callback is implemented, EPF drivers call
>    pci_epc_get_features(), which has this code:
> 
>         if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
>                 return NULL;
> 
> So, it will return NULL for invalid func_no / vfunc_no.
> 
> I think this currently makes it quite hard to remove the NULL checks on the
> return value from a epc->ops_get_features() call in the EPF drivers.
> 
> 
> 
> 
> How pci-epf-test has managed to "workaround" this the silliness of having
> 
> features = pci_epc_get_features(epc, func_no, vfunc_no);
> if (!features)
> 
> checks everywhere (problem 3): It calls pci_epc_get_features() once in .bind()
> and if it fails, it fails bind(), if it returns non-NULL, it caches the result:
> https://github.com/torvalds/linux/blob/v6.19/drivers/pci/endpoint/functions/pci-epf-test.c#L1112-L1123
> 
> That way, all other places in pci-epf-test.c does not need to NULL check
> pci_epc_get_features(). (Instead it uses the cached value in struct pci_epf_test *)
> 
> pci-epf-vntb.c should probably do something similar to avoid sprinkling
> NULL checks all over pci-epf-vntb.c.

Niklas, agreed, I had the same thought (ie. bind-time check could be
sufficient). Thanks for the follow-up.

Alok, thanks for picking it up.

Best regards,
Koichiro


> 
> 
> Kind regards,
> Niklas

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-20 17:42   ` Koichiro Den
@ 2026-02-20 17:59     ` Koichiro Den
  2026-02-27 15:34     ` Niklas Cassel
  1 sibling, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-20 17:59 UTC (permalink / raw)
  To: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, cassel, Frank.Li,
	shinichiro.kawasaki, christian.bruel
  Cc: mmaddireddy, linux-pci, linux-kernel, ntb

On Sat, Feb 21, 2026 at 02:42:37AM +0900, Koichiro Den wrote:
> On Thu, Feb 19, 2026 at 05:13:18PM +0900, Koichiro Den wrote:
> > Some endpoint platforms cannot use platform MSI / GIC ITS to implement
> > EP-side doorbells. In those cases, EPF drivers cannot provide an
> > interrupt-driven doorbell and often fall back to polling.
> > 
> > Add an "embedded" doorbell backend that uses a controller-integrated
> > doorbell target (e.g. DesignWare integrated eDMA interrupt-emulation
> > doorbell).
> > 
> > The backend locates the doorbell register and a corresponding Linux IRQ
> > via the EPC aux-resource API. If the doorbell register is already
> > exposed via a fixed BAR mapping, provide BAR+offset. Otherwise provide
> > the physical address so EPF drivers can map it into BAR space.
> > 
> > When MSI doorbell allocation fails with -ENODEV,
> > pci_epf_alloc_doorbell() falls back to this embedded backend.
> > 
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> > Changes since v8:
> >   - Add MMIO address alignment check
> >   - Drop 'eDMA' word from the subject
> > 
> >  drivers/pci/endpoint/pci-ep-msi.c | 99 ++++++++++++++++++++++++++++++-
> >  1 file changed, 97 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
> > index 50badffa9d72..f287fbf684ca 100644
> > --- a/drivers/pci/endpoint/pci-ep-msi.c
> > +++ b/drivers/pci/endpoint/pci-ep-msi.c
> > @@ -6,6 +6,8 @@
> >   * Author: Frank Li <Frank.Li@nxp.com>
> >   */
> >  
> > +#include <linux/align.h>
> > +#include <linux/cleanup.h>
> >  #include <linux/device.h>
> >  #include <linux/export.h>
> >  #include <linux/interrupt.h>
> > @@ -36,6 +38,86 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
> >  	pci_epc_put(epc);
> >  }
> >  
> > +static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
> > +{
> > +	const struct pci_epc_aux_resource *doorbell = NULL;
> > +	struct pci_epf_doorbell_msg *msg;
> > +	struct pci_epc *epc = epf->epc;
> > +	struct device *dev = &epf->dev;
> > +	int count, ret, i;
> > +	u64 addr;
> > +
> > +	count = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
> > +					  NULL, 0);
> > +	if (count == -EOPNOTSUPP || count == 0)
> > +		return -ENODEV;
> > +	if (count < 0)
> > +		return count;
> > +
> > +	struct pci_epc_aux_resource *res __free(kfree) =
> > +				kcalloc(count, sizeof(*res), GFP_KERNEL);
> > +	if (!res)
> > +		return -ENOMEM;
> > +
> > +	ret = pci_epc_get_aux_resources(epc, epf->func_no, epf->vfunc_no,
> > +					res, count);
> > +	if (ret == -EOPNOTSUPP || ret == 0)
> > +		return -ENODEV;
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	count = ret;
> > +
> > +	for (i = 0; i < count; i++) {
> > +		if (res[i].type == PCI_EPC_AUX_DOORBELL_MMIO) {
> > +			if (doorbell) {
> > +				dev_warn(dev,
> > +					 "Duplicate DOORBELL_MMIO resource found\n");
> > +				continue;
> > +			}
> > +			doorbell = &res[i];
> > +		}
> > +	}
> > +	if (!doorbell)
> > +		return -ENODEV;
> > +
> > +	addr = doorbell->phys_addr;
> > +	if (!IS_ALIGNED(addr, sizeof(u32)))
> > +		return -EINVAL;
> > +
> > +	msg = kcalloc(num_db, sizeof(*msg), GFP_KERNEL);
> > +	if (!msg)
> > +		return -ENOMEM;
> > +
> > +	/*
> > +	 * Embedded doorbell backends (e.g. DesignWare eDMA interrupt emulation)
> > +	 * typically provide a single IRQ and do not offer per-doorbell
> > +	 * distinguishable address/data pairs. The EPC aux resource therefore
> > +	 * exposes one DOORBELL_MMIO entry (u.db_mmio.irq).
> > +	 *
> > +	 * Still, pci_epf_alloc_doorbell() allows requesting multiple doorbells.
> > +	 * For such backends we replicate the same address/data for each entry
> > +	 * and mark the IRQ as shared (IRQF_SHARED). Consumers must treat them
> > +	 * as equivalent "kick" doorbells.
> > +	 */
> > +	for (i = 0; i < num_db; i++)
> > +		msg[i] = (struct pci_epf_doorbell_msg) {
> > +			.msg.address_lo = (u32)addr,
> > +			.msg.address_hi = (u32)(addr >> 32),
> 
> On second thought, I'm wondering whether it makes sense to handle the case where
> the embedded doorbell target resides behind an IOMMU in this series.
> 
> In v9, we simply expose the raw physical address without establishing an IOMMU
> mapping. When the EPC parent device is attached to an IOMMU domain, a Host->EP
> MMIO write through the BAR window may result in an IOMMU fault.
> 
> Initially, I planned to submit IOMMU support separately as a follow-up series
> once this series is accepted, to avoid making this series too large [1].
> 
> However, for consistency with the MSI doorbell case when CONFIG_IRQ_MSI_IOMMU=y,
> it might be cleaner to handle the IOVA mapping as part of this series.
> 
> [1] Supporting such an IOMMU-backed case would likely require additional
>     patches for vNTB + ntb_transport to demonstrate usability, such as:
>     https://lore.kernel.org/all/20260118135440.1958279-12-den@valinux.co.jp/
>     https://lore.kernel.org/all/20260118135440.1958279-16-den@valinux.co.jp/
>     https://lore.kernel.org/all/20260118135440.1958279-19-den@valinux.co.jp/
> 
> Perhaps the cleanest option would be to submit these three as a prerequisite
> series.
> 
> Conceptually, the change would look like the following (to be applied on top of
> this v9 Patch 9/9):

(Not 9/9 but 7/7. Sorry for the confusion.)

> 
> 
> diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
> index f287fbf684ca..05423c83ae45 100644
> --- a/drivers/pci/endpoint/pci-ep-msi.c
> +++ b/drivers/pci/endpoint/pci-ep-msi.c
> @@ -44,6 +44,9 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
>         struct pci_epf_doorbell_msg *msg;
>         struct pci_epc *epc = epf->epc;
>         struct device *dev = &epf->dev;
> +       phys_addr_t phys_base;
> +       size_t map_size, off;
> +       dma_addr_t iova_base;
>         int count, ret, i;
>         u64 addr;
> 
> @@ -85,6 +88,17 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
>         if (!IS_ALIGNED(addr, sizeof(u32)))
>                 return -EINVAL;
> 
> +       phys_base = addr & PAGE_MASK;
> +       off = addr - phys_base;
> +       map_size = PAGE_ALIGN(off + sizeof(u32));
> +
> +       iova_base = dma_map_resource(epc->dev.parent, phys_base, map_size,
> +                                    DMA_FROM_DEVICE, 0);
> +       if (dma_mapping_error(epc->dev.parent, iova_base))
> +               return -EIO;
> +
> +       addr = iova_base + off;
> +
>         msg = kcalloc(num_db, sizeof(*msg), GFP_KERNEL);
>         if (!msg)
>                 return -ENOMEM;
> @@ -111,6 +125,8 @@ static int pci_epf_alloc_doorbell_embedded(struct pci_epf *epf, u16 num_db)
>                         .bar = doorbell->bar,
>                         .offset = (doorbell->bar == NO_BAR) ? 0 :
>                                   doorbell->bar_offset,
> +                       .iova_base = iova_base,
> +                       .iova_size = map_size,
>                 };
> 
>         epf->num_db = num_db;
> @@ -211,11 +227,18 @@ EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
> 
>  void pci_epf_free_doorbell(struct pci_epf *epf)
>  {
> +       struct pci_epf_doorbell_msg *msg0;
> +       struct pci_epc *epc = epf->epc;
> +
>         if (!epf->db_msg)
>                 return;
> 
> -       if (epf->db_msg[0].type == PCI_EPF_DOORBELL_MSI)
> +       msg0 = &epf->db_msg[0];
> +       if (msg0->type == PCI_EPF_DOORBELL_MSI)
>                 platform_device_msi_free_irqs_all(epf->epc->dev.parent);
> +       else if (msg0->type == PCI_EPF_DOORBELL_EMBEDDED)
> +               dma_unmap_resource(epc->dev.parent, msg0->iova_base,
> +                                  msg0->iova_size, DMA_FROM_DEVICE, 0);
> 
>         kfree(epf->db_msg);
>         epf->db_msg = NULL;
> diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
> index cd747447a1ea..e39251a5a6f7 100644
> --- a/include/linux/pci-epf.h
> +++ b/include/linux/pci-epf.h
> @@ -176,6 +176,8 @@ struct pci_epf_doorbell_msg {
>         struct msi_msg msg;
>         int virq;
>         unsigned long irq_flags;
> +       dma_addr_t iova_base;
> +       size_t iova_size;
>         enum pci_epf_doorbell_type type;
>         enum pci_barno bar;
>         resource_size_t offset;
> 
> ----8<----
> 
> Note: pci_epc_aux_resource was intentionally designed to expose a common
> 'phys_addr' field (rather than a DMA address), because some use cases require a
> raw physical address. For example, in the remote dw-edma scenario, the host side
> programs the (EP-local) physical address directly into
> dw_edma_chip->ll_region_*[i].paddr.
> 
> Frank, since this would affect Patch 9/9, I would appreciate it if you could

(Not 9/9 but 7/7. Same typo as above. Sorry.)

Koichiro

> take another look and share your thoughts. I had to drop your Reviewed-by tag in
> v9 due to a small change, so a re-review would be very helpful in any case.
> 
> Niklas, any comments would be appreciated.
> 
> Best regards,
> Koichiro
> 
> 
> > +			.msg.data = doorbell->u.db_mmio.data,
> > +			.virq = doorbell->u.db_mmio.irq,
> > +			.irq_flags = IRQF_SHARED,
> > +			.type = PCI_EPF_DOORBELL_EMBEDDED,
> > +			.bar = doorbell->bar,
> > +			.offset = (doorbell->bar == NO_BAR) ? 0 :
> > +				  doorbell->bar_offset,
> > +		};
> > +
> > +	epf->num_db = num_db;
> > +	epf->db_msg = msg;
> > +	return 0;
> > +}
> > +
> >  static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
> >  {
> >  	struct pci_epf_doorbell_msg *msg;
> > @@ -109,8 +191,21 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
> >  	if (!ret)
> >  		return 0;
> >  
> > -	dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
> > -	return ret;
> > +	/*
> > +	 * Fall back to embedded doorbell only when platform MSI is unavailable
> > +	 * for this EPC.
> > +	 */
> > +	if (ret != -ENODEV)
> > +		return ret;
> > +
> > +	ret = pci_epf_alloc_doorbell_embedded(epf, num_db);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	dev_info(dev, "Using embedded (DMA) doorbell fallback\n");
> > +	return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
> >  
> > -- 
> > 2.51.0
> > 
> > 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
                   ` (6 preceding siblings ...)
  2026-02-19  8:13 ` [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
@ 2026-02-27 15:06 ` Niklas Cassel
  7 siblings, 0 replies; 18+ messages in thread
From: Niklas Cassel @ 2026-02-27 15:06 UTC (permalink / raw)
  To: Koichiro Den
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, Frank.Li, shinichiro.kawasaki,
	christian.bruel, mmaddireddy, linux-pci, linux-kernel, ntb

On Thu, Feb 19, 2026 at 05:13:11PM +0900, Koichiro Den wrote:

(snip)

> Tested on
> ---------
> 
> I re-tested the embedded (DMA) doorbell fallback path (via pci-epf-test)
> on R-Car Spider boards (with this v9 series):
> 
>   $ ./pci_endpoint_test -t DOORBELL_TEST
>   TAP version 13
>   1..1
>   # Starting 1 tests from 1 test cases.
>   #  RUN           pcie_ep_doorbell.DOORBELL_TEST ...
>   #            OK  pcie_ep_doorbell.DOORBELL_TEST
>   ok 1 pcie_ep_doorbell.DOORBELL_TEST
>   # PASSED: 1 / 1 tests passed.
>   # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
> 

For the series:
Tested-by: Niklas Cassel <cassel@kernel.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-20 17:42   ` Koichiro Den
  2026-02-20 17:59     ` Koichiro Den
@ 2026-02-27 15:34     ` Niklas Cassel
  2026-02-28 16:33       ` Koichiro Den
  1 sibling, 1 reply; 18+ messages in thread
From: Niklas Cassel @ 2026-02-27 15:34 UTC (permalink / raw)
  To: Koichiro Den
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, Frank.Li, shinichiro.kawasaki,
	christian.bruel, mmaddireddy, linux-pci, linux-kernel, ntb

On Sat, Feb 21, 2026 at 02:42:35AM +0900, Koichiro Den wrote:
> On second thought, I'm wondering whether it makes sense to handle the case where
> the embedded doorbell target resides behind an IOMMU in this series.
> 
> In v9, we simply expose the raw physical address without establishing an IOMMU
> mapping. When the EPC parent device is attached to an IOMMU domain, a Host->EP
> MMIO write through the BAR window may result in an IOMMU fault.
> 
> Initially, I planned to submit IOMMU support separately as a follow-up series
> once this series is accepted, to avoid making this series too large [1].
>
> Niklas, any comments would be appreciated.

These patches are for NTB/vNTB:

> [1] Supporting such an IOMMU-backed case would likely require additional
>     patches for vNTB + ntb_transport to demonstrate usability, such as:
>     https://lore.kernel.org/all/20260118135440.1958279-12-den@valinux.co.jp/
>     https://lore.kernel.org/all/20260118135440.1958279-16-den@valinux.co.jp/
>     https://lore.kernel.org/all/20260118135440.1958279-19-den@valinux.co.jp/

If the diff you pasted above is all you need for pci-epf-test to pass the
doorbell test case when running against a PCI endpoint with IOMMU enabled,
then I suggest you just send a v10 with those changes included, without
any additional dependencies.

I understand that you would need additional dependencies for vNTB to be able
to use eDMA doorbell on a PCI endpoint with IOMMU enabled.

Perhaps, drop the vNTB changes from this series, focus only on pci-epf-test,
get this series merged, and then submit an follow up series that adds eDMA
doorbells with IOMMU support for vNTB?


Kind regards,
Niklas

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback
  2026-02-27 15:34     ` Niklas Cassel
@ 2026-02-28 16:33       ` Koichiro Den
  0 siblings, 0 replies; 18+ messages in thread
From: Koichiro Den @ 2026-02-28 16:33 UTC (permalink / raw)
  To: Niklas Cassel
  Cc: jingoohan1, mani, lpieralisi, kwilczynski, robh, bhelgaas, kishon,
	jdmason, dave.jiang, allenbh, Frank.Li, shinichiro.kawasaki,
	christian.bruel, mmaddireddy, linux-pci, linux-kernel, ntb

On Fri, Feb 27, 2026 at 04:34:02PM +0100, Niklas Cassel wrote:
> On Sat, Feb 21, 2026 at 02:42:35AM +0900, Koichiro Den wrote:
> > On second thought, I'm wondering whether it makes sense to handle the case where
> > the embedded doorbell target resides behind an IOMMU in this series.
> > 
> > In v9, we simply expose the raw physical address without establishing an IOMMU
> > mapping. When the EPC parent device is attached to an IOMMU domain, a Host->EP
> > MMIO write through the BAR window may result in an IOMMU fault.
> > 
> > Initially, I planned to submit IOMMU support separately as a follow-up series
> > once this series is accepted, to avoid making this series too large [1].
> >
> > Niklas, any comments would be appreciated.
> 
> These patches are for NTB/vNTB:
> 
> > [1] Supporting such an IOMMU-backed case would likely require additional
> >     patches for vNTB + ntb_transport to demonstrate usability, such as:
> >     https://lore.kernel.org/all/20260118135440.1958279-12-den@valinux.co.jp/
> >     https://lore.kernel.org/all/20260118135440.1958279-16-den@valinux.co.jp/
> >     https://lore.kernel.org/all/20260118135440.1958279-19-den@valinux.co.jp/
> 
> If the diff you pasted above is all you need for pci-epf-test to pass the
> doorbell test case when running against a PCI endpoint with IOMMU enabled,
> then I suggest you just send a v10 with those changes included, without
> any additional dependencies.

Thanks for the comment, Niklas.

The three patches mentioned above are unrelated to whether pci-epf-test passes
when running against a PCI endpoint with IOMMU enabled. From that perspective,
the code snippet I pasted in the same comment (which you trimmed here) is the
only relevant change.

I'll prepare a v10 with that snippet (polished up as needed) squashed into Patch
7. Before doing so, I'll also take a closer look at your v2 series to see if I
can help move it forward.

> 
> I understand that you would need additional dependencies for vNTB to be able
> to use eDMA doorbell on a PCI endpoint with IOMMU enabled.
> 
> Perhaps, drop the vNTB changes from this series, focus only on pci-epf-test,
> get this series merged, and then submit an follow up series that adds eDMA
> doorbells with IOMMU support for vNTB?

The vNTB changes already included in this series (i.e. [PATCH v9 5/7]) are
necessary. Without them, vNTB can break because the doorbell fallback can occur
behind pci_epf_alloc_doorbell().

Regarding the three patches mentioned above, since I included the vNTB ping
performance improvement in the cover letter, I thought it made sense to consider
those three patches as prerequisites for this series. However, as you suggest,
it makes sense to treat them as a follow-up series.

Best regards,
Koichiro

> 
> 
> Kind regards,
> Niklas

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2026-02-28 16:33 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-19  8:13 [PATCH v9 0/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
2026-02-19  8:13 ` [PATCH v9 1/7] PCI: endpoint: Add auxiliary resource query API Koichiro Den
2026-02-19  8:13 ` [PATCH v9 2/7] PCI: dwc: Record integrated eDMA register window Koichiro Den
2026-02-19  8:13 ` [PATCH v9 3/7] PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource API Koichiro Den
2026-02-19  8:13 ` [PATCH v9 4/7] PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends Koichiro Den
2026-02-19  8:13 ` [PATCH v9 5/7] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags Koichiro Den
2026-02-19 16:30   ` ALOK TIWARI
2026-02-20  3:35     ` Koichiro Den
2026-02-20 10:27       ` Niklas Cassel
2026-02-20 17:53         ` Koichiro Den
2026-02-20 15:14       ` ALOK TIWARI
2026-02-19  8:13 ` [PATCH v9 6/7] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets Koichiro Den
2026-02-19  8:13 ` [PATCH v9 7/7] PCI: endpoint: pci-ep-msi: Add embedded doorbell fallback Koichiro Den
2026-02-20 17:42   ` Koichiro Den
2026-02-20 17:59     ` Koichiro Den
2026-02-27 15:34     ` Niklas Cassel
2026-02-28 16:33       ` Koichiro Den
2026-02-27 15:06 ` [PATCH v9 0/7] " Niklas Cassel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox