RE: [EXT] Re: [PATCH v14 08/21] PCI: dwc: Add support for triggering INTx IRQs from endpoint drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Frank,

> From: Frank Li, Sent: Wednesday, May 3, 2023 2:04 AM
> 
> >
> > On Wed, Apr 26, 2023 at 01:55:44PM +0900, Yoshihiro Shimoda wrote:
> > > Add support for triggering INTx IRQs by using outbound iATU.
> > > Outbound iATU is utilized to send assert and de-assert INTx TLPs.
> > > The message is generated based on the payloadless Msg TLP with type
> > > 0x14, where 0x4 is the routing code implying the Terminate at
> > > Receiver message. The message code is specified as b1000xx for
> > > the INTx assertion and b1001xx for the INTx de-assertion.
> >
> > [PATCH v14 08/21] PCI: dwc: Add support for triggering INTx IRQs from
> > endpoint drivers
> >
> > What about shortening the subject out a bit:
> > "PCI: designware-ep: Add INTx IRQs support"
> > ?
> >
> > >
> > > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
> > > ---
> > >  .../pci/controller/dwc/pcie-designware-ep.c   | 71 +++++++++++++++++--
> > >  drivers/pci/controller/dwc/pcie-designware.h  |  2 +
> > >  2 files changed, 69 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > index 96375b0aba82..b35ed2b06193 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > @@ -6,6 +6,7 @@
> > >   * Author: Kishon Vijay Abraham I <kishon@xxxxxx>
> > >   */
> > >
> > > +#include <linux/delay.h>
> > >  #include <linux/of.h>
> > >  #include <linux/platform_device.h>
> > >
> > > @@ -485,14 +486,63 @@ static const struct pci_epc_ops epc_ops = {
> > >       .get_features           = dw_pcie_ep_get_features,
> > >  };
> > >
> > > +static int dw_pcie_ep_send_msg(struct dw_pcie_ep *ep, u8 func_no, u8
> > code,
> > > +                            u8 routing)
> > > +{
> > > +     struct dw_pcie_outbound_atu atu = { 0 };
> > > +     struct pci_epc *epc = ep->epc;
> > > +     int ret;
> > > +
> > > +     atu.func_no = func_no;
> > > +     atu.code = code;
> > > +     atu.routing = routing;
> > > +     atu.type = PCIE_ATU_TYPE_MSG;
> > > +     atu.cpu_addr = ep->intx_mem_phys;
> > > +     atu.size = epc->mem->window.page_size;
> > > +
> > > +     ret = dw_pcie_ep_outbound_atu(ep, &atu);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     writel(0, ep->intx_mem);
> > > +
> > > +     dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->intx_mem_phys);
> > > +
> > > +     return 0;
> > > +}
> > > +
> >
> > > +static int __dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8
> > func_no,
> > > +                                      int intx)
> > > +{
> > > +     int ret;
> > > +
> > > +     ret = dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_ASSERT_INTA +
> > intx,
> > > +                               PCI_MSG_ROUTING_LOCAL);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     /*
> > > +      * The documents of PCIe and the controller don't mention how long
> > > +      * the INTx should be asserted. If 10 usec, sometimes it failed.
> > > +      * So, asserted for 50 usec.
> > > +      */
> > > +     usleep_range(50, 100);
> 
> It is good method to implement legacy irq support. But there is problem which need be considered.
> 
> According to PCI spec, section 6.2.1 PCI-compatible INTx Emulation
> 
> PCI Express emulates the PCI interrupt mechanism including the Interrupt Pin and Interrupt Line registers of the PCI
> Configuration Space for PCI device Functions. PCI Express non-Switch devices may optionally support these registers for
> backwards compatibility. Switch devices are required to support them. Actual interrupt signaling uses in-band Messages
> rather than being signaled using physical pins.
> Two types of Messages are defined, Assert_INTx and Deassert_INTx, for emulation of PCI INTx signaling, where x is A, B,
> C, and D for respective PCI interrupt signals. These Messages are used to provide "virtual wires" for signaling interrupts
> across a Link. Switches collect these virtual wires and present a combined set at the Switch's Upstream Port. Ultimately,
> the virtual wires are routed to the Root Complex which maps the virtual wires to system interrupt resources. Devices
> must use assert/deassert Messages in pairs to emulate PCI interrupt **level-triggered** signaling. Actual mapping of PCI
> Express INTx emulation to system interrupts is implementation specific as is mapping of physical interrupt signals in
> conventional PCI.
> 
> It should be level triggered.   When call __dw_pcie_ep_raise_intx_irq, should be just assert INTx, then after PCI
> Host driver's  irq handler to clear irq,  EP side can desert INTx.
> 
> So it should be two functions, one function raise INTx,  and another one desert INTx.   But I don't know
> How to avoid host side possible flood irq happen if EP can't desert INTx in time.

I also don't know how to design dessert INTx...

To Kishon,

Do you have any comments about supporting deassert INTx on PCIe EP framework?
I checked the Documentation/PCI/endpoint/pci-endpoint.rst, but it doesn't mention
about it. Should I modify the PCIe EP framework while I submit this patch series?
If possible, after this patch series have been merged into upstream, I'll try
to consider this problem somehow.

Best regards,
Yoshihiro Shimoda

> > > +
> > > +     return dw_pcie_ep_send_msg(ep, func_no,
> > PCI_CODE_DEASSERT_INTA + intx,
> > > +                                PCI_MSG_ROUTING_LOCAL);
> > > +}
> >
> > Why do you need the underscored version of the method? I don't see it
> > being utilized anywhere but in the dw_pcie_ep_raise_intx_irq()
> > function. Thus its body can be completely moved to
> > dw_pcie_ep_raise_intx_irq().
> >
> > -Serge(y)
> >
> > > +
> > >  int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
> > >  {
> > >       struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> > >       struct device *dev = pci->dev;
> > >
> > > -     dev_err(dev, "EP cannot trigger INTx IRQs\n");
> > > +     if (!ep->intx_mem) {
> > > +             dev_err(dev, "INTx not supported\n");
> > > +             return -EOPNOTSUPP;
> > > +     }
> > >
> > > -     return -EINVAL;
> > > +     return __dw_pcie_ep_raise_intx_irq(ep, func_no, 0);
> > >  }
> > >  EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq);
> > >
> > > @@ -623,6 +673,10 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
> > >
> > >       dw_pcie_edma_remove(pci);
> > >
> > > +     if (ep->intx_mem)
> > > +             pci_epc_mem_free_addr(epc, ep->intx_mem_phys, ep-
> > >intx_mem,
> > > +                                   epc->mem->window.page_size);
> > > +
> > >       pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
> > >                             epc->mem->window.page_size);
> > >
> > > @@ -794,9 +848,14 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > >               goto err_exit_epc_mem;
> > >       }
> > >
> > > +     ep->intx_mem = pci_epc_mem_alloc_addr(epc, &ep-
> > >intx_mem_phys,
> > > +                                           epc->mem->window.page_size);
> > > +     if (!ep->intx_mem)
> > > +             dev_warn(dev, "Failed to reserve memory for INTx\n");
> > > +
> > >       ret = dw_pcie_edma_detect(pci);
> > >       if (ret)
> > > -             goto err_free_epc_mem;
> > > +             goto err_free_epc_mem_intx;
> > >
> > >       if (ep->ops->get_features) {
> > >               epc_features = ep->ops->get_features(ep);
> > > @@ -813,7 +872,11 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > >  err_remove_edma:
> > >       dw_pcie_edma_remove(pci);
> > >
> > > -err_free_epc_mem:
> > > +err_free_epc_mem_intx:
> > > +     if (ep->intx_mem)
> > > +             pci_epc_mem_free_addr(epc, ep->intx_mem_phys, ep-
> > >intx_mem,
> > > +                                   epc->mem->window.page_size);
> > > +
> > >       pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
> > >                             epc->mem->window.page_size);
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.h
> > b/drivers/pci/controller/dwc/pcie-designware.h
> > > index 954d504890a1..8c08159ea08e 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > > @@ -369,6 +369,8 @@ struct dw_pcie_ep {
> > >       unsigned long           *ob_window_map;
> > >       void __iomem            *msi_mem;
> > >       phys_addr_t             msi_mem_phys;
> > > +     void __iomem            *intx_mem;
> > > +     phys_addr_t             intx_mem_phys;
> > >       struct pci_epf_bar      *epf_bar[PCI_STD_NUM_BARS];
> > >  };
> > >
> > > --
> > > 2.25.1
> > >




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux