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 void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int); 31}; 32 33struct gen_pci_cfg_windows { 34 struct resource res; 35 struct resource *bus_range; 36 void __iomem **win; 37 38 const struct gen_pci_cfg_bus_ops *ops; 39}; 40 41struct gen_pci { 42 struct pci_host_bridge host; 43 struct gen_pci_cfg_windows cfg; 44 struct list_head resources; 45}; 46 47static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, 48 unsigned int devfn, 49 int where) 50{ 51 struct pci_sys_data *sys = bus->sysdata; 52 struct gen_pci *pci = sys->private_data; 53 resource_size_t idx = bus->number - pci->cfg.bus_range->start; 54 55 return pci->cfg.win[idx] + ((devfn << 8) | where); 56} 57 58static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = { 59 .bus_shift = 16, 60 .map_bus = gen_pci_map_cfg_bus_cam, 61}; 62 63static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, 64 unsigned int devfn, 65 int where) 66{ 67 struct pci_sys_data *sys = bus->sysdata; 68 struct gen_pci *pci = sys->private_data; 69 resource_size_t idx = bus->number - pci->cfg.bus_range->start; 70 71 return pci->cfg.win[idx] + ((devfn << 12) | where); 72} 73 74static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = { 75 .bus_shift = 20, 76 .map_bus = gen_pci_map_cfg_bus_ecam, 77}; 78 79static struct pci_ops gen_pci_ops = { 80 .read = pci_generic_config_read, 81 .write = pci_generic_config_write, 82}; 83 84static const struct of_device_id gen_pci_of_match[] = { 85 { .compatible = "pci-host-cam-generic", 86 .data = &gen_pci_cfg_cam_bus_ops }, 87 88 { .compatible = "pci-host-ecam-generic", 89 .data = &gen_pci_cfg_ecam_bus_ops }, 90 91 { }, 92}; 93MODULE_DEVICE_TABLE(of, gen_pci_of_match); 94 95static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) 96{ 97 pci_free_resource_list(&pci->resources); 98} 99 100static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) 101{ 102 int err, res_valid = 0; 103 struct device *dev = pci->host.dev.parent; 104 struct device_node *np = dev->of_node; 105 resource_size_t iobase; 106 struct resource_entry *win; 107 108 err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, 109 &iobase); 110 if (err) 111 return err; 112 113 resource_list_for_each_entry(win, &pci->resources) { 114 struct resource *parent, *res = win->res; 115 116 switch (resource_type(res)) { 117 case IORESOURCE_IO: 118 parent = &ioport_resource; 119 err = pci_remap_iospace(res, iobase); 120 if (err) { 121 dev_warn(dev, "error %d: failed to map resource %pR\n", 122 err, res); 123 continue; 124 } 125 break; 126 case IORESOURCE_MEM: 127 parent = &iomem_resource; 128 res_valid |= !(res->flags & IORESOURCE_PREFETCH); 129 break; 130 case IORESOURCE_BUS: 131 pci->cfg.bus_range = res; 132 default: 133 continue; 134 } 135 136 err = devm_request_resource(dev, parent, res); 137 if (err) 138 goto out_release_res; 139 } 140 141 if (!res_valid) { 142 dev_err(dev, "non-prefetchable memory resource required\n"); 143 err = -EINVAL; 144 goto out_release_res; 145 } 146 147 return 0; 148 149out_release_res: 150 gen_pci_release_of_pci_ranges(pci); 151 return err; 152} 153 154static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 155{ 156 int err; 157 u8 bus_max; 158 resource_size_t busn; 159 struct resource *bus_range; 160 struct device *dev = pci->host.dev.parent; 161 struct device_node *np = dev->of_node; 162 163 err = of_address_to_resource(np, 0, &pci->cfg.res); 164 if (err) { 165 dev_err(dev, "missing \"reg\" property\n"); 166 return err; 167 } 168 169 /* Limit the bus-range to fit within reg */ 170 bus_max = pci->cfg.bus_range->start + 171 (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; 172 pci->cfg.bus_range->end = min_t(resource_size_t, 173 pci->cfg.bus_range->end, bus_max); 174 175 pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), 176 sizeof(*pci->cfg.win), GFP_KERNEL); 177 if (!pci->cfg.win) 178 return -ENOMEM; 179 180 /* Map our Configuration Space windows */ 181 if (!devm_request_mem_region(dev, pci->cfg.res.start, 182 resource_size(&pci->cfg.res), 183 "Configuration Space")) 184 return -ENOMEM; 185 186 bus_range = pci->cfg.bus_range; 187 for (busn = bus_range->start; busn <= bus_range->end; ++busn) { 188 u32 idx = busn - bus_range->start; 189 u32 sz = 1 << pci->cfg.ops->bus_shift; 190 191 pci->cfg.win[idx] = devm_ioremap(dev, 192 pci->cfg.res.start + busn * sz, 193 sz); 194 if (!pci->cfg.win[idx]) 195 return -ENOMEM; 196 } 197 198 return 0; 199} 200 201static int gen_pci_setup(int nr, struct pci_sys_data *sys) 202{ 203 struct gen_pci *pci = sys->private_data; 204 list_splice_init(&pci->resources, &sys->resources); 205 return 1; 206} 207 208static int gen_pci_probe(struct platform_device *pdev) 209{ 210 int err; 211 const char *type; 212 const struct of_device_id *of_id; 213 const int *prop; 214 struct device *dev = &pdev->dev; 215 struct device_node *np = dev->of_node; 216 struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 217 struct hw_pci hw = { 218 .nr_controllers = 1, 219 .private_data = (void **)&pci, 220 .setup = gen_pci_setup, 221 .map_irq = of_irq_parse_and_map_pci, 222 .ops = &gen_pci_ops, 223 }; 224 225 if (!pci) 226 return -ENOMEM; 227 228 type = of_get_property(np, "device_type", NULL); 229 if (!type || strcmp(type, "pci")) { 230 dev_err(dev, "invalid \"device_type\" %s\n", type); 231 return -EINVAL; 232 } 233 234 prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL); 235 if (prop) { 236 if (*prop) 237 pci_add_flags(PCI_PROBE_ONLY); 238 else 239 pci_clear_flags(PCI_PROBE_ONLY); 240 } 241 242 of_id = of_match_node(gen_pci_of_match, np); 243 pci->cfg.ops = of_id->data; 244 gen_pci_ops.map_bus = pci->cfg.ops->map_bus; 245 pci->host.dev.parent = dev; 246 INIT_LIST_HEAD(&pci->host.windows); 247 INIT_LIST_HEAD(&pci->resources); 248 249 /* Parse our PCI ranges and request their resources */ 250 err = gen_pci_parse_request_of_pci_ranges(pci); 251 if (err) 252 return err; 253 254 /* Parse and map our Configuration Space windows */ 255 err = gen_pci_parse_map_cfg_windows(pci); 256 if (err) { 257 gen_pci_release_of_pci_ranges(pci); 258 return err; 259 } 260 261 pci_common_init_dev(dev, &hw); 262 return 0; 263} 264 265static struct platform_driver gen_pci_driver = { 266 .driver = { 267 .name = "pci-host-generic", 268 .of_match_table = gen_pci_of_match, 269 }, 270 .probe = gen_pci_probe, 271}; 272module_platform_driver(gen_pci_driver); 273 274MODULE_DESCRIPTION("Generic PCI host driver"); 275MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); 276MODULE_LICENSE("GPL v2"); 277