Hello Frank, On Tue, Oct 15, 2024 at 06:07:17PM -0400, Frank Li wrote: > Add three registers: doorbell_bar, doorbell_addr, and doorbell_data, > along with doorbell_done. Use pci_epf_alloc_doorbell() to allocate a > doorbell address space. > > Enable the Root Complex (RC) side driver to trigger pci-epc-test's doorbell > callback handler by writing doorbell_data to the mapped doorbell_bar's > address space. > > Set doorbell_done in the doorbell callback to indicate completion. > > To avoid broken compatibility, use new PID/VID and set RevID bigger than 0. > So only new pcitest program can distinguish with/without doorbell support > and avoid wrongly write test data to doorbell bar. > > Signed-off-by: Frank Li <Frank.Li@xxxxxxx> > --- > drivers/pci/endpoint/functions/pci-epf-test.c | 58 ++++++++++++++++++++++++++- > 1 file changed, 56 insertions(+), 2 deletions(-) > > diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c > index 7c2ed6eae53ad..c054d621353a6 100644 > --- a/drivers/pci/endpoint/functions/pci-epf-test.c > +++ b/drivers/pci/endpoint/functions/pci-epf-test.c > @@ -11,12 +11,14 @@ > #include <linux/dmaengine.h> > #include <linux/io.h> > #include <linux/module.h> > +#include <linux/msi.h> > #include <linux/slab.h> > #include <linux/pci_ids.h> > #include <linux/random.h> > > #include <linux/pci-epc.h> > #include <linux/pci-epf.h> > +#include <linux/pci-ep-msi.h> > #include <linux/pci_regs.h> > > #define IRQ_TYPE_INTX 0 > @@ -39,6 +41,7 @@ > #define STATUS_IRQ_RAISED BIT(6) > #define STATUS_SRC_ADDR_INVALID BIT(7) > #define STATUS_DST_ADDR_INVALID BIT(8) > +#define STATUS_DOORBELL_SUCCESS BIT(9) > > #define FLAG_USE_DMA BIT(0) > > @@ -50,6 +53,7 @@ struct pci_epf_test { > void *reg[PCI_STD_NUM_BARS]; > struct pci_epf *epf; > enum pci_barno test_reg_bar; > + enum pci_barno doorbell_bar; > size_t msix_table_offset; > struct delayed_work cmd_handler; > struct dma_chan *dma_chan_tx; > @@ -74,6 +78,9 @@ struct pci_epf_test_reg { > u32 irq_type; > u32 irq_number; > u32 flags; > + u32 doorbell_bar; > + u32 doorbell_addr; > + u32 doorbell_data; > } __packed; > > static struct pci_epf_header test_header = { > @@ -695,7 +702,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf) > enum pci_barno test_reg_bar = epf_test->test_reg_bar; > > for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { > - if (!epf_test->reg[bar]) > + if (!epf_test->reg[bar] && bar != epf_test->doorbell_bar) > continue; > > ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, > @@ -810,11 +817,24 @@ static int pci_epf_test_link_down(struct pci_epf *epf) > return 0; > } > > +static int pci_epf_test_doorbell(struct pci_epf *epf, int index) > +{ > + struct pci_epf_test *epf_test = epf_get_drvdata(epf); > + enum pci_barno test_reg_bar = epf_test->test_reg_bar; > + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; > + > + reg->status |= STATUS_DOORBELL_SUCCESS; > + pci_epf_test_raise_irq(epf_test, reg); > + > + return 0; > +} > + > static const struct pci_epc_event_ops pci_epf_test_event_ops = { > .epc_init = pci_epf_test_epc_init, > .epc_deinit = pci_epf_test_epc_deinit, > .link_up = pci_epf_test_link_up, > .link_down = pci_epf_test_link_down, > + .doorbell = pci_epf_test_doorbell, > }; > > static int pci_epf_test_alloc_space(struct pci_epf *epf) > @@ -853,7 +873,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) > if (bar == NO_BAR) > break; > > - if (bar == test_reg_bar) > + if (bar == test_reg_bar || bar == epf_test->doorbell_bar) > continue; > > base = pci_epf_alloc_space(epf, bar_size[bar], bar, > @@ -887,7 +907,11 @@ static int pci_epf_test_bind(struct pci_epf *epf) > struct pci_epf_test *epf_test = epf_get_drvdata(epf); > const struct pci_epc_features *epc_features; > enum pci_barno test_reg_bar = BAR_0; > + enum pci_barno doorbell_bar = NO_BAR; > struct pci_epc *epc = epf->epc; > + struct msi_msg *msg; > + u64 doorbell_addr; > + u32 align; > > if (WARN_ON_ONCE(!epc)) > return -EINVAL; > @@ -905,10 +929,40 @@ static int pci_epf_test_bind(struct pci_epf *epf) > epf_test->test_reg_bar = test_reg_bar; > epf_test->epc_features = epc_features; > > + align = epc_features->align; > + align = align ? align : 128; > + > + /* Only revid >=1 support RC-to-EP Door bell */ > + ret = epf->header->revid > 0 ? pci_epf_alloc_doorbell(epf, 1) : -EINVAL; I really, really don't like this idea. This means that you would need to write a revid > 1 in configfs to test this. I also don't think that it is right that pci-epf-test takes ownership of "rev". How about something like this instead: My thinking is that you add a doorbell_capable struct member to epc_features, and then populate CAPS_DOORBELL_SUPPORT based on epc_features in pci_epf_test_init_caps() (similar to how my proposal sets CAPS_MSI_SUPPORT).