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
  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 int gen_pci_config_read(struct pci_bus *bus, unsigned int devfn,
  80                                int where, int size, u32 *val)
  81{
  82        void __iomem *addr;
  83        struct pci_sys_data *sys = bus->sysdata;
  84        struct gen_pci *pci = sys->private_data;
  85
  86        addr = pci->cfg.ops->map_bus(bus, devfn, where);
  87
  88        switch (size) {
  89        case 1:
  90                *val = readb(addr);
  91                break;
  92        case 2:
  93                *val = readw(addr);
  94                break;
  95        default:
  96                *val = readl(addr);
  97        }
  98
  99        return PCIBIOS_SUCCESSFUL;
 100}
 101
 102static int gen_pci_config_write(struct pci_bus *bus, unsigned int devfn,
 103                                 int where, int size, u32 val)
 104{
 105        void __iomem *addr;
 106        struct pci_sys_data *sys = bus->sysdata;
 107        struct gen_pci *pci = sys->private_data;
 108
 109        addr = pci->cfg.ops->map_bus(bus, devfn, where);
 110
 111        switch (size) {
 112        case 1:
 113                writeb(val, addr);
 114                break;
 115        case 2:
 116                writew(val, addr);
 117                break;
 118        default:
 119                writel(val, addr);
 120        }
 121
 122        return PCIBIOS_SUCCESSFUL;
 123}
 124
 125static struct pci_ops gen_pci_ops = {
 126        .read   = gen_pci_config_read,
 127        .write  = gen_pci_config_write,
 128};
 129
 130static const struct of_device_id gen_pci_of_match[] = {
 131        { .compatible = "pci-host-cam-generic",
 132          .data = &gen_pci_cfg_cam_bus_ops },
 133
 134        { .compatible = "pci-host-ecam-generic",
 135          .data = &gen_pci_cfg_ecam_bus_ops },
 136
 137        { },
 138};
 139MODULE_DEVICE_TABLE(of, gen_pci_of_match);
 140
 141static int gen_pci_calc_io_offset(struct device *dev,
 142                                  struct of_pci_range *range,
 143                                  struct resource *res,
 144                                  resource_size_t *offset)
 145{
 146        static atomic_t wins = ATOMIC_INIT(0);
 147        int err, idx, max_win;
 148        unsigned int window;
 149
 150        if (!PAGE_ALIGNED(range->cpu_addr))
 151                return -EINVAL;
 152
 153        max_win = (IO_SPACE_LIMIT + 1) / SZ_64K;
 154        idx = atomic_inc_return(&wins);
 155        if (idx > max_win)
 156                return -ENOSPC;
 157
 158        window = (idx - 1) * SZ_64K;
 159        err = pci_ioremap_io(window, range->cpu_addr);
 160        if (err)
 161                return err;
 162
 163        of_pci_range_to_resource(range, dev->of_node, res);
 164        res->start = window;
 165        res->end = res->start + range->size - 1;
 166        *offset = window - range->pci_addr;
 167        return 0;
 168}
 169
 170static int gen_pci_calc_mem_offset(struct device *dev,
 171                                   struct of_pci_range *range,
 172                                   struct resource *res,
 173                                   resource_size_t *offset)
 174{
 175        of_pci_range_to_resource(range, dev->of_node, res);
 176        *offset = range->cpu_addr - range->pci_addr;
 177        return 0;
 178}
 179
 180static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
 181{
 182        struct pci_host_bridge_window *win;
 183
 184        list_for_each_entry(win, &pci->resources, list)
 185                release_resource(win->res);
 186
 187        pci_free_resource_list(&pci->resources);
 188}
 189
 190static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
 191{
 192        struct of_pci_range range;
 193        struct of_pci_range_parser parser;
 194        int err, res_valid = 0;
 195        struct device *dev = pci->host.dev.parent;
 196        struct device_node *np = dev->of_node;
 197
 198        if (of_pci_range_parser_init(&parser, np)) {
 199                dev_err(dev, "missing \"ranges\" property\n");
 200                return -EINVAL;
 201        }
 202
 203        for_each_of_pci_range(&parser, &range) {
 204                struct resource *parent, *res;
 205                resource_size_t offset;
 206                u32 restype = range.flags & IORESOURCE_TYPE_BITS;
 207
 208                res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL);
 209                if (!res) {
 210                        err = -ENOMEM;
 211                        goto out_release_res;
 212                }
 213
 214                switch (restype) {
 215                case IORESOURCE_IO:
 216                        parent = &ioport_resource;
 217                        err = gen_pci_calc_io_offset(dev, &range, res, &offset);
 218                        break;
 219                case IORESOURCE_MEM:
 220                        parent = &iomem_resource;
 221                        err = gen_pci_calc_mem_offset(dev, &range, res, &offset);
 222                        res_valid |= !(res->flags & IORESOURCE_PREFETCH || err);
 223                        break;
 224                default:
 225                        err = -EINVAL;
 226                        continue;
 227                }
 228
 229                if (err) {
 230                        dev_warn(dev,
 231                                 "error %d: failed to add resource [type 0x%x, %lld bytes]\n",
 232                                 err, restype, range.size);
 233                        continue;
 234                }
 235
 236                err = request_resource(parent, res);
 237                if (err)
 238                        goto out_release_res;
 239
 240                pci_add_resource_offset(&pci->resources, res, offset);
 241        }
 242
 243        if (!res_valid) {
 244                dev_err(dev, "non-prefetchable memory resource required\n");
 245                err = -EINVAL;
 246                goto out_release_res;
 247        }
 248
 249        return 0;
 250
 251out_release_res:
 252        gen_pci_release_of_pci_ranges(pci);
 253        return err;
 254}
 255
 256static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
 257{
 258        int err;
 259        u8 bus_max;
 260        resource_size_t busn;
 261        struct resource *bus_range;
 262        struct device *dev = pci->host.dev.parent;
 263        struct device_node *np = dev->of_node;
 264
 265        if (of_pci_parse_bus_range(np, &pci->cfg.bus_range))
 266                pci->cfg.bus_range = (struct resource) {
 267                        .name   = np->name,
 268                        .start  = 0,
 269                        .end    = 0xff,
 270                        .flags  = IORESOURCE_BUS,
 271                };
 272
 273        err = of_address_to_resource(np, 0, &pci->cfg.res);
 274        if (err) {
 275                dev_err(dev, "missing \"reg\" property\n");
 276                return err;
 277        }
 278
 279        pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range),
 280                                    sizeof(*pci->cfg.win), GFP_KERNEL);
 281        if (!pci->cfg.win)
 282                return -ENOMEM;
 283
 284        /* Limit the bus-range to fit within reg */
 285        bus_max = pci->cfg.bus_range.start +
 286                  (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
 287        pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end,
 288                                       bus_max);
 289
 290        /* Map our Configuration Space windows */
 291        if (!devm_request_mem_region(dev, pci->cfg.res.start,
 292                                     resource_size(&pci->cfg.res),
 293                                     "Configuration Space"))
 294                return -ENOMEM;
 295
 296        bus_range = &pci->cfg.bus_range;
 297        for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
 298                u32 idx = busn - bus_range->start;
 299                u32 sz = 1 << pci->cfg.ops->bus_shift;
 300
 301                pci->cfg.win[idx] = devm_ioremap(dev,
 302                                                 pci->cfg.res.start + busn * sz,
 303                                                 sz);
 304                if (!pci->cfg.win[idx])
 305                        return -ENOMEM;
 306        }
 307
 308        /* Register bus resource */
 309        pci_add_resource(&pci->resources, bus_range);
 310        return 0;
 311}
 312
 313static int gen_pci_setup(int nr, struct pci_sys_data *sys)
 314{
 315        struct gen_pci *pci = sys->private_data;
 316        list_splice_init(&pci->resources, &sys->resources);
 317        return 1;
 318}
 319
 320static int gen_pci_probe(struct platform_device *pdev)
 321{
 322        int err;
 323        const char *type;
 324        const struct of_device_id *of_id;
 325        const int *prop;
 326        struct device *dev = &pdev->dev;
 327        struct device_node *np = dev->of_node;
 328        struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 329        struct hw_pci hw = {
 330                .nr_controllers = 1,
 331                .private_data   = (void **)&pci,
 332                .setup          = gen_pci_setup,
 333                .map_irq        = of_irq_parse_and_map_pci,
 334                .ops            = &gen_pci_ops,
 335        };
 336
 337        if (!pci)
 338                return -ENOMEM;
 339
 340        type = of_get_property(np, "device_type", NULL);
 341        if (!type || strcmp(type, "pci")) {
 342                dev_err(dev, "invalid \"device_type\" %s\n", type);
 343                return -EINVAL;
 344        }
 345
 346        prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
 347        if (prop) {
 348                if (*prop)
 349                        pci_add_flags(PCI_PROBE_ONLY);
 350                else
 351                        pci_clear_flags(PCI_PROBE_ONLY);
 352        }
 353
 354        of_id = of_match_node(gen_pci_of_match, np);
 355        pci->cfg.ops = of_id->data;
 356        pci->host.dev.parent = dev;
 357        INIT_LIST_HEAD(&pci->host.windows);
 358        INIT_LIST_HEAD(&pci->resources);
 359
 360        /* Parse our PCI ranges and request their resources */
 361        err = gen_pci_parse_request_of_pci_ranges(pci);
 362        if (err)
 363                return err;
 364
 365        /* Parse and map our Configuration Space windows */
 366        err = gen_pci_parse_map_cfg_windows(pci);
 367        if (err) {
 368                gen_pci_release_of_pci_ranges(pci);
 369                return err;
 370        }
 371
 372        pci_common_init_dev(dev, &hw);
 373        return 0;
 374}
 375
 376static struct platform_driver gen_pci_driver = {
 377        .driver = {
 378                .name = "pci-host-generic",
 379                .owner = THIS_MODULE,
 380                .of_match_table = gen_pci_of_match,
 381        },
 382        .probe = gen_pci_probe,
 383};
 384module_platform_driver(gen_pci_driver);
 385
 386MODULE_DESCRIPTION("Generic PCI host driver");
 387MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
 388MODULE_LICENSE("GPL v2");
 389