summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2021-05-04 14:54:19 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2021-05-05 23:03:56 +0200
commita08f3c7add53eaaa4ab453ac3f06c24ec8927579 (patch)
treed0d794479622b8054d0ae746a5dff0524cfe472c /drivers/pci
parent82e97870feb6303ecc71371abc76a606e724b065 (diff)
parent28910e01c43d9735f06fddbeaa42df3e112d1b3e (diff)
Merge commit '28910e01c43d9735f06fddbeaa42df3e112d1b3e' into toradex_5.4-2.3.x-imx
This basically contains NXP BSP Patch L5.4.70_2.3.2 plus kernel.org v5.4.115 from https://github.com/Freescale/linux-fslc/tree/5.4-2.3.x-imx. Related-to: ELB-3958 Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c144
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c4
-rw-r--r--drivers/pci/controller/pci-xgene-msi.c10
-rw-r--r--drivers/pci/controller/pcie-mediatek.c7
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c14
-rw-r--r--drivers/pci/pci.c13
-rw-r--r--drivers/pci/quirks.c3
-rw-r--r--drivers/pci/setup-res.c6
-rw-r--r--drivers/pci/syscall.c10
9 files changed, 147 insertions, 64 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 7963e27b754c..663f41df33ab 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -46,6 +46,7 @@
#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
+#define IMX8MQ_GPR_PCIE_VREG_BYPASS BIT(12)
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
#define IMX8_HSIO_PCIEB_BASE_ADDR 0x5f010000
@@ -143,8 +144,10 @@ struct imx6_pcie {
u32 hsio_cfg;
u32 ext_osc;
u32 local_addr;
+ u32 l1ss_clkreq;
int link_gen;
struct regulator *vpcie;
+ struct regulator *vph;
void __iomem *phy_base;
void __iomem *hsmix_base;
@@ -1652,6 +1655,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_REF_USE_PAD,
IMX8MQ_GPR_PCIE_REF_USE_PAD);
+ /*
+ * Regarding to the datasheet, the PCIE_VPH is suggested
+ * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the
+ * VREG_BYPASS should be cleared to zero.
+ */
+ if (imx6_pcie->vph &&
+ regulator_get_voltage(imx6_pcie->vph) > 3000000)
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ imx6_pcie_grp_offset(imx6_pcie),
+ IMX8MQ_GPR_PCIE_VREG_BYPASS,
+ 0);
break;
case IMX8MP:
case IMX8MP_EP:
@@ -1943,6 +1957,8 @@ err_reset_phy:
imx6_pcie_clk_disable(imx6_pcie);
if (imx6_pcie->vpcie != NULL)
regulator_disable(imx6_pcie->vpcie);
+ if (imx6_pcie->dis_gpiod)
+ gpiod_set_value_cansleep(imx6_pcie->dis_gpiod, 0);
}
return ret;
@@ -2257,6 +2273,26 @@ static struct attribute_group imx_pcie_attrgroup = {
.attrs = imx_pcie_rc_attrs,
};
+static void imx6_pcie_clkreq_enable(struct imx6_pcie *imx6_pcie)
+{
+ /*
+ * If the L1SS is supported, disable the over ride after link up.
+ * Let the the CLK_REQ# controlled by HW L1SS automatically.
+ */
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ case IMX8MM:
+ case IMX8MP:
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ imx6_pcie_grp_offset(imx6_pcie),
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ 0);
+ break;
+ default:
+ break;
+ };
+}
+
#ifdef CONFIG_PM_SLEEP
static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
{
@@ -2389,6 +2425,8 @@ static int imx6_pcie_resume_noirq(struct device *dev)
ret = imx6_pcie_establish_link(imx6_pcie);
if (ret < 0)
dev_info(dev, "pcie link is down after resume.\n");
+ if (imx6_pcie->l1ss_clkreq)
+ imx6_pcie_clkreq_enable(imx6_pcie);
}
return 0;
@@ -2411,7 +2449,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
void __iomem *iomem;
struct regmap_config regconfig = imx6_pcie_regconfig;
int ret;
- u32 reg, val;
+ u32 val;
imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL);
if (!imx6_pcie)
@@ -2484,6 +2522,10 @@ static int imx6_pcie_probe(struct platform_device *pdev)
imx6_pcie->ext_osc = 0;
if (of_property_read_u32(node, "local-addr", &imx6_pcie->local_addr))
imx6_pcie->local_addr = 0;
+ if (of_property_read_bool(node, "l1ss-disabled"))
+ imx6_pcie->l1ss_clkreq = 0;
+ else
+ imx6_pcie->l1ss_clkreq = 1;
/* Fetch GPIOs */
imx6_pcie->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq",
@@ -2731,6 +2773,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
imx6_pcie->vpcie = NULL;
}
+ imx6_pcie->vph = devm_regulator_get_optional(&pdev->dev, "vph");
+ if (IS_ERR(imx6_pcie->vph)) {
+ if (PTR_ERR(imx6_pcie->vph) != -ENODEV)
+ return PTR_ERR(imx6_pcie->vph);
+ imx6_pcie->vph = NULL;
+ }
+
platform_set_drvdata(pdev, imx6_pcie);
ret = imx6_pcie_attach_pd(dev);
@@ -2742,6 +2791,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
dev_err(dev, "failed to enable the epdev_on regulator\n");
goto err_ret;
}
+ if (imx6_pcie->dis_gpiod)
+ gpiod_set_value_cansleep(imx6_pcie->dis_gpiod, 1);
imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
@@ -2777,45 +2828,6 @@ static int imx6_pcie_probe(struct platform_device *pdev)
}
pci_imx_set_msi_en(&imx6_pcie->pci->pp);
- /*
- * If the L1SS is enabled, disable the over ride after link up.
- * Let the the CLK_REQ# controlled by HW L1SS automatically.
- */
- ret = imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_L1SS;
- if (IS_ENABLED(CONFIG_PCIEASPM_POWER_SUPERSAVE) && (ret > 0)) {
- switch (imx6_pcie->drvdata->variant) {
- case IMX8MQ:
- case IMX8MM:
- case IMX8MP:
- case IMX8MQ_EP:
- case IMX8MM_EP:
- case IMX8MP_EP:
- regmap_update_bits(imx6_pcie->iomuxc_gpr,
- imx6_pcie_grp_offset(imx6_pcie),
- IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
- 0);
- break;
- case IMX8QXP:
- case IMX8QXP_EP:
- regmap_update_bits(imx6_pcie->iomuxc_gpr,
- IMX8QM_CSR_MISC_OFFSET,
- IMX8QM_MISC_CLKREQ_OVERRIDE_EN_1,
- 0);
- break;
- case IMX8QM:
- case IMX8QM_EP:
- if (imx6_pcie->controller_id)
- reg = IMX8QM_MISC_CLKREQ_OVERRIDE_EN_1;
- else
- reg = IMX8QM_MISC_CLKREQ_OVERRIDE_EN_0;
- regmap_update_bits(imx6_pcie->iomuxc_gpr,
- IMX8QM_CSR_MISC_OFFSET,
- reg, 0);
- break;
- default:
- break;
- };
- }
break;
case DW_PCIE_EP_TYPE:
if (!IS_ENABLED(CONFIG_PCI_IMX_EP))
@@ -3012,6 +3024,58 @@ static void imx6_pcie_quirk(struct pci_dev *dev)
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_SYNOPSYS, 0xabcd,
PCI_CLASS_BRIDGE_PCI, 8, imx6_pcie_quirk);
+static void imx6_pcie_l1ss_quirk(struct pci_dev *dev)
+{
+ u32 reg, rc_l1sub, ep_l1sub, header;
+ int ttl, ret;
+ int pos = PCI_CFG_SPACE_SIZE;
+ struct pci_bus *bus = dev->bus;
+ struct pcie_port *pp = bus->sysdata;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
+
+ /* Return directly, if the L1SS is not supported by RC */
+ if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_L1SS))
+ return;
+
+ /* Make sure the L1SS is not force disabled. */
+ if (imx6_pcie->l1ss_clkreq == 0)
+ return;
+
+ reg = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
+ rc_l1sub = dw_pcie_readl_dbi(pci, reg + PCI_L1SS_CAP);
+
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+ ret = dw_pcie_read(pp->va_cfg0_base + pos, 4, &header);
+ /*
+ * If we have no capabilities, this is indicated by cap ID,
+ * cap version and next pointer all being 0.
+ */
+ if (header == 0)
+ return;
+
+ while (ttl-- > 0) {
+ if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_L1SS && pos != 0)
+ break;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ if (pos < PCI_CFG_SPACE_SIZE)
+ break;
+
+ ret = dw_pcie_read(pp->va_cfg0_base + pos, 4, &header);
+ }
+ ret = dw_pcie_read(pp->va_cfg0_base + pos + PCI_L1SS_CAP, 4, &ep_l1sub);
+
+ if ((rc_l1sub && ep_l1sub) && PCI_L1SS_CAP_L1_PM_SS) {
+ imx6_pcie->l1ss_clkreq = 1;
+ imx6_pcie_clkreq_enable(imx6_pcie);
+ } else {
+ imx6_pcie->l1ss_clkreq = 0;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SYNOPSYS, 0xabcd, imx6_pcie_l1ss_quirk);
+
static int __init imx6_pcie_init(void)
{
#ifdef CONFIG_ARM
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 14196c0287a2..a8eab4e67af1 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -402,7 +402,9 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
/* enable external reference clock */
val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
- val &= ~PHY_REFCLK_USE_PAD;
+ /* USE_PAD is required only for ipq806x */
+ if (!of_device_is_compatible(node, "qcom,pcie-apq8064"))
+ val &= ~PHY_REFCLK_USE_PAD;
val |= PHY_REFCLK_SSP_EN;
writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c
index f4c02da84e59..0bfa5065b440 100644
--- a/drivers/pci/controller/pci-xgene-msi.c
+++ b/drivers/pci/controller/pci-xgene-msi.c
@@ -384,13 +384,9 @@ static int xgene_msi_hwirq_alloc(unsigned int cpu)
if (!msi_group->gic_irq)
continue;
- irq_set_chained_handler(msi_group->gic_irq,
- xgene_msi_isr);
- err = irq_set_handler_data(msi_group->gic_irq, msi_group);
- if (err) {
- pr_err("failed to register GIC IRQ handler\n");
- return -EINVAL;
- }
+ irq_set_chained_handler_and_data(msi_group->gic_irq,
+ xgene_msi_isr, msi_group);
+
/*
* Statically allocate MSI GIC IRQs to each CPU core.
* With 8-core X-Gene v1, 2 MSI GIC IRQs are allocated
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 626a7c352dfd..728a59655825 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1063,14 +1063,14 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
err = of_pci_get_devfn(child);
if (err < 0) {
dev_err(dev, "failed to parse devfn: %d\n", err);
- return err;
+ goto error_put_node;
}
slot = PCI_SLOT(err);
err = mtk_pcie_parse_port(pcie, child, slot);
if (err)
- return err;
+ goto error_put_node;
}
err = mtk_pcie_subsys_powerup(pcie);
@@ -1086,6 +1086,9 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
mtk_pcie_subsys_powerdown(pcie);
return 0;
+error_put_node:
+ of_node_put(child);
+ return err;
}
static int mtk_pcie_probe(struct platform_device *pdev)
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index cdbfa5df3a51..dbfa0b55d31a 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -34,12 +34,11 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
if (nbytes >= MAX_DRC_NAME_LEN)
return 0;
- memcpy(drc_name, buf, nbytes);
+ strscpy(drc_name, buf, nbytes + 1);
end = strchr(drc_name, '\n');
- if (!end)
- end = &drc_name[nbytes];
- *end = '\0';
+ if (end)
+ *end = '\0';
rc = dlpar_add_slot(drc_name);
if (rc)
@@ -65,12 +64,11 @@ static ssize_t remove_slot_store(struct kobject *kobj,
if (nbytes >= MAX_DRC_NAME_LEN)
return 0;
- memcpy(drc_name, buf, nbytes);
+ strscpy(drc_name, buf, nbytes + 1);
end = strchr(drc_name, '\n');
- if (!end)
- end = &drc_name[nbytes];
- *end = '\0';
+ if (end)
+ *end = '\0';
rc = dlpar_remove_slot(drc_name);
if (rc)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 89dece8a4132..3c3bc9f58498 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3471,7 +3471,14 @@ u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
return 0;
pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
- return (cap & PCI_REBAR_CAP_SIZES) >> 4;
+ cap &= PCI_REBAR_CAP_SIZES;
+
+ /* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */
+ if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f &&
+ bar == 0 && cap == 0x7000)
+ cap = 0x3f000;
+
+ return cap >> 4;
}
/**
@@ -3896,6 +3903,10 @@ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
ret = logic_pio_register_range(range);
if (ret)
kfree(range);
+
+ /* Ignore duplicates due to deferred probing */
+ if (ret == -EEXIST)
+ ret = 0;
#endif
return ret;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c2f1834ad0d8..705ef3f050ac 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4115,6 +4115,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9183,
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c135 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9215,
+ quirk_dma_func1_alias);
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220,
quirk_dma_func1_alias);
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index d21fa04fa44d..da5023e27951 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -409,10 +409,16 @@ EXPORT_SYMBOL(pci_release_resource);
int pci_resize_resource(struct pci_dev *dev, int resno, int size)
{
struct resource *res = dev->resource + resno;
+ struct pci_host_bridge *host;
int old, ret;
u32 sizes;
u16 cmd;
+ /* Check if we must preserve the firmware's resource assignment */
+ host = pci_find_host_bridge(dev->bus);
+ if (host->preserve_config)
+ return -ENOTSUPP;
+
/* Make sure the resource isn't assigned before resizing it. */
if (!(res->flags & IORESOURCE_UNSET))
return -EBUSY;
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 31e39558d49d..8b003c890b87 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -20,7 +20,7 @@ SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
u16 word;
u32 dword;
long err;
- long cfg_ret;
+ int cfg_ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -46,7 +46,7 @@ SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
}
err = -EIO;
- if (cfg_ret != PCIBIOS_SUCCESSFUL)
+ if (cfg_ret)
goto error;
switch (len) {
@@ -105,7 +105,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
if (err)
break;
err = pci_user_write_config_byte(dev, off, byte);
- if (err != PCIBIOS_SUCCESSFUL)
+ if (err)
err = -EIO;
break;
@@ -114,7 +114,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
if (err)
break;
err = pci_user_write_config_word(dev, off, word);
- if (err != PCIBIOS_SUCCESSFUL)
+ if (err)
err = -EIO;
break;
@@ -123,7 +123,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
if (err)
break;
err = pci_user_write_config_dword(dev, off, dword);
- if (err != PCIBIOS_SUCCESSFUL)
+ if (err)
err = -EIO;
break;