[PATCH v7 8/9] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets

Frank Li Frank.li at nxp.com
Mon Feb 16 08:18:42 PST 2026


On Mon, Feb 16, 2026 at 01:38:46AM +0900, Koichiro Den wrote:
> 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 at valinux.co.jp>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>  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 defe1e2ea427..7b0955b4c703 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -87,6 +87,7 @@ struct pci_epf_test {
>  	const struct pci_epc_features *epc_features;
>  	struct pci_epf_bar	db_bar;
>  	bool			db_irq_requested;
> +	bool			db_bar_programmed;
>  	size_t			bar_size[PCI_STD_NUM_BARS];
>  };
>
> @@ -730,7 +731,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;
> @@ -742,13 +745,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,
> @@ -761,25 +779,33 @@ 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_doorbell_cleanup;
> +		if (ret)
> +			goto err_doorbell_cleanup;
> +	}
>
>  	if (size_add(offset, sizeof(u32)) > epf->bar[bar].size)
>  		goto err_doorbell_cleanup;
>
>  	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_doorbell_cleanup;
> +		ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar);
> +		if (ret)
> +			goto err_doorbell_cleanup;
> +
> +		epf_test->db_bar_programmed = true;
> +	}
>
>  	status |= STATUS_DOORBELL_ENABLE_SUCCESS;
>  	reg->status = cpu_to_le32(status);
> @@ -806,17 +832,21 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *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
>



More information about the Linux-rockchip mailing list