From f1e8bd21e39ed51d1c5b69f29eee05ceb06b7fb4 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:13:51 -0500 Subject: PCI: faraday: Convert IRQ masking to raw PCI config accessors Current ftpci100 driver host bridge controller driver requires struct pci_bus to be created in order to mask and clear IRQs using standard PCI bus config accessors. This struct pci_bus dependency is fictitious and burdens the driver with unneeded constraints (eg to use separate APIs to create and scan the root bus). Add PCI raw config space accessors to PCIe ftpci100 driver and remove the fictitious struct pci_bus dependency. Signed-off-by: Lorenzo Pieralisi [bhelgaas: folded in raw PCI read accessor from http://lkml.kernel.org/r/20170621162651.25315-1-linus.walleij@linaro.org The clock piece of the above posting goes with the separate "Add clock handling" patch.] Signed-off-by: Bjorn Helgaas Acked-by: Linus Walleij --- drivers/pci/host/pci-ftpci100.c | 81 ++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 33 deletions(-) (limited to 'drivers/pci/host/pci-ftpci100.c') diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index d26501c..1ad6b25 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -178,12 +178,11 @@ static int faraday_res_to_memcfg(resource_size_t mem_base, return 0; } -static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, - int config, int size, u32 *value) +static int faraday_raw_pci_read_config(struct faraday_pci *p, int bus_number, + unsigned int fn, int config, int size, + u32 *value) { - struct faraday_pci *p = bus->sysdata; - - writel(PCI_CONF_BUS(bus->number) | + writel(PCI_CONF_BUS(bus_number) | PCI_CONF_DEVICE(PCI_SLOT(fn)) | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | @@ -197,24 +196,28 @@ static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, else if (size == 2) *value = (*value >> (8 * (config & 3))) & 0xFFFF; + return PCIBIOS_SUCCESSFUL; +} + +static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, + int config, int size, u32 *value) +{ + struct faraday_pci *p = bus->sysdata; + dev_dbg(&bus->dev, "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value); - return PCIBIOS_SUCCESSFUL; + return faraday_raw_pci_read_config(p, bus->number, fn, config, size, value); } -static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, - int config, int size, u32 value) +static int faraday_raw_pci_write_config(struct faraday_pci *p, int bus_number, + unsigned int fn, int config, int size, + u32 value) { - struct faraday_pci *p = bus->sysdata; int ret = PCIBIOS_SUCCESSFUL; - dev_dbg(&bus->dev, - "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", - PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); - - writel(PCI_CONF_BUS(bus->number) | + writel(PCI_CONF_BUS(bus_number) | PCI_CONF_DEVICE(PCI_SLOT(fn)) | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | @@ -238,6 +241,19 @@ static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, return ret; } +static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, + int config, int size, u32 value) +{ + struct faraday_pci *p = bus->sysdata; + + dev_dbg(&bus->dev, + "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", + PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); + + return faraday_raw_pci_write_config(p, bus->number, fn, config, size, + value); +} + static struct pci_ops faraday_pci_ops = { .read = faraday_pci_read_config, .write = faraday_pci_write_config, @@ -248,10 +264,10 @@ static void faraday_pci_ack_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTSTS_SHIFT); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_mask_irq(struct irq_data *d) @@ -259,10 +275,10 @@ static void faraday_pci_mask_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~((0xF << PCI_CTRL2_INTSTS_SHIFT) | BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT)); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_unmask_irq(struct irq_data *d) @@ -270,10 +286,10 @@ static void faraday_pci_unmask_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_irq_handler(struct irq_desc *desc) @@ -282,7 +298,7 @@ static void faraday_pci_irq_handler(struct irq_desc *desc) struct irq_chip *irqchip = irq_desc_get_chip(desc); unsigned int irq_stat, reg, i; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); irq_stat = reg >> PCI_CTRL2_INTSTS_SHIFT; chained_irq_enter(irqchip, desc); @@ -403,8 +419,8 @@ static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p, dev_info(dev, "DMA MEM%d BASE: 0x%016llx -> 0x%016llx config %08x\n", i + 1, range.pci_addr, end, val); if (i <= 2) { - faraday_pci_write_config(p->bus, 0, confreg[i], - 4, val); + faraday_raw_pci_write_config(p, 0, 0, confreg[i], + 4, val); } else { dev_err(dev, "ignore extraneous dma-range %d\n", i); break; @@ -496,17 +512,8 @@ static int faraday_pci_probe(struct platform_device *pdev) val |= PCI_COMMAND_MEMORY; val |= PCI_COMMAND_MASTER; writel(val, p->base + PCI_CTRL); - - list_splice_init(&res, &host->windows); - ret = pci_register_host_bridge(host); - if (ret) { - dev_err(dev, "failed to register host: %d\n", ret); - return ret; - } - p->bus = host->bus; - /* Mask and clear all interrupts */ - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); if (variant->cascaded_irq) { ret = faraday_pci_setup_cascaded_irq(p); if (ret) { @@ -519,6 +526,14 @@ static int faraday_pci_probe(struct platform_device *pdev) if (ret) return ret; + list_splice_init(&res, &host->windows); + ret = pci_register_host_bridge(host); + if (ret) { + dev_err(dev, "failed to register host: %d\n", ret); + return ret; + } + p->bus = host->bus; + pci_scan_child_bus(p->bus); pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); pci_bus_assign_resources(p->bus); -- cgit v1.1 From 9aa17a772084e192a2364340794f0d44ac73dd4c Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:13:53 -0500 Subject: PCI: faraday: Fix host bridge memory leakage When probing the PCI host controller driver, if an error occurs, the probe function code does not free memory allocated for the struct pci_host_bridge resulting in memory leakage. Move the struct pci_host_bridge allocation over to the respective devm interface to fix the issue. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Linus Walleij Cc: Arnd Bergmann --- drivers/pci/host/pci-ftpci100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/host/pci-ftpci100.c') diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index 1ad6b25..ce5700e 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -448,7 +448,7 @@ static int faraday_pci_probe(struct platform_device *pdev) u32 val; LIST_HEAD(res); - host = pci_alloc_host_bridge(sizeof(*p)); + host = devm_pci_alloc_host_bridge(dev, sizeof(*p)); if (!host) return -ENOMEM; -- cgit v1.1 From cea9bc0be624fb0dc488cb10df40be1323b6b758 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:13:55 -0500 Subject: PCI: Make pci_register_host_bridge() PCI core internal With the introduction of pci_scan_root_bus_bridge() there is no need to export pci_register_host_bridge() to other kernel subsystems other than the PCI compilation unit that needs it. Make pci_register_host_bridge() static to its compilation unit and convert the existing drivers usage over to pci_scan_root_bus_bridge(). Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Cc: Arnd Bergmann --- drivers/pci/host/pci-ftpci100.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/pci/host/pci-ftpci100.c') diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index ce5700e..2ee2ffb 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -527,14 +527,13 @@ static int faraday_pci_probe(struct platform_device *pdev) return ret; list_splice_init(&res, &host->windows); - ret = pci_register_host_bridge(host); + ret = pci_scan_root_bus_bridge(host); if (ret) { - dev_err(dev, "failed to register host: %d\n", ret); + dev_err(dev, "failed to scan host: %d\n", ret); return ret; } p->bus = host->bus; - pci_scan_child_bus(p->bus); pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); pci_bus_assign_resources(p->bus); pci_bus_add_devices(p->bus); -- cgit v1.1 From f7c2e69b65fe657e0a32d8db761525cc6109720b Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:14:08 -0500 Subject: PCI: faraday: Drop pci_fixup_irqs() Since, through struct pci_host_bridge.map/swizzle_irq hooks, IRQs are now allocated in the pci_assign_irq() callback automatically, PCI host bridge drivers can stop relying on pci_fixup_irqs() for IRQ allocation. Drop pci_fixup_irqs() usage from PCI ftpci100 host bridge driver. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Cc: Linus Walleij --- drivers/pci/host/pci-ftpci100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci/host/pci-ftpci100.c') diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index 2ee2ffb..e938eeb 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -456,6 +456,8 @@ static int faraday_pci_probe(struct platform_device *pdev) host->ops = &faraday_pci_ops; host->busnr = 0; host->msi = NULL; + host->map_irq = of_irq_parse_and_map_pci; + host->swizzle_irq = pci_common_swizzle; p = pci_host_bridge_priv(host); host->sysdata = p; p->dev = dev; @@ -534,7 +536,6 @@ static int faraday_pci_probe(struct platform_device *pdev) } p->bus = host->bus; - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); pci_bus_assign_resources(p->bus); pci_bus_add_devices(p->bus); pci_free_resource_list(&res); -- cgit v1.1 From 2eeb02b28579fc317504a691f3acb0b9bf94b42b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 May 2017 19:23:24 +0200 Subject: PCI: faraday: Add clock handling Add some optional clock handling to the Faraday FTPCI100. We just get and prepare+enable the clocks right now, if they exist. We can add more elaborate clock handling later. Signed-off-by: Linus Walleij [bhelgaas: folded in "Make clocks compulsory" fix from http://lkml.kernel.org/r/20170621085730.28804-1-linus.walleij@linaro.org Also folded in the clock max/cur speed fixes from http://lkml.kernel.org/r/20170621162651.25315-1-linus.walleij@linaro.org] Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-ftpci100.c | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/pci/host/pci-ftpci100.c') diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index e938eeb..5162dff 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * Special configuration registers directly in the first few words @@ -37,6 +38,7 @@ #define PCI_CONFIG 0x28 /* PCI configuration command register */ #define PCI_DATA 0x2C +#define FARADAY_PCI_STATUS_CMD 0x04 /* Status and command */ #define FARADAY_PCI_PMC 0x40 /* Power management control */ #define FARADAY_PCI_PMCSR 0x44 /* Power management status */ #define FARADAY_PCI_CTRL1 0x48 /* Control register 1 */ @@ -45,6 +47,8 @@ #define FARADAY_PCI_MEM2_BASE_SIZE 0x54 /* Memory base and size #2 */ #define FARADAY_PCI_MEM3_BASE_SIZE 0x58 /* Memory base and size #3 */ +#define PCI_STATUS_66MHZ_CAPABLE BIT(21) + /* Bits 31..28 gives INTD..INTA status */ #define PCI_CTRL2_INTSTS_SHIFT 28 #define PCI_CTRL2_INTMASK_CMDERR BIT(27) @@ -117,6 +121,7 @@ struct faraday_pci { void __iomem *base; struct irq_domain *irqdomain; struct pci_bus *bus; + struct clk *bus_clk; }; static int faraday_res_to_memcfg(resource_size_t mem_base, @@ -444,6 +449,9 @@ static int faraday_pci_probe(struct platform_device *pdev) struct resource *mem; struct resource *io; struct pci_host_bridge *host; + struct clk *clk; + unsigned char max_bus_speed = PCI_SPEED_33MHz; + unsigned char cur_bus_speed = PCI_SPEED_33MHz; int ret; u32 val; LIST_HEAD(res); @@ -462,6 +470,24 @@ static int faraday_pci_probe(struct platform_device *pdev) host->sysdata = p; p->dev = dev; + /* Retrieve and enable optional clocks */ + clk = devm_clk_get(dev, "PCLK"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "could not prepare PCLK\n"); + return ret; + } + p->bus_clk = devm_clk_get(dev, "PCICLK"); + if (IS_ERR(p->bus_clk)) + return PTR_ERR(clk); + ret = clk_prepare_enable(p->bus_clk); + if (ret) { + dev_err(dev, "could not prepare PCICLK\n"); + return ret; + } + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); p->base = devm_ioremap_resource(dev, regs); if (IS_ERR(p->base)) @@ -524,6 +550,34 @@ static int faraday_pci_probe(struct platform_device *pdev) } } + /* Check bus clock if we can gear up to 66 MHz */ + if (!IS_ERR(p->bus_clk)) { + unsigned long rate; + u32 val; + + faraday_raw_pci_read_config(p, 0, 0, + FARADAY_PCI_STATUS_CMD, 4, &val); + rate = clk_get_rate(p->bus_clk); + + if ((rate == 33000000) && (val & PCI_STATUS_66MHZ_CAPABLE)) { + dev_info(dev, "33MHz bus is 66MHz capable\n"); + max_bus_speed = PCI_SPEED_66MHz; + ret = clk_set_rate(p->bus_clk, 66000000); + if (ret) + dev_err(dev, "failed to set bus clock\n"); + } else { + dev_info(dev, "33MHz only bus\n"); + max_bus_speed = PCI_SPEED_33MHz; + } + + /* Bumping the clock may fail so read back the rate */ + rate = clk_get_rate(p->bus_clk); + if (rate == 33000000) + cur_bus_speed = PCI_SPEED_33MHz; + if (rate == 66000000) + cur_bus_speed = PCI_SPEED_66MHz; + } + ret = faraday_pci_parse_map_dma_ranges(p, dev->of_node); if (ret) return ret; @@ -535,6 +589,8 @@ static int faraday_pci_probe(struct platform_device *pdev) return ret; } p->bus = host->bus; + p->bus->max_bus_speed = max_bus_speed; + p->bus->cur_bus_speed = cur_bus_speed; pci_bus_assign_resources(p->bus); pci_bus_add_devices(p->bus); -- cgit v1.1