Re: [PATCH v10 6/7] PCI: endpoint: pci-epf-test: Reuse pre-exposed doorbell targets
Frank Li <[email protected]> Mon, 23 Mar 2026 14:41:41 -0400
| Newsgroups | dev.linux.lists.ntb,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <acGJZZzK241BHZMb@lizhi-Precision-Tower-5810> |
On Mon, Mar 02, 2026 at 04:14:26PM +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. > > Tested-by: Niklas Cassel <[email protected]> > Signed-off-by: Koichiro Den <[email protected]> > --- Reviewed-by: Frank Li <[email protected]> > 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 14e61ebe1f11..b6c865b0883d 100644 > --- a/drivers/pci/endpoint/functions/pci-epf-test.c > +++ b/drivers/pci/endpoint/functions/pci-epf-test.c > @@ -93,6 +93,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]; > }; > > @@ -732,7 +733,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, > @@ -760,22 +778,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); > @@ -805,17 +831,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 >