linux/drivers/pci/host/pci-host-generic.c
<<
>>
Prefs
   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
  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        .map_bus        = gen_pci_map_cfg_bus_cam,
  69};
  70
  71static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
  72                                              unsigned int devfn,
  73                                              int where)
  74{
  75        struct gen_pci *pci = bus->sysdata;
  76        resource_size_t idx = bus->number - pci->cfg.bus_range->start;
  77
  78        return pci->cfg.win[idx] + ((devfn << 12) | where);
  79}
  80
  81static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
  82        .bus_shift      = 20,
  83        .map_bus        = gen_pci_map_cfg_bus_ecam,
  84};
  85
  86static struct pci_ops gen_pci_ops = {
  87        .read   = pci_generic_config_read,
  88        .write  = pci_generic_config_write,
  89};
  90
  91static const struct of_device_id gen_pci_of_match[] = {
  92        { .compatible = "pci-host-cam-generic",
  93          .data = &gen_pci_cfg_cam_bus_ops },
  94
  95        { .compatible = "pci-host-ecam-generic",
  96          .data = &gen_pci_cfg_ecam_bus_ops },
  97
  98        { },
  99};
 100MODULE_DEVICE_TABLE(of, gen_pci_of_match);
 101
 102static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
 103{
 104        pci_free_resource_list(&pci->resources);
 105}
 106
 107static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
 108{
 109        int err, res_valid = 0;
 110        struct device *dev = pci->host.dev.parent;
 111        struct device_node *np = dev->of_node;
 112        resource_size_t iobase;
 113        struct resource_entry *win;
 114
 115        err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
 116                                               &iobase);
 117        if (err)
 118                return err;
 119
 120        resource_list_for_each_entry(win, &pci->resources) {
 121                struct resource *parent, *res = win->res;
 122
 123                switch (resource_type(res)) {
 124                case IORESOURCE_IO:
 125                        parent = &ioport_resource;
 126                        err = pci_remap_iospace(res, iobase);
 127                        if (err) {
 128                                dev_warn(dev, "error %d: failed to map resource %pR\n",
 129                                         err, res);
 130                                continue;
 131                        }
 132                        break;
 133                case IORESOURCE_MEM:
 134                        parent = &iomem_resource;
 135                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
 136                        break;
 137                case IORESOURCE_BUS:
 138                        pci->cfg.bus_range = res;
 139                default:
 140                        continue;
 141                }
 142
 143                err = devm_request_resource(dev, parent, res);
 144                if (err)
 145                        goto out_release_res;
 146        }
 147
 148        if (!res_valid) {
 149                dev_err(dev, "non-prefetchable memory resource required\n");
 150                err = -EINVAL;
 151                goto out_release_res;
 152        }
 153
 154        return 0;
 155
 156out_release_res:
 157        gen_pci_release_of_pci_ranges(pci);
 158        return err;
 159}
 160
 161static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
 162{
 163        int err;
 164        u8 bus_max;
 165        resource_size_t busn;
 166        struct resource *bus_range;
 167        struct device *dev = pci->host.dev.parent;
 168        struct device_node *np = dev->of_node;
 169
 170        err = of_address_to_resource(np, 0, &pci->cfg.res);
 171        if (err) {
 172                dev_err(dev, "missing \"reg\" property\n");
 173                return err;
 174        }
 175
 176        /* Limit the bus-range to fit within reg */
 177        bus_max = pci->cfg.bus_range->start +
 178                  (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
 179        pci->cfg.bus_range->end = min_t(resource_size_t,
 180                                        pci->cfg.bus_range->end, bus_max);
 181
 182        pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
 183                                    sizeof(*pci->cfg.win), GFP_KERNEL);
 184        if (!pci->cfg.win)
 185                return -ENOMEM;
 186
 187        /* Map our Configuration Space windows */
 188        if (!devm_request_mem_region(dev, pci->cfg.res.start,
 189                                     resource_size(&pci->cfg.res),
 190                                     "Configuration Space"))
 191                return -ENOMEM;
 192
 193        bus_range = pci->cfg.bus_range;
 194        for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
 195                u32 idx = busn - bus_range->start;
 196                u32 sz = 1 << pci->cfg.ops->bus_shift;
 197
 198                pci->cfg.win[idx] = devm_ioremap(dev,
 199                                                 pci->cfg.res.start + busn * sz,
 200                                                 sz);
 201                if (!pci->cfg.win[idx])
 202                        return -ENOMEM;
 203        }
 204
 205        return 0;
 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 pci_bus *bus, *child;
 218
 219        if (!pci)
 220                return -ENOMEM;
 221
 222        type = of_get_property(np, "device_type", NULL);
 223        if (!type || strcmp(type, "pci")) {
 224                dev_err(dev, "invalid \"device_type\" %s\n", type);
 225                return -EINVAL;
 226        }
 227
 228        prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
 229        if (prop) {
 230                if (*prop)
 231                        pci_add_flags(PCI_PROBE_ONLY);
 232                else
 233                        pci_clear_flags(PCI_PROBE_ONLY);
 234        }
 235
 236        of_id = of_match_node(gen_pci_of_match, np);
 237        pci->cfg.ops = of_id->data;
 238        gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
 239        pci->host.dev.parent = dev;
 240        INIT_LIST_HEAD(&pci->host.windows);
 241        INIT_LIST_HEAD(&pci->resources);
 242
 243        /* Parse our PCI ranges and request their resources */
 244        err = gen_pci_parse_request_of_pci_ranges(pci);
 245        if (err)
 246                return err;
 247
 248        /* Parse and map our Configuration Space windows */
 249        err = gen_pci_parse_map_cfg_windows(pci);
 250        if (err) {
 251                gen_pci_release_of_pci_ranges(pci);
 252                return err;
 253        }
 254
 255        /* Do not reassign resources if probe only */
 256        if (!pci_has_flag(PCI_PROBE_ONLY))
 257                pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
 258
 259        bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources);
 260        if (!bus) {
 261                dev_err(dev, "Scanning rootbus failed");
 262                return -ENODEV;
 263        }
 264
 265        pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
 266
 267        if (!pci_has_flag(PCI_PROBE_ONLY)) {
 268                pci_bus_size_bridges(bus);
 269                pci_bus_assign_resources(bus);
 270
 271                list_for_each_entry(child, &bus->children, node)
 272                        pcie_bus_configure_settings(child);
 273        }
 274
 275        pci_bus_add_devices(bus);
 276        return 0;
 277}
 278
 279static struct platform_driver gen_pci_driver = {
 280        .driver = {
 281                .name = "pci-host-generic",
 282                .of_match_table = gen_pci_of_match,
 283        },
 284        .probe = gen_pci_probe,
 285};
 286module_platform_driver(gen_pci_driver);
 287
 288MODULE_DESCRIPTION("Generic PCI host driver");
 289MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
 290MODULE_LICENSE("GPL v2");
 291