diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-30 18:08:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-30 18:08:38 -0400 |
commit | d4562267b995fa3917717cc7773dad9c1f1ca658 (patch) | |
tree | 53fa59669e1531acb084f21470fbf2e9271f656b | |
parent | 89970a04d70c6c9e5e4492fd4096c0b5630a478c (diff) | |
parent | 9abb27c7594a62bbf6385e20b7f5a90b4eceae2f (diff) |
Merge tag 'pci-v4.11-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI fixes from Bjorn Helgaas:
- fix iProc memory corruption
- fix ThunderX usage of unregistered PNP/ACPI ID
- fix ThunderX resource reservation on early firmware
* tag 'pci-v4.11-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
PCI: thunder-pem: Add legacy firmware support for Cavium ThunderX host controller
PCI: thunder-pem: Use Cavium assigned hardware ID for ThunderX host controller
PCI: iproc: Save host bridge window resource in struct iproc_pcie
-rw-r--r-- | drivers/pci/host/pci-thunder-pem.c | 58 | ||||
-rw-r--r-- | drivers/pci/host/pcie-iproc-bcma.c | 24 | ||||
-rw-r--r-- | drivers/pci/host/pcie-iproc-platform.c | 19 | ||||
-rw-r--r-- | drivers/pci/host/pcie-iproc.h | 1 |
4 files changed, 78 insertions, 24 deletions
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 52b5bdccf5f0..b89c373555c5 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * Copyright (C) 2015 - 2016 Cavium, Inc. | 14 | * Copyright (C) 2015 - 2016 Cavium, Inc. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bitfield.h> | ||
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
@@ -334,6 +335,50 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, | |||
334 | 335 | ||
335 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) | 336 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) |
336 | 337 | ||
338 | #define PEM_RES_BASE 0x87e0c0000000UL | ||
339 | #define PEM_NODE_MASK GENMASK(45, 44) | ||
340 | #define PEM_INDX_MASK GENMASK(26, 24) | ||
341 | #define PEM_MIN_DOM_IN_NODE 4 | ||
342 | #define PEM_MAX_DOM_IN_NODE 10 | ||
343 | |||
344 | static void thunder_pem_reserve_range(struct device *dev, int seg, | ||
345 | struct resource *r) | ||
346 | { | ||
347 | resource_size_t start = r->start, end = r->end; | ||
348 | struct resource *res; | ||
349 | const char *regionid; | ||
350 | |||
351 | regionid = kasprintf(GFP_KERNEL, "PEM RC:%d", seg); | ||
352 | if (!regionid) | ||
353 | return; | ||
354 | |||
355 | res = request_mem_region(start, end - start + 1, regionid); | ||
356 | if (res) | ||
357 | res->flags &= ~IORESOURCE_BUSY; | ||
358 | else | ||
359 | kfree(regionid); | ||
360 | |||
361 | dev_info(dev, "%pR %s reserved\n", r, | ||
362 | res ? "has been" : "could not be"); | ||
363 | } | ||
364 | |||
365 | static void thunder_pem_legacy_fw(struct acpi_pci_root *root, | ||
366 | struct resource *res_pem) | ||
367 | { | ||
368 | int node = acpi_get_node(root->device->handle); | ||
369 | int index; | ||
370 | |||
371 | if (node == NUMA_NO_NODE) | ||
372 | node = 0; | ||
373 | |||
374 | index = root->segment - PEM_MIN_DOM_IN_NODE; | ||
375 | index -= node * PEM_MAX_DOM_IN_NODE; | ||
376 | res_pem->start = PEM_RES_BASE | FIELD_PREP(PEM_NODE_MASK, node) | | ||
377 | FIELD_PREP(PEM_INDX_MASK, index); | ||
378 | res_pem->end = res_pem->start + SZ_16M - 1; | ||
379 | res_pem->flags = IORESOURCE_MEM; | ||
380 | } | ||
381 | |||
337 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) | 382 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) |
338 | { | 383 | { |
339 | struct device *dev = cfg->parent; | 384 | struct device *dev = cfg->parent; |
@@ -346,10 +391,17 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) | |||
346 | if (!res_pem) | 391 | if (!res_pem) |
347 | return -ENOMEM; | 392 | return -ENOMEM; |
348 | 393 | ||
349 | ret = acpi_get_rc_resources(dev, "THRX0002", root->segment, res_pem); | 394 | ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem); |
395 | |||
396 | /* | ||
397 | * If we fail to gather resources it means that we run with old | ||
398 | * FW where we need to calculate PEM-specific resources manually. | ||
399 | */ | ||
350 | if (ret) { | 400 | if (ret) { |
351 | dev_err(dev, "can't get rc base address\n"); | 401 | thunder_pem_legacy_fw(root, res_pem); |
352 | return ret; | 402 | /* Reserve PEM-specific resources and PCI configuration space */ |
403 | thunder_pem_reserve_range(dev, root->segment, res_pem); | ||
404 | thunder_pem_reserve_range(dev, root->segment, &cfg->res); | ||
353 | } | 405 | } |
354 | 406 | ||
355 | return thunder_pem_init(dev, cfg, res_pem); | 407 | return thunder_pem_init(dev, cfg, res_pem); |
diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c index bd4c9ec25edc..384c27e664fe 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/host/pcie-iproc-bcma.c | |||
@@ -44,8 +44,7 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) | |||
44 | { | 44 | { |
45 | struct device *dev = &bdev->dev; | 45 | struct device *dev = &bdev->dev; |
46 | struct iproc_pcie *pcie; | 46 | struct iproc_pcie *pcie; |
47 | LIST_HEAD(res); | 47 | LIST_HEAD(resources); |
48 | struct resource res_mem; | ||
49 | int ret; | 48 | int ret; |
50 | 49 | ||
51 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | 50 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); |
@@ -63,22 +62,23 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) | |||
63 | 62 | ||
64 | pcie->base_addr = bdev->addr; | 63 | pcie->base_addr = bdev->addr; |
65 | 64 | ||
66 | res_mem.start = bdev->addr_s[0]; | 65 | pcie->mem.start = bdev->addr_s[0]; |
67 | res_mem.end = bdev->addr_s[0] + SZ_128M - 1; | 66 | pcie->mem.end = bdev->addr_s[0] + SZ_128M - 1; |
68 | res_mem.name = "PCIe MEM space"; | 67 | pcie->mem.name = "PCIe MEM space"; |
69 | res_mem.flags = IORESOURCE_MEM; | 68 | pcie->mem.flags = IORESOURCE_MEM; |
70 | pci_add_resource(&res, &res_mem); | 69 | pci_add_resource(&resources, &pcie->mem); |
71 | 70 | ||
72 | pcie->map_irq = iproc_pcie_bcma_map_irq; | 71 | pcie->map_irq = iproc_pcie_bcma_map_irq; |
73 | 72 | ||
74 | ret = iproc_pcie_setup(pcie, &res); | 73 | ret = iproc_pcie_setup(pcie, &resources); |
75 | if (ret) | 74 | if (ret) { |
76 | dev_err(dev, "PCIe controller setup failed\n"); | 75 | dev_err(dev, "PCIe controller setup failed\n"); |
77 | 76 | pci_free_resource_list(&resources); | |
78 | pci_free_resource_list(&res); | 77 | return ret; |
78 | } | ||
79 | 79 | ||
80 | bcma_set_drvdata(bdev, pcie); | 80 | bcma_set_drvdata(bdev, pcie); |
81 | return ret; | 81 | return 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | static void iproc_pcie_bcma_remove(struct bcma_device *bdev) | 84 | static void iproc_pcie_bcma_remove(struct bcma_device *bdev) |
diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index f4909bb0b2ad..8c6a327ca6cd 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c | |||
@@ -51,7 +51,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
51 | struct device_node *np = dev->of_node; | 51 | struct device_node *np = dev->of_node; |
52 | struct resource reg; | 52 | struct resource reg; |
53 | resource_size_t iobase = 0; | 53 | resource_size_t iobase = 0; |
54 | LIST_HEAD(res); | 54 | LIST_HEAD(resources); |
55 | int ret; | 55 | int ret; |
56 | 56 | ||
57 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | 57 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); |
@@ -96,10 +96,10 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
96 | pcie->phy = NULL; | 96 | pcie->phy = NULL; |
97 | } | 97 | } |
98 | 98 | ||
99 | ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &iobase); | 99 | ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &resources, |
100 | &iobase); | ||
100 | if (ret) { | 101 | if (ret) { |
101 | dev_err(dev, | 102 | dev_err(dev, "unable to get PCI host bridge resources\n"); |
102 | "unable to get PCI host bridge resources\n"); | ||
103 | return ret; | 103 | return ret; |
104 | } | 104 | } |
105 | 105 | ||
@@ -112,14 +112,15 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) | |||
112 | pcie->map_irq = of_irq_parse_and_map_pci; | 112 | pcie->map_irq = of_irq_parse_and_map_pci; |
113 | } | 113 | } |
114 | 114 | ||
115 | ret = iproc_pcie_setup(pcie, &res); | 115 | ret = iproc_pcie_setup(pcie, &resources); |
116 | if (ret) | 116 | if (ret) { |
117 | dev_err(dev, "PCIe controller setup failed\n"); | 117 | dev_err(dev, "PCIe controller setup failed\n"); |
118 | 118 | pci_free_resource_list(&resources); | |
119 | pci_free_resource_list(&res); | 119 | return ret; |
120 | } | ||
120 | 121 | ||
121 | platform_set_drvdata(pdev, pcie); | 122 | platform_set_drvdata(pdev, pcie); |
122 | return ret; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
125 | static int iproc_pcie_pltfm_remove(struct platform_device *pdev) | 126 | static int iproc_pcie_pltfm_remove(struct platform_device *pdev) |
diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 04fed8e907f1..0bbe2ea44f3e 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h | |||
@@ -90,6 +90,7 @@ struct iproc_pcie { | |||
90 | #ifdef CONFIG_ARM | 90 | #ifdef CONFIG_ARM |
91 | struct pci_sys_data sysdata; | 91 | struct pci_sys_data sysdata; |
92 | #endif | 92 | #endif |
93 | struct resource mem; | ||
93 | struct pci_bus *root_bus; | 94 | struct pci_bus *root_bus; |
94 | struct phy *phy; | 95 | struct phy *phy; |
95 | int (*map_irq)(const struct pci_dev *, u8, u8); | 96 | int (*map_irq)(const struct pci_dev *, u8, u8); |