From 2850b05c9644d0f4c9df6cc77d628d7e0598a0cc Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 26 Nov 2013 11:02:52 -0700 Subject: PCI: mvebu: Drop writes to bridge Secondary Status register There are no writable bits in the secondary status register, only RO and RW1C (write-1-to-clear) bits. The driver never sets any of the RW1C bits, so the status register should always be 0, just remove the set from the write path. Someday the RW1C bits should be copied/cleared directly from registers in the HW. [bhelgaas: changelog tweaks] Signed-off-by: Jason Gunthorpe Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper --- drivers/pci/host/pci-mvebu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/host') diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index c269e430c760..6f5a20f3cdf6 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -500,7 +500,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, */ bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32; bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32; - bridge->secondary_status = value >> 16; mvebu_pcie_handle_iobase_change(port); break; -- cgit v1.2.3 From 43a16f94445310800e39d54aaa534f2ce7dbe0a2 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 26 Nov 2013 11:02:54 -0700 Subject: PCI: mvebu: Obey bridge PCI_COMMAND_MEM and PCI_COMMAND_IO bits When PCI_COMMAND_MEMORY/PCI_COMMAND_IO are cleared, the bridge should not allocate windows or even look at the window limit/base registers. Otherwise we may set up bogus windows while the PCI core code performs discovery. The core will leave PCI_COMMAND_IO cleared if it doesn't need an IO window. Have mvebu_pcie_handle_*_change respect the bits, and call the change function whenever the bits changes. Tested-by: Thomas Petazzoni Signed-off-by: Jason Gunthorpe Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper --- drivers/pci/host/pci-mvebu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/pci/host') diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 6f5a20f3cdf6..94294123e7bd 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -300,7 +300,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) /* Are the new iobase/iolimit values invalid? */ if (port->bridge.iolimit < port->bridge.iobase || - port->bridge.iolimitupper < port->bridge.iobaseupper) { + port->bridge.iolimitupper < port->bridge.iobaseupper || + !(port->bridge.command & PCI_COMMAND_IO)) { /* If a window was configured, remove it */ if (port->iowin_base) { @@ -337,7 +338,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) { /* Are the new membase/memlimit values invalid? */ - if (port->bridge.memlimit < port->bridge.membase) { + if (port->bridge.memlimit < port->bridge.membase || + !(port->bridge.command & PCI_COMMAND_MEMORY)) { /* If a window was configured, remove it */ if (port->memwin_base) { @@ -485,8 +487,16 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, switch (where & ~3) { case PCI_COMMAND: + { + u32 old = bridge->command; + bridge->command = value & 0xffff; + if ((old ^ bridge->command) & PCI_COMMAND_IO) + mvebu_pcie_handle_iobase_change(port); + if ((old ^ bridge->command) & PCI_COMMAND_MEMORY) + mvebu_pcie_handle_membase_change(port); break; + } case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; -- cgit v1.2.3 From 641e674d6c0f974162c4c8cc0081c7ffc50b3911 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 26 Nov 2013 11:02:55 -0700 Subject: PCI: mvebu: Support a bridge with no IO port window Make pcie-io-aperture and the IO port MBUS ID in ranges optional. If not provided the bridge reports to Linux that IO space mapping is not supported and refuses to configure an IO MBUS window. This allows both complete disable (do not specify pcie-io-aperture) and per-port disable (do not specify a IO target ranges entry for the port). Most PCIe devices these days do not require IO support to function, so having an option to disable it in the driver is useful. Tested-by: Thomas Petazzoni Signed-off-by: Jason Gunthorpe Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper --- drivers/pci/host/pci-mvebu.c | 63 ++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 20 deletions(-) (limited to 'drivers/pci/host') diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 94294123e7bd..abd560e46757 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -150,6 +150,11 @@ static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg) return readl(port->base + reg); } +static inline bool mvebu_has_ioport(struct mvebu_pcie_port *port) +{ + return port->io_target != -1 && port->io_attr != -1; +} + static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) { return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); @@ -314,6 +319,12 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) return; } + if (!mvebu_has_ioport(port)) { + dev_WARN(&port->pcie->pdev->dev, + "Attempt to set IO when IO is disabled\n"); + return; + } + /* * We read the PCI-to-PCI bridge emulated registers, and * calculate the base address and size of the address decoding @@ -428,9 +439,12 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, break; case PCI_IO_BASE: - *value = (bridge->secondary_status << 16 | - bridge->iolimit << 8 | - bridge->iobase); + if (!mvebu_has_ioport(port)) + *value = bridge->secondary_status << 16; + else + *value = (bridge->secondary_status << 16 | + bridge->iolimit << 8 | + bridge->iobase); break; case PCI_MEMORY_BASE: @@ -490,6 +504,9 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, { u32 old = bridge->command; + if (!mvebu_has_ioport(port)) + value &= ~PCI_COMMAND_IO; + bridge->command = value & 0xffff; if ((old ^ bridge->command) & PCI_COMMAND_IO) mvebu_pcie_handle_iobase_change(port); @@ -660,7 +677,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) struct mvebu_pcie *pcie = sys_to_pcie(sys); int i; - pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset); + if (resource_size(&pcie->realio) != 0) + pci_add_resource_offset(&sys->resources, &pcie->realio, + sys->io_offset); pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); @@ -761,12 +780,17 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev, #define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) static int mvebu_get_tgt_attr(struct device_node *np, int devfn, - unsigned long type, int *tgt, int *attr) + unsigned long type, + unsigned int *tgt, + unsigned int *attr) { const int na = 3, ns = 2; const __be32 *range; int rlen, nranges, rangesz, pna, i; + *tgt = -1; + *attr = -1; + range = of_get_property(np, "ranges", &rlen); if (!range) return -EINVAL; @@ -836,16 +860,15 @@ static int mvebu_pcie_probe(struct platform_device *pdev) } mvebu_mbus_get_pcie_io_aperture(&pcie->io); - if (resource_size(&pcie->io) == 0) { - dev_err(&pdev->dev, "invalid I/O aperture size\n"); - return -EINVAL; - } - pcie->realio.flags = pcie->io.flags; - pcie->realio.start = PCIBIOS_MIN_IO; - pcie->realio.end = min_t(resource_size_t, - IO_SPACE_LIMIT, - resource_size(&pcie->io)); + if (resource_size(&pcie->io) != 0) { + pcie->realio.flags = pcie->io.flags; + pcie->realio.start = PCIBIOS_MIN_IO; + pcie->realio.end = min_t(resource_size_t, + IO_SPACE_LIMIT, + resource_size(&pcie->io)); + } else + pcie->realio = pcie->io; /* Get the bus range */ ret = of_pci_parse_bus_range(np, &pcie->busn); @@ -904,12 +927,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev) continue; } - ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, - &port->io_target, &port->io_attr); - if (ret < 0) { - dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", - port->port, port->lane); - continue; + if (resource_size(&pcie->io) != 0) + mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, + &port->io_target, &port->io_attr); + else { + port->io_target = -1; + port->io_attr = -1; } port->reset_gpio = of_get_named_gpio_flags(child, -- cgit v1.2.3 From 84f47190d6be1cb99cd4a680e1018080d93800a8 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 4 Dec 2013 18:30:41 +0100 Subject: PCI: mvebu: Remove duplicate of_clk_get_by_name() call Probably due to a merge conflict resolution gone bad, the PCI clock is got twice. Remove the redundant call of of_clk_get_by_name(). Signed-off-by: Andrew Lunn Signed-off-by: Bjorn Helgaas Reviewed-by: Jingoo Han Acked-by: Jason Cooper --- drivers/pci/host/pci-mvebu.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/pci/host') diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index abd560e46757..6f35df5fedce 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -981,14 +981,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev) mvebu_pcie_set_local_dev_nr(port, 1); - port->clk = of_clk_get_by_name(child, NULL); - if (IS_ERR(port->clk)) { - dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", - port->port, port->lane); - iounmap(port->base); - continue; - } - port->dn = child; spin_lock_init(&port->conf_lock); mvebu_sw_pci_bridge_init(port); -- cgit v1.2.3