OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acpi/] [pci_irq.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 1.1.1.1 $)
3
 *
4
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6
 *  Copyright (C) 2002       Dominik Brodowski <devel@brodo.de>
7
 *
8
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or (at
13
 *  your option) any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful, but
16
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 *  General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License along
21
 *  with this program; if not, write to the Free Software Foundation, Inc.,
22
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23
 *
24
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
 */
26
 
27
#include <linux/config.h>
28
 
29
#include <linux/kernel.h>
30
#include <linux/module.h>
31
#include <linux/init.h>
32
#include <linux/types.h>
33
#include <linux/proc_fs.h>
34
#include <linux/spinlock.h>
35
#include <linux/pm.h>
36
#include <linux/pci.h>
37
#include <linux/acpi.h>
38
#ifdef CONFIG_X86_IO_APIC
39
#include <asm/mpspec.h>
40
#endif
41
#ifdef CONFIG_IOSAPIC
42
# include <asm/iosapic.h>
43
#endif
44
#include <acpi/acpi_bus.h>
45
#include <acpi/acpi_drivers.h>
46
 
47
 
48
#define _COMPONENT              ACPI_PCI_COMPONENT
49
ACPI_MODULE_NAME                ("pci_irq")
50
 
51
#define PREFIX                  "PCI: "
52
 
53
struct acpi_prt_list            acpi_prt;
54
 
55
#ifdef CONFIG_X86
56
extern void eisa_set_level_irq(unsigned int irq);
57
#endif
58
 
59
 
60
/* --------------------------------------------------------------------------
61
                         PCI IRQ Routing Table (PRT) Support
62
   -------------------------------------------------------------------------- */
63
 
64
static struct acpi_prt_entry *
65
acpi_pci_irq_find_prt_entry (
66
        int                     segment,
67
        int                     bus,
68
        int                     device,
69
        int                     pin)
70
{
71
        struct list_head        *node = NULL;
72
        struct acpi_prt_entry   *entry = NULL;
73
 
74
        ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry");
75
 
76
        if (!acpi_prt.count)
77
                return_PTR(NULL);
78
 
79
        /*
80
         * Parse through all PRT entries looking for a match on the specified
81
         * PCI device's segment, bus, device, and pin (don't care about func).
82
         *
83
         * TBD: Acquire/release lock
84
         */
85
        list_for_each(node, &acpi_prt.entries) {
86
                entry = list_entry(node, struct acpi_prt_entry, node);
87
                if ((segment == entry->id.segment)
88
                        && (bus == entry->id.bus)
89
                        && (device == entry->id.device)
90
                        && (pin == entry->pin)) {
91
                        return_PTR(entry);
92
                }
93
        }
94
 
95
        return_PTR(NULL);
96
}
97
 
98
 
99
static int
100
acpi_pci_irq_add_entry (
101
        acpi_handle                     handle,
102
        int                             segment,
103
        int                             bus,
104
        struct acpi_pci_routing_table   *prt)
105
{
106
        struct acpi_prt_entry   *entry = NULL;
107
 
108
        ACPI_FUNCTION_TRACE("acpi_pci_irq_add_entry");
109
 
110
        if (!prt)
111
                return_VALUE(-EINVAL);
112
 
113
        entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
114
        if (!entry)
115
                return_VALUE(-ENOMEM);
116
        memset(entry, 0, sizeof(struct acpi_prt_entry));
117
 
118
        entry->id.segment = segment;
119
        entry->id.bus = bus;
120
        entry->id.device = (prt->address >> 16) & 0xFFFF;
121
        entry->id.function = prt->address & 0xFFFF;
122
        entry->pin = prt->pin;
123
 
124
        /*
125
         * Type 1: Dynamic
126
         * ---------------
127
         * The 'source' field specifies the PCI interrupt link device used to
128
         * configure the IRQ assigned to this slot|dev|pin.  The 'source_index'
129
         * indicates which resource descriptor in the resource template (of
130
         * the link device) this interrupt is allocated from.
131
         *
132
         * NOTE: Don't query the Link Device for IRQ information at this time
133
         *       because Link Device enumeration may not have occurred yet
134
         *       (e.g. exists somewhere 'below' this _PRT entry in the ACPI
135
         *       namespace).
136
         */
137
        if (prt->source[0]) {
138
                acpi_get_handle(handle, prt->source, &entry->link.handle);
139
                entry->link.index = prt->source_index;
140
        }
141
        /*
142
         * Type 2: Static
143
         * --------------
144
         * The 'source' field is NULL, and the 'source_index' field specifies
145
         * the IRQ value, which is hardwired to specific interrupt inputs on
146
         * the interrupt controller.
147
         */
148
        else
149
                entry->link.index = prt->source_index;
150
 
151
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
152
                "      %02X:%02X:%02X[%c] -> %s[%d]\n",
153
                entry->id.segment, entry->id.bus, entry->id.device,
154
                ('A' + entry->pin), prt->source, entry->link.index));
155
 
156
        /* TBD: Acquire/release lock */
157
        list_add_tail(&entry->node, &acpi_prt.entries);
158
        acpi_prt.count++;
159
 
160
        return_VALUE(0);
161
}
162
 
163
 
164
int
165
acpi_pci_irq_add_prt (
166
        acpi_handle             handle,
167
        int                     segment,
168
        int                     bus)
169
{
170
        acpi_status                     status = AE_OK;
171
        char                            pathname[ACPI_PATHNAME_MAX] = {0};
172
        struct acpi_buffer              buffer = {0, NULL};
173
        struct acpi_pci_routing_table   *prt = NULL;
174
        struct acpi_pci_routing_table   *entry = NULL;
175
        static int                      first_time = 1;
176
 
177
        ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt");
178
 
179
        if (first_time) {
180
                acpi_prt.count = 0;
181
                INIT_LIST_HEAD(&acpi_prt.entries);
182
                first_time = 0;
183
        }
184
 
185
        /*
186
         * NOTE: We're given a 'handle' to the _PRT object's parent device
187
         *       (either a PCI root bridge or PCI-PCI bridge).
188
         */
189
 
190
        buffer.length = sizeof(pathname);
191
        buffer.pointer = pathname;
192
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
193
 
194
        printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
195
                pathname);
196
 
197
        /*
198
         * Evaluate this _PRT and add its entries to our global list (acpi_prt).
199
         */
200
 
201
        buffer.length = 0;
202
        buffer.pointer = NULL;
203
        status = acpi_get_irq_routing_table(handle, &buffer);
204
        if (status != AE_BUFFER_OVERFLOW) {
205
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
206
                        acpi_format_exception(status)));
207
                return_VALUE(-ENODEV);
208
        }
209
 
210
        prt = kmalloc(buffer.length, GFP_KERNEL);
211
        if (!prt)
212
                return_VALUE(-ENOMEM);
213
        memset(prt, 0, buffer.length);
214
        buffer.pointer = prt;
215
 
216
        status = acpi_get_irq_routing_table(handle, &buffer);
217
        if (ACPI_FAILURE(status)) {
218
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
219
                        acpi_format_exception(status)));
220
                kfree(buffer.pointer);
221
                return_VALUE(-ENODEV);
222
        }
223
 
224
        entry = prt;
225
 
226
        while (entry && (entry->length > 0)) {
227
                acpi_pci_irq_add_entry(handle, segment, bus, entry);
228
                entry = (struct acpi_pci_routing_table *)
229
                        ((unsigned long) entry + entry->length);
230
        }
231
 
232
        kfree(prt);
233
 
234
        return_VALUE(0);
235
}
236
 
237
 
238
/* --------------------------------------------------------------------------
239
                          PCI Interrupt Routing Support
240
   -------------------------------------------------------------------------- */
241
 
242
int
243
acpi_pci_irq_lookup (
244
        int                     segment,
245
        int                     bus,
246
        int                     device,
247
        int                     pin)
248
{
249
        struct acpi_prt_entry   *entry = NULL;
250
 
251
        ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
252
 
253
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
254
                "Searching for PRT entry for %02x:%02x:%02x[%c]\n",
255
                segment, bus, device, ('A' + pin)));
256
 
257
        entry = acpi_pci_irq_find_prt_entry(segment, bus, device, pin);
258
        if (!entry) {
259
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
260
                return_VALUE(0);
261
        }
262
 
263
        if (!entry->irq && entry->link.handle) {
264
                entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, NULL, NULL);
265
                if (!entry->irq) {
266
                        ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
267
                        return_VALUE(0);
268
                }
269
        }
270
        else if (!entry->irq) {
271
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n"));
272
                return_VALUE(0);
273
        }
274
 
275
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq));
276
 
277
        return_VALUE(entry->irq);
278
}
279
 
280
static int
281
acpi_pci_irq_derive (
282
        struct pci_dev          *dev,
283
        int                     pin)
284
{
285
        struct pci_dev          *bridge = dev;
286
        int                     irq = 0;
287
        u8                      bridge_pin = 0;
288
 
289
        ACPI_FUNCTION_TRACE("acpi_pci_irq_derive");
290
 
291
        if (!dev)
292
                return_VALUE(-EINVAL);
293
 
294
        /*
295
         * Attempt to derive an IRQ for this device from a parent bridge's
296
         * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge)
297
         */
298
        while (!irq && bridge->bus->self) {
299
                pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
300
                bridge = bridge->bus->self;
301
 
302
                if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
303
                        /* PC card has the same IRQ as its cardbridge */
304
                        pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, &bridge_pin);
305
                        if (!bridge_pin) {
306
                                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
307
                                        "No interrupt pin configured for device %s\n",
308
                                        pci_name(bridge)));
309
                                return_VALUE(0);
310
                        }
311
                        /* Pin is from 0 to 3 */
312
                        bridge_pin --;
313
                        pin = bridge_pin;
314
                }
315
 
316
                irq = acpi_pci_irq_lookup(0, bridge->bus->number,
317
                                PCI_SLOT(bridge->devfn), pin);
318
        }
319
 
320
        if (!irq) {
321
                ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to derive IRQ for device %s\n", dev->slot_name));
322
                return_VALUE(0);
323
        }
324
 
325
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
326
                irq, pci_name(dev), pci_name(bridge)));
327
 
328
        return_VALUE(irq);
329
}
330
 
331
 
332
int
333
acpi_pci_irq_enable (
334
        struct pci_dev          *dev)
335
{
336
        int                     irq = 0;
337
        u8                      pin = 0;
338
 
339
        ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
340
 
341
        if (!dev)
342
                return_VALUE(-EINVAL);
343
 
344
        pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
345
        if (!pin) {
346
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", dev->slot_name));
347
                return_VALUE(0);
348
        }
349
        pin--;
350
 
351
        if (!dev->bus) {
352
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) 'bus' field\n"));
353
                return_VALUE(-ENODEV);
354
        }
355
 
356
        /*
357
         * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
358
         * values override any BIOS-assigned IRQs set during boot.
359
         */
360
        irq = acpi_pci_irq_lookup(0, dev->bus->number, PCI_SLOT(dev->devfn), pin);
361
 
362
        /*
363
         * If no PRT entry was found, we'll try to derive an IRQ from the
364
         * device's parent bridge.
365
         */
366
        if (!irq)
367
                irq = acpi_pci_irq_derive(dev, pin);
368
 
369
        /*
370
         * No IRQ known to the ACPI subsystem - maybe the BIOS /
371
         * driver reported one, then use it. Exit in any case.
372
         */
373
        if (!irq) {
374
                printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), dev->slot_name);
375
                /* Interrupt Line values above 0xF are forbidden */
376
                if (dev->irq && dev->irq >= 0xF) {
377
                        printk(" - using IRQ %d\n", dev->irq);
378
                        return_VALUE(dev->irq);
379
                }
380
                else {
381
                        printk("\n");
382
                        return_VALUE(0);
383
                }
384
        }
385
 
386
        dev->irq = irq;
387
 
388
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", dev->slot_name, dev->irq));
389
 
390
        /*
391
         * Make sure all (legacy) PCI IRQs are set as level-triggered.
392
         */
393
#ifdef CONFIG_X86
394
        {
395
                static u16 irq_mask;
396
                if ((dev->irq < 16) &&  !((1 << dev->irq) & irq_mask)) {
397
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq));
398
                        irq_mask |= (1 << dev->irq);
399
                        eisa_set_level_irq(dev->irq);
400
                }
401
        }
402
#endif
403
#ifdef CONFIG_IOSAPIC
404
        if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
405
                iosapic_enable_intr(dev->irq);
406
#endif
407
 
408
        return_VALUE(dev->irq);
409
}
410
 
411
 
412
int __init
413
acpi_pci_irq_init (void)
414
{
415
        struct pci_dev          *dev = NULL;
416
 
417
        ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
418
 
419
        if (!acpi_prt.count) {
420
                printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ "
421
                        "routing entries\n");
422
                return_VALUE(-ENODEV);
423
        }
424
 
425
        /* Make sure all link devices have a valid IRQ. */
426
        if (acpi_pci_link_check()) {
427
                return_VALUE(-ENODEV);
428
        }
429
 
430
#ifdef CONFIG_X86_IO_APIC
431
        /* Program IOAPICs using data from PRT entries. */
432
        if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
433
                mp_parse_prt();
434
#endif
435
#ifdef CONFIG_IOSAPIC
436
        if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
437
                iosapic_parse_prt();
438
#endif
439
 
440
        pci_for_each_dev(dev)
441
                acpi_pci_irq_enable(dev);
442
 
443
        return_VALUE(0);
444
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.