diff options
Diffstat (limited to 'kernel/drivers/pci/host/pcie-rcar.c')
-rw-r--r-- | kernel/drivers/pci/host/pcie-rcar.c | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/kernel/drivers/pci/host/pcie-rcar.c b/kernel/drivers/pci/host/pcie-rcar.c index c086210f2..414c33686 100644 --- a/kernel/drivers/pci/host/pcie-rcar.c +++ b/kernel/drivers/pci/host/pcie-rcar.c @@ -108,6 +108,8 @@ #define RCAR_PCI_MAX_RESOURCES 4 #define MAX_NR_INBOUND_MAPS 6 +static unsigned long global_io_offset; + struct rcar_msi { DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; @@ -124,7 +126,16 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip) } /* Structure representing the PCIe interface */ +/* + * ARM pcibios functions expect the ARM struct pci_sys_data as the PCI + * sysdata. Add pci_sys_data as the first element in struct gen_pci so + * that when we use a gen_pci pointer as sysdata, it is also a pointer to + * a struct pci_sys_data. + */ struct rcar_pcie { +#ifdef CONFIG_ARM + struct pci_sys_data sys; +#endif struct device *dev; void __iomem *base; struct resource res[RCAR_PCI_MAX_RESOURCES]; @@ -135,11 +146,6 @@ struct rcar_pcie { struct rcar_msi msi; }; -static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys) -{ - return sys->private_data; -} - static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned long reg) { @@ -258,7 +264,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata); + struct rcar_pcie *pcie = bus->sysdata; int ret; ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ, @@ -283,7 +289,7 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata); + struct rcar_pcie *pcie = bus->sysdata; int shift, ret; u32 data; @@ -353,13 +359,12 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie) rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win)); } -static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) +static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pcie) { - struct rcar_pcie *pcie = sys_to_pcie(sys); struct resource *res; int i; - pcie->root_bus_nr = -1; + pcie->root_bus_nr = pcie->busn.start; /* Setup PCI resources */ for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) { @@ -372,32 +377,53 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) if (res->flags & IORESOURCE_IO) { phys_addr_t io_start = pci_pio_to_address(res->start); - pci_ioremap_io(nr * SZ_64K, io_start); - } else - pci_add_resource(&sys->resources, res); + pci_ioremap_io(global_io_offset, io_start); + global_io_offset += SZ_64K; + } + + pci_add_resource(resource, res); } - pci_add_resource(&sys->resources, &pcie->busn); + pci_add_resource(resource, &pcie->busn); return 1; } -static struct hw_pci rcar_pci = { - .setup = rcar_pcie_setup, - .map_irq = of_irq_parse_and_map_pci, - .ops = &rcar_pcie_ops, -}; - -static void rcar_pcie_enable(struct rcar_pcie *pcie) +static int rcar_pcie_enable(struct rcar_pcie *pcie) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct pci_bus *bus, *child; + LIST_HEAD(res); - rcar_pci.nr_controllers = 1; - rcar_pci.private_data = (void **)&pcie; -#ifdef CONFIG_PCI_MSI - rcar_pci.msi_ctrl = &pcie->msi.chip; -#endif + rcar_pcie_setup(&res, pcie); + + /* Do not reassign resources if probe only */ + if (!pci_has_flag(PCI_PROBE_ONLY)) + pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); - pci_common_init_dev(&pdev->dev, &rcar_pci); + if (IS_ENABLED(CONFIG_PCI_MSI)) + bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr, + &rcar_pcie_ops, pcie, &res, &pcie->msi.chip); + else + bus = pci_scan_root_bus(pcie->dev, pcie->root_bus_nr, + &rcar_pcie_ops, pcie, &res); + + if (!bus) { + dev_err(pcie->dev, "Scanning rootbus failed"); + return -ENODEV; + } + + pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); + + if (!pci_has_flag(PCI_PROBE_ONLY)) { + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + + pci_bus_add_devices(bus); + + return 0; } static int phy_wait_for_ack(struct rcar_pcie *pcie) @@ -664,7 +690,6 @@ static int rcar_msi_map(struct irq_domain *domain, unsigned int irq, { irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq); irq_set_chip_data(irq, domain->host_data); - set_irq_flags(irq, IRQF_VALID); return 0; } @@ -695,14 +720,16 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* Two irqs are for MSI, but they are also used for non-MSI irqs */ err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, - IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + IRQF_SHARED | IRQF_NO_THREAD, + rcar_msi_irq_chip.name, pcie); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); goto err; } err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq, - IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + IRQF_SHARED | IRQF_NO_THREAD, + rcar_msi_irq_chip.name, pcie); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); goto err; @@ -971,9 +998,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) data = rcar_pci_read_reg(pcie, MACSR); dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); - rcar_pcie_enable(pcie); - - return 0; + return rcar_pcie_enable(pcie); } static struct platform_driver rcar_pcie_driver = { |