On 5/5/22 12:12, Dmitry Baryshkov wrote: > On some of Qualcomm platforms each group of 32 MSI vectors is routed to the > separate GIC interrupt. Thus to receive higher MSI vectors properly, > add separate msi_host_init()/msi_host_deinit() handling additional host > IRQs. > > Note, that if DT doesn't list extra MSI interrupts, the driver will limit > the amount of supported MSI vectors accordingly (to 32). > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> > --- > drivers/pci/controller/dwc/pcie-qcom.c | 137 ++++++++++++++++++++++++- > 1 file changed, 136 insertions(+), 1 deletion(-) > > diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c > index 375f27ab9403..6cd1c2cc6d9e 100644 > --- a/drivers/pci/controller/dwc/pcie-qcom.c > +++ b/drivers/pci/controller/dwc/pcie-qcom.c > @@ -194,6 +194,7 @@ struct qcom_pcie_ops { > > struct qcom_pcie_cfg { > const struct qcom_pcie_ops *ops; > + unsigned int has_split_msi_irqs:1; > unsigned int pipe_clk_need_muxing:1; > unsigned int has_tbu_clk:1; > unsigned int has_ddrss_sf_tbu_clk:1; > @@ -209,6 +210,7 @@ struct qcom_pcie { > struct phy *phy; > struct gpio_desc *reset; > const struct qcom_pcie_cfg *cfg; > + int msi_irqs[MAX_MSI_CTRLS]; > }; > > #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) > @@ -1387,6 +1389,124 @@ static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie) > return 0; > } > > +static void qcom_chained_msi_isr(struct irq_desc *desc) > +{ > + struct irq_chip *chip = irq_desc_get_chip(desc); > + int irq = irq_desc_get_irq(desc); > + struct pcie_port *pp; > + int i, pos; > + unsigned long val; > + u32 status, num_ctrls; > + struct dw_pcie *pci; > + struct qcom_pcie *pcie; > + > + chained_irq_enter(chip, desc); > + > + pp = irq_desc_get_handler_data(desc); > + pci = to_dw_pcie_from_pp(pp); > + pcie = to_qcom_pcie(pci); > + > + /* > + * Unlike generic dw_handle_msi_irq(), we can determine which group of > + * MSIs triggered the IRQ, so process just that group. > + */ > + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; > + > + for (i = 0; i < num_ctrls; i++) { > + if (pcie->msi_irqs[i] == irq) > + break; > + } > + > + if (WARN_ON_ONCE(unlikely(i == num_ctrls))) > + goto out; > + > + status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS + > + (i * MSI_REG_CTRL_BLOCK_SIZE)); > + if (!status) > + goto out; > + > + val = status; > + pos = 0; > + while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL, > + pos)) != MAX_MSI_IRQS_PER_CTRL) { > + generic_handle_domain_irq(pp->irq_domain, > + (i * MAX_MSI_IRQS_PER_CTRL) + > + pos); > + pos++; > + } > + > +out: > + chained_irq_exit(chip, desc); > +} > + > +static int qcom_pcie_msi_host_init(struct pcie_port *pp) > +{ > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); > + struct qcom_pcie *pcie = to_qcom_pcie(pci); > + struct platform_device *pdev = to_platform_device(pci->dev); > + char irq_name[] = "msiXXX"; > + unsigned int ctrl, num_ctrls; > + int msi_irq, ret; > + > + pp->msi_irq = -EINVAL; > + > + /* > + * We provide our own implementation of MSI init/deinit, but rely on > + * using the rest of DWC MSI functionality. > + */ > + pp->has_msi_ctrl = true; > + > + msi_irq = platform_get_irq_byname_optional(pdev, "msi"); > + if (msi_irq < 0) { > + msi_irq = platform_get_irq(pdev, 0); > + if (msi_irq < 0) > + return msi_irq; > + } > + > + pcie->msi_irqs[0] = msi_irq; > + > + for (num_ctrls = 1; num_ctrls < MAX_MSI_CTRLS; num_ctrls++) { > + snprintf(irq_name, sizeof(irq_name), "msi%d", num_ctrls + 1); > + msi_irq = platform_get_irq_byname_optional(pdev, irq_name); > + if (msi_irq == -ENXIO) > + break; > + > + pcie->msi_irqs[num_ctrls] = msi_irq; > + } > + > + pp->num_vectors = num_ctrls * MAX_MSI_IRQS_PER_CTRL; > + dev_info(&pdev->dev, "Using %d MSI vectors\n", pp->num_vectors); > + for (ctrl = 0; ctrl < num_ctrls; ctrl++) > + pp->irq_mask[ctrl] = ~0; > + > + ret = dw_pcie_allocate_msi(pp); > + if (ret) > + return ret; > + > + for (ctrl = 0; ctrl < num_ctrls; ctrl++) > + irq_set_chained_handler_and_data(pcie->msi_irqs[ctrl], > + qcom_chained_msi_isr, > + pp) Align on the open brace, please. ; > + > + return 0; > +} > + > +static void qcom_pcie_msi_host_deinit(struct pcie_port *pp) > +{ > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); > + struct qcom_pcie *pcie = to_qcom_pcie(pci); > + unsigned int ctrl, num_ctrls; > + > + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; > + > + for (ctrl = 0; ctrl < num_ctrls; ctrl++) > + irq_set_chained_handler_and_data(pcie->msi_irqs[ctrl], > + NULL, > + NULL); ditto. -- regards, Stan