~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/x86/pci/acpi.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <linux/pci.h>
 
2
#include <linux/acpi.h>
 
3
#include <linux/init.h>
 
4
#include <linux/irq.h>
 
5
#include <linux/dmi.h>
 
6
#include <linux/slab.h>
 
7
#include <asm/numa.h>
 
8
#include <asm/pci_x86.h>
 
9
 
 
10
struct pci_root_info {
 
11
        struct acpi_device *bridge;
 
12
        char *name;
 
13
        unsigned int res_num;
 
14
        struct resource *res;
 
15
        struct pci_bus *bus;
 
16
        int busnum;
 
17
};
 
18
 
 
19
static bool pci_use_crs = true;
 
20
 
 
21
static int __init set_use_crs(const struct dmi_system_id *id)
 
22
{
 
23
        pci_use_crs = true;
 
24
        return 0;
 
25
}
 
26
 
 
27
static const struct dmi_system_id pci_use_crs_table[] __initconst = {
 
28
        /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
 
29
        {
 
30
                .callback = set_use_crs,
 
31
                .ident = "IBM System x3800",
 
32
                .matches = {
 
33
                        DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
 
34
                        DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
 
35
                },
 
36
        },
 
37
        /* https://bugzilla.kernel.org/show_bug.cgi?id=16007 */
 
38
        /* 2006 AMD HT/VIA system with two host bridges */
 
39
        {
 
40
                .callback = set_use_crs,
 
41
                .ident = "ASRock ALiveSATA2-GLAN",
 
42
                .matches = {
 
43
                        DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
 
44
                },
 
45
        },
 
46
        /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
 
47
        /* 2006 AMD HT/VIA system with two host bridges */
 
48
        {
 
49
                .callback = set_use_crs,
 
50
                .ident = "ASUS M2V-MX SE",
 
51
                .matches = {
 
52
                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 
53
                        DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
 
54
                        DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
 
55
                },
 
56
        },
 
57
        {}
 
58
};
 
59
 
 
60
void __init pci_acpi_crs_quirks(void)
 
61
{
 
62
        int year;
 
63
 
 
64
        if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
 
65
                pci_use_crs = false;
 
66
 
 
67
        dmi_check_system(pci_use_crs_table);
 
68
 
 
69
        /*
 
70
         * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
 
71
         * takes precedence over anything we figured out above.
 
72
         */
 
73
        if (pci_probe & PCI_ROOT_NO_CRS)
 
74
                pci_use_crs = false;
 
75
        else if (pci_probe & PCI_USE__CRS)
 
76
                pci_use_crs = true;
 
77
 
 
78
        printk(KERN_INFO "PCI: %s host bridge windows from ACPI; "
 
79
               "if necessary, use \"pci=%s\" and report a bug\n",
 
80
               pci_use_crs ? "Using" : "Ignoring",
 
81
               pci_use_crs ? "nocrs" : "use_crs");
 
82
}
 
83
 
 
84
static acpi_status
 
85
resource_to_addr(struct acpi_resource *resource,
 
86
                        struct acpi_resource_address64 *addr)
 
87
{
 
88
        acpi_status status;
 
89
        struct acpi_resource_memory24 *memory24;
 
90
        struct acpi_resource_memory32 *memory32;
 
91
        struct acpi_resource_fixed_memory32 *fixed_memory32;
 
92
 
 
93
        memset(addr, 0, sizeof(*addr));
 
94
        switch (resource->type) {
 
95
        case ACPI_RESOURCE_TYPE_MEMORY24:
 
96
                memory24 = &resource->data.memory24;
 
97
                addr->resource_type = ACPI_MEMORY_RANGE;
 
98
                addr->minimum = memory24->minimum;
 
99
                addr->address_length = memory24->address_length;
 
100
                addr->maximum = addr->minimum + addr->address_length - 1;
 
101
                return AE_OK;
 
102
        case ACPI_RESOURCE_TYPE_MEMORY32:
 
103
                memory32 = &resource->data.memory32;
 
104
                addr->resource_type = ACPI_MEMORY_RANGE;
 
105
                addr->minimum = memory32->minimum;
 
106
                addr->address_length = memory32->address_length;
 
107
                addr->maximum = addr->minimum + addr->address_length - 1;
 
108
                return AE_OK;
 
109
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
 
110
                fixed_memory32 = &resource->data.fixed_memory32;
 
111
                addr->resource_type = ACPI_MEMORY_RANGE;
 
112
                addr->minimum = fixed_memory32->address;
 
113
                addr->address_length = fixed_memory32->address_length;
 
114
                addr->maximum = addr->minimum + addr->address_length - 1;
 
115
                return AE_OK;
 
116
        case ACPI_RESOURCE_TYPE_ADDRESS16:
 
117
        case ACPI_RESOURCE_TYPE_ADDRESS32:
 
118
        case ACPI_RESOURCE_TYPE_ADDRESS64:
 
119
                status = acpi_resource_to_address64(resource, addr);
 
120
                if (ACPI_SUCCESS(status) &&
 
121
                    (addr->resource_type == ACPI_MEMORY_RANGE ||
 
122
                    addr->resource_type == ACPI_IO_RANGE) &&
 
123
                    addr->address_length > 0) {
 
124
                        return AE_OK;
 
125
                }
 
126
                break;
 
127
        }
 
128
        return AE_ERROR;
 
129
}
 
130
 
 
131
static acpi_status
 
132
count_resource(struct acpi_resource *acpi_res, void *data)
 
133
{
 
134
        struct pci_root_info *info = data;
 
135
        struct acpi_resource_address64 addr;
 
136
        acpi_status status;
 
137
 
 
138
        status = resource_to_addr(acpi_res, &addr);
 
139
        if (ACPI_SUCCESS(status))
 
140
                info->res_num++;
 
141
        return AE_OK;
 
142
}
 
143
 
 
144
static acpi_status
 
145
setup_resource(struct acpi_resource *acpi_res, void *data)
 
146
{
 
147
        struct pci_root_info *info = data;
 
148
        struct resource *res;
 
149
        struct acpi_resource_address64 addr;
 
150
        acpi_status status;
 
151
        unsigned long flags;
 
152
        u64 start, end;
 
153
 
 
154
        status = resource_to_addr(acpi_res, &addr);
 
155
        if (!ACPI_SUCCESS(status))
 
156
                return AE_OK;
 
157
 
 
158
        if (addr.resource_type == ACPI_MEMORY_RANGE) {
 
159
                flags = IORESOURCE_MEM;
 
160
                if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
 
161
                        flags |= IORESOURCE_PREFETCH;
 
162
        } else if (addr.resource_type == ACPI_IO_RANGE) {
 
163
                flags = IORESOURCE_IO;
 
164
        } else
 
165
                return AE_OK;
 
166
 
 
167
        start = addr.minimum + addr.translation_offset;
 
168
        end = addr.maximum + addr.translation_offset;
 
169
 
 
170
        res = &info->res[info->res_num];
 
171
        res->name = info->name;
 
172
        res->flags = flags;
 
173
        res->start = start;
 
174
        res->end = end;
 
175
        res->child = NULL;
 
176
 
 
177
        if (!pci_use_crs) {
 
178
                dev_printk(KERN_DEBUG, &info->bridge->dev,
 
179
                           "host bridge window %pR (ignored)\n", res);
 
180
                return AE_OK;
 
181
        }
 
182
 
 
183
        info->res_num++;
 
184
        if (addr.translation_offset)
 
185
                dev_info(&info->bridge->dev, "host bridge window %pR "
 
186
                         "(PCI address [%#llx-%#llx])\n",
 
187
                         res, res->start - addr.translation_offset,
 
188
                         res->end - addr.translation_offset);
 
189
        else
 
190
                dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
 
191
 
 
192
        return AE_OK;
 
193
}
 
194
 
 
195
static bool resource_contains(struct resource *res, resource_size_t point)
 
196
{
 
197
        if (res->start <= point && point <= res->end)
 
198
                return true;
 
199
        return false;
 
200
}
 
201
 
 
202
static void coalesce_windows(struct pci_root_info *info, unsigned long type)
 
203
{
 
204
        int i, j;
 
205
        struct resource *res1, *res2;
 
206
 
 
207
        for (i = 0; i < info->res_num; i++) {
 
208
                res1 = &info->res[i];
 
209
                if (!(res1->flags & type))
 
210
                        continue;
 
211
 
 
212
                for (j = i + 1; j < info->res_num; j++) {
 
213
                        res2 = &info->res[j];
 
214
                        if (!(res2->flags & type))
 
215
                                continue;
 
216
 
 
217
                        /*
 
218
                         * I don't like throwing away windows because then
 
219
                         * our resources no longer match the ACPI _CRS, but
 
220
                         * the kernel resource tree doesn't allow overlaps.
 
221
                         */
 
222
                        if (resource_contains(res1, res2->start) ||
 
223
                            resource_contains(res1, res2->end) ||
 
224
                            resource_contains(res2, res1->start) ||
 
225
                            resource_contains(res2, res1->end)) {
 
226
                                res1->start = min(res1->start, res2->start);
 
227
                                res1->end = max(res1->end, res2->end);
 
228
                                dev_info(&info->bridge->dev,
 
229
                                         "host bridge window expanded to %pR; %pR ignored\n",
 
230
                                         res1, res2);
 
231
                                res2->flags = 0;
 
232
                        }
 
233
                }
 
234
        }
 
235
}
 
236
 
 
237
static void add_resources(struct pci_root_info *info)
 
238
{
 
239
        int i;
 
240
        struct resource *res, *root, *conflict;
 
241
 
 
242
        if (!pci_use_crs)
 
243
                return;
 
244
 
 
245
        coalesce_windows(info, IORESOURCE_MEM);
 
246
        coalesce_windows(info, IORESOURCE_IO);
 
247
 
 
248
        for (i = 0; i < info->res_num; i++) {
 
249
                res = &info->res[i];
 
250
 
 
251
                if (res->flags & IORESOURCE_MEM)
 
252
                        root = &iomem_resource;
 
253
                else if (res->flags & IORESOURCE_IO)
 
254
                        root = &ioport_resource;
 
255
                else
 
256
                        continue;
 
257
 
 
258
                conflict = insert_resource_conflict(root, res);
 
259
                if (conflict)
 
260
                        dev_info(&info->bridge->dev,
 
261
                                 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
 
262
                                 res, conflict->name, conflict);
 
263
                else
 
264
                        pci_bus_add_resource(info->bus, res, 0);
 
265
        }
 
266
}
 
267
 
 
268
static void
 
269
get_current_resources(struct acpi_device *device, int busnum,
 
270
                        int domain, struct pci_bus *bus)
 
271
{
 
272
        struct pci_root_info info;
 
273
        size_t size;
 
274
 
 
275
        if (pci_use_crs)
 
276
                pci_bus_remove_resources(bus);
 
277
 
 
278
        info.bridge = device;
 
279
        info.bus = bus;
 
280
        info.res_num = 0;
 
281
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
 
282
                                &info);
 
283
        if (!info.res_num)
 
284
                return;
 
285
 
 
286
        size = sizeof(*info.res) * info.res_num;
 
287
        info.res = kmalloc(size, GFP_KERNEL);
 
288
        if (!info.res)
 
289
                goto res_alloc_fail;
 
290
 
 
291
        info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
 
292
        if (!info.name)
 
293
                goto name_alloc_fail;
 
294
 
 
295
        info.res_num = 0;
 
296
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
 
297
                                &info);
 
298
 
 
299
        add_resources(&info);
 
300
        return;
 
301
 
 
302
name_alloc_fail:
 
303
        kfree(info.res);
 
304
res_alloc_fail:
 
305
        return;
 
306
}
 
307
 
 
308
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
 
309
{
 
310
        struct acpi_device *device = root->device;
 
311
        int domain = root->segment;
 
312
        int busnum = root->secondary.start;
 
313
        struct pci_bus *bus;
 
314
        struct pci_sysdata *sd;
 
315
        int node;
 
316
#ifdef CONFIG_ACPI_NUMA
 
317
        int pxm;
 
318
#endif
 
319
 
 
320
        if (domain && !pci_domains_supported) {
 
321
                printk(KERN_WARNING "pci_bus %04x:%02x: "
 
322
                       "ignored (multiple domains not supported)\n",
 
323
                       domain, busnum);
 
324
                return NULL;
 
325
        }
 
326
 
 
327
        node = -1;
 
328
#ifdef CONFIG_ACPI_NUMA
 
329
        pxm = acpi_get_pxm(device->handle);
 
330
        if (pxm >= 0)
 
331
                node = pxm_to_node(pxm);
 
332
        if (node != -1)
 
333
                set_mp_bus_to_node(busnum, node);
 
334
        else
 
335
#endif
 
336
                node = get_mp_bus_to_node(busnum);
 
337
 
 
338
        if (node != -1 && !node_online(node))
 
339
                node = -1;
 
340
 
 
341
        /* Allocate per-root-bus (not per bus) arch-specific data.
 
342
         * TODO: leak; this memory is never freed.
 
343
         * It's arguable whether it's worth the trouble to care.
 
344
         */
 
345
        sd = kzalloc(sizeof(*sd), GFP_KERNEL);
 
346
        if (!sd) {
 
347
                printk(KERN_WARNING "pci_bus %04x:%02x: "
 
348
                       "ignored (out of memory)\n", domain, busnum);
 
349
                return NULL;
 
350
        }
 
351
 
 
352
        sd->domain = domain;
 
353
        sd->node = node;
 
354
        /*
 
355
         * Maybe the desired pci bus has been already scanned. In such case
 
356
         * it is unnecessary to scan the pci bus with the given domain,busnum.
 
357
         */
 
358
        bus = pci_find_bus(domain, busnum);
 
359
        if (bus) {
 
360
                /*
 
361
                 * If the desired bus exits, the content of bus->sysdata will
 
362
                 * be replaced by sd.
 
363
                 */
 
364
                memcpy(bus->sysdata, sd, sizeof(*sd));
 
365
                kfree(sd);
 
366
        } else {
 
367
                bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
 
368
                if (bus) {
 
369
                        get_current_resources(device, busnum, domain, bus);
 
370
                        bus->subordinate = pci_scan_child_bus(bus);
 
371
                }
 
372
        }
 
373
 
 
374
        /* After the PCI-E bus has been walked and all devices discovered,
 
375
         * configure any settings of the fabric that might be necessary.
 
376
         */
 
377
        if (bus) {
 
378
                struct pci_bus *child;
 
379
                list_for_each_entry(child, &bus->children, node) {
 
380
                        struct pci_dev *self = child->self;
 
381
                        if (!self)
 
382
                                continue;
 
383
 
 
384
                        pcie_bus_configure_settings(child, self->pcie_mpss);
 
385
                }
 
386
        }
 
387
 
 
388
        if (!bus)
 
389
                kfree(sd);
 
390
 
 
391
        if (bus && node != -1) {
 
392
#ifdef CONFIG_ACPI_NUMA
 
393
                if (pxm >= 0)
 
394
                        dev_printk(KERN_DEBUG, &bus->dev,
 
395
                                   "on NUMA node %d (pxm %d)\n", node, pxm);
 
396
#else
 
397
                dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
 
398
#endif
 
399
        }
 
400
 
 
401
        return bus;
 
402
}
 
403
 
 
404
int __init pci_acpi_init(void)
 
405
{
 
406
        struct pci_dev *dev = NULL;
 
407
 
 
408
        if (acpi_noirq)
 
409
                return -ENODEV;
 
410
 
 
411
        printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
 
412
        acpi_irq_penalty_init();
 
413
        pcibios_enable_irq = acpi_pci_irq_enable;
 
414
        pcibios_disable_irq = acpi_pci_irq_disable;
 
415
        x86_init.pci.init_irq = x86_init_noop;
 
416
 
 
417
        if (pci_routeirq) {
 
418
                /*
 
419
                 * PCI IRQ routing is set up by pci_enable_device(), but we
 
420
                 * also do it here in case there are still broken drivers that
 
421
                 * don't use pci_enable_device().
 
422
                 */
 
423
                printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
 
424
                for_each_pci_dev(dev)
 
425
                        acpi_pci_irq_enable(dev);
 
426
        }
 
427
 
 
428
        return 0;
 
429
}