summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2019-07-26 10:40:07 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2019-08-15 06:51:37 -0400
commit075af61c19cdc32b94fd697c610c9a07fa21866e (patch)
tree79a48733d44265c5f12887a4e9fc8a7d463ce47f
parent5f9e832c137075045d15cd6899ab0505cfb2ca4b (diff)
PCI: imx6: Limit DBI register length
Define the length of the DBI registers and limit config space to its length. This makes sure that the kernel does not access registers beyond that point, avoiding the following abort on a i.MX 6Quad: # cat /sys/devices/soc0/soc/1ffc000.pcie/pci0000\:00/0000\:00\:00.0/config [ 100.021433] Unhandled fault: imprecise external abort (0x1406) at 0xb6ea7000 ... [ 100.056423] PC is at dw_pcie_read+0x50/0x84 [ 100.060790] LR is at dw_pcie_rd_own_conf+0x44/0x48 ... Signed-off-by: Stefan Agner <stefan@agner.ch> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 9b5cb5b70389..8b8efa3063f5 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -57,6 +57,7 @@ enum imx6_pcie_variants {
57struct imx6_pcie_drvdata { 57struct imx6_pcie_drvdata {
58 enum imx6_pcie_variants variant; 58 enum imx6_pcie_variants variant;
59 u32 flags; 59 u32 flags;
60 int dbi_length;
60}; 61};
61 62
62struct imx6_pcie { 63struct imx6_pcie {
@@ -1212,6 +1213,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
1212 .variant = IMX6Q, 1213 .variant = IMX6Q,
1213 .flags = IMX6_PCIE_FLAG_IMX6_PHY | 1214 .flags = IMX6_PCIE_FLAG_IMX6_PHY |
1214 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, 1215 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
1216 .dbi_length = 0x200,
1215 }, 1217 },
1216 [IMX6SX] = { 1218 [IMX6SX] = {
1217 .variant = IMX6SX, 1219 .variant = IMX6SX,
@@ -1254,6 +1256,37 @@ static struct platform_driver imx6_pcie_driver = {
1254 .shutdown = imx6_pcie_shutdown, 1256 .shutdown = imx6_pcie_shutdown,
1255}; 1257};
1256 1258
1259static void imx6_pcie_quirk(struct pci_dev *dev)
1260{
1261 struct pci_bus *bus = dev->bus;
1262 struct pcie_port *pp = bus->sysdata;
1263
1264 /* Bus parent is the PCI bridge, its parent is this platform driver */
1265 if (!bus->dev.parent || !bus->dev.parent->parent)
1266 return;
1267
1268 /* Make sure we only quirk devices associated with this driver */
1269 if (bus->dev.parent->parent->driver != &imx6_pcie_driver.driver)
1270 return;
1271
1272 if (bus->number == pp->root_bus_nr) {
1273 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1274 struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
1275
1276 /*
1277 * Limit config length to avoid the kernel reading beyond
1278 * the register set and causing an abort on i.MX 6Quad
1279 */
1280 if (imx6_pcie->drvdata->dbi_length) {
1281 dev->cfg_size = imx6_pcie->drvdata->dbi_length;
1282 dev_info(&dev->dev, "Limiting cfg_size to %d\n",
1283 dev->cfg_size);
1284 }
1285 }
1286}
1287DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_SYNOPSYS, 0xabcd,
1288 PCI_CLASS_BRIDGE_PCI, 8, imx6_pcie_quirk);
1289
1257static int __init imx6_pcie_init(void) 1290static int __init imx6_pcie_init(void)
1258{ 1291{
1259#ifdef CONFIG_ARM 1292#ifdef CONFIG_ARM