diff options
Diffstat (limited to 'drivers/pci/host')
-rw-r--r-- | drivers/pci/host/pci-exynos.c | 5 | ||||
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 225 | ||||
-rw-r--r-- | drivers/pci/host/pci-mvebu.c | 104 | ||||
-rw-r--r-- | drivers/pci/host/pci-rcar-gen2.c | 12 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 2 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.c | 91 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.h | 4 |
7 files changed, 286 insertions, 157 deletions
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 24beed38ddc..3de6bfbbe8e 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -468,7 +468,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, int ret; exynos_pcie_sideband_dbi_r_mode(pp, true); - ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); + ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); exynos_pcie_sideband_dbi_r_mode(pp, false); return ret; } @@ -479,7 +479,8 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, int ret; exynos_pcie_sideband_dbi_w_mode(pp, true); - ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, val); + ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), + where, size, val); exynos_pcie_sideband_dbi_w_mode(pp, false); return ret; } diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index bd70af8f31a..e8663a8c340 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -44,10 +44,18 @@ struct imx6_pcie { void __iomem *mem_base; }; +/* PCIe Root Complex registers (memory-mapped) */ +#define PCIE_RC_LCR 0x7c +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf + /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) +#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29) +#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4) #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) #define PCIE_PHY_CTRL_DATA_LOC 0 @@ -59,6 +67,9 @@ struct imx6_pcie { #define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT_ACK_LOC 16 +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C +#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) + /* PHY registers (not memory-mapped) */ #define PCIE_PHY_RX_ASIC_OUT 0x100D @@ -209,15 +220,9 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); - gpio_set_value(imx6_pcie->reset_gpio, 0); - msleep(100); - gpio_set_value(imx6_pcie->reset_gpio, 1); - return 0; } @@ -261,6 +266,12 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) /* allow the clocks to stabilize */ usleep_range(200, 500); + /* Some boards don't have PCIe reset GPIO. */ + if (gpio_is_valid(imx6_pcie->reset_gpio)) { + gpio_set_value(imx6_pcie->reset_gpio, 0); + msleep(100); + gpio_set_value(imx6_pcie->reset_gpio, 1); + } return 0; err_pcie_axi: @@ -299,11 +310,90 @@ static void imx6_pcie_init_phy(struct pcie_port *pp) IMX6Q_GPR8_TX_SWING_LOW, 127 << 25); } -static void imx6_pcie_host_init(struct pcie_port *pp) +static int imx6_pcie_wait_for_link(struct pcie_port *pp) +{ + int count = 200; + + while (!dw_pcie_link_up(pp)) { + usleep_range(100, 1000); + if (--count) + continue; + + dev_err(pp->dev, "phy link never came up\n"); + dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", + readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), + readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); + return -EINVAL; + } + + return 0; +} + +static int imx6_pcie_start_link(struct pcie_port *pp) { - int count = 0; struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + uint32_t tmp; + int ret, count; + /* + * Force Gen1 operation when starting the link. In case the link is + * started in Gen2 mode, there is a possibility the devices on the + * bus will not be detected at all. This happens with PCIe switches. + */ + tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; + tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; + writel(tmp, pp->dbi_base + PCIE_RC_LCR); + + /* Start LTSSM. */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + + ret = imx6_pcie_wait_for_link(pp); + if (ret) + return ret; + + /* Allow Gen2 mode after the link is up. */ + tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; + tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; + writel(tmp, pp->dbi_base + PCIE_RC_LCR); + + /* + * Start Directed Speed Change so the best possible speed both link + * partners support can be negotiated. + */ + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp |= PORT_LOGIC_SPEED_CHANGE; + writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + + count = 200; + while (count--) { + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + /* Test if the speed change finished. */ + if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) + break; + usleep_range(100, 1000); + } + + /* Make sure link training is finished as well! */ + if (count) + ret = imx6_pcie_wait_for_link(pp); + else + ret = -EINVAL; + + if (ret) { + dev_err(pp->dev, "Failed to bring link up!\n"); + } else { + tmp = readl(pp->dbi_base + 0x80); + dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf); + } + + return ret; +} + +static void imx6_pcie_host_init(struct pcie_port *pp) +{ imx6_pcie_assert_core_reset(pp); imx6_pcie_init_phy(pp); @@ -312,33 +402,41 @@ static void imx6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + imx6_pcie_start_link(pp); +} - while (!dw_pcie_link_up(pp)) { - usleep_range(100, 1000); - count++; - if (count >= 200) { - dev_err(pp->dev, "phy link never came up\n"); - dev_dbg(pp->dev, - "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", - readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), - readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); - break; - } - } +static void imx6_pcie_reset_phy(struct pcie_port *pp) +{ + uint32_t temp; + + pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp); + temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN | + PHY_RX_OVRD_IN_LO_RX_PLL_EN); + pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp); + + usleep_range(2000, 3000); - return; + pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp); + temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN | + PHY_RX_OVRD_IN_LO_RX_PLL_EN); + pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp); } static int imx6_pcie_link_up(struct pcie_port *pp) { - u32 rc, ltssm, rx_valid, temp; + u32 rc, ltssm, rx_valid; - /* link is debug bit 36, debug register 1 starts at bit 32 */ - rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32)); - if (rc) - return -EAGAIN; + /* + * Test if the PHY reports that the link is up and also that + * the link training finished. It might happen that the PHY + * reports the link is already up, but the link training bit + * is still set, so make sure to check the training is done + * as well here. + */ + rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1); + if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) && + !(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING)) + return 1; /* * From L0, initiate MAC entry to gen2 if EP/RC supports gen2. @@ -358,21 +456,7 @@ static int imx6_pcie_link_up(struct pcie_port *pp) dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n"); - pcie_phy_read(pp->dbi_base, - PHY_RX_OVRD_IN_LO, &temp); - temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN - | PHY_RX_OVRD_IN_LO_RX_PLL_EN); - pcie_phy_write(pp->dbi_base, - PHY_RX_OVRD_IN_LO, temp); - - usleep_range(2000, 3000); - - pcie_phy_read(pp->dbi_base, - PHY_RX_OVRD_IN_LO, &temp); - temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN - | PHY_RX_OVRD_IN_LO_RX_PLL_EN); - pcie_phy_write(pp->dbi_base, - PHY_RX_OVRD_IN_LO, temp); + imx6_pcie_reset_phy(pp); return 0; } @@ -426,30 +510,19 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) "imprecise external abort"); dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!dbi_base) { - dev_err(&pdev->dev, "dbi_base memory resource not found\n"); - return -ENODEV; - } - pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base); - if (IS_ERR(pp->dbi_base)) { - ret = PTR_ERR(pp->dbi_base); - goto err; - } + if (IS_ERR(pp->dbi_base)) + return PTR_ERR(pp->dbi_base); /* Fetch GPIOs */ imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); - if (!gpio_is_valid(imx6_pcie->reset_gpio)) { - dev_err(&pdev->dev, "no reset-gpio defined\n"); - ret = -ENODEV; - } - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->reset_gpio, - GPIOF_OUT_INIT_LOW, - "PCIe reset"); - if (ret) { - dev_err(&pdev->dev, "unable to get reset gpio\n"); - goto err; + if (gpio_is_valid(imx6_pcie->reset_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio, + GPIOF_OUT_INIT_LOW, "PCIe reset"); + if (ret) { + dev_err(&pdev->dev, "unable to get reset gpio\n"); + return ret; + } } imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); @@ -460,7 +533,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) "PCIe power enable"); if (ret) { dev_err(&pdev->dev, "unable to get power-on gpio\n"); - goto err; + return ret; } } @@ -472,7 +545,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) "PCIe wake up"); if (ret) { dev_err(&pdev->dev, "unable to get wake-up gpio\n"); - goto err; + return ret; } } @@ -484,7 +557,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) "PCIe disable endpoint"); if (ret) { dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); - goto err; + return ret; } } @@ -493,32 +566,28 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) if (IS_ERR(imx6_pcie->lvds_gate)) { dev_err(&pdev->dev, "lvds_gate clock select missing or invalid\n"); - ret = PTR_ERR(imx6_pcie->lvds_gate); - goto err; + return PTR_ERR(imx6_pcie->lvds_gate); } imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m"); if (IS_ERR(imx6_pcie->sata_ref_100m)) { dev_err(&pdev->dev, "sata_ref_100m clock source missing or invalid\n"); - ret = PTR_ERR(imx6_pcie->sata_ref_100m); - goto err; + return PTR_ERR(imx6_pcie->sata_ref_100m); } imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m"); if (IS_ERR(imx6_pcie->pcie_ref_125m)) { dev_err(&pdev->dev, "pcie_ref_125m clock source missing or invalid\n"); - ret = PTR_ERR(imx6_pcie->pcie_ref_125m); - goto err; + return PTR_ERR(imx6_pcie->pcie_ref_125m); } imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi"); if (IS_ERR(imx6_pcie->pcie_axi)) { dev_err(&pdev->dev, "pcie_axi clock source missing or invalid\n"); - ret = PTR_ERR(imx6_pcie->pcie_axi); - goto err; + return PTR_ERR(imx6_pcie->pcie_axi); } /* Grab GPR config register range */ @@ -526,19 +595,15 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); if (IS_ERR(imx6_pcie->iomuxc_gpr)) { dev_err(&pdev->dev, "unable to find iomuxc registers\n"); - ret = PTR_ERR(imx6_pcie->iomuxc_gpr); - goto err; + return PTR_ERR(imx6_pcie->iomuxc_gpr); } ret = imx6_add_pcie_port(pp, pdev); if (ret < 0) - goto err; + return ret; platform_set_drvdata(pdev, imx6_pcie); return 0; - -err: - return ret; } static const struct of_device_id imx6_pcie_of_match[] = { diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index c269e430c76..13478ecd411 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); @@ -300,7 +305,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) { @@ -313,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 @@ -330,14 +342,13 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, port->iowin_base, port->iowin_size, iobase); - - pci_ioremap_io(iobase, port->iowin_base); } 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) { @@ -426,9 +437,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: @@ -447,6 +461,11 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, *value = 0; break; + case PCI_INTERRUPT_LINE: + /* LINE PIN MIN_GNT MAX_LAT */ + *value = 0; + break; + default: *value = 0xffffffff; return PCIBIOS_BAD_REGISTER_NUMBER; @@ -485,8 +504,19 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, switch (where & ~3) { case PCI_COMMAND: + { + 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); + 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; @@ -500,7 +530,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; @@ -651,7 +680,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); @@ -702,9 +733,9 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, * aligned on their size */ if (res->flags & IORESOURCE_IO) - return round_up(start, max((resource_size_t)SZ_64K, size)); + return round_up(start, max_t(resource_size_t, SZ_64K, size)); else if (res->flags & IORESOURCE_MEM) - return round_up(start, max((resource_size_t)SZ_1M, size)); + return round_up(start, max_t(resource_size_t, SZ_1M, size)); else return start; } @@ -752,12 +783,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; @@ -827,16 +863,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); @@ -895,12 +930,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, @@ -949,14 +984,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); @@ -964,6 +991,10 @@ static int mvebu_pcie_probe(struct platform_device *pdev) } pcie->nports = i; + + for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K) + pci_ioremap_io(i, pcie->io.start + i); + mvebu_pcie_msi_enable(pcie); mvebu_pcie_enable(pcie); @@ -983,8 +1014,7 @@ static struct platform_driver mvebu_pcie_driver = { .driver = { .owner = THIS_MODULE, .name = "mvebu-pcie", - .of_match_table = - of_match_ptr(mvebu_pcie_of_match_table), + .of_match_table = mvebu_pcie_of_match_table, /* driver unloading/unbinding currently not supported */ .suppress_bind_attrs = true, }, diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index cbaa5c4397e..ceec147baec 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> /* AHB-PCI Bridge PCI communication registers */ @@ -77,6 +78,7 @@ #define RCAR_PCI_NR_CONTROLLERS 3 struct rcar_pci_priv { + struct device *dev; void __iomem *reg; struct resource io_res; struct resource mem_res; @@ -169,8 +171,11 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) void __iomem *reg = priv->reg; u32 val; + pm_runtime_enable(priv->dev); + pm_runtime_get_sync(priv->dev); + val = ioread32(reg + RCAR_PCI_UNIT_REV_REG); - pr_info("PCI: bus%u revision %x\n", sys->busnr, val); + dev_info(priv->dev, "PCI: bus%u revision %x\n", sys->busnr, val); /* Disable Direct Power Down State and assert reset */ val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD; @@ -276,8 +281,8 @@ static int __init rcar_pci_probe(struct platform_device *pdev) cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg = devm_ioremap_resource(&pdev->dev, cfg_res); - if (!reg) - return -ENODEV; + if (IS_ERR(reg)) + return PTR_ERR(reg); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!mem_res || !mem_res->start) @@ -301,6 +306,7 @@ static int __init rcar_pci_probe(struct platform_device *pdev) priv->irq = platform_get_irq(pdev, 0); priv->reg = reg; + priv->dev = &pdev->dev; return rcar_pci_add_controller(priv); } diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 0afbbbc55c8..b8ba2f79455 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -805,7 +805,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) afi_writel(pcie, value, AFI_PCIE_CONFIG); value = afi_readl(pcie, AFI_FUSE); - value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; + value |= AFI_FUSE_PCIE_T0_GEN2_DIS; afi_writel(pcie, value, AFI_FUSE); /* initialize internal PHY, enable up to 16 PCIE lanes */ diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index e33b68be039..17ce88f79d2 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -74,7 +74,7 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) return sys->private_data; } -int cfg_read(void __iomem *addr, int where, int size, u32 *val) +int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val) { *val = readl(addr); @@ -88,7 +88,7 @@ int cfg_read(void __iomem *addr, int where, int size, u32 *val) return PCIBIOS_SUCCESSFUL; } -int cfg_write(void __iomem *addr, int where, int size, u32 val) +int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val) { if (size == 4) writel(val, addr); @@ -126,7 +126,8 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, if (pp->ops->rd_own_conf) ret = pp->ops->rd_own_conf(pp, where, size, val); else - ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); + ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, + size, val); return ret; } @@ -139,8 +140,8 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, if (pp->ops->wr_own_conf) ret = pp->ops->wr_own_conf(pp, where, size, val); else - ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, - val); + ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where, + size, val); return ret; } @@ -167,11 +168,13 @@ void dw_handle_msi_irq(struct pcie_port *pp) while ((pos = find_next_bit(&val, 32, pos)) != 32) { irq = irq_find_mapping(pp->irq_domain, i * 32 + pos); + dw_pcie_wr_own_conf(pp, + PCIE_MSI_INTR0_STATUS + i * 12, + 4, 1 << pos); generic_handle_irq(irq); pos++; } } - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val); } } @@ -209,6 +212,23 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0) return 0; } +static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, + unsigned int nvec, unsigned int pos) +{ + unsigned int i, res, bit, val; + + for (i = 0; i < nvec; i++) { + irq_set_msi_desc_off(irq_base, i, NULL); + clear_bit(pos + i, pp->msi_irq_in_use); + /* Disable corresponding interrupt on MSI controller */ + res = ((pos + i) / 32) * 12; + bit = (pos + i) % 32; + dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); + val &= ~(1 << bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); + } +} + static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) { int res, bit, irq, pos0, pos1, i; @@ -242,18 +262,25 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) if (!irq) goto no_valid_irq; - i = 0; - while (i < no_irqs) { + /* + * irq_create_mapping (called from dw_pcie_host_init) pre-allocates + * descs so there is no need to allocate descs here. We can therefore + * assume that if irq_find_mapping above returns non-zero, then the + * descs are also successfully allocated. + */ + + for (i = 0; i < no_irqs; i++) { + if (irq_set_msi_desc_off(irq, i, desc) != 0) { + clear_irq_range(pp, irq, i, pos0); + goto no_valid_irq; + } set_bit(pos0 + i, pp->msi_irq_in_use); - irq_alloc_descs((irq + i), (irq + i), 1, 0); - irq_set_msi_desc(irq + i, desc); /*Enable corresponding interrupt in MSI interrupt controller */ res = ((pos0 + i) / 32) * 12; bit = (pos0 + i) % 32; dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); val |= 1 << bit; dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); - i++; } *pos = pos0; @@ -266,7 +293,7 @@ no_valid_irq: static void clear_irq(unsigned int irq) { - int res, bit, val, pos; + unsigned int pos, nvec; struct irq_desc *desc; struct msi_desc *msi; struct pcie_port *pp; @@ -281,18 +308,15 @@ static void clear_irq(unsigned int irq) return; } + /* undo what was done in assign_irq */ pos = data->hwirq; + nvec = 1 << msi->msi_attrib.multiple; - irq_free_desc(irq); - - clear_bit(pos, pp->msi_irq_in_use); + clear_irq_range(pp, irq, nvec, pos); - /* Disable corresponding interrupt on MSI interrupt controller */ - res = (pos / 32) * 12; - bit = pos % 32; - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); - val &= ~(1 << bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); + /* all irqs cleared; reset attributes */ + msi->irq = 0; + msi->msi_attrib.multiple = 0; } static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, @@ -320,10 +344,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, if (irq < 0) return irq; - msg_ctr &= ~PCI_MSI_FLAGS_QSIZE; - msg_ctr |= msgvec << 4; - pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, - msg_ctr); + /* + * write_msi_msg() will update PCI_MSI_FLAGS so there is + * no need to explicitly call pci_write_config_word(). + */ desc->msi_attrib.multiple = msgvec; msg.address_lo = virt_to_phys((void *)pp->msi_data); @@ -394,6 +418,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp) + global_io_offset); pp->config.io_size = resource_size(&pp->io); pp->config.io_bus_addr = range.pci_addr; + pp->io_base = range.cpu_addr; } if (restype == IORESOURCE_MEM) { of_pci_range_to_resource(&range, np, &pp->mem); @@ -419,7 +444,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp) pp->cfg0_base = pp->cfg.start; pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; - pp->io_base = pp->io.start; pp->mem_base = pp->mem.start; pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, @@ -551,11 +575,13 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, if (bus->parent->number == pp->root_bus_nr) { dw_pcie_prog_viewport_cfg0(pp, busdev); - ret = cfg_read(pp->va_cfg0_base + address, where, size, val); + ret = dw_pcie_cfg_read(pp->va_cfg0_base + address, where, size, + val); dw_pcie_prog_viewport_mem_outbound(pp); } else { dw_pcie_prog_viewport_cfg1(pp, busdev); - ret = cfg_read(pp->va_cfg1_base + address, where, size, val); + ret = dw_pcie_cfg_read(pp->va_cfg1_base + address, where, size, + val); dw_pcie_prog_viewport_io_outbound(pp); } @@ -574,18 +600,19 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, if (bus->parent->number == pp->root_bus_nr) { dw_pcie_prog_viewport_cfg0(pp, busdev); - ret = cfg_write(pp->va_cfg0_base + address, where, size, val); + ret = dw_pcie_cfg_write(pp->va_cfg0_base + address, where, size, + val); dw_pcie_prog_viewport_mem_outbound(pp); } else { dw_pcie_prog_viewport_cfg1(pp, busdev); - ret = cfg_write(pp->va_cfg1_base + address, where, size, val); + ret = dw_pcie_cfg_write(pp->va_cfg1_base + address, where, size, + val); dw_pcie_prog_viewport_io_outbound(pp); } return ret; } - static int dw_pcie_valid_config(struct pcie_port *pp, struct pci_bus *bus, int dev) { @@ -679,7 +706,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys) if (global_io_offset < SZ_1M && pp->config.io_size > 0) { sys->io_offset = global_io_offset - pp->config.io_bus_addr; - pci_ioremap_io(sys->io_offset, pp->io.start); + pci_ioremap_io(global_io_offset, pp->io_base); global_io_offset += SZ_64K; pci_add_resource_offset(&sys->resources, &pp->io, sys->io_offset); diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index c15379be237..3063b3594d8 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -66,8 +66,8 @@ struct pcie_host_ops { void (*host_init)(struct pcie_port *pp); }; -int cfg_read(void __iomem *addr, int where, int size, u32 *val); -int cfg_write(void __iomem *addr, int where, int size, u32 val); +int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); +int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val); void dw_handle_msi_irq(struct pcie_port *pp); void dw_pcie_msi_init(struct pcie_port *pp); int dw_pcie_link_up(struct pcie_port *pp); |