Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: generic: Expose pci_host_common_probe() for use by other drivers

Move pci_host_common_probe() and associated functions to pci-host-common.c,
where it can be shared with other drivers. Make it public (not static)
and update Kconfig and Makefile to build it. No functional change
intended.

[bhelgaas: split into separate patch, changelog]
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Will Deacon <will.deacon@arm.com>

authored by

David Daney and committed by
Bjorn Helgaas
4e64dbe2 d51b3710

+203 -165
+1
MAINTAINERS
··· 8373 8373 L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 8374 8374 S: Maintained 8375 8375 F: Documentation/devicetree/bindings/pci/host-generic-pci.txt 8376 + F: drivers/pci/host/pci-host-common.c 8376 8377 F: drivers/pci/host/pci-host-generic.c 8377 8378 8378 8379 PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
+4
drivers/pci/host/Kconfig
··· 53 53 help 54 54 Say Y here if you want PCIe controller support on R-Car Gen2 SoCs. 55 55 56 + config PCI_HOST_COMMON 57 + bool 58 + 56 59 config PCI_HOST_GENERIC 57 60 bool "Generic PCI host controller" 58 61 depends on (ARM || ARM64) && OF 62 + select PCI_HOST_COMMON 59 63 help 60 64 Say Y here if you want to support a simple generic PCI host 61 65 controller, such as the one emulated by kvmtool.
+1
drivers/pci/host/Makefile
··· 6 6 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o 7 7 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o 8 8 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o 9 + obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o 9 10 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o 10 11 obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o 11 12 obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
+194
drivers/pci/host/pci-host-common.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License version 2 as 4 + * published by the Free Software Foundation. 5 + * 6 + * This program is distributed in the hope that it will be useful, 7 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 + * GNU General Public License for more details. 10 + * 11 + * You should have received a copy of the GNU General Public License 12 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 13 + * 14 + * Copyright (C) 2014 ARM Limited 15 + * 16 + * Author: Will Deacon <will.deacon@arm.com> 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/of_address.h> 22 + #include <linux/of_pci.h> 23 + #include <linux/platform_device.h> 24 + 25 + #include "pci-host-common.h" 26 + 27 + static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) 28 + { 29 + pci_free_resource_list(&pci->resources); 30 + } 31 + 32 + static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) 33 + { 34 + int err, res_valid = 0; 35 + struct device *dev = pci->host.dev.parent; 36 + struct device_node *np = dev->of_node; 37 + resource_size_t iobase; 38 + struct resource_entry *win; 39 + 40 + err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, 41 + &iobase); 42 + if (err) 43 + return err; 44 + 45 + resource_list_for_each_entry(win, &pci->resources) { 46 + struct resource *parent, *res = win->res; 47 + 48 + switch (resource_type(res)) { 49 + case IORESOURCE_IO: 50 + parent = &ioport_resource; 51 + err = pci_remap_iospace(res, iobase); 52 + if (err) { 53 + dev_warn(dev, "error %d: failed to map resource %pR\n", 54 + err, res); 55 + continue; 56 + } 57 + break; 58 + case IORESOURCE_MEM: 59 + parent = &iomem_resource; 60 + res_valid |= !(res->flags & IORESOURCE_PREFETCH); 61 + break; 62 + case IORESOURCE_BUS: 63 + pci->cfg.bus_range = res; 64 + default: 65 + continue; 66 + } 67 + 68 + err = devm_request_resource(dev, parent, res); 69 + if (err) 70 + goto out_release_res; 71 + } 72 + 73 + if (!res_valid) { 74 + dev_err(dev, "non-prefetchable memory resource required\n"); 75 + err = -EINVAL; 76 + goto out_release_res; 77 + } 78 + 79 + return 0; 80 + 81 + out_release_res: 82 + gen_pci_release_of_pci_ranges(pci); 83 + return err; 84 + } 85 + 86 + static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 87 + { 88 + int err; 89 + u8 bus_max; 90 + resource_size_t busn; 91 + struct resource *bus_range; 92 + struct device *dev = pci->host.dev.parent; 93 + struct device_node *np = dev->of_node; 94 + u32 sz = 1 << pci->cfg.ops->bus_shift; 95 + 96 + err = of_address_to_resource(np, 0, &pci->cfg.res); 97 + if (err) { 98 + dev_err(dev, "missing \"reg\" property\n"); 99 + return err; 100 + } 101 + 102 + /* Limit the bus-range to fit within reg */ 103 + bus_max = pci->cfg.bus_range->start + 104 + (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; 105 + pci->cfg.bus_range->end = min_t(resource_size_t, 106 + pci->cfg.bus_range->end, bus_max); 107 + 108 + pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), 109 + sizeof(*pci->cfg.win), GFP_KERNEL); 110 + if (!pci->cfg.win) 111 + return -ENOMEM; 112 + 113 + /* Map our Configuration Space windows */ 114 + if (!devm_request_mem_region(dev, pci->cfg.res.start, 115 + resource_size(&pci->cfg.res), 116 + "Configuration Space")) 117 + return -ENOMEM; 118 + 119 + bus_range = pci->cfg.bus_range; 120 + for (busn = bus_range->start; busn <= bus_range->end; ++busn) { 121 + u32 idx = busn - bus_range->start; 122 + 123 + pci->cfg.win[idx] = devm_ioremap(dev, 124 + pci->cfg.res.start + idx * sz, 125 + sz); 126 + if (!pci->cfg.win[idx]) 127 + return -ENOMEM; 128 + } 129 + 130 + return 0; 131 + } 132 + 133 + int pci_host_common_probe(struct platform_device *pdev, 134 + struct gen_pci *pci) 135 + { 136 + int err; 137 + const char *type; 138 + struct device *dev = &pdev->dev; 139 + struct device_node *np = dev->of_node; 140 + struct pci_bus *bus, *child; 141 + 142 + type = of_get_property(np, "device_type", NULL); 143 + if (!type || strcmp(type, "pci")) { 144 + dev_err(dev, "invalid \"device_type\" %s\n", type); 145 + return -EINVAL; 146 + } 147 + 148 + of_pci_check_probe_only(); 149 + 150 + pci->host.dev.parent = dev; 151 + INIT_LIST_HEAD(&pci->host.windows); 152 + INIT_LIST_HEAD(&pci->resources); 153 + 154 + /* Parse our PCI ranges and request their resources */ 155 + err = gen_pci_parse_request_of_pci_ranges(pci); 156 + if (err) 157 + return err; 158 + 159 + /* Parse and map our Configuration Space windows */ 160 + err = gen_pci_parse_map_cfg_windows(pci); 161 + if (err) { 162 + gen_pci_release_of_pci_ranges(pci); 163 + return err; 164 + } 165 + 166 + /* Do not reassign resources if probe only */ 167 + if (!pci_has_flag(PCI_PROBE_ONLY)) 168 + pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); 169 + 170 + 171 + bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start, 172 + &pci->cfg.ops->ops, pci, &pci->resources); 173 + if (!bus) { 174 + dev_err(dev, "Scanning rootbus failed"); 175 + return -ENODEV; 176 + } 177 + 178 + pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); 179 + 180 + if (!pci_has_flag(PCI_PROBE_ONLY)) { 181 + pci_bus_size_bridges(bus); 182 + pci_bus_assign_resources(bus); 183 + 184 + list_for_each_entry(child, &bus->children, node) 185 + pcie_bus_configure_settings(child); 186 + } 187 + 188 + pci_bus_add_devices(bus); 189 + return 0; 190 + } 191 + 192 + MODULE_DESCRIPTION("Generic PCI host driver common code"); 193 + MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); 194 + MODULE_LICENSE("GPL v2");
+3
drivers/pci/host/pci-host-common.h
··· 41 41 struct list_head resources; 42 42 }; 43 43 44 + int pci_host_common_probe(struct platform_device *pdev, 45 + struct gen_pci *pci); 46 + 44 47 #endif /* _PCI_HOST_COMMON_H */
-165
drivers/pci/host/pci-host-generic.c
··· 76 76 }; 77 77 MODULE_DEVICE_TABLE(of, gen_pci_of_match); 78 78 79 - static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) 80 - { 81 - pci_free_resource_list(&pci->resources); 82 - } 83 - 84 - static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) 85 - { 86 - int err, res_valid = 0; 87 - struct device *dev = pci->host.dev.parent; 88 - struct device_node *np = dev->of_node; 89 - resource_size_t iobase; 90 - struct resource_entry *win; 91 - 92 - err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, 93 - &iobase); 94 - if (err) 95 - return err; 96 - 97 - resource_list_for_each_entry(win, &pci->resources) { 98 - struct resource *parent, *res = win->res; 99 - 100 - switch (resource_type(res)) { 101 - case IORESOURCE_IO: 102 - parent = &ioport_resource; 103 - err = pci_remap_iospace(res, iobase); 104 - if (err) { 105 - dev_warn(dev, "error %d: failed to map resource %pR\n", 106 - err, res); 107 - continue; 108 - } 109 - break; 110 - case IORESOURCE_MEM: 111 - parent = &iomem_resource; 112 - res_valid |= !(res->flags & IORESOURCE_PREFETCH); 113 - break; 114 - case IORESOURCE_BUS: 115 - pci->cfg.bus_range = res; 116 - default: 117 - continue; 118 - } 119 - 120 - err = devm_request_resource(dev, parent, res); 121 - if (err) 122 - goto out_release_res; 123 - } 124 - 125 - if (!res_valid) { 126 - dev_err(dev, "non-prefetchable memory resource required\n"); 127 - err = -EINVAL; 128 - goto out_release_res; 129 - } 130 - 131 - return 0; 132 - 133 - out_release_res: 134 - gen_pci_release_of_pci_ranges(pci); 135 - return err; 136 - } 137 - 138 - static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 139 - { 140 - int err; 141 - u8 bus_max; 142 - resource_size_t busn; 143 - struct resource *bus_range; 144 - struct device *dev = pci->host.dev.parent; 145 - struct device_node *np = dev->of_node; 146 - u32 sz = 1 << pci->cfg.ops->bus_shift; 147 - 148 - err = of_address_to_resource(np, 0, &pci->cfg.res); 149 - if (err) { 150 - dev_err(dev, "missing \"reg\" property\n"); 151 - return err; 152 - } 153 - 154 - /* Limit the bus-range to fit within reg */ 155 - bus_max = pci->cfg.bus_range->start + 156 - (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; 157 - pci->cfg.bus_range->end = min_t(resource_size_t, 158 - pci->cfg.bus_range->end, bus_max); 159 - 160 - pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), 161 - sizeof(*pci->cfg.win), GFP_KERNEL); 162 - if (!pci->cfg.win) 163 - return -ENOMEM; 164 - 165 - /* Map our Configuration Space windows */ 166 - if (!devm_request_mem_region(dev, pci->cfg.res.start, 167 - resource_size(&pci->cfg.res), 168 - "Configuration Space")) 169 - return -ENOMEM; 170 - 171 - bus_range = pci->cfg.bus_range; 172 - for (busn = bus_range->start; busn <= bus_range->end; ++busn) { 173 - u32 idx = busn - bus_range->start; 174 - 175 - pci->cfg.win[idx] = devm_ioremap(dev, 176 - pci->cfg.res.start + idx * sz, 177 - sz); 178 - if (!pci->cfg.win[idx]) 179 - return -ENOMEM; 180 - } 181 - 182 - return 0; 183 - } 184 - 185 - static int pci_host_common_probe(struct platform_device *pdev, 186 - struct gen_pci *pci) 187 - { 188 - int err; 189 - const char *type; 190 - struct device *dev = &pdev->dev; 191 - struct device_node *np = dev->of_node; 192 - struct pci_bus *bus, *child; 193 - 194 - type = of_get_property(np, "device_type", NULL); 195 - if (!type || strcmp(type, "pci")) { 196 - dev_err(dev, "invalid \"device_type\" %s\n", type); 197 - return -EINVAL; 198 - } 199 - 200 - of_pci_check_probe_only(); 201 - 202 - pci->host.dev.parent = dev; 203 - INIT_LIST_HEAD(&pci->host.windows); 204 - INIT_LIST_HEAD(&pci->resources); 205 - 206 - /* Parse our PCI ranges and request their resources */ 207 - err = gen_pci_parse_request_of_pci_ranges(pci); 208 - if (err) 209 - return err; 210 - 211 - /* Parse and map our Configuration Space windows */ 212 - err = gen_pci_parse_map_cfg_windows(pci); 213 - if (err) { 214 - gen_pci_release_of_pci_ranges(pci); 215 - return err; 216 - } 217 - 218 - /* Do not reassign resources if probe only */ 219 - if (!pci_has_flag(PCI_PROBE_ONLY)) 220 - pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); 221 - 222 - 223 - bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start, 224 - &pci->cfg.ops->ops, pci, &pci->resources); 225 - if (!bus) { 226 - dev_err(dev, "Scanning rootbus failed"); 227 - return -ENODEV; 228 - } 229 - 230 - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); 231 - 232 - if (!pci_has_flag(PCI_PROBE_ONLY)) { 233 - pci_bus_size_bridges(bus); 234 - pci_bus_assign_resources(bus); 235 - 236 - list_for_each_entry(child, &bus->children, node) 237 - pcie_bus_configure_settings(child); 238 - } 239 - 240 - pci_bus_add_devices(bus); 241 - return 0; 242 - } 243 - 244 79 static int gen_pci_probe(struct platform_device *pdev) 245 80 { 246 81 struct device *dev = &pdev->dev;