pci_irq.c 14.9 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

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
struct acpi_prt_entry {
	struct list_head	node;
	struct acpi_pci_id	id;
	u8			pin;
	struct {
		acpi_handle		handle;
		u32			index;
	}			link;
	u32			irq;
};

struct acpi_prt_list {
	int			count;
	struct list_head	entries;
};

L
Len Brown 已提交
60
static struct acpi_prt_list acpi_prt;
L
Linus Torvalds 已提交
61 62
static DEFINE_SPINLOCK(acpi_prt_lock);

63 64
static inline char pin_name(int pin)
{
65
	return 'A' + pin - 1;
66 67
}

L
Linus Torvalds 已提交
68 69 70 71
/* --------------------------------------------------------------------------
                         PCI IRQ Routing Table (PRT) Support
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
72 73 74
static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
							  int bus,
							  int device, int pin)
L
Linus Torvalds 已提交
75
{
L
Len Brown 已提交
76
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
77 78

	if (!acpi_prt.count)
79
		return NULL;
L
Linus Torvalds 已提交
80 81 82 83 84 85 86

	/*
	 * 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);
87
	list_for_each_entry(entry, &acpi_prt.entries, node) {
L
Len Brown 已提交
88 89 90 91
		if ((segment == entry->id.segment)
		    && (bus == entry->id.bus)
		    && (device == entry->id.device)
		    && (pin == entry->pin)) {
L
Linus Torvalds 已提交
92
			spin_unlock(&acpi_prt_lock);
93
			return entry;
L
Linus Torvalds 已提交
94 95 96 97
		}
	}

	spin_unlock(&acpi_prt_lock);
98
	return NULL;
L
Linus Torvalds 已提交
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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/* 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',
155 156
		"\\_SB_.PCI0.ISA_.LNKA",
		"\\_SB_.PCI0.ISA_.LNKB"},
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	{ 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 &&
182
		    pin_name(entry->pin) == quirk->pin &&
183 184 185
		    !strcmp(prt->source, quirk->source) &&
		    strlen(prt->source) >= strlen(quirk->actual_source)) {
			printk(KERN_WARNING PREFIX "firmware reports "
186
				"%04x:%02x:%02x PCI INT %c connected to %s; "
187 188
				"changing to %s\n",
				entry->id.segment, entry->id.bus,
189
				entry->id.device, pin_name(entry->pin),
190 191 192 193 194 195
				prt->source, quirk->actual_source);
			strcpy(prt->source, quirk->actual_source);
		}
	}
}

L
Linus Torvalds 已提交
196
static int
L
Len Brown 已提交
197 198
acpi_pci_irq_add_entry(acpi_handle handle,
		       int segment, int bus, struct acpi_pci_routing_table *prt)
L
Linus Torvalds 已提交
199
{
L
Len Brown 已提交
200
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
201

202
	entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
L
Linus Torvalds 已提交
203
	if (!entry)
204
		return -ENOMEM;
L
Linus Torvalds 已提交
205

206 207 208 209 210
	/*
	 * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses
	 * 1=INTA, 2=INTB.  We use the PCI encoding throughout, so convert
	 * it here.
	 */
L
Linus Torvalds 已提交
211 212 213
	entry->id.segment = segment;
	entry->id.bus = bus;
	entry->id.device = (prt->address >> 16) & 0xFFFF;
214
	entry->pin = prt->pin + 1;
L
Linus Torvalds 已提交
215

216 217
	do_prt_fixups(entry, prt);

L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	/*
	 * 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,
246
			      "      %04x:%02x:%02x[%c] -> %s[%d]\n",
L
Len Brown 已提交
247
			      entry->id.segment, entry->id.bus,
248 249
			      entry->id.device, pin_name(entry->pin),
			      prt->source, entry->link.index));
L
Linus Torvalds 已提交
250 251 252 253 254 255

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

256
	return 0;
L
Linus Torvalds 已提交
257 258 259
}

static void
L
Len Brown 已提交
260
acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry)
L
Linus Torvalds 已提交
261
{
L
Len Brown 已提交
262
	if (segment == entry->id.segment && bus == entry->id.bus) {
L
Linus Torvalds 已提交
263 264 265 266 267 268
		acpi_prt.count--;
		list_del(&entry->node);
		kfree(entry);
	}
}

L
Len Brown 已提交
269
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
L
Linus Torvalds 已提交
270
{
271 272 273
	acpi_status status;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	struct acpi_pci_routing_table *entry;
L
Len Brown 已提交
274
	static int first_time = 1;
L
Linus Torvalds 已提交
275 276 277 278 279 280 281

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

282 283 284 285
	/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
	if (ACPI_FAILURE(status))
		return -ENODEV;
L
Linus Torvalds 已提交
286 287

	printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
288
	       (char *) buffer.pointer);
L
Linus Torvalds 已提交
289

290
	kfree(buffer.pointer);
L
Linus Torvalds 已提交
291

292
	buffer.length = ACPI_ALLOCATE_BUFFER;
L
Linus Torvalds 已提交
293 294 295 296
	buffer.pointer = NULL;

	status = acpi_get_irq_routing_table(handle, &buffer);
	if (ACPI_FAILURE(status)) {
297 298
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
				acpi_format_exception(status)));
L
Linus Torvalds 已提交
299
		kfree(buffer.pointer);
300
		return -ENODEV;
L
Linus Torvalds 已提交
301 302
	}

303
	entry = buffer.pointer;
L
Linus Torvalds 已提交
304 305 306
	while (entry && (entry->length > 0)) {
		acpi_pci_irq_add_entry(handle, segment, bus, entry);
		entry = (struct acpi_pci_routing_table *)
L
Len Brown 已提交
307
		    ((unsigned long)entry + entry->length);
L
Linus Torvalds 已提交
308 309
	}

310
	kfree(buffer.pointer);
311
	return 0;
L
Linus Torvalds 已提交
312 313
}

L
Len Brown 已提交
314
void acpi_pci_irq_del_prt(int segment, int bus)
L
Linus Torvalds 已提交
315
{
L
Len Brown 已提交
316 317
	struct list_head *node = NULL, *n = NULL;
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
318

L
Len Brown 已提交
319
	if (!acpi_prt.count) {
L
Linus Torvalds 已提交
320 321 322
		return;
	}

L
Len Brown 已提交
323
	printk(KERN_DEBUG
324 325
	       "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
	       segment, bus);
L
Linus Torvalds 已提交
326 327 328 329 330 331 332 333
	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 已提交
334

L
Linus Torvalds 已提交
335 336 337
/* --------------------------------------------------------------------------
                          PCI Interrupt Routing Support
   -------------------------------------------------------------------------- */
L
Len Brown 已提交
338
typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **);
L
Linus Torvalds 已提交
339

340 341
static int
acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
B
Bob Moore 已提交
342
		      int *triggering, int *polarity, char **link)
343
{
L
Len Brown 已提交
344
	int irq;
345 346 347 348


	if (entry->link.handle) {
		irq = acpi_pci_link_allocate_irq(entry->link.handle,
B
Bob Moore 已提交
349 350
						 entry->link.index, triggering,
						 polarity, link);
351
		if (irq < 0) {
352 353
			printk(KERN_WARNING PREFIX
				      "Invalid IRQ link routing entry\n");
354
			return -1;
355 356 357
		}
	} else {
		irq = entry->link.index;
B
Bob Moore 已提交
358 359
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
360 361
	}

362
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found GSI %d\n", irq));
363
	return irq;
364 365 366 367
}

static int
acpi_pci_free_irq(struct acpi_prt_entry *entry,
B
Bob Moore 已提交
368
		  int *triggering, int *polarity, char **link)
369
{
L
Len Brown 已提交
370
	int irq;
371 372 373 374 375 376

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

L
Linus Torvalds 已提交
380 381 382 383 384 385
/*
 * acpi_pci_irq_lookup
 * success: return IRQ >= 0
 * failure: return -1
 */
static int
L
Len Brown 已提交
386 387 388
acpi_pci_irq_lookup(struct pci_bus *bus,
		    int device,
		    int pin,
B
Bob Moore 已提交
389 390
		    int *triggering,
		    int *polarity, char **link, irq_lookup_func func)
L
Linus Torvalds 已提交
391
{
L
Len Brown 已提交
392
	struct acpi_prt_entry *entry = NULL;
L
Linus Torvalds 已提交
393 394
	int segment = pci_domain_nr(bus);
	int bus_nr = bus->number;
395
	int ret;
L
Linus Torvalds 已提交
396 397


L
Len Brown 已提交
398
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
399
			  "Searching for _PRT entry for %04x:%02x:%02x[%c]\n",
400
			  segment, bus_nr, device, pin_name(pin)));
L
Linus Torvalds 已提交
401

L
Len Brown 已提交
402
	entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin);
L
Linus Torvalds 已提交
403
	if (!entry) {
404
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_PRT entry not found\n"));
405
		return -1;
L
Linus Torvalds 已提交
406
	}
L
Len Brown 已提交
407

B
Bob Moore 已提交
408
	ret = func(entry, triggering, polarity, link);
409
	return ret;
L
Linus Torvalds 已提交
410 411 412 413 414 415 416 417
}

/*
 * acpi_pci_irq_derive
 * success: return IRQ >= 0
 * failure: return < 0
 */
static int
L
Len Brown 已提交
418 419
acpi_pci_irq_derive(struct pci_dev *dev,
		    int pin,
B
Bob Moore 已提交
420 421
		    int *triggering,
		    int *polarity, char **link, irq_lookup_func func)
L
Linus Torvalds 已提交
422
{
L
Len Brown 已提交
423 424
	struct pci_dev *bridge = dev;
	int irq = -1;
425
	u8 bridge_pin = 0, orig_pin = pin;
L
Linus Torvalds 已提交
426 427 428 429 430 431 432


	/* 
	 * 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) {
433
		pin = (((pin - 1) + PCI_SLOT(bridge->devfn)) % 4) + 1;
L
Linus Torvalds 已提交
434 435 436 437
		bridge = bridge->bus->self;

		if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
			/* PC card has the same IRQ as its cardbridge */
438
			bridge_pin = bridge->pin;
L
Linus Torvalds 已提交
439
			if (!bridge_pin) {
L
Len Brown 已提交
440 441 442
				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
						  "No interrupt pin configured for device %s\n",
						  pci_name(bridge)));
443
				return -1;
L
Linus Torvalds 已提交
444 445 446 447 448
			}
			pin = bridge_pin;
		}

		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
B
Bob Moore 已提交
449
					  pin, triggering, polarity,
L
Len Brown 已提交
450
					  link, func);
L
Linus Torvalds 已提交
451 452 453
	}

	if (irq < 0) {
454
		dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
455
			 pin_name(orig_pin));
456
		return -1;
L
Linus Torvalds 已提交
457 458
	}

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

462
	return irq;
L
Linus Torvalds 已提交
463 464 465 466 467 468 469 470
}

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

L
Len Brown 已提交
471
int acpi_pci_irq_enable(struct pci_dev *dev)
L
Linus Torvalds 已提交
472
{
473
	int gsi = 0;
L
Len Brown 已提交
474
	u8 pin = 0;
B
Bob Moore 已提交
475 476
	int triggering = ACPI_LEVEL_SENSITIVE;
	int polarity = ACPI_ACTIVE_LOW;
L
Len Brown 已提交
477
	char *link = NULL;
478
	char link_desc[16];
L
Len Brown 已提交
479
	int rc;
L
Linus Torvalds 已提交
480 481


482
	pin = dev->pin;
L
Linus Torvalds 已提交
483
	if (!pin) {
L
Len Brown 已提交
484 485 486
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "No interrupt pin configured for device %s\n",
				  pci_name(dev)));
487
		return 0;
L
Linus Torvalds 已提交
488 489 490 491 492 493
	}

	/* 
	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
	 * values override any BIOS-assigned IRQs set during boot.
	 */
494
	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
B
Bob Moore 已提交
495
				  &triggering, &polarity, &link,
L
Len Brown 已提交
496
				  acpi_pci_allocate_irq);
L
Linus Torvalds 已提交
497 498 499 500 501

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

507
	if (gsi < 0) {
508 509 510 511 512 513 514 515
		/*
		 * 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 已提交
516 517 518 519
	/*
	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
	 * driver reported one, then use it. Exit in any case.
	 */
520
	if (gsi < 0) {
521
		dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin));
L
Linus Torvalds 已提交
522
		/* Interrupt Line values above 0xF are forbidden */
523
		if (dev->irq > 0 && (dev->irq <= 0xF)) {
L
Linus Torvalds 已提交
524
			printk(" - using IRQ %d\n", dev->irq);
L
Len Brown 已提交
525 526
			acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE,
					  ACPI_ACTIVE_LOW);
527
			return 0;
L
Len Brown 已提交
528
		} else {
L
Linus Torvalds 已提交
529
			printk("\n");
530
			return 0;
L
Linus Torvalds 已提交
531
		}
L
Len Brown 已提交
532
	}
L
Linus Torvalds 已提交
533

534
	rc = acpi_register_gsi(gsi, triggering, polarity);
535
	if (rc < 0) {
536
		dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
537
			 pin_name(pin));
538
		return rc;
539 540
	}
	dev->irq = rc;
L
Linus Torvalds 已提交
541 542

	if (link)
543 544 545
		snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
	else
		link_desc[0] = '\0';
L
Linus Torvalds 已提交
546

547
	dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
548
		 pin_name(pin), link_desc, gsi,
549 550
		 (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
		 (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
L
Linus Torvalds 已提交
551

552
	return 0;
L
Linus Torvalds 已提交
553 554
}

555
/* FIXME: implement x86/x86_64 version */
L
Len Brown 已提交
556 557 558
void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
{
}
559

L
Len Brown 已提交
560
void acpi_pci_irq_disable(struct pci_dev *dev)
L
Linus Torvalds 已提交
561
{
L
Len Brown 已提交
562 563
	int gsi = 0;
	u8 pin = 0;
B
Bob Moore 已提交
564 565
	int triggering = ACPI_LEVEL_SENSITIVE;
	int polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
566 567


568
	pin = dev->pin;
L
Linus Torvalds 已提交
569
	if (!pin)
570
		return;
L
Linus Torvalds 已提交
571 572 573 574

	/*
	 * First we check the PCI IRQ routing table (PRT) for an IRQ.
	 */
L
Len Brown 已提交
575
	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
B
Bob Moore 已提交
576
				  &triggering, &polarity, NULL,
L
Len Brown 已提交
577
				  acpi_pci_free_irq);
L
Linus Torvalds 已提交
578 579 580 581 582
	/*
	 * 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 已提交
583
		gsi = acpi_pci_irq_derive(dev, pin,
B
Bob Moore 已提交
584
					  &triggering, &polarity, NULL,
L
Len Brown 已提交
585
					  acpi_pci_free_irq);
L
Linus Torvalds 已提交
586
	if (gsi < 0)
587
		return;
L
Linus Torvalds 已提交
588 589 590 591 592 593

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

594
	dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
L
Linus Torvalds 已提交
595 596
	acpi_unregister_gsi(gsi);
}