pci_irq.c 16.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 *  pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 11 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *  Copyright (C) 2002       Dominik Brodowski <devel@brodo.de>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */


28
#include <linux/dmi.h>
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

#define _COMPONENT		ACPI_PCI_COMPONENT
42
ACPI_MODULE_NAME("pci_irq");
L
Linus Torvalds 已提交
43

L
Len Brown 已提交
44
static struct acpi_prt_list acpi_prt;
L
Linus Torvalds 已提交
45 46 47 48 49 50
static DEFINE_SPINLOCK(acpi_prt_lock);

/* --------------------------------------------------------------------------
                         PCI IRQ Routing Table (PRT) Support
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
51 52 53
static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
							  int bus,
							  int device, int pin)
L
Linus Torvalds 已提交
54
{
L
Len Brown 已提交
55
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
56 57

	if (!acpi_prt.count)
58
		return NULL;
L
Linus Torvalds 已提交
59 60 61 62 63 64 65

	/*
	 * Parse through all PRT entries looking for a match on the specified
	 * PCI device's segment, bus, device, and pin (don't care about func).
	 *
	 */
	spin_lock(&acpi_prt_lock);
66
	list_for_each_entry(entry, &acpi_prt.entries, node) {
L
Len Brown 已提交
67 68 69 70
		if ((segment == entry->id.segment)
		    && (bus == entry->id.bus)
		    && (device == entry->id.device)
		    && (pin == entry->pin)) {
L
Linus Torvalds 已提交
71
			spin_unlock(&acpi_prt_lock);
72
			return entry;
L
Linus Torvalds 已提交
73 74 75 76
		}
	}

	spin_unlock(&acpi_prt_lock);
77
	return NULL;
L
Linus Torvalds 已提交
78 79
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */
static struct dmi_system_id medion_md9580[] = {
	{
		.ident = "Medion MD9580-F laptop",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
			DMI_MATCH(DMI_PRODUCT_NAME, "A555"),
		},
	},
	{ }
};

/* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */
static struct dmi_system_id dell_optiplex[] = {
	{
		.ident = "Dell Optiplex GX1",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"),
		},
	},
	{ }
};

/* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */
static struct dmi_system_id hp_t5710[] = {
	{
		.ident = "HP t5710",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
			DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"),
			DMI_MATCH(DMI_BOARD_NAME, "098Ch"),
		},
	},
	{ }
};

struct prt_quirk {
	struct dmi_system_id	*system;
	unsigned int		segment;
	unsigned int		bus;
	unsigned int		device;
	unsigned char		pin;
	char			*source;	/* according to BIOS */
	char			*actual_source;
};

/*
 * These systems have incorrect _PRT entries.  The BIOS claims the PCI
 * interrupt at the listed segment/bus/device/pin is connected to the first
 * link device, but it is actually connected to the second.
 */
static struct prt_quirk prt_quirks[] = {
	{ medion_md9580, 0, 0, 9, 'A',
134 135
		"\\_SB_.PCI0.ISA_.LNKA",
		"\\_SB_.PCI0.ISA_.LNKB"},
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
	{ dell_optiplex, 0, 0, 0xd, 'A',
		"\\_SB_.LNKB",
		"\\_SB_.LNKA"},
	{ hp_t5710, 0, 0, 1, 'A',
		"\\_SB_.PCI0.LNK1",
		"\\_SB_.PCI0.LNK3"},
};

static void
do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
{
	int i;
	struct prt_quirk *quirk;

	for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) {
		quirk = &prt_quirks[i];

		/* All current quirks involve link devices, not GSIs */
		if (!prt->source)
			continue;

		if (dmi_check_system(quirk->system) &&
		    entry->id.segment == quirk->segment &&
		    entry->id.bus == quirk->bus &&
		    entry->id.device == quirk->device &&
		    entry->pin + 'A' == quirk->pin &&
		    !strcmp(prt->source, quirk->source) &&
		    strlen(prt->source) >= strlen(quirk->actual_source)) {
			printk(KERN_WARNING PREFIX "firmware reports "
				"%04x:%02x:%02x[%c] connected to %s; "
				"changing to %s\n",
				entry->id.segment, entry->id.bus,
				entry->id.device, 'A' + entry->pin,
				prt->source, quirk->actual_source);
			strcpy(prt->source, quirk->actual_source);
		}
	}
}

L
Linus Torvalds 已提交
175
static int
L
Len Brown 已提交
176 177
acpi_pci_irq_add_entry(acpi_handle handle,
		       int segment, int bus, struct acpi_pci_routing_table *prt)
L
Linus Torvalds 已提交
178
{
L
Len Brown 已提交
179
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
180 181 182


	if (!prt)
183
		return -EINVAL;
L
Linus Torvalds 已提交
184

185
	entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
L
Linus Torvalds 已提交
186
	if (!entry)
187
		return -ENOMEM;
L
Linus Torvalds 已提交
188 189 190 191 192 193 194

	entry->id.segment = segment;
	entry->id.bus = bus;
	entry->id.device = (prt->address >> 16) & 0xFFFF;
	entry->id.function = prt->address & 0xFFFF;
	entry->pin = prt->pin;

195 196
	do_prt_fixups(entry, prt);

L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
	/*
	 * Type 1: Dynamic
	 * ---------------
	 * The 'source' field specifies the PCI interrupt link device used to
	 * configure the IRQ assigned to this slot|dev|pin.  The 'source_index'
	 * indicates which resource descriptor in the resource template (of
	 * the link device) this interrupt is allocated from.
	 * 
	 * NOTE: Don't query the Link Device for IRQ information at this time
	 *       because Link Device enumeration may not have occurred yet
	 *       (e.g. exists somewhere 'below' this _PRT entry in the ACPI
	 *       namespace).
	 */
	if (prt->source[0]) {
		acpi_get_handle(handle, prt->source, &entry->link.handle);
		entry->link.index = prt->source_index;
	}
	/*
	 * Type 2: Static
	 * --------------
	 * The 'source' field is NULL, and the 'source_index' field specifies
	 * the IRQ value, which is hardwired to specific interrupt inputs on
	 * the interrupt controller.
	 */
	else
		entry->link.index = prt->source_index;

	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
L
Len Brown 已提交
225 226 227 228
			      "      %02X:%02X:%02X[%c] -> %s[%d]\n",
			      entry->id.segment, entry->id.bus,
			      entry->id.device, ('A' + entry->pin), prt->source,
			      entry->link.index));
L
Linus Torvalds 已提交
229 230 231 232 233 234

	spin_lock(&acpi_prt_lock);
	list_add_tail(&entry->node, &acpi_prt.entries);
	acpi_prt.count++;
	spin_unlock(&acpi_prt_lock);

235
	return 0;
L
Linus Torvalds 已提交
236 237 238
}

static void
L
Len Brown 已提交
239
acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry)
L
Linus Torvalds 已提交
240
{
L
Len Brown 已提交
241
	if (segment == entry->id.segment && bus == entry->id.bus) {
L
Linus Torvalds 已提交
242 243 244 245 246 247
		acpi_prt.count--;
		list_del(&entry->node);
		kfree(entry);
	}
}

L
Len Brown 已提交
248
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
L
Linus Torvalds 已提交
249
{
L
Len Brown 已提交
250 251 252 253 254 255
	acpi_status status = AE_OK;
	char *pathname = NULL;
	struct acpi_buffer buffer = { 0, NULL };
	struct acpi_pci_routing_table *prt = NULL;
	struct acpi_pci_routing_table *entry = NULL;
	static int first_time = 1;
L
Linus Torvalds 已提交
256 257


258
	pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
L
Len Brown 已提交
259
	if (!pathname)
260
		return -ENOMEM;
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

	if (first_time) {
		acpi_prt.count = 0;
		INIT_LIST_HEAD(&acpi_prt.entries);
		first_time = 0;
	}

	/* 
	 * NOTE: We're given a 'handle' to the _PRT object's parent device
	 *       (either a PCI root bridge or PCI-PCI bridge).
	 */

	buffer.length = ACPI_PATHNAME_MAX;
	buffer.pointer = pathname;
	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);

	printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
L
Len Brown 已提交
278
	       pathname);
L
Linus Torvalds 已提交
279 280 281 282 283 284 285 286 287 288

	/* 
	 * Evaluate this _PRT and add its entries to our global list (acpi_prt).
	 */

	buffer.length = 0;
	buffer.pointer = NULL;
	kfree(pathname);
	status = acpi_get_irq_routing_table(handle, &buffer);
	if (status != AE_BUFFER_OVERFLOW) {
289 290
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
				acpi_format_exception(status)));
291
		return -ENODEV;
L
Linus Torvalds 已提交
292 293
	}

294
	prt = kzalloc(buffer.length, GFP_KERNEL);
L
Len Brown 已提交
295
	if (!prt) {
296
		return -ENOMEM;
L
Linus Torvalds 已提交
297 298 299 300 301
	}
	buffer.pointer = prt;

	status = acpi_get_irq_routing_table(handle, &buffer);
	if (ACPI_FAILURE(status)) {
302 303
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
				acpi_format_exception(status)));
L
Linus Torvalds 已提交
304
		kfree(buffer.pointer);
305
		return -ENODEV;
L
Linus Torvalds 已提交
306 307 308 309 310 311 312
	}

	entry = prt;

	while (entry && (entry->length > 0)) {
		acpi_pci_irq_add_entry(handle, segment, bus, entry);
		entry = (struct acpi_pci_routing_table *)
L
Len Brown 已提交
313
		    ((unsigned long)entry + entry->length);
L
Linus Torvalds 已提交
314 315 316 317
	}

	kfree(prt);

318
	return 0;
L
Linus Torvalds 已提交
319 320
}

L
Len Brown 已提交
321
void acpi_pci_irq_del_prt(int segment, int bus)
L
Linus Torvalds 已提交
322
{
L
Len Brown 已提交
323 324
	struct list_head *node = NULL, *n = NULL;
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
325

L
Len Brown 已提交
326
	if (!acpi_prt.count) {
L
Linus Torvalds 已提交
327 328 329
		return;
	}

L
Len Brown 已提交
330 331 332
	printk(KERN_DEBUG
	       "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment,
	       bus);
L
Linus Torvalds 已提交
333 334 335 336 337 338 339 340
	spin_lock(&acpi_prt_lock);
	list_for_each_safe(node, n, &acpi_prt.entries) {
		entry = list_entry(node, struct acpi_prt_entry, node);

		acpi_pci_irq_del_entry(segment, bus, entry);
	}
	spin_unlock(&acpi_prt_lock);
}
L
Len Brown 已提交
341

L
Linus Torvalds 已提交
342 343 344
/* --------------------------------------------------------------------------
                          PCI Interrupt Routing Support
   -------------------------------------------------------------------------- */
L
Len Brown 已提交
345
typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **);
L
Linus Torvalds 已提交
346

347 348
static int
acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
B
Bob Moore 已提交
349
		      int *triggering, int *polarity, char **link)
350
{
L
Len Brown 已提交
351
	int irq;
352 353 354 355


	if (entry->link.handle) {
		irq = acpi_pci_link_allocate_irq(entry->link.handle,
B
Bob Moore 已提交
356 357
						 entry->link.index, triggering,
						 polarity, link);
358
		if (irq < 0) {
359 360
			printk(KERN_WARNING PREFIX
				      "Invalid IRQ link routing entry\n");
361
			return -1;
362 363 364
		}
	} else {
		irq = entry->link.index;
B
Bob Moore 已提交
365 366
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
367 368 369
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
370
	return irq;
371 372 373 374
}

static int
acpi_pci_free_irq(struct acpi_prt_entry *entry,
B
Bob Moore 已提交
375
		  int *triggering, int *polarity, char **link)
376
{
L
Len Brown 已提交
377
	int irq;
378 379 380 381 382 383

	if (entry->link.handle) {
		irq = acpi_pci_link_free_irq(entry->link.handle);
	} else {
		irq = entry->link.index;
	}
384
	return irq;
385
}
L
Len Brown 已提交
386

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
#ifdef CONFIG_X86_IO_APIC
extern int noioapicquirk;

static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
{
	struct pci_bus *bus_it;

	for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
		if (!bus_it->self)
			return 0;

		printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor,
				bus_it->self->device);

		if (bus_it->self->irq_reroute_variant)
			return bus_it->self->irq_reroute_variant;
	}
	return 0;
}
#endif /* CONFIG_X86_IO_APIC */

L
Linus Torvalds 已提交
408 409 410 411 412 413
/*
 * acpi_pci_irq_lookup
 * success: return IRQ >= 0
 * failure: return -1
 */
static int
L
Len Brown 已提交
414 415 416
acpi_pci_irq_lookup(struct pci_bus *bus,
		    int device,
		    int pin,
B
Bob Moore 已提交
417 418
		    int *triggering,
		    int *polarity, char **link, irq_lookup_func func)
L
Linus Torvalds 已提交
419
{
L
Len Brown 已提交
420
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
421 422
	int segment = pci_domain_nr(bus);
	int bus_nr = bus->number;
423
	int ret;
L
Linus Torvalds 已提交
424 425


L
Len Brown 已提交
426 427 428
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Searching for PRT entry for %02x:%02x:%02x[%c]\n",
			  segment, bus_nr, device, ('A' + pin)));
L
Linus Torvalds 已提交
429

L
Len Brown 已提交
430
	entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin);
L
Linus Torvalds 已提交
431 432
	if (!entry) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
433
		return -1;
L
Linus Torvalds 已提交
434
	}
L
Len Brown 已提交
435

B
Bob Moore 已提交
436
	ret = func(entry, triggering, polarity, link);
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471

#ifdef CONFIG_X86_IO_APIC
	/*
	 * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the
	 * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel
	 * does during interrupt handling). When this INTx generation cannot be
	 * disabled, we reroute these interrupts to their legacy equivalent to
	 * get rid of spurious interrupts.
	 */
        if (!noioapicquirk) {
		switch (bridge_has_boot_interrupt_variant(bus)) {
		case 0:
			/* no rerouting necessary */
			break;

		case INTEL_IRQ_REROUTE_VARIANT:
			/*
			 * Remap according to INTx routing table in 6700PXH
			 * specs, intel order number 302628-002, section
			 * 2.15.2. Other chipsets (80332, ...) have the same
			 * mapping and are handled here as well.
			 */
			printk(KERN_INFO "pci irq %d -> rerouted to legacy "
					 "irq %d\n", ret, (ret % 4) + 16);
			ret = (ret % 4) + 16;
			break;

		default:
			printk(KERN_INFO "not rerouting irq %d to legacy irq: "
					 "unknown mapping\n", ret);
			break;
		}
	}
#endif /* CONFIG_X86_IO_APIC */

472
	return ret;
L
Linus Torvalds 已提交
473 474 475 476 477 478 479 480
}

/*
 * acpi_pci_irq_derive
 * success: return IRQ >= 0
 * failure: return < 0
 */
static int
L
Len Brown 已提交
481 482
acpi_pci_irq_derive(struct pci_dev *dev,
		    int pin,
B
Bob Moore 已提交
483 484
		    int *triggering,
		    int *polarity, char **link, irq_lookup_func func)
L
Linus Torvalds 已提交
485
{
L
Len Brown 已提交
486 487 488
	struct pci_dev *bridge = dev;
	int irq = -1;
	u8 bridge_pin = 0;
L
Linus Torvalds 已提交
489 490 491


	if (!dev)
492
		return -EINVAL;
L
Linus Torvalds 已提交
493 494 495 496 497 498 499 500 501 502 503

	/* 
	 * Attempt to derive an IRQ for this device from a parent bridge's
	 * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
	 */
	while (irq < 0 && bridge->bus->self) {
		pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
		bridge = bridge->bus->self;

		if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
			/* PC card has the same IRQ as its cardbridge */
504
			bridge_pin = bridge->pin;
L
Linus Torvalds 已提交
505
			if (!bridge_pin) {
L
Len Brown 已提交
506 507 508
				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
						  "No interrupt pin configured for device %s\n",
						  pci_name(bridge)));
509
				return -1;
L
Linus Torvalds 已提交
510 511
			}
			/* Pin is from 0 to 3 */
L
Len Brown 已提交
512
			bridge_pin--;
L
Linus Torvalds 已提交
513 514 515 516
			pin = bridge_pin;
		}

		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
B
Bob Moore 已提交
517
					  pin, triggering, polarity,
L
Len Brown 已提交
518
					  link, func);
L
Linus Torvalds 已提交
519 520 521
	}

	if (irq < 0) {
522 523
		printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n",
			      pci_name(dev));
524
		return -1;
L
Linus Torvalds 已提交
525 526 527
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
L
Len Brown 已提交
528
			  irq, pci_name(dev), pci_name(bridge)));
L
Linus Torvalds 已提交
529

530
	return irq;
L
Linus Torvalds 已提交
531 532 533 534 535 536 537 538
}

/*
 * acpi_pci_irq_enable
 * success: return 0
 * failure: return < 0
 */

L
Len Brown 已提交
539
int acpi_pci_irq_enable(struct pci_dev *dev)
L
Linus Torvalds 已提交
540
{
L
Len Brown 已提交
541 542
	int irq = 0;
	u8 pin = 0;
B
Bob Moore 已提交
543 544
	int triggering = ACPI_LEVEL_SENSITIVE;
	int polarity = ACPI_ACTIVE_LOW;
L
Len Brown 已提交
545 546
	char *link = NULL;
	int rc;
L
Linus Torvalds 已提交
547 548 549


	if (!dev)
550
		return -EINVAL;
L
Len Brown 已提交
551

552
	pin = dev->pin;
L
Linus Torvalds 已提交
553
	if (!pin) {
L
Len Brown 已提交
554 555 556
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "No interrupt pin configured for device %s\n",
				  pci_name(dev)));
557
		return 0;
L
Linus Torvalds 已提交
558 559 560 561
	}
	pin--;

	if (!dev->bus) {
562
		printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n");
563
		return -ENODEV;
L
Linus Torvalds 已提交
564 565 566 567 568 569
	}

	/* 
	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
	 * values override any BIOS-assigned IRQs set during boot.
	 */
L
Len Brown 已提交
570
	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
B
Bob Moore 已提交
571
				  &triggering, &polarity, &link,
L
Len Brown 已提交
572
				  acpi_pci_allocate_irq);
L
Linus Torvalds 已提交
573 574 575 576 577 578

	/*
	 * If no PRT entry was found, we'll try to derive an IRQ from the
	 * device's parent bridge.
	 */
	if (irq < 0)
B
Bob Moore 已提交
579 580
		irq = acpi_pci_irq_derive(dev, pin, &triggering,
					  &polarity, &link,
L
Len Brown 已提交
581 582
					  acpi_pci_allocate_irq);

583 584 585 586 587 588 589 590 591
	if (irq < 0) {
		/*
		 * IDE legacy mode controller IRQs are magic. Why do compat
		 * extensions always make such a nasty mess.
		 */
		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
				(dev->class & 0x05) == 0)
			return 0;
	}
L
Linus Torvalds 已提交
592 593 594 595 596 597
	/*
	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
	 * driver reported one, then use it. Exit in any case.
	 */
	if (irq < 0) {
		printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
L
Len Brown 已提交
598
		       pci_name(dev), ('A' + pin));
L
Linus Torvalds 已提交
599
		/* Interrupt Line values above 0xF are forbidden */
600
		if (dev->irq > 0 && (dev->irq <= 0xF)) {
L
Linus Torvalds 已提交
601
			printk(" - using IRQ %d\n", dev->irq);
L
Len Brown 已提交
602 603
			acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE,
					  ACPI_ACTIVE_LOW);
604
			return 0;
L
Len Brown 已提交
605
		} else {
L
Linus Torvalds 已提交
606
			printk("\n");
607
			return 0;
L
Linus Torvalds 已提交
608
		}
L
Len Brown 已提交
609
	}
L
Linus Torvalds 已提交
610

B
Bob Moore 已提交
611
	rc = acpi_register_gsi(irq, triggering, polarity);
612 613 614
	if (rc < 0) {
		printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed "
		       "to register GSI\n", pci_name(dev), ('A' + pin));
615
		return rc;
616 617
	}
	dev->irq = rc;
L
Linus Torvalds 已提交
618 619

	printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
L
Len Brown 已提交
620
	       pci_name(dev), 'A' + pin);
L
Linus Torvalds 已提交
621 622 623 624 625

	if (link)
		printk("Link [%s] -> ", link);

	printk("GSI %u (%s, %s) -> IRQ %d\n", irq,
B
Bob Moore 已提交
626 627
	       (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
	       (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
L
Linus Torvalds 已提交
628

629
	return 0;
L
Linus Torvalds 已提交
630 631
}

632
/* FIXME: implement x86/x86_64 version */
L
Len Brown 已提交
633 634 635
void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
{
}
636

L
Len Brown 已提交
637
void acpi_pci_irq_disable(struct pci_dev *dev)
L
Linus Torvalds 已提交
638
{
L
Len Brown 已提交
639 640
	int gsi = 0;
	u8 pin = 0;
B
Bob Moore 已提交
641 642
	int triggering = ACPI_LEVEL_SENSITIVE;
	int polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
643 644


645
	if (!dev || !dev->bus)
646
		return;
L
Linus Torvalds 已提交
647

648
	pin = dev->pin;
L
Linus Torvalds 已提交
649
	if (!pin)
650
		return;
L
Linus Torvalds 已提交
651 652 653 654 655
	pin--;

	/*
	 * First we check the PCI IRQ routing table (PRT) for an IRQ.
	 */
L
Len Brown 已提交
656
	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
B
Bob Moore 已提交
657
				  &triggering, &polarity, NULL,
L
Len Brown 已提交
658
				  acpi_pci_free_irq);
L
Linus Torvalds 已提交
659 660 661 662 663
	/*
	 * If no PRT entry was found, we'll try to derive an IRQ from the
	 * device's parent bridge.
	 */
	if (gsi < 0)
L
Len Brown 已提交
664
		gsi = acpi_pci_irq_derive(dev, pin,
B
Bob Moore 已提交
665
					  &triggering, &polarity, NULL,
L
Len Brown 已提交
666
					  acpi_pci_free_irq);
L
Linus Torvalds 已提交
667
	if (gsi < 0)
668
		return;
L
Linus Torvalds 已提交
669 670 671 672 673 674 675 676 677 678 679

	/*
	 * TBD: It might be worth clearing dev->irq by magic constant
	 * (e.g. PCI_UNDEFINED_IRQ).
	 */

	printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n",
	       pci_name(dev));

	acpi_unregister_gsi(gsi);

680
	return;
L
Linus Torvalds 已提交
681
}