diff options
Diffstat (limited to 'drivers/pci')
33 files changed, 542 insertions, 807 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 7a8f1c5e65af..73de4efcbe6e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -1,6 +1,10 @@ # # PCI configuration # +config PCI_BUS_ADDR_T_64BIT + def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) + depends on PCI + config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 90fa3a78fb7c..6fbd3f2b5992 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -92,11 +92,11 @@ void pci_bus_remove_resources(struct pci_bus *bus) } static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT static struct pci_bus_region pci_64_bit = {0, - (dma_addr_t) 0xffffffffffffffffULL}; -static struct pci_bus_region pci_high = {(dma_addr_t) 0x100000000ULL, - (dma_addr_t) 0xffffffffffffffffULL}; + (pci_bus_addr_t) 0xffffffffffffffffULL}; +static struct pci_bus_region pci_high = {(pci_bus_addr_t) 0x100000000ULL, + (pci_bus_addr_t) 0xffffffffffffffffULL}; #endif /* @@ -200,7 +200,7 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t), void *alignf_data) { -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT int rc; if (res->flags & IORESOURCE_MEM_64) { diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 9c48e9986bc7..c132bddc03f3 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -134,4 +134,15 @@ config PCIE_IPROC_PLATFORM Say Y here if you want to use the Broadcom iProc PCIe controller through the generic platform bus interface +config PCIE_IPROC_BCMA + bool "Broadcom iProc PCIe BCMA bus driver" + depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST) + select PCIE_IPROC + select BCMA + select PCI_DOMAINS + default ARCH_BCM_5301X + help + Say Y here if you want to use the Broadcom iProc PCIe controller + through the BCMA bus interface + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 1957431d3fcc..140d66f796e4 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o +obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 2d57e19a2cd4..80db09e47800 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -93,9 +93,9 @@ static int dra7xx_pcie_link_up(struct pcie_port *pp) static int dra7xx_pcie_establish_link(struct pcie_port *pp) { - u32 reg; - unsigned int retries = 1000; struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + u32 reg; + unsigned int retries; if (dw_pcie_link_up(pp)) { dev_err(pp->dev, "link is already up\n"); @@ -106,19 +106,14 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp) reg |= LTSSM_EN; dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); - while (retries--) { - reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); - if (reg & LINK_UP) - break; + for (retries = 0; retries < 1000; retries++) { + if (dw_pcie_link_up(pp)) + return 0; usleep_range(10, 20); } - if (retries == 0) { - dev_err(pp->dev, "link is not up\n"); - return -ETIMEDOUT; - } - - return 0; + dev_err(pp->dev, "link is not up\n"); + return -EINVAL; } static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index c139237e0e52..f9f468d9a819 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -316,9 +316,9 @@ static void exynos_pcie_assert_reset(struct pcie_port *pp) static int exynos_pcie_establish_link(struct pcie_port *pp) { - u32 val; - int count = 0; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + u32 val; + unsigned int retries; if (dw_pcie_link_up(pp)) { dev_err(pp->dev, "Link already up\n"); @@ -357,27 +357,23 @@ static int exynos_pcie_establish_link(struct pcie_port *pp) PCIE_APP_LTSSM_ENABLE); /* check if the link is up or not */ - while (!dw_pcie_link_up(pp)) { - mdelay(100); - count++; - if (count == 10) { - while (exynos_phy_readl(exynos_pcie, - PCIE_PHY_PLL_LOCKED) == 0) { - val = exynos_blk_readl(exynos_pcie, - PCIE_PHY_PLL_LOCKED); - dev_info(pp->dev, "PLL Locked: 0x%x\n", val); - } - /* power off phy */ - exynos_pcie_power_off_phy(pp); - - dev_err(pp->dev, "PCIe Link Fail\n"); - return -EINVAL; + for (retries = 0; retries < 10; retries++) { + if (dw_pcie_link_up(pp)) { + dev_info(pp->dev, "Link up\n"); + return 0; } + mdelay(100); } - dev_info(pp->dev, "Link up\n"); + while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { + val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); + dev_info(pp->dev, "PLL Locked: 0x%x\n", val); + } + /* power off phy */ + exynos_pcie_power_off_phy(pp); - return 0; + dev_err(pp->dev, "PCIe Link Fail\n"); + return -EINVAL; } static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index fdb95367721e..233a196c6e66 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -47,6 +47,8 @@ struct imx6_pcie { #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf +#define PCIE_RC_LCSR 0x80 + /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 #define PCIE_PL_PFLR (PL_OFFSET + 0x08) @@ -335,21 +337,36 @@ static void imx6_pcie_init_phy(struct pcie_port *pp) static int imx6_pcie_wait_for_link(struct pcie_port *pp) { - int count = 200; + unsigned int retries; - while (!dw_pcie_link_up(pp)) { + for (retries = 0; retries < 200; retries++) { + if (dw_pcie_link_up(pp)) + return 0; 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; + 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; +} + +static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp) +{ + u32 tmp; + unsigned int retries; + + for (retries = 0; retries < 200; retries++) { + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + /* Test if the speed change finished. */ + if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) + return 0; + usleep_range(100, 1000); + } + + dev_err(pp->dev, "Speed change timeout\n"); + return -EINVAL; } static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) @@ -359,11 +376,11 @@ static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) return dw_handle_msi_irq(pp); } -static int imx6_pcie_start_link(struct pcie_port *pp) +static int imx6_pcie_establish_link(struct pcie_port *pp) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); - uint32_t tmp; - int ret, count; + u32 tmp; + int ret; /* * Force Gen1 operation when starting the link. In case the link is @@ -397,29 +414,22 @@ static int imx6_pcie_start_link(struct pcie_port *pp) 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); + ret = imx6_pcie_wait_for_speed_change(pp); + if (ret) { + dev_err(pp->dev, "Failed to bring link up!\n"); + return ret; } /* Make sure link training is finished as well! */ - if (count) - ret = imx6_pcie_wait_for_link(pp); - else - ret = -EINVAL; - + ret = imx6_pcie_wait_for_link(pp); 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; } - return ret; + tmp = readl(pp->dbi_base + PCIE_RC_LCSR); + dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf); + return 0; } static void imx6_pcie_host_init(struct pcie_port *pp) @@ -432,7 +442,7 @@ static void imx6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - imx6_pcie_start_link(pp); + imx6_pcie_establish_link(pp); if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_init(pp); @@ -440,19 +450,19 @@ static void imx6_pcie_host_init(struct pcie_port *pp) static void imx6_pcie_reset_phy(struct pcie_port *pp) { - uint32_t temp; + u32 tmp; - 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); + pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp); + tmp |= (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, tmp); 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 | + pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp); + tmp &= ~(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); + pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp); } static int imx6_pcie_link_up(struct pcie_port *pp) diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 75333b0c4f0a..b75d684aefcd 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -88,7 +88,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs); static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) { struct pcie_port *pp = &ks_pcie->pp; - int count = 200; + unsigned int retries; dw_pcie_setup_rc(pp); @@ -99,17 +99,15 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) ks_dw_pcie_initiate_link_train(ks_pcie); /* check if the link is up or not */ - while (!dw_pcie_link_up(pp)) { + for (retries = 0; retries < 200; retries++) { + if (dw_pcie_link_up(pp)) + return 0; usleep_range(100, 1000); - if (--count) { - ks_dw_pcie_initiate_link_train(ks_pcie); - continue; - } - dev_err(pp->dev, "phy link never came up\n"); - return -EINVAL; + ks_dw_pcie_initiate_link_train(ks_pcie); } - return 0; + dev_err(pp->dev, "phy link never came up\n"); + return -EINVAL; } static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 4a6e62f67579..b2328ea13dcf 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -62,22 +62,27 @@ static int ls_pcie_link_up(struct pcie_port *pp) return 1; } +static int ls_pcie_establish_link(struct pcie_port *pp) +{ + unsigned int retries; + + for (retries = 0; retries < 200; retries++) { + if (dw_pcie_link_up(pp)) + return 0; + usleep_range(100, 1000); + } + + dev_err(pp->dev, "phy link never came up\n"); + return -EINVAL; +} + static void ls_pcie_host_init(struct pcie_port *pp) { struct ls_pcie *pcie = to_ls_pcie(pp); - int count = 0; u32 val; dw_pcie_setup_rc(pp); - - while (!ls_pcie_link_up(pp)) { - usleep_range(100, 1000); - count++; - if (count >= 200) { - dev_err(pp->dev, "phy link never came up\n"); - return; - } - } + ls_pcie_establish_link(pp); /* * LS1021A Workaround for internal TKT228622 diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 1ab863551920..70aa09556ec5 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -751,21 +751,6 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) return 1; } -static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) -{ - struct mvebu_pcie *pcie = sys_to_pcie(sys); - struct pci_bus *bus; - - bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr, - &mvebu_pcie_ops, sys, &sys->resources); - if (!bus) - return NULL; - - pci_scan_child_bus(bus); - - return bus; -} - static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, const struct resource *res, resource_size_t start, @@ -809,12 +794,11 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie) hw.nr_controllers = 1; hw.private_data = (void **)&pcie; hw.setup = mvebu_pcie_setup; - hw.scan = mvebu_pcie_scan_bus; hw.map_irq = of_irq_parse_and_map_pci; hw.ops = &mvebu_pcie_ops; hw.align_resource = mvebu_pcie_align_resource; - pci_common_init(&hw); + pci_common_init_dev(&pcie->pdev->dev, &hw); } /* diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 00e92720d7f7..10c05718dbfd 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -630,21 +630,6 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) return irq; } -static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys) -{ - struct tegra_pcie *pcie = sys_to_pcie(sys); - struct pci_bus *bus; - - bus = pci_create_root_bus(pcie->dev, sys->busnr, &tegra_pcie_ops, sys, - &sys->resources); - if (!bus) - return NULL; - - pci_scan_child_bus(bus); - - return bus; -} - static irqreturn_t tegra_pcie_isr(int irq, void *arg) { const char *err_msg[] = { @@ -1831,7 +1816,6 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) hw.private_data = (void **)&pcie; hw.setup = tegra_pcie_setup; hw.map_irq = tegra_pcie_map_irq; - hw.scan = tegra_pcie_scan_bus; hw.ops = &tegra_pcie_ops; pci_common_init_dev(pcie->dev, &hw); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 2e9f84fdd9ce..69486be7181e 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -31,6 +31,7 @@ #define PORT_LINK_MODE_1_LANES (0x1 << 16) #define PORT_LINK_MODE_2_LANES (0x3 << 16) #define PORT_LINK_MODE_4_LANES (0x7 << 16) +#define PORT_LINK_MODE_8_LANES (0xf << 16) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) @@ -38,6 +39,7 @@ #define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8) #define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8) #define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8) +#define PORT_LOGIC_LINK_WIDTH_8_LANES (0x8 << 8) #define PCIE_MSI_ADDR_LO 0x820 #define PCIE_MSI_ADDR_HI 0x824 @@ -150,6 +152,21 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, return ret; } +static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index, + int type, u64 cpu_addr, u64 pci_addr, u32 size) +{ + dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index, + PCIE_ATU_VIEWPORT); + dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1), + PCIE_ATU_LIMIT); + dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET); + dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); +} + static struct irq_chip dw_msi_irq_chip = { .name = "PCI-MSI", .irq_enable = pci_msi_unmask_irq, @@ -493,6 +510,11 @@ int dw_pcie_host_init(struct pcie_port *pp) if (pp->ops->host_init) pp->ops->host_init(pp); + if (!pp->ops->rd_other_conf) + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_MEM, pp->mem_mod_base, + pp->mem_bus_addr, pp->mem_size); + dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0); /* program correct class for RC */ @@ -515,115 +537,73 @@ int dw_pcie_host_init(struct pcie_port *pp) return 0; } -static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev) -{ - /* Program viewport 0 : OUTBOUND : CFG0 */ - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->cfg0_size - 1, - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG0, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); -} - -static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev) -{ - /* Program viewport 1 : OUTBOUND : CFG1 */ - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->cfg1_size - 1, - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); -} - -static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) -{ - /* Program viewport 0 : OUTBOUND : MEM */ - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->mem_size - 1, - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, pp->mem_bus_addr, PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, upper_32_bits(pp->mem_bus_addr), - PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); -} - -static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) -{ - /* Program viewport 1 : OUTBOUND : IO */ - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->io_mod_base + pp->io_size - 1, - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, pp->io_bus_addr, PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, upper_32_bits(pp->io_bus_addr), - PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); -} - static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { - int ret = PCIBIOS_SUCCESSFUL; - u32 address, busdev; + int ret, type; + u32 address, busdev, cfg_size; + u64 cpu_addr; + void __iomem *va_cfg_base; busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); address = where & ~0x3; if (bus->parent->number == pp->root_bus_nr) { - dw_pcie_prog_viewport_cfg0(pp, busdev); - ret = dw_pcie_cfg_read(pp->va_cfg0_base + address, where, size, - val); - dw_pcie_prog_viewport_mem_outbound(pp); + type = PCIE_ATU_TYPE_CFG0; + cpu_addr = pp->cfg0_mod_base; + cfg_size = pp->cfg0_size; + va_cfg_base = pp->va_cfg0_base; } else { - dw_pcie_prog_viewport_cfg1(pp, busdev); - ret = dw_pcie_cfg_read(pp->va_cfg1_base + address, where, size, - val); - dw_pcie_prog_viewport_io_outbound(pp); + type = PCIE_ATU_TYPE_CFG1; + cpu_addr = pp->cfg1_mod_base; + cfg_size = pp->cfg1_size; + va_cfg_base = pp->va_cfg1_base; } + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, + type, cpu_addr, + busdev, cfg_size); + ret = dw_pcie_cfg_read(va_cfg_base + address, where, size, val); + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_IO, pp->io_mod_base, + pp->io_bus_addr, pp->io_size); + return ret; } static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, u32 devfn, int where, int size, u32 val) { - int ret = PCIBIOS_SUCCESSFUL; - u32 address, busdev; + int ret, type; + u32 address, busdev, cfg_size; + u64 cpu_addr; + void __iomem *va_cfg_base; busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); address = where & ~0x3; if (bus->parent->number == pp->root_bus_nr) { - dw_pcie_prog_viewport_cfg0(pp, busdev); - ret = dw_pcie_cfg_write(pp->va_cfg0_base + address, where, size, - val); - dw_pcie_prog_viewport_mem_outbound(pp); + type = PCIE_ATU_TYPE_CFG0; + cpu_addr = pp->cfg0_mod_base; + cfg_size = pp->cfg0_size; + va_cfg_base = pp->va_cfg0_base; } else { - dw_pcie_prog_viewport_cfg1(pp, busdev); - ret = dw_pcie_cfg_write(pp->va_cfg1_base + address, where, size, - val); - dw_pcie_prog_viewport_io_outbound(pp); + type = PCIE_ATU_TYPE_CFG1; + cpu_addr = pp->cfg1_mod_base; + cfg_size = pp->cfg1_size; + va_cfg_base = pp->va_cfg1_base; } + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, + type, cpu_addr, + busdev, cfg_size); + ret = dw_pcie_cfg_write(va_cfg_base + address, where, size, val); + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_IO, pp->io_mod_base, + pp->io_bus_addr, pp->io_size); + return ret; } @@ -728,13 +708,11 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) struct pcie_port *pp = sys_to_pcie(sys); pp->root_bus_nr = sys->busnr; - bus = pci_create_root_bus(pp->dev, sys->busnr, + bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops, sys, &sys->resources); if (!bus) return NULL; - pci_scan_child_bus(bus); - if (bus && pp->ops->scan_bus) pp->ops->scan_bus(pp); @@ -778,6 +756,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp) case 4: val |= PORT_LINK_MODE_4_LANES; break; + case 8: + val |= PORT_LINK_MODE_8_LANES; + break; } dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL); @@ -794,6 +775,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp) case 4: val |= PORT_LOGIC_LINK_WIDTH_4_LANES; break; + case 8: + val |= PORT_LOGIC_LINK_WIDTH_8_LANES; + break; } dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL); diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c new file mode 100644 index 000000000000..96a7d999fd5e --- /dev/null +++ b/drivers/pci/host/pcie-iproc-bcma.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 Broadcom Corporation + * Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/phy/phy.h> +#include <linux/bcma/bcma.h> +#include <linux/ioport.h> + +#include "pcie-iproc.h" + + +/* NS: CLASS field is R/O, and set to wrong 0x200 value */ +static void bcma_pcie2_fixup_class(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_PCI << 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8012, bcma_pcie2_fixup_class); + +static int iproc_pcie_bcma_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct pci_sys_data *sys = dev->sysdata; + struct iproc_pcie *pcie = sys->private_data; + struct bcma_device *bdev = container_of(pcie->dev, struct bcma_device, dev); + + return bcma_core_irq(bdev, 5); +} + +static int iproc_pcie_bcma_probe(struct bcma_device *bdev) +{ + struct iproc_pcie *pcie; + LIST_HEAD(res); + struct resource res_mem; + int ret; + + pcie = devm_kzalloc(&bdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &bdev->dev; + bcma_set_drvdata(bdev, pcie); + + pcie->base = bdev->io_addr; + + res_mem.start = bdev->addr_s[0]; + res_mem.end = bdev->addr_s[0] + SZ_128M - 1; + res_mem.name = "PCIe MEM space"; + res_mem.flags = IORESOURCE_MEM; + pci_add_resource(&res, &res_mem); + + pcie->map_irq = iproc_pcie_bcma_map_irq; + + ret = iproc_pcie_setup(pcie, &res); + if (ret) + dev_err(pcie->dev, "PCIe controller setup failed\n"); + + pci_free_resource_list(&res); + + return ret; +} + +static void iproc_pcie_bcma_remove(struct bcma_device *bdev) +{ + struct iproc_pcie *pcie = bcma_get_drvdata(bdev); + + iproc_pcie_remove(pcie); +} + +static const struct bcma_device_id iproc_pcie_bcma_table[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS), + {}, +}; +MODULE_DEVICE_TABLE(bcma, iproc_pcie_bcma_table); + +static struct bcma_driver iproc_pcie_bcma_driver = { + .name = KBUILD_MODNAME, + .id_table = iproc_pcie_bcma_table, + .probe = iproc_pcie_bcma_probe, + .remove = iproc_pcie_bcma_remove, +}; + +static int __init iproc_pcie_bcma_init(void) +{ + return bcma_driver_register(&iproc_pcie_bcma_driver); +} +module_init(iproc_pcie_bcma_init); + +static void __exit iproc_pcie_bcma_exit(void) +{ + bcma_driver_unregister(&iproc_pcie_bcma_driver); +} +module_exit(iproc_pcie_bcma_exit); + +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_DESCRIPTION("Broadcom iProc PCIe BCMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index afad6c21fcfa..9aedc8eb2c6e 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -69,15 +69,15 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) return ret; } - pcie->resources = &res; + pcie->map_irq = of_irq_parse_and_map_pci; - ret = iproc_pcie_setup(pcie); - if (ret) { + ret = iproc_pcie_setup(pcie, &res); + if (ret) dev_err(pcie->dev, "PCIe controller setup failed\n"); - return ret; - } - return 0; + pci_free_resource_list(&res); + + return ret; } static int iproc_pcie_pltfm_remove(struct platform_device *pdev) diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 329e1b54528b..d77481ea553e 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -183,7 +183,7 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie) writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN); } -int iproc_pcie_setup(struct iproc_pcie *pcie) +int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) { int ret; struct pci_bus *bus; @@ -211,7 +211,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie) pcie->sysdata.private_data = pcie; bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, - &pcie->sysdata, pcie->resources); + &pcie->sysdata, res); if (!bus) { dev_err(pcie->dev, "unable to create PCI root bus\n"); ret = -ENOMEM; @@ -229,7 +229,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie) pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); + pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); pci_bus_add_devices(bus); return 0; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index e28075ed1856..ba0a108309cc 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -29,14 +29,14 @@ struct iproc_pcie { struct device *dev; void __iomem *base; - struct list_head *resources; struct pci_sys_data sysdata; struct pci_bus *root_bus; struct phy *phy; int irqs[IPROC_PCIE_MAX_NUM_IRQS]; + int (*map_irq)(const struct pci_dev *, u8, u8); }; -int iproc_pcie_setup(struct iproc_pcie *pcie); +int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res); int iproc_pcie_remove(struct iproc_pcie *pcie); #endif /* _PCIE_IPROC_H */ diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 020d78890719..dfec4281bd50 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -146,10 +146,10 @@ struct pcie_app_reg { static int spear13xx_pcie_establish_link(struct pcie_port *pp) { u32 val; - int count = 0; struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; u32 exp_cap_off = EXP_CAP_ID_OFFSET; + unsigned int retries; if (dw_pcie_link_up(pp)) { dev_err(pp->dev, "link already up\n"); @@ -201,17 +201,16 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp) &app_reg->app_ctrl_0); /* check if the link is up or not */ - while (!dw_pcie_link_up(pp)) { - mdelay(100); - count++; - if (count == 10) { - dev_err(pp->dev, "link Fail\n"); - return -EINVAL; + for (retries = 0; retries < 10; retries++) { + if (dw_pcie_link_up(pp)) { + dev_info(pp->dev, "link up\n"); + return 0; } + mdelay(100); } - dev_info(pp->dev, "link up\n"); - return 0; + dev_err(pp->dev, "link Fail\n"); + return -EINVAL; } static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 4a9aa08b08f1..b616e7588ff4 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -61,9 +61,6 @@ pciehp-objs := pciehp_core.o \ pciehp_ctrl.o \ pciehp_pci.o \ pciehp_hpc.o -ifdef CONFIG_ACPI -pciehp-objs += pciehp_acpi.o -endif shpchp-objs := shpchp_core.o \ shpchp_ctrl.o \ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bcb90e4888dd..ff538568a617 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -632,15 +632,14 @@ static void trim_stale_devices(struct pci_dev *dev) { struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; - bool alive = false; + bool alive = dev->ignore_hotplug; if (adev) { acpi_status status; unsigned long long sta; status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); - alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) - || dev->ignore_hotplug; + alive = alive || (ACPI_SUCCESS(status) && device_status_valid(sta)); } if (!alive) alive = pci_device_is_present(dev); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index b11521953485..57cd1327346f 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -132,11 +132,7 @@ struct controller { int pciehp_sysfs_enable_slot(struct slot *slot); int pciehp_sysfs_disable_slot(struct slot *slot); -u8 pciehp_handle_attention_button(struct slot *p_slot); -u8 pciehp_handle_switch_change(struct slot *p_slot); -u8 pciehp_handle_presence_change(struct slot *p_slot); -u8 pciehp_handle_power_fault(struct slot *p_slot); -void pciehp_handle_linkstate_change(struct slot *p_slot); +void pciehp_queue_interrupt_event(struct slot *slot, u32 event_type); int pciehp_configure_device(struct slot *p_slot); int pciehp_unconfigure_device(struct slot *p_slot); void pciehp_queue_pushbutton_work(struct work_struct *work); @@ -167,21 +163,4 @@ static inline const char *slot_name(struct slot *slot) return hotplug_slot_name(slot->hotplug_slot); } -#ifdef CONFIG_ACPI -#include <linux/pci-acpi.h> - -void __init pciehp_acpi_slot_detection_init(void); -int pciehp_acpi_slot_detection_check(struct pci_dev *dev); - -static inline void pciehp_firmware_init(void) -{ - pciehp_acpi_slot_detection_init(); -} -#else -#define pciehp_firmware_init() do {} while (0) -static inline int pciehp_acpi_slot_detection_check(struct pci_dev *dev) -{ - return 0; -} -#endif /* CONFIG_ACPI */ #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c deleted file mode 100644 index 93cc9266e8cb..000000000000 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ACPI related functions for PCI Express Hot Plug driver. - * - * Copyright (C) 2008 Kenji Kaneshige - * Copyright (C) 2008 Fujitsu Limited. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <linux/acpi.h> -#include <linux/pci.h> -#include <linux/pci_hotplug.h> -#include <linux/slab.h> -#include <linux/module.h> -#include "pciehp.h" - -#define PCIEHP_DETECT_PCIE (0) -#define PCIEHP_DETECT_ACPI (1) -#define PCIEHP_DETECT_AUTO (2) -#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO - -struct dummy_slot { - u32 number; - struct list_head list; -}; - -static int slot_detection_mode; -static char *pciehp_detect_mode; -module_param(pciehp_detect_mode, charp, 0444); -MODULE_PARM_DESC(pciehp_detect_mode, - "Slot detection mode: pcie, acpi, auto\n" - " pcie - Use PCIe based slot detection\n" - " acpi - Use ACPI for slot detection\n" - " auto(default) - Auto select mode. Use acpi option if duplicate\n" - " slot ids are found. Otherwise, use pcie option\n"); - -int pciehp_acpi_slot_detection_check(struct pci_dev *dev) -{ - if (slot_detection_mode != PCIEHP_DETECT_ACPI) - return 0; - if (acpi_pci_detect_ejectable(ACPI_HANDLE(&dev->dev))) - return 0; - return -ENODEV; -} - -static int __init parse_detect_mode(void) -{ - if (!pciehp_detect_mode) - return PCIEHP_DETECT_DEFAULT; - if (!strcmp(pciehp_detect_mode, "pcie")) - return PCIEHP_DETECT_PCIE; - if (!strcmp(pciehp_detect_mode, "acpi")) - return PCIEHP_DETECT_ACPI; - if (!strcmp(pciehp_detect_mode, "auto")) - return PCIEHP_DETECT_AUTO; - warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", - pciehp_detect_mode); - return PCIEHP_DETECT_DEFAULT; -} - -static int __initdata dup_slot_id; -static int __initdata acpi_slot_detected; -static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); - -/* Dummy driver for duplicate name detection */ -static int __init dummy_probe(struct pcie_device *dev) -{ - u32 slot_cap; - acpi_handle handle; - struct dummy_slot *slot, *tmp; - struct pci_dev *pdev = dev->port; - - pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - slot->number = (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19; - list_for_each_entry(tmp, &dummy_slots, list) { - if (tmp->number == slot->number) - dup_slot_id++; - } - list_add_tail(&slot->list, &dummy_slots); - handle = ACPI_HANDLE(&pdev->dev); - if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) - acpi_slot_detected = 1; - return -ENODEV; /* dummy driver always returns error */ -} - -static struct pcie_port_service_driver __initdata dummy_driver = { - .name = "pciehp_dummy", - .port_type = PCIE_ANY_PORT, - .service = PCIE_PORT_SERVICE_HP, - .probe = dummy_probe, -}; - -static int __init select_detection_mode(void) -{ - struct dummy_slot *slot, *tmp; - - if (pcie_port_service_register(&dummy_driver)) - return PCIEHP_DETECT_ACPI; - pcie_port_service_unregister(&dummy_driver); - list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { - list_del(&slot->list); - kfree(slot); - } - if (acpi_slot_detected && dup_slot_id) - return PCIEHP_DETECT_ACPI; - return PCIEHP_DETECT_PCIE; -} - -void __init pciehp_acpi_slot_detection_init(void) -{ - slot_detection_mode = parse_detect_mode(); - if (slot_detection_mode != PCIEHP_DETECT_AUTO) - goto out; - slot_detection_mode = select_detection_mode(); -out: - if (slot_detection_mode == PCIEHP_DETECT_ACPI) - info("Using ACPI for slot detection.\n"); -} diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 07aa722bb12c..612b21a14df5 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -77,11 +77,6 @@ static int reset_slot (struct hotplug_slot *slot, int probe); */ static void release_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; - - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, hotplug_slot_name(hotplug_slot)); - kfree(hotplug_slot->ops); kfree(hotplug_slot->info); kfree(hotplug_slot); @@ -129,14 +124,10 @@ static int init_slot(struct controller *ctrl) slot->hotplug_slot = hotplug; snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); - ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:00 sun=%x\n", - pci_domain_nr(ctrl->pcie->port->subordinate), - ctrl->pcie->port->subordinate->number, PSN(ctrl)); retval = pci_hp_register(hotplug, ctrl->pcie->port->subordinate, 0, name); if (retval) - ctrl_err(ctrl, - "pci_hp_register failed with error %d\n", retval); + ctrl_err(ctrl, "pci_hp_register failed: error %d\n", retval); out: if (retval) { kfree(ops); @@ -158,9 +149,6 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - pciehp_set_attention_status(slot, status); return 0; } @@ -170,9 +158,6 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - return pciehp_sysfs_enable_slot(slot); } @@ -181,9 +166,6 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - return pciehp_sysfs_disable_slot(slot); } @@ -191,9 +173,6 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - pciehp_get_power_status(slot, value); return 0; } @@ -202,9 +181,6 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - pciehp_get_attention_status(slot, value); return 0; } @@ -213,9 +189,6 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - pciehp_get_latch_status(slot, value); return 0; } @@ -224,9 +197,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - pciehp_get_adapter_status(slot, value); return 0; } @@ -235,9 +205,6 @@ static int reset_slot(struct hotplug_slot *hotplug_slot, int probe) { struct slot *slot = hotplug_slot->private; - ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", - __func__, slot_name(slot)); - return pciehp_reset_slot(slot, probe); } @@ -248,24 +215,21 @@ static int pciehp_probe(struct pcie_device *dev) struct slot *slot; u8 occupied, poweron; - if (pciehp_force) - dev_info(&dev->device, - "Bypassing BIOS check for pciehp use on %s\n", - pci_name(dev->port)); - else if (pciehp_acpi_slot_detection_check(dev->port)) - goto err_out_none; + /* If this is not a "hotplug" service, we have no business here. */ + if (dev->service != PCIE_PORT_SERVICE_HP) + return -ENODEV; if (!dev->port->subordinate) { /* Can happen if we run out of bus numbers during probe */ dev_err(&dev->device, "Hotplug bridge without secondary bus, ignoring\n"); - goto err_out_none; + return -ENODEV; } ctrl = pcie_init(dev); if (!ctrl) { dev_err(&dev->device, "Controller initialization failed\n"); - goto err_out_none; + return -ENODEV; } set_service_data(dev, ctrl); @@ -275,14 +239,14 @@ static int pciehp_probe(struct pcie_device *dev) if (rc == -EBUSY) ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n"); else - ctrl_err(ctrl, "Slot initialization failed\n"); + ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc); goto err_out_release_ctlr; } /* Enable events after we have setup the data structures */ rc = pcie_init_notification(ctrl); if (rc) { - ctrl_err(ctrl, "Notification initialization failed\n"); + ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc); goto err_out_free_ctrl_slot; } @@ -305,7 +269,6 @@ err_out_free_ctrl_slot: cleanup_slot(ctrl); err_out_release_ctlr: pciehp_release_ctrl(ctrl); -err_out_none: return -ENODEV; } @@ -366,7 +329,6 @@ static int __init pcied_init(void) { int retval = 0; - pciehp_firmware_init(); retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f052e951b23e..f3796124ad7c 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -37,138 +37,20 @@ static void interrupt_event_handler(struct work_struct *work); -static int queue_interrupt_event(struct slot *p_slot, u32 event_type) +void pciehp_queue_interrupt_event(struct slot *p_slot, u32 event_type) { struct event_info *info; info = kmalloc(sizeof(*info), GFP_ATOMIC); - if (!info) - return -ENOMEM; + if (!info) { + ctrl_err(p_slot->ctrl, "dropped event %d (ENOMEM)\n", event_type); + return; + } + INIT_WORK(&info->work, interrupt_event_handler); info->event_type = event_type; info->p_slot = p_slot; - INIT_WORK(&info->work, interrupt_event_handler); - queue_work(p_slot->wq, &info->work); - - return 0; -} - -u8 pciehp_handle_attention_button(struct slot *p_slot) -{ - u32 event_type; - struct controller *ctrl = p_slot->ctrl; - - /* Attention Button Change */ - ctrl_dbg(ctrl, "Attention button interrupt received\n"); - - /* - * Button pressed - See if need to TAKE ACTION!!! - */ - ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); - event_type = INT_BUTTON_PRESS; - - queue_interrupt_event(p_slot, event_type); - - return 0; -} - -u8 pciehp_handle_switch_change(struct slot *p_slot) -{ - u8 getstatus; - u32 event_type; - struct controller *ctrl = p_slot->ctrl; - - /* Switch Change */ - ctrl_dbg(ctrl, "Switch interrupt received\n"); - - pciehp_get_latch_status(p_slot, &getstatus); - if (getstatus) { - /* - * Switch opened - */ - ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); - event_type = INT_SWITCH_OPEN; - } else { - /* - * Switch closed - */ - ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); - event_type = INT_SWITCH_CLOSE; - } - - queue_interrupt_event(p_slot, event_type); - - return 1; -} - -u8 pciehp_handle_presence_change(struct slot *p_slot) -{ - u32 event_type; - u8 presence_save; - struct controller *ctrl = p_slot->ctrl; - - /* Presence Change */ - ctrl_dbg(ctrl, "Presence/Notify input change\n"); - - /* Switch is open, assume a presence change - * Save the presence state - */ - pciehp_get_adapter_status(p_slot, &presence_save); - if (presence_save) { - /* - * Card Present - */ - ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot)); - event_type = INT_PRESENCE_ON; - } else { - /* - * Not Present - */ - ctrl_info(ctrl, "Card not present on Slot(%s)\n", - slot_name(p_slot)); - event_type = INT_PRESENCE_OFF; - } - - queue_interrupt_event(p_slot, event_type); - - return 1; -} - -u8 pciehp_handle_power_fault(struct slot *p_slot) -{ - u32 event_type; - struct controller *ctrl = p_slot->ctrl; - - /* power fault */ - ctrl_dbg(ctrl, "Power fault interrupt received\n"); - ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); - event_type = INT_POWER_FAULT; - ctrl_info(ctrl, "Power fault bit %x set\n", 0); - queue_interrupt_event(p_slot, event_type); - - return 1; -} - -void pciehp_handle_linkstate_change(struct slot *p_slot) -{ - u32 event_type; - struct controller *ctrl = p_slot->ctrl; - - /* Link Status Change */ - ctrl_dbg(ctrl, "Data Link Layer State change\n"); - - if (pciehp_check_link_active(ctrl)) { - ctrl_info(ctrl, "slot(%s): Link Up event\n", - slot_name(p_slot)); - event_type = INT_LINK_UP; - } else { - ctrl_info(ctrl, "slot(%s): Link Down event\n", - slot_name(p_slot)); - event_type = INT_LINK_DOWN; - } - - queue_interrupt_event(p_slot, event_type); } /* The following routines constitute the bulk of the @@ -298,10 +180,6 @@ static void pciehp_power_thread(struct work_struct *work) switch (info->req) { case DISABLE_REQ: - ctrl_dbg(p_slot->ctrl, - "Disabling domain:bus:device=%04x:%02x:00\n", - pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), - p_slot->ctrl->pcie->port->subordinate->number); mutex_lock(&p_slot->hotplug_lock); pciehp_disable_slot(p_slot); mutex_unlock(&p_slot->hotplug_lock); @@ -310,10 +188,6 @@ static void pciehp_power_thread(struct work_struct *work) mutex_unlock(&p_slot->lock); break; case ENABLE_REQ: - ctrl_dbg(p_slot->ctrl, - "Enabling domain:bus:device=%04x:%02x:00\n", - pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), - p_slot->ctrl->pcie->port->subordinate->number); mutex_lock(&p_slot->hotplug_lock); ret = pciehp_enable_slot(p_slot); mutex_unlock(&p_slot->hotplug_lock); @@ -416,7 +290,7 @@ static void handle_button_press_event(struct slot *p_slot) ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); break; default: - ctrl_warn(ctrl, "Not a valid state\n"); + ctrl_warn(ctrl, "ignoring invalid state %#x\n", p_slot->state); break; } } @@ -507,8 +381,8 @@ static void handle_link_event(struct slot *p_slot, u32 event) } break; default: - ctrl_err(ctrl, "Not a valid state on slot(%s)\n", - slot_name(p_slot)); + ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n", + p_slot->state, slot_name(p_slot)); kfree(info); break; } @@ -532,7 +406,6 @@ static void interrupt_event_handler(struct work_struct *work) pciehp_green_led_off(p_slot); break; case INT_PRESENCE_ON: - ctrl_dbg(ctrl, "Surprise Insertion\n"); handle_surprise_event(p_slot); break; case INT_PRESENCE_OFF: @@ -540,7 +413,6 @@ static void interrupt_event_handler(struct work_struct *work) * Regardless of surprise capability, we need to * definitely remove a card that has been pulled out! */ - ctrl_dbg(ctrl, "Surprise Removal\n"); handle_surprise_event(p_slot); break; case INT_LINK_UP: @@ -647,8 +519,8 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot) slot_name(p_slot)); break; default: - ctrl_err(ctrl, "Not a valid state on slot %s\n", - slot_name(p_slot)); + ctrl_err(ctrl, "invalid state %#x on slot %s\n", + p_slot->state, slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); @@ -682,8 +554,8 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot) slot_name(p_slot)); break; default: - ctrl_err(ctrl, "Not a valid state on slot %s\n", - slot_name(p_slot)); + ctrl_err(ctrl, "invalid state %#x on slot %s\n", + p_slot->state, slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0ebf754fc177..2913f7e68a10 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -176,20 +176,17 @@ static void pcie_wait_cmd(struct controller *ctrl) jiffies_to_msecs(jiffies - ctrl->cmd_started)); } -/** - * pcie_write_cmd - Issue controller command - * @ctrl: controller to which the command is issued - * @cmd: command value written to slot control register - * @mask: bitmask of slot control register to be modified - */ -static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) +static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, + u16 mask, bool wait) { struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; mutex_lock(&ctrl->ctrl_lock); - /* Wait for any previous command that might still be in progress */ + /* + * Always wait for any previous command that might still be in progress + */ pcie_wait_cmd(ctrl); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); @@ -201,9 +198,33 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ctrl->cmd_started = jiffies; ctrl->slot_ctrl = slot_ctrl; + /* + * Optionally wait for the hardware to be ready for a new command, + * indicating completion of the above issued command. + */ + if (wait) + pcie_wait_cmd(ctrl); + mutex_unlock(&ctrl->ctrl_lock); } +/** + * pcie_write_cmd - Issue controller command + * @ctrl: controller to which the command is issued + * @cmd: command value written to slot control register + * @mask: bitmask of slot control register to be modified + */ +static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) +{ + pcie_do_write_cmd(ctrl, cmd, mask, true); +} + +/* Same as above without waiting for the hardware to latch */ +static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask) +{ + pcie_do_write_cmd(ctrl, cmd, mask, false); +} + bool pciehp_check_link_active(struct controller *ctrl) { struct pci_dev *pdev = ctrl_dev(ctrl); @@ -291,7 +312,8 @@ int pciehp_check_link_status(struct controller *ctrl) ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); if ((lnk_status & PCI_EXP_LNKSTA_LT) || !(lnk_status & PCI_EXP_LNKSTA_NLW)) { - ctrl_err(ctrl, "Link Training Error occurs\n"); + ctrl_err(ctrl, "link training error: status %#06x\n", + lnk_status); return -1; } @@ -422,7 +444,7 @@ void pciehp_set_attention_status(struct slot *slot, u8 value) default: return; } - pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); + pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); } @@ -434,7 +456,8 @@ void pciehp_green_led_on(struct slot *slot) if (!PWR_LED(ctrl)) return; - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, PCI_EXP_SLTCTL_PIC); + pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, + PCI_EXP_SLTCTL_PIC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, PCI_EXP_SLTCTL_PWR_IND_ON); @@ -447,7 +470,8 @@ void pciehp_green_led_off(struct slot *slot) if (!PWR_LED(ctrl)) return; - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, PCI_EXP_SLTCTL_PIC); + pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, + PCI_EXP_SLTCTL_PIC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, PCI_EXP_SLTCTL_PWR_IND_OFF); @@ -460,7 +484,8 @@ void pciehp_green_led_blink(struct slot *slot) if (!PWR_LED(ctrl)) return; - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_PIC); + pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, + PCI_EXP_SLTCTL_PIC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, PCI_EXP_SLTCTL_PWR_IND_BLINK); @@ -510,6 +535,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) struct pci_dev *dev; struct slot *slot = ctrl->slot; u16 detected, intr_loc; + u8 open, present; + bool link; /* * In order to guarantee that all interrupt events are @@ -532,7 +559,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) intr_loc); } while (detected); - ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc); + ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", intr_loc); /* Check Command Complete Interrupt Pending */ if (intr_loc & PCI_EXP_SLTSTA_CC) { @@ -555,25 +582,44 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_HANDLED; /* Check MRL Sensor Changed */ - if (intr_loc & PCI_EXP_SLTSTA_MRLSC) - pciehp_handle_switch_change(slot); + if (intr_loc & PCI_EXP_SLTSTA_MRLSC) { + pciehp_get_latch_status(slot, &open); + ctrl_info(ctrl, "Latch %s on Slot(%s)\n", + open ? "open" : "close", slot_name(slot)); + pciehp_queue_interrupt_event(slot, open ? INT_SWITCH_OPEN : + INT_SWITCH_CLOSE); + } /* Check Attention Button Pressed */ - if (intr_loc & PCI_EXP_SLTSTA_ABP) - pciehp_handle_attention_button(slot); + if (intr_loc & PCI_EXP_SLTSTA_ABP) { + ctrl_info(ctrl, "Button pressed on Slot(%s)\n", + slot_name(slot)); + pciehp_queue_interrupt_event(slot, INT_BUTTON_PRESS); + } /* Check Presence Detect Changed */ - if (intr_loc & PCI_EXP_SLTSTA_PDC) - pciehp_handle_presence_change(slot); + if (intr_loc & PCI_EXP_SLTSTA_PDC) { + pciehp_get_adapter_status(slot, &present); + ctrl_info(ctrl, "Card %spresent on Slot(%s)\n", + present ? "" : "not ", slot_name(slot)); + pciehp_queue_interrupt_event(slot, present ? INT_PRESENCE_ON : + INT_PRESENCE_OFF); + } /* Check Power Fault Detected */ if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { ctrl->power_fault_detected = 1; - pciehp_handle_power_fault(slot); + ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(slot)); + pciehp_queue_interrupt_event(slot, INT_POWER_FAULT); } - if (intr_loc & PCI_EXP_SLTSTA_DLLSC) - pciehp_handle_linkstate_change(slot); + if (intr_loc & PCI_EXP_SLTSTA_DLLSC) { + link = pciehp_check_link_active(ctrl); + ctrl_info(ctrl, "slot(%s): Link %s event\n", + slot_name(slot), link ? "Up" : "Down"); + pciehp_queue_interrupt_event(slot, link ? INT_LINK_UP : + INT_LINK_DOWN); + } return IRQ_HANDLED; } @@ -613,7 +659,7 @@ void pcie_enable_notification(struct controller *ctrl) PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_DLLSCE); - pcie_write_cmd(ctrl, cmd, mask); + pcie_write_cmd_nowait(ctrl, cmd, mask); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); } @@ -664,7 +710,7 @@ int pciehp_reset_slot(struct slot *slot, int probe) pci_reset_bridge_secondary_bus(ctrl->pcie->port); pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); - pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); + pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); if (pciehp_poll_mode) @@ -724,48 +770,13 @@ static void pcie_cleanup_slot(struct controller *ctrl) static inline void dbg_ctrl(struct controller *ctrl) { - int i; - u16 reg16; struct pci_dev *pdev = ctrl->pcie->port; + u16 reg16; if (!pciehp_debug) return; - ctrl_info(ctrl, "Hotplug Controller:\n"); - ctrl_info(ctrl, " Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", - pci_name(pdev), pdev->irq); - ctrl_info(ctrl, " Vendor ID : 0x%04x\n", pdev->vendor); - ctrl_info(ctrl, " Device ID : 0x%04x\n", pdev->device); - ctrl_info(ctrl, " Subsystem ID : 0x%04x\n", - pdev->subsystem_device); - ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", - pdev->subsystem_vendor); - ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", - pci_pcie_cap(pdev)); - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (!pci_resource_len(pdev, i)) - continue; - ctrl_info(ctrl, " PCI resource [%d] : %pR\n", - i, &pdev->resource[i]); - } ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); - ctrl_info(ctrl, " Physical Slot Number : %d\n", PSN(ctrl)); - ctrl_info(ctrl, " Attention Button : %3s\n", - ATTN_BUTTN(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " Power Controller : %3s\n", - POWER_CTRL(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " MRL Sensor : %3s\n", - MRL_SENS(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " Attention Indicator : %3s\n", - ATTN_LED(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " Power Indicator : %3s\n", - PWR_LED(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " Hot-Plug Surprise : %3s\n", - HP_SUPR_RM(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " EMI Present : %3s\n", - EMI(ctrl) ? "yes" : "no"); - ctrl_info(ctrl, " Command Completed : %3s\n", - NO_CMD_CMPL(ctrl) ? "no" : "yes"); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); @@ -794,10 +805,8 @@ struct controller *pcie_init(struct pcie_device *dev) /* Check if Data Link Layer Link Active Reporting is implemented */ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); - if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { - ctrl_dbg(ctrl, "Link Active Reporting supported\n"); + if (link_cap & PCI_EXP_LNKCAP_DLLLARC) ctrl->link_active_reporting = 1; - } /* Clear all remaining event bits in Slot Status register */ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, @@ -805,13 +814,15 @@ struct controller *pcie_init(struct pcie_device *dev) PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC); - ctrl_info(ctrl, "Slot #%d AttnBtn%c AttnInd%c PwrInd%c PwrCtrl%c MRL%c Interlock%c NoCompl%c LLActRep%c\n", + ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c\n", (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19, FLAG(slot_cap, PCI_EXP_SLTCAP_ABP), - FLAG(slot_cap, PCI_EXP_SLTCAP_AIP), - FLAG(slot_cap, PCI_EXP_SLTCAP_PIP), FLAG(slot_cap, PCI_EXP_SLTCAP_PCP), FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP), + FLAG(slot_cap, PCI_EXP_SLTCAP_AIP), + FLAG(slot_cap, PCI_EXP_SLTCAP_PIP), + FLAG(slot_cap, PCI_EXP_SLTCAP_HPC), + FLAG(slot_cap, PCI_EXP_SLTCAP_HPS), FLAG(slot_cap, PCI_EXP_SLTCAP_EIP), FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS), FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC)); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index c3e7dfcf9ff5..f66be868ad21 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -185,27 +185,6 @@ void __weak arch_restore_msi_irqs(struct pci_dev *dev) return default_restore_msi_irqs(dev); } -static void msi_set_enable(struct pci_dev *dev, int enable) -{ - u16 control; - - pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); - control &= ~PCI_MSI_FLAGS_ENABLE; - if (enable) - control |= PCI_MSI_FLAGS_ENABLE; - pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); -} - -static void msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set) -{ - u16 ctrl; - - pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl); - ctrl &= ~clear; - ctrl |= set; - pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl); -} - static inline __attribute_const__ u32 msi_mask(unsigned x) { /* Don't shift by >= width of type */ @@ -452,7 +431,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) entry = irq_get_msi_desc(dev->irq); pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 0); + pci_msi_set_enable(dev, 0); arch_restore_msi_irqs(dev); pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); @@ -473,14 +452,14 @@ static void __pci_restore_msix_state(struct pci_dev *dev) /* route the table */ pci_intx_for_msi(dev, 0); - msix_clear_and_set_ctrl(dev, 0, + pci_msix_clear_and_set_ctrl(dev, 0, PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); arch_restore_msi_irqs(dev); list_for_each_entry(entry, &dev->msi_list, list) msix_mask_irq(entry, entry->masked); - msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); } void pci_restore_msi_state(struct pci_dev *dev) @@ -647,7 +626,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) int ret; unsigned mask; - msi_set_enable(dev, 0); /* Disable MSI during set up */ + pci_msi_set_enable(dev, 0); /* Disable MSI during set up */ entry = msi_setup_entry(dev, nvec); if (!entry) @@ -683,7 +662,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) /* Set MSI enabled bits */ pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 1); + pci_msi_set_enable(dev, 1); dev->msi_enabled = 1; dev->irq = entry->irq; @@ -775,7 +754,7 @@ static int msix_capability_init(struct pci_dev *dev, void __iomem *base; /* Ensure MSI-X is disabled while it is set up */ - msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control); /* Request & Map MSI-X table region */ @@ -801,7 +780,7 @@ static int msix_capability_init(struct pci_dev *dev, * MSI-X registers. We need to mask all the vectors to prevent * interrupts coming in before they're fully set up. */ - msix_clear_and_set_ctrl(dev, 0, + pci_msix_clear_and_set_ctrl(dev, 0, PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE); msix_program_entries(dev, entries); @@ -814,7 +793,7 @@ static int msix_capability_init(struct pci_dev *dev, pci_intx_for_msi(dev, 0); dev->msix_enabled = 1; - msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); return 0; @@ -919,7 +898,7 @@ void pci_msi_shutdown(struct pci_dev *dev) BUG_ON(list_empty(&dev->msi_list)); desc = list_first_entry(&dev->msi_list, struct msi_desc, list); - msi_set_enable(dev, 0); + pci_msi_set_enable(dev, 0); pci_intx_for_msi(dev, 1); dev->msi_enabled = 0; @@ -1027,7 +1006,7 @@ void pci_msix_shutdown(struct pci_dev *dev) __pci_msix_desc_mask_irq(entry, 1); } - msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; } @@ -1062,18 +1041,6 @@ EXPORT_SYMBOL(pci_msi_enabled); void pci_msi_init_pci_dev(struct pci_dev *dev) { INIT_LIST_HEAD(&dev->msi_list); - - /* Disable the msi hardware to avoid screaming interrupts - * during boot. This is the power on reset default so - * usually this should be a noop. - */ - dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (dev->msi_cap) - msi_set_enable(dev, 0); - - dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (dev->msix_cap) - msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); } /** diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index acc4b6ef78c4..0008c950452c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3101,39 +3101,6 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); -/** - * pci_msi_off - disables any MSI or MSI-X capabilities - * @dev: the PCI device to operate on - * - * If you want to use MSI, see pci_enable_msi() and friends. - * This is a lower-level primitive that allows us to disable - * MSI operation at the device level. - */ -void pci_msi_off(struct pci_dev *dev) -{ - int pos; - u16 control; - - /* - * This looks like it could go in msi.c, but we need it even when - * CONFIG_PCI_MSI=n. For the same reason, we can't use - * dev->msi_cap or dev->msix_cap here. - */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (pos) { - pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); - control &= ~PCI_MSI_FLAGS_ENABLE; - pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); - } - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos) { - pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); - control &= ~PCI_MSIX_FLAGS_ENABLE; - pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); - } -} -EXPORT_SYMBOL_GPL(pci_msi_off); - int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) { return dma_set_max_seg_size(&dev->dev, size); @@ -4324,6 +4291,17 @@ bool pci_device_is_present(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(pci_device_is_present); +void pci_ignore_hotplug(struct pci_dev *dev) +{ + struct pci_dev *bridge = dev->bus->self; + + dev->ignore_hotplug = 1; + /* Propagate the "ignore hotplug" setting to the parent bridge. */ + if (bridge) + bridge->ignore_hotplug = 1; +} +EXPORT_SYMBOL_GPL(pci_ignore_hotplug); + #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; static DEFINE_SPINLOCK(resource_alignment_lock); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9bd762c237ab..4ff0ff1c4088 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -146,6 +146,27 @@ static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif +static inline void pci_msi_set_enable(struct pci_dev *dev, int enable) +{ + u16 control; + + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; + if (enable) + control |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); +} + +static inline void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set) +{ + u16 ctrl; + + pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl); + ctrl &= ~clear; + ctrl |= set; + pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl); +} + void pci_realloc_get_opt(char *); static inline int pci_no_d1d2(struct pci_dev *dev) @@ -216,17 +237,6 @@ void __pci_bus_assign_resources(const struct pci_bus *bus, struct list_head *fail_head); bool pci_bus_clip_resource(struct pci_dev *dev, int idx); -/** - * pci_ari_enabled - query ARI forwarding status - * @bus: the PCI bus - * - * Returns 1 if ARI forwarding is enabled, or 0 if not enabled; - */ -static inline int pci_ari_enabled(struct pci_bus *bus) -{ - return bus->self && bus->self->ari_enabled; -} - void pci_reassigndev_resource_alignment(struct pci_dev *dev); void pci_disable_bridge_window(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 5653ea94547f..9803e3d039fe 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -425,8 +425,7 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) if (driver && driver->reset_link) { status = driver->reset_link(udev); - } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM || - pci_pcie_type(udev) == PCI_EXP_TYPE_ROOT_PORT) { + } else if (udev->has_secondary_link) { status = default_reset_link(udev); } else { dev_printk(KERN_DEBUG, &dev->dev, diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 7d4fcdc512aa..317e3558a35e 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -127,15 +127,12 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) { struct pci_dev *child; struct pci_bus *linkbus = link->pdev->subordinate; + u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0; - list_for_each_entry(child, &linkbus->devices, bus_list) { - if (enable) - pcie_capability_set_word(child, PCI_EXP_LNKCTL, - PCI_EXP_LNKCTL_CLKREQ_EN); - else - pcie_capability_clear_word(child, PCI_EXP_LNKCTL, - PCI_EXP_LNKCTL_CLKREQ_EN); - } + list_for_each_entry(child, &linkbus->devices, bus_list) + pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CLKREQ_EN, + val); link->clkpm_enabled = !!enable; } @@ -525,7 +522,7 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) INIT_LIST_HEAD(&link->children); INIT_LIST_HEAD(&link->link); link->pdev = pdev; - if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) { + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) { struct pcie_link_state *parent; parent = pdev->bus->parent->self->link_state; if (!parent) { @@ -559,10 +556,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) if (!aspm_support_enabled) return; - if (!pci_is_pcie(pdev) || pdev->link_state) + if (pdev->link_state) return; - if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && - pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) + + /* + * We allocate pcie_link_state for the component on the upstream + * end of a Link, so there's nothing to do unless this device has a + * Link on its secondary side. + */ + if (!pdev->has_secondary_link) return; /* VIA has a strange chipset, root port is under a bridge */ @@ -675,10 +677,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) { struct pcie_link_state *link = pdev->link_state; - if (aspm_disabled || !pci_is_pcie(pdev) || !link) - return; - if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) && - (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)) + if (aspm_disabled || !link) return; /* * Devices changed PM state, we should recheck if latency @@ -696,16 +695,12 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { struct pcie_link_state *link = pdev->link_state; - if (aspm_disabled || !pci_is_pcie(pdev) || !link) + if (aspm_disabled || !link) return; if (aspm_policy != POLICY_POWERSAVE) return; - if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) && - (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)) - return; - down_read(&pci_bus_sem); mutex_lock(&aspm_lock); pcie_config_aspm_path(link); @@ -714,8 +709,7 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) up_read(&pci_bus_sem); } -static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, - bool force) +static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) { struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link; @@ -723,8 +717,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, if (!pci_is_pcie(pdev)) return; - if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT || - pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM) + if (pdev->has_secondary_link) parent = pdev; if (!parent || !parent->link_state) return; @@ -737,7 +730,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, * a similar mechanism using "PciASPMOptOut", which is also * ignored in this situation. */ - if (aspm_disabled && !force) { + if (aspm_disabled) { dev_warn(&pdev->dev, "can't disable ASPM; OS doesn't have ASPM control\n"); return; } @@ -763,7 +756,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, void pci_disable_link_state_locked(struct pci_dev *pdev, int state) { - __pci_disable_link_state(pdev, state, false, false); + __pci_disable_link_state(pdev, state, false); } EXPORT_SYMBOL(pci_disable_link_state_locked); @@ -778,7 +771,7 @@ EXPORT_SYMBOL(pci_disable_link_state_locked); */ void pci_disable_link_state(struct pci_dev *pdev, int state) { - __pci_disable_link_state(pdev, state, true, false); + __pci_disable_link_state(pdev, state, true); } EXPORT_SYMBOL(pci_disable_link_state); @@ -907,9 +900,7 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { struct pcie_link_state *link_state = pdev->link_state; - if (!pci_is_pcie(pdev) || - (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && - pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) + if (!link_state) return; if (link_state->aspm_support) @@ -924,9 +915,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { struct pcie_link_state *link_state = pdev->link_state; - if (!pci_is_pcie(pdev) || - (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && - pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) + if (!link_state) return; if (link_state->aspm_support) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6675a7a1b9fc..cefd636681b6 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -254,8 +254,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } if (res->flags & IORESOURCE_MEM_64) { - if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && - sz64 > 0x100000000ULL) { + if ((sizeof(pci_bus_addr_t) < 8 || sizeof(resource_size_t) < 8) + && sz64 > 0x100000000ULL) { res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; res->start = 0; res->end = 0; @@ -264,7 +264,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto out; } - if ((sizeof(dma_addr_t) < 8) && l) { + if ((sizeof(pci_bus_addr_t) < 8) && l) { /* Above 32-bit boundary; try to reallocate */ res->flags |= IORESOURCE_UNSET; res->start = 0; @@ -399,7 +399,7 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) struct pci_dev *dev = child->self; u16 mem_base_lo, mem_limit_lo; u64 base64, limit64; - dma_addr_t base, limit; + pci_bus_addr_t base, limit; struct pci_bus_region region; struct resource *res; @@ -426,8 +426,8 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) } } - base = (dma_addr_t) base64; - limit = (dma_addr_t) limit64; + base = (pci_bus_addr_t) base64; + limit = (pci_bus_addr_t) limit64; if (base != base64) { dev_err(&dev->dev, "can't handle bridge window above 4GB (bus address %#010llx)\n", @@ -973,6 +973,8 @@ void set_pcie_port_type(struct pci_dev *pdev) { int pos; u16 reg16; + int type; + struct pci_dev *parent; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (!pos) @@ -982,6 +984,22 @@ void set_pcie_port_type(struct pci_dev *pdev) pdev->pcie_flags_reg = reg16; pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, ®16); pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD; + + /* + * A Root Port is always the upstream end of a Link. No PCIe + * component has two Links. Two Links are connected by a Switch + * that has a Port on each Link and internal logic to connect the + * two Ports. + */ + type = pci_pcie_type(pdev); + if (type == PCI_EXP_TYPE_ROOT_PORT) + pdev->has_secondary_link = 1; + else if (type == PCI_EXP_TYPE_UPSTREAM || + type == PCI_EXP_TYPE_DOWNSTREAM) { + parent = pci_upstream_bridge(pdev); + if (!parent->has_secondary_link) + pdev->has_secondary_link = 1; + } } void set_pcie_hotplug_bridge(struct pci_dev *pdev) @@ -1085,6 +1103,22 @@ int pci_cfg_space_size(struct pci_dev *dev) #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) +static void pci_msi_setup_pci_dev(struct pci_dev *dev) +{ + /* + * Disable the MSI hardware to avoid screaming interrupts + * during boot. This is the power on reset default so + * usually this should be a noop. + */ + dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (dev->msi_cap) + pci_msi_set_enable(dev, 0); + + dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (dev->msix_cap) + pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); +} + /** * pci_setup_device - fill in class and map information of a device * @dev: the device structure to fill @@ -1140,6 +1174,8 @@ int pci_setup_device(struct pci_dev *dev) /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; + pci_msi_setup_pci_dev(dev); + /* Early fixups, before probing the BARs */ pci_fixup_device(pci_fixup_early, dev); /* device class may be changed after fixup */ @@ -1611,7 +1647,7 @@ static int only_one_child(struct pci_bus *bus) return 0; if (pci_pcie_type(parent) == PCI_EXP_TYPE_ROOT_PORT) return 1; - if (pci_pcie_type(parent) == PCI_EXP_TYPE_DOWNSTREAM && + if (parent->has_secondary_link && !pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS)) return 1; return 0; @@ -2094,25 +2130,6 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, } EXPORT_SYMBOL(pci_scan_root_bus); -/* Deprecated; use pci_scan_root_bus() instead */ -struct pci_bus *pci_scan_bus_parented(struct device *parent, - int bus, struct pci_ops *ops, void *sysdata) -{ - LIST_HEAD(resources); - struct pci_bus *b; - - pci_add_resource(&resources, &ioport_resource); - pci_add_resource(&resources, &iomem_resource); - pci_add_resource(&resources, &busn_resource); - b = pci_create_root_bus(parent, bus, ops, sysdata, &resources); - if (b) - pci_scan_child_bus(b); - else - pci_free_resource_list(&resources); - return b; -} -EXPORT_SYMBOL(pci_scan_bus_parented); - struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c6dc1dfd25d5..c77dfe5aaed6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1600,7 +1600,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_a static void quirk_pcie_mch(struct pci_dev *pdev) { - pci_msi_off(pdev); pdev->no_msi = 1; } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch); @@ -1614,7 +1613,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir */ static void quirk_pcie_pxh(struct pci_dev *dev) { - pci_msi_off(dev); dev->no_msi = 1; dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n"); } @@ -3572,6 +3570,8 @@ static void quirk_dma_func1_alias(struct pci_dev *dev) * SKUs this function is not present, making this a ghost requester. * https://bugzilla.kernel.org/show_bug.cgi?id=42679 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9120, + quirk_dma_func1_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ @@ -3740,6 +3740,8 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = { /* Wellsburg (X99) PCH */ 0x8d10, 0x8d11, 0x8d12, 0x8d13, 0x8d14, 0x8d15, 0x8d16, 0x8d17, 0x8d18, 0x8d19, 0x8d1a, 0x8d1b, 0x8d1c, 0x8d1d, 0x8d1e, + /* Lynx Point (9 series) PCH */ + 0x8c90, 0x8c92, 0x8c94, 0x8c96, 0x8c98, 0x8c9a, 0x8c9c, 0x8c9e, }; static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) diff --git a/drivers/pci/vc.c b/drivers/pci/vc.c index 7e1304d2e389..dfbab61a1b47 100644 --- a/drivers/pci/vc.c +++ b/drivers/pci/vc.c @@ -108,8 +108,7 @@ static void pci_vc_enable(struct pci_dev *dev, int pos, int res) struct pci_dev *link = NULL; /* Enable VCs from the downstream device */ - if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || - pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) + if (!dev->has_secondary_link) return; ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF); diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 7cfd2db02deb..240f38872085 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -446,9 +446,15 @@ static int pcifront_scan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus) { struct pci_bus *b; + LIST_HEAD(resources); struct pcifront_sd *sd = NULL; struct pci_bus_entry *bus_entry = NULL; int err = 0; + static struct resource busn_res = { + .start = 0, + .end = 255, + .flags = IORESOURCE_BUS, + }; #ifndef CONFIG_PCI_DOMAINS if (domain != 0) { @@ -470,17 +476,21 @@ static int pcifront_scan_root(struct pcifront_device *pdev, err = -ENOMEM; goto err_out; } + pci_add_resource(&resources, &ioport_resource); + pci_add_resource(&resources, &iomem_resource); + pci_add_resource(&resources, &busn_res); pcifront_init_sd(sd, domain, bus, pdev); pci_lock_rescan_remove(); - b = pci_scan_bus_parented(&pdev->xdev->dev, bus, - &pcifront_bus_ops, sd); + b = pci_scan_root_bus(&pdev->xdev->dev, bus, + &pcifront_bus_ops, sd, &resources); if (!b) { dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n"); err = -ENOMEM; pci_unlock_rescan_remove(); + pci_free_resource_list(&resources); goto err_out; } @@ -488,7 +498,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev, list_add(&bus_entry->list, &pdev->root_buses); - /* pci_scan_bus_parented skips devices which do not have a have + /* pci_scan_root_bus skips devices which do not have a * devfn==0. The pcifront_scan_bus enumerates all devfn. */ err = pcifront_scan_bus(pdev, domain, bus, b); |