linux/drivers/pci/setup-res.c
<<
>>
Prefs
   1/*
   2 *      drivers/pci/setup-res.c
   3 *
   4 * Extruded from code written by
   5 *      Dave Rusling (david.rusling@reo.mts.dec.com)
   6 *      David Mosberger (davidm@cs.arizona.edu)
   7 *      David Miller (davem@redhat.com)
   8 *
   9 * Support routines for initializing a PCI subsystem.
  10 */
  11
  12/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
  13
  14/*
  15 * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
  16 *           Resource sorting
  17 */
  18
  19#include <linux/init.h>
  20#include <linux/kernel.h>
  21#include <linux/pci.h>
  22#include <linux/errno.h>
  23#include <linux/ioport.h>
  24#include <linux/cache.h>
  25#include <linux/slab.h>
  26#include "pci.h"
  27
  28
  29void pci_update_resource(struct pci_dev *dev, int resno)
  30{
  31        struct pci_bus_region region;
  32        u32 new, check, mask;
  33        int reg;
  34        enum pci_bar_type type;
  35        struct resource *res = dev->resource + resno;
  36
  37        /*
  38         * Ignore resources for unimplemented BARs and unused resource slots
  39         * for 64 bit BARs.
  40         */
  41        if (!res->flags)
  42                return;
  43
  44        /*
  45         * Ignore non-moveable resources.  This might be legacy resources for
  46         * which no functional BAR register exists or another important
  47         * system resource we shouldn't move around.
  48         */
  49        if (res->flags & IORESOURCE_PCI_FIXED)
  50                return;
  51
  52        pcibios_resource_to_bus(dev, &region, res);
  53
  54        dev_dbg(&dev->dev, "BAR %d: got res %pR bus [%#llx-%#llx] "
  55                "flags %#lx\n", resno, res,
  56                 (unsigned long long)region.start,
  57                 (unsigned long long)region.end,
  58                 (unsigned long)res->flags);
  59
  60        new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
  61        if (res->flags & IORESOURCE_IO)
  62                mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
  63        else
  64                mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
  65
  66        reg = pci_resource_bar(dev, resno, &type);
  67        if (!reg)
  68                return;
  69        if (type != pci_bar_unknown) {
  70                if (!(res->flags & IORESOURCE_ROM_ENABLE))
  71                        return;
  72                new |= PCI_ROM_ADDRESS_ENABLE;
  73        }
  74
  75        pci_write_config_dword(dev, reg, new);
  76        pci_read_config_dword(dev, reg, &check);
  77
  78        if ((new ^ check) & mask) {
  79                dev_err(&dev->dev, "BAR %d: error updating (%#08x != %#08x)\n",
  80                        resno, new, check);
  81        }
  82
  83        if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
  84            (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
  85                new = region.start >> 16 >> 16;
  86                pci_write_config_dword(dev, reg + 4, new);
  87                pci_read_config_dword(dev, reg + 4, &check);
  88                if (check != new) {
  89                        dev_err(&dev->dev, "BAR %d: error updating "
  90                               "(high %#08x != %#08x)\n", resno, new, check);
  91                }
  92        }
  93        res->flags &= ~IORESOURCE_UNSET;
  94        dev_dbg(&dev->dev, "BAR %d: moved to bus [%#llx-%#llx] flags %#lx\n",
  95                resno, (unsigned long long)region.start,
  96                (unsigned long long)region.end, res->flags);
  97}
  98
  99int pci_claim_resource(struct pci_dev *dev, int resource)
 100{
 101        struct resource *res = &dev->resource[resource];
 102        struct resource *root;
 103        int err;
 104
 105        root = pci_find_parent_resource(dev, res);
 106
 107        err = -EINVAL;
 108        if (root != NULL)
 109                err = request_resource(root, res);
 110
 111        if (err) {
 112                const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
 113                dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
 114                        resource,
 115                        root ? "address space collision on" :
 116                                "no parent found for",
 117                        dtype, res);
 118        }
 119
 120        return err;
 121}
 122EXPORT_SYMBOL(pci_claim_resource);
 123
 124#ifdef CONFIG_PCI_QUIRKS
 125void pci_disable_bridge_window(struct pci_dev *dev)
 126{
 127        dev_dbg(&dev->dev, "Disabling bridge window.\n");
 128
 129        /* MMIO Base/Limit */
 130        pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
 131
 132        /* Prefetchable MMIO Base/Limit */
 133        pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
 134        pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
 135        pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
 136}
 137#endif  /* CONFIG_PCI_QUIRKS */
 138
 139static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
 140                                 int resno)
 141{
 142        struct resource *res = dev->resource + resno;
 143        resource_size_t size, min, align;
 144        int ret;
 145
 146        size = resource_size(res);
 147        min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
 148        align = pci_resource_alignment(dev, res);
 149
 150        /* First, try exact prefetching match.. */
 151        ret = pci_bus_alloc_resource(bus, res, size, align, min,
 152                                     IORESOURCE_PREFETCH,
 153                                     pcibios_align_resource, dev);
 154
 155        if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
 156                /*
 157                 * That failed.
 158                 *
 159                 * But a prefetching area can handle a non-prefetching
 160                 * window (it will just not perform as well).
 161                 */
 162                ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
 163                                             pcibios_align_resource, dev);
 164        }
 165
 166        if (!ret) {
 167                res->flags &= ~IORESOURCE_STARTALIGN;
 168                if (resno < PCI_BRIDGE_RESOURCES)
 169                        pci_update_resource(dev, resno);
 170        }
 171
 172        return ret;
 173}
 174
 175int pci_assign_resource(struct pci_dev *dev, int resno)
 176{
 177        struct resource *res = dev->resource + resno;
 178        resource_size_t align;
 179        struct pci_bus *bus;
 180        int ret;
 181
 182        align = pci_resource_alignment(dev, res);
 183        if (!align) {
 184                dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
 185                        "alignment) %pR flags %#lx\n",
 186                        resno, res, res->flags);
 187                return -EINVAL;
 188        }
 189
 190        bus = dev->bus;
 191        while ((ret = __pci_assign_resource(bus, dev, resno))) {
 192                if (bus->parent && bus->self->transparent)
 193                        bus = bus->parent;
 194                else
 195                        bus = NULL;
 196                if (bus)
 197                        continue;
 198                break;
 199        }
 200
 201        if (ret)
 202                dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
 203                        resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
 204
 205        return ret;
 206}
 207
 208/* Sort resources by alignment */
 209void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 210{
 211        int i;
 212
 213        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 214                struct resource *r;
 215                struct resource_list *list, *tmp;
 216                resource_size_t r_align;
 217
 218                r = &dev->resource[i];
 219
 220                if (r->flags & IORESOURCE_PCI_FIXED)
 221                        continue;
 222
 223                if (!(r->flags) || r->parent)
 224                        continue;
 225
 226                r_align = pci_resource_alignment(dev, r);
 227                if (!r_align) {
 228                        dev_warn(&dev->dev, "BAR %d: bogus alignment "
 229                                "%pR flags %#lx\n",
 230                                i, r, r->flags);
 231                        continue;
 232                }
 233                for (list = head; ; list = list->next) {
 234                        resource_size_t align = 0;
 235                        struct resource_list *ln = list->next;
 236
 237                        if (ln)
 238                                align = pci_resource_alignment(ln->dev, ln->res);
 239
 240                        if (r_align > align) {
 241                                tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
 242                                if (!tmp)
 243                                        panic("pdev_sort_resources(): "
 244                                              "kmalloc() failed!\n");
 245                                tmp->next = ln;
 246                                tmp->res = r;
 247                                tmp->dev = dev;
 248                                list->next = tmp;
 249                                break;
 250                        }
 251                }
 252        }
 253}
 254
 255int pci_enable_resources(struct pci_dev *dev, int mask)
 256{
 257        u16 cmd, old_cmd;
 258        int i;
 259        struct resource *r;
 260
 261        pci_read_config_word(dev, PCI_COMMAND, &cmd);
 262        old_cmd = cmd;
 263
 264        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 265                if (!(mask & (1 << i)))
 266                        continue;
 267
 268                r = &dev->resource[i];
 269
 270                if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
 271                        continue;
 272                if ((i == PCI_ROM_RESOURCE) &&
 273                                (!(r->flags & IORESOURCE_ROM_ENABLE)))
 274                        continue;
 275
 276                if (!r->parent) {
 277                        dev_err(&dev->dev, "device not available because of "
 278                                "BAR %d %pR collisions\n", i, r);
 279                        return -EINVAL;
 280                }
 281
 282                if (r->flags & IORESOURCE_IO)
 283                        cmd |= PCI_COMMAND_IO;
 284                if (r->flags & IORESOURCE_MEM)
 285                        cmd |= PCI_COMMAND_MEMORY;
 286        }
 287
 288        if (cmd != old_cmd) {
 289                dev_info(&dev->dev, "enabling device (%04x -> %04x)\n",
 290                         old_cmd, cmd);
 291                pci_write_config_word(dev, PCI_COMMAND, cmd);
 292        }
 293        return 0;
 294}
 295