1/* 2 * Simple, generic PCI host controller driver targetting firmware-initialised 3 * systems and virtual machines (e.g. the PCI emulation provided by kvmtool). 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * 17 * Copyright (C) 2014 ARM Limited 18 * 19 * Author: Will Deacon <will.deacon@arm.com> 20 */ 21 22#include <linux/kernel.h> 23#include <linux/module.h> 24#include <linux/of_address.h> 25#include <linux/of_pci.h> 26#include <linux/platform_device.h> 27 28struct gen_pci_cfg_bus_ops { 29 u32 bus_shift; 30 struct pci_ops ops; 31}; 32 33struct gen_pci_cfg_windows { 34 struct resource res; 35 struct resource *bus_range; 36 void __iomem **win; 37 38 struct gen_pci_cfg_bus_ops *ops; 39}; 40 41/* 42 * ARM pcibios functions expect the ARM struct pci_sys_data as the PCI 43 * sysdata. Add pci_sys_data as the first element in struct gen_pci so 44 * that when we use a gen_pci pointer as sysdata, it is also a pointer to 45 * a struct pci_sys_data. 46 */ 47struct gen_pci { 48#ifdef CONFIG_ARM 49 struct pci_sys_data sys; 50#endif 51 struct pci_host_bridge host; 52 struct gen_pci_cfg_windows cfg; 53 struct list_head resources; 54}; 55 56static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, 57 unsigned int devfn, 58 int where) 59{ 60 struct gen_pci *pci = bus->sysdata; 61 resource_size_t idx = bus->number - pci->cfg.bus_range->start; 62 63 return pci->cfg.win[idx] + ((devfn << 8) | where); 64} 65 66static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = { 67 .bus_shift = 16, 68 .ops = { 69 .map_bus = gen_pci_map_cfg_bus_cam, 70 .read = pci_generic_config_read, 71 .write = pci_generic_config_write, 72 } 73}; 74 75static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, 76 unsigned int devfn, 77 int where) 78{ 79 struct gen_pci *pci = bus->sysdata; 80 resource_size_t idx = bus->number - pci->cfg.bus_range->start; 81 82 return pci->cfg.win[idx] + ((devfn << 12) | where); 83} 84 85static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = { 86 .bus_shift = 20, 87 .ops = { 88 .map_bus = gen_pci_map_cfg_bus_ecam, 89 .read = pci_generic_config_read, 90 .write = pci_generic_config_write, 91 } 92}; 93 94static const struct of_device_id gen_pci_of_match[] = { 95 { .compatible = "pci-host-cam-generic", 96 .data = &gen_pci_cfg_cam_bus_ops }, 97 98 { .compatible = "pci-host-ecam-generic", 99 .data = &gen_pci_cfg_ecam_bus_ops }, 100 101 { }, 102}; 103MODULE_DEVICE_TABLE(of, gen_pci_of_match); 104 105static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) 106{ 107 pci_free_resource_list(&pci->resources); 108} 109 110static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) 111{ 112 int err, res_valid = 0; 113 struct device *dev = pci->host.dev.parent; 114 struct device_node *np = dev->of_node; 115 resource_size_t iobase; 116 struct resource_entry *win; 117 118 err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, 119 &iobase); 120 if (err) 121 return err; 122 123 resource_list_for_each_entry(win, &pci->resources) { 124 struct resource *parent, *res = win->res; 125 126 switch (resource_type(res)) { 127 case IORESOURCE_IO: 128 parent = &ioport_resource; 129 err = pci_remap_iospace(res, iobase); 130 if (err) { 131 dev_warn(dev, "error %d: failed to map resource %pR\n", 132 err, res); 133 continue; 134 } 135 break; 136 case IORESOURCE_MEM: 137 parent = &iomem_resource; 138 res_valid |= !(res->flags & IORESOURCE_PREFETCH); 139 break; 140 case IORESOURCE_BUS: 141 pci->cfg.bus_range = res; 142 default: 143 continue; 144 } 145 146 err = devm_request_resource(dev, parent, res); 147 if (err) 148 goto out_release_res; 149 } 150 151 if (!res_valid) { 152 dev_err(dev, "non-prefetchable memory resource required\n"); 153 err = -EINVAL; 154 goto out_release_res; 155 } 156 157 return 0; 158 159out_release_res: 160 gen_pci_release_of_pci_ranges(pci); 161 return err; 162} 163 164static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 165{ 166 int err; 167 u8 bus_max; 168 resource_size_t busn; 169 struct resource *bus_range; 170 struct device *dev = pci->host.dev.parent; 171 struct device_node *np = dev->of_node; 172 u32 sz = 1 << pci->cfg.ops->bus_shift; 173 174 err = of_address_to_resource(np, 0, &pci->cfg.res); 175 if (err) { 176 dev_err(dev, "missing \"reg\" property\n"); 177 return err; 178 } 179 180 /* Limit the bus-range to fit within reg */ 181 bus_max = pci->cfg.bus_range->start + 182 (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; 183 pci->cfg.bus_range->end = min_t(resource_size_t, 184 pci->cfg.bus_range->end, bus_max); 185 186 pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), 187 sizeof(*pci->cfg.win), GFP_KERNEL); 188 if (!pci->cfg.win) 189 return -ENOMEM; 190 191 /* Map our Configuration Space windows */ 192 if (!devm_request_mem_region(dev, pci->cfg.res.start, 193 resource_size(&pci->cfg.res), 194 "Configuration Space")) 195 return -ENOMEM; 196 197 bus_range = pci->cfg.bus_range; 198 for (busn = bus_range->start; busn <= bus_range->end; ++busn) { 199 u32 idx = busn - bus_range->start; 200 201 pci->cfg.win[idx] = devm_ioremap(dev, 202 pci->cfg.res.start + idx * sz, 203 sz); 204 if (!pci->cfg.win[idx]) 205 return -ENOMEM; 206 } 207 208 return 0; 209} 210 211static int gen_pci_probe(struct platform_device *pdev) 212{ 213 int err; 214 const char *type; 215 const struct of_device_id *of_id; 216 struct device *dev = &pdev->dev; 217 struct device_node *np = dev->of_node; 218 struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 219 struct pci_bus *bus, *child; 220 221 if (!pci) 222 return -ENOMEM; 223 224 type = of_get_property(np, "device_type", NULL); 225 if (!type || strcmp(type, "pci")) { 226 dev_err(dev, "invalid \"device_type\" %s\n", type); 227 return -EINVAL; 228 } 229 230 of_pci_check_probe_only(); 231 232 of_id = of_match_node(gen_pci_of_match, np); 233 pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data; 234 pci->host.dev.parent = dev; 235 INIT_LIST_HEAD(&pci->host.windows); 236 INIT_LIST_HEAD(&pci->resources); 237 238 /* Parse our PCI ranges and request their resources */ 239 err = gen_pci_parse_request_of_pci_ranges(pci); 240 if (err) 241 return err; 242 243 /* Parse and map our Configuration Space windows */ 244 err = gen_pci_parse_map_cfg_windows(pci); 245 if (err) { 246 gen_pci_release_of_pci_ranges(pci); 247 return err; 248 } 249 250 /* Do not reassign resources if probe only */ 251 if (!pci_has_flag(PCI_PROBE_ONLY)) 252 pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); 253 254 255 bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start, 256 &pci->cfg.ops->ops, pci, &pci->resources); 257 if (!bus) { 258 dev_err(dev, "Scanning rootbus failed"); 259 return -ENODEV; 260 } 261 262 pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); 263 264 if (!pci_has_flag(PCI_PROBE_ONLY)) { 265 pci_bus_size_bridges(bus); 266 pci_bus_assign_resources(bus); 267 268 list_for_each_entry(child, &bus->children, node) 269 pcie_bus_configure_settings(child); 270 } 271 272 pci_bus_add_devices(bus); 273 return 0; 274} 275 276static struct platform_driver gen_pci_driver = { 277 .driver = { 278 .name = "pci-host-generic", 279 .of_match_table = gen_pci_of_match, 280 }, 281 .probe = gen_pci_probe, 282}; 283module_platform_driver(gen_pci_driver); 284 285MODULE_DESCRIPTION("Generic PCI host driver"); 286MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); 287MODULE_LICENSE("GPL v2"); 288