[PATCH v2 2/5] pci:host: Add Altera PCIe host controller driver

Ley Foon Tan lftan at altera.com
Mon Aug 3 03:34:41 PDT 2015


On Fri, Jul 31, 2015 at 8:34 PM, Marc Zyngier <marc.zyngier at arm.com> wrote:
> On 31/07/15 11:15, Ley Foon Tan wrote:
>> This patch adds the Altera PCIe host controller driver.
>>
>> Signed-off-by: Ley Foon Tan <lftan at altera.com>
>> ---
>>  drivers/pci/host/Kconfig       |   8 +
>>  drivers/pci/host/Makefile      |   1 +
>>  drivers/pci/host/pcie-altera.c | 526 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 535 insertions(+)
>>  create mode 100644 drivers/pci/host/pcie-altera.c
>>
>> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
>> index 675c2d1..108500a 100644
>> --- a/drivers/pci/host/Kconfig
>> +++ b/drivers/pci/host/Kconfig
>> @@ -145,4 +145,12 @@ config PCIE_IPROC_BCMA
>>         Say Y here if you want to use the Broadcom iProc PCIe controller
>>         through the BCMA bus interface
>>
>> +config PCIE_ALTERA
>> +     tristate "Altera PCIe controller"
>> +     depends on ARCH_SOCFPGA
>> +     select PCI_MSI_IRQ_DOMAIN if PCI_MSI
>
> Why would you select this here? MSI support is in another driver, so I
> don't see the point.
Will move select PCI_MSI_IRQ_DOMAIN to config  PCIE_ALTERA_MSI section.

>
>> +     help
>> +       Say Y here if you want to enable PCIe controller support for Altera
>> +       SoCFPGA family of SoCs.
>> +
>>  endmenu

>> +static const struct irq_domain_ops intx_domain_ops = {
>> +     .map = altera_pcie_intx_map,
>> +};
>> +
>> +static irqreturn_t altera_pcie_isr(int irq, void *arg)
>> +{
>> +     struct altera_pcie *pcie = arg;
>> +     u32 status, i;
>> +
>> +     status = cra_readl(pcie, P2A_INT_STATUS) & P2A_INT_STS_ALL;
>> +
>> +     /* clear interrupts */
>> +     cra_writel(pcie, status, P2A_INT_STATUS);
>> +
>> +     for (i = 0; i < INTX_NUM; i++) {
>> +             if (status & (1 << i))
>
> find_first/next_set_bit?
Yes, change this to find_first_bit().

>
>> +                     generic_handle_irq(irq_find_mapping(pcie->irq_domain,
>> +                                                     i + 1));
>
> Rule of thumb: if you're calling generic_handle_irq from an interrupt
> handler, this is a chained IRQ controller. Please implement it as such.
Okay, will change this to chained_irq_enter/chained_irq_exit implementation.
>
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static void altera_pcie_release_of_pci_ranges(struct altera_pcie *pcie)
>> +{
>> +     pci_free_resource_list(&pcie->resources);
>> +}
>> +
>> +static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
>> +{
>> +     int err, res_valid = 0;
>> +     struct device *dev = &pcie->pdev->dev;
>> +     struct device_node *np = dev->of_node;
>> +     resource_size_t iobase;
>> +     struct resource_entry *win;
>> +     int offset = 0;
>> +
>> +     err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pcie->resources,
>> +                                            &iobase);
>> +     if (err)
>> +             return err;
>> +
>> +     resource_list_for_each_entry(win, &pcie->resources) {
>> +             struct resource *parent, *res = win->res;
>> +
>> +             switch (resource_type(res)) {
>> +             case IORESOURCE_MEM:
>> +                     parent = &iomem_resource;
>> +                     res_valid |= !(res->flags & IORESOURCE_PREFETCH);
>> +                     cra_writel(pcie, res->start,
>> +                             A2P_ADDR_MAP_LO0 + offset);
>> +                     cra_writel(pcie, 0,
>> +                             A2P_ADDR_MAP_HI0 + offset);
>> +                     offset += ATT_ENTRY_SIZE;
>> +                     break;
>> +             default:
>> +                     continue;
>> +             }
>> +
>> +             err = devm_request_resource(dev, parent, res);
>> +             if (err)
>> +                     goto out_release_res;
>> +     }
>> +
>> +     if (!res_valid) {
>> +             dev_err(dev, "non-prefetchable memory resource required\n");
>> +             err = -EINVAL;
>> +             goto out_release_res;
>> +     }
>> +
>> +     return 0;
>> +
>> +out_release_res:
>> +     altera_pcie_release_of_pci_ranges(pcie);
>> +     return err;
>> +}
>> +
>> +static void altera_pcie_free_irq_domain(struct altera_pcie *pcie)
>> +{
>> +     int i;
>> +     u32 irq;
>> +
>> +     for (i = 0; i < INTX_NUM; i++) {
>> +             irq = irq_find_mapping(pcie->irq_domain, i);
>> +             if (irq > 0)
>> +                     irq_dispose_mapping(irq);
>> +     }
>> +
>> +     irq_domain_remove(pcie->irq_domain);
>> +}
>> +
>> +static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
>> +{
>> +     struct device *dev = &pcie->pdev->dev;
>> +     struct device_node *node = dev->of_node;
>> +
>> +     /* Setup INTx */
>> +     pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM,
>> +                                     &intx_domain_ops, pcie);
>> +     if (!pcie->irq_domain) {
>> +             dev_err(dev, "Failed to get a INTx IRQ domain\n");
>> +             return PTR_ERR(pcie->irq_domain);
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int altera_pcie_parse_dt(struct altera_pcie *pcie)
>> +{
>> +     struct resource *cra;
>> +     int ret;
>> +     struct platform_device *pdev = pcie->pdev;
>> +
>> +     cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra");
>> +     pcie->cra_base = devm_ioremap_resource(&pdev->dev, cra);
>> +     if (IS_ERR(pcie->cra_base)) {
>> +             dev_err(&pdev->dev, "get Cra resource failed\n");
>> +             return PTR_ERR(pcie->cra_base);
>> +     }
>> +
>> +     /* setup IRQ */
>> +     pcie->hwirq = platform_get_irq(pdev, 0);
>> +     if (pcie->hwirq <= 0) {
>
> This is definitely not a hardware interrupt number. It is completely
> virtual. I suggest you give it a better name.
Noted.

>
>> +             dev_err(&pdev->dev, "failed to get IRQ: %d\n", pcie->hwirq);
>> +             return -EINVAL;
>> +     }
>> +     ret = devm_request_irq(&pdev->dev, pcie->hwirq, altera_pcie_isr,
>> +                     IRQF_SHARED, pdev->name, pcie);
>
> You're implementing a cascading interrupt controller again. Please fix
> it just like you did for your MSI support.
Sure, will change to irq_set_chained_handler_and_data here.


Thanks for reviewing.

Regards
Ley Foon



More information about the linux-arm-kernel mailing list