[PATCH 3/6] pci:host: Add Altera PCIe host controller driver

Ley Foon Tan lftan at altera.com
Wed Jul 29 04:08:16 PDT 2015


On Wed, Jul 29, 2015 at 11:43 AM, Rob Herring <robherring2 at gmail.com> wrote:
> On Tue, Jul 28, 2015 at 5:45 AM, Ley Foon Tan <lftan at altera.com> wrote:
>> This patch adds the Altera PCIe host controller driver.
>>
>> Signed-off-by: Ley Foon Tan <lftan at altera.com>

>> +
>> +static int altera_pcie_setup(int nr, struct pci_sys_data *sys)
>> +{
>> +       struct altera_pcie *pcie = sys->private_data;
>> +
>> +       list_splice_init(&pcie->resources, &sys->resources);
>> +
>> +       return 1;
>> +}
>> +
>> +static int altera_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
>> +{
>> +       struct altera_pcie *pcie = sys_to_pcie(pdev->bus->sysdata);
>> +       int irq;
>> +
>> +       irq = of_irq_parse_and_map_pci(pdev, slot, pin);
>> +
>> +       if (!irq)
>> +               irq = pcie->hwirq;
>> +
>> +       return irq;
>> +}
>
> This should not be needed as the core code should take care of this.
Okay.

>
>> +
>> +static struct pci_bus *altera_pcie_scan_bus(int nr, struct pci_sys_data *sys)
>> +{
>> +       struct altera_pcie *pcie = sys_to_pcie(sys);
>> +       struct pci_bus *bus;
>> +
>> +       pcie->root_bus_nr = sys->busnr;
>> +       bus = pci_scan_root_bus(&pcie->pdev->dev, sys->busnr, &altera_pcie_ops,
>> +                               sys, &sys->resources);
>> +
>> +       return bus;
>> +}
>> +
>> +static struct hw_pci altera_pcie_hw __initdata = {
>> +#ifdef CONFIG_PCI_DOMAINS
>> +       .domain                 = 0,
>> +#endif
>> +       .nr_controllers         = 1,
>> +       .ops                    = &altera_pcie_ops,
>> +       .setup                  = altera_pcie_setup,
>> +       .map_irq                        = altera_pcie_map_irq,
>> +       .scan                   = altera_pcie_scan_bus,
>
> You should be able to only have an empty hw_pci struct now.
Will remove this.

>> +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) {
>> +               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);
>> +
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "failed to request irq %d\n", pcie->hwirq);
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int altera_pcie_probe(struct platform_device *pdev)
>> +{
>> +       struct altera_pcie *pcie;
>> +       int ret;
>> +
>> +       pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
>> +       if (!pcie)
>> +               return -ENOMEM;
>> +
>> +       pcie->pdev = pdev;
>> +
>> +       ret = altera_pcie_parse_dt(pcie);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Parsing DT failed\n");
>> +               return ret;
>> +       }
>> +
>> +       INIT_LIST_HEAD(&pcie->resources);
>> +
>> +       ret = altera_pcie_parse_request_of_pci_ranges(pcie);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed add resources\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = altera_pcie_init_irq_domain(pcie);
>
> I don't think you need an irq domain here.
The controller have one single interrupt  for INTx. So, we need IRQ
domain for map and decode
the 4 INTx interrupt and route them to this domain.

>
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed creating IRQ Domain\n");
>> +               return ret;
>> +       }
>> +
>> +       pcie->root_bus_nr = -1;
>> +
>> +       /* clear all interrupts */
>> +       cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
>> +       /* enable all interrupts */
>> +       cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
>> +
>> +       altera_pcie_hw.private_data = (void **)&pcie;
>> +
>> +       pci_common_init_dev(&pdev->dev, &altera_pcie_hw);
>
> You should not call this, but call pci_scan_root_bus directly. See
> pci-host-generic.c or pci-versatile.c for examples.
Okay, will change to pci_scan_root_bus.

Thanks.

Regards
Ley Foon



More information about the linux-arm-kernel mailing list