pci_link.c 24.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6
/*
 *  pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $)
 *
 *  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>
7
 *  Copyright (c) 2015, The Linux Foundation. All rights reserved.
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  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.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * TBD: 
 *      1. Support more than one IRQ resource entry per link device (index).
 *	2. Implement start/stop mechanism and use ACPI Bus Driver facilities
 *	   for IRQ management (e.g. start()->_SRS).
 */

29
#include <linux/syscore_ops.h>
L
Linus Torvalds 已提交
30 31 32 33 34 35 36
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
I
Ingo Molnar 已提交
37
#include <linux/mutex.h>
38
#include <linux/slab.h>
39
#include <linux/acpi.h>
L
Linus Torvalds 已提交
40

41 42
#include "internal.h"

43
#define _COMPONENT			ACPI_PCI_COMPONENT
44
ACPI_MODULE_NAME("pci_link");
L
Linus Torvalds 已提交
45 46 47 48
#define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
#define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
#define ACPI_PCI_LINK_FILE_INFO		"info"
#define ACPI_PCI_LINK_FILE_STATUS	"state"
49 50
#define ACPI_PCI_LINK_MAX_POSSIBLE	16

51 52 53
static int acpi_pci_link_add(struct acpi_device *device,
			     const struct acpi_device_id *not_used);
static void acpi_pci_link_remove(struct acpi_device *device);
L
Linus Torvalds 已提交
54

55
static const struct acpi_device_id link_device_ids[] = {
56 57 58 59
	{"PNP0C0F", 0},
	{"", 0},
};

60
static struct acpi_scan_handler pci_link_handler = {
61
	.ids = link_device_ids,
62 63
	.attach = acpi_pci_link_add,
	.detach = acpi_pci_link_remove,
L
Linus Torvalds 已提交
64 65
};

66 67 68 69
/*
 * If a link is initialized, we never change its active and initialized
 * later even the link is disable. Instead, we just repick the active irq
 */
L
Linus Torvalds 已提交
70
struct acpi_pci_link_irq {
71
	u32 active;		/* Current IRQ */
B
Bob Moore 已提交
72
	u8 triggering;		/* All IRQs */
73
	u8 polarity;		/* All IRQs */
L
Len Brown 已提交
74 75
	u8 resource_type;
	u8 possible_count;
76
	u32 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
L
Len Brown 已提交
77 78
	u8 initialized:1;
	u8 reserved:7;
L
Linus Torvalds 已提交
79 80 81
};

struct acpi_pci_link {
82
	struct list_head		list;
83 84 85
	struct acpi_device		*device;
	struct acpi_pci_link_irq	irq;
	int				refcnt;
L
Linus Torvalds 已提交
86 87
};

88
static LIST_HEAD(acpi_link_list);
A
Adrian Bunk 已提交
89
static DEFINE_MUTEX(acpi_link_lock);
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97

/* --------------------------------------------------------------------------
                            PCI Link Device Management
   -------------------------------------------------------------------------- */

/*
 * set context (link) possible list from resource list
 */
98 99
static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
						void *context)
L
Linus Torvalds 已提交
100
{
101
	struct acpi_pci_link *link = context;
102
	u32 i;
L
Linus Torvalds 已提交
103

104
	switch (resource->type) {
B
Bob Moore 已提交
105
	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
106
	case ACPI_RESOURCE_TYPE_END_TAG:
107
		return AE_OK;
B
Bob Moore 已提交
108
	case ACPI_RESOURCE_TYPE_IRQ:
L
Len Brown 已提交
109 110
		{
			struct acpi_resource_irq *p = &resource->data.irq;
B
Bob Moore 已提交
111
			if (!p || !p->interrupt_count) {
112 113
				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
						  "Blank _PRS IRQ resource\n"));
114
				return AE_OK;
L
Linus Torvalds 已提交
115
			}
L
Len Brown 已提交
116
			for (i = 0;
B
Bob Moore 已提交
117
			     (i < p->interrupt_count
L
Len Brown 已提交
118 119
			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
				if (!p->interrupts[i]) {
120 121 122
					printk(KERN_WARNING PREFIX
					       "Invalid _PRS IRQ %d\n",
					       p->interrupts[i]);
L
Len Brown 已提交
123 124 125 126 127
					continue;
				}
				link->irq.possible[i] = p->interrupts[i];
				link->irq.possible_count++;
			}
B
Bob Moore 已提交
128 129 130
			link->irq.triggering = p->triggering;
			link->irq.polarity = p->polarity;
			link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ;
L
Len Brown 已提交
131
			break;
L
Linus Torvalds 已提交
132
		}
B
Bob Moore 已提交
133
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
L
Len Brown 已提交
134
		{
B
Bob Moore 已提交
135
			struct acpi_resource_extended_irq *p =
L
Len Brown 已提交
136
			    &resource->data.extended_irq;
B
Bob Moore 已提交
137
			if (!p || !p->interrupt_count) {
138
				printk(KERN_WARNING PREFIX
139
					      "Blank _PRS EXT IRQ resource\n");
140
				return AE_OK;
L
Len Brown 已提交
141 142
			}
			for (i = 0;
B
Bob Moore 已提交
143
			     (i < p->interrupt_count
L
Len Brown 已提交
144 145
			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
				if (!p->interrupts[i]) {
146 147 148
					printk(KERN_WARNING PREFIX
					       "Invalid _PRS IRQ %d\n",
					       p->interrupts[i]);
L
Len Brown 已提交
149 150 151 152
					continue;
				}
				link->irq.possible[i] = p->interrupts[i];
				link->irq.possible_count++;
L
Linus Torvalds 已提交
153
			}
B
Bob Moore 已提交
154 155 156
			link->irq.triggering = p->triggering;
			link->irq.polarity = p->polarity;
			link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
L
Len Brown 已提交
157
			break;
L
Linus Torvalds 已提交
158 159
		}
	default:
160 161
		printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ\n",
		       resource->type);
162
		return AE_OK;
L
Linus Torvalds 已提交
163 164
	}

165
	return AE_CTRL_TERMINATE;
L
Linus Torvalds 已提交
166 167
}

L
Len Brown 已提交
168
static int acpi_pci_link_get_possible(struct acpi_pci_link *link)
L
Linus Torvalds 已提交
169
{
L
Len Brown 已提交
170
	acpi_status status;
L
Linus Torvalds 已提交
171

172
	status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
L
Len Brown 已提交
173
				     acpi_pci_link_check_possible, link);
L
Linus Torvalds 已提交
174
	if (ACPI_FAILURE(status)) {
175
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
176
		return -ENODEV;
L
Linus Torvalds 已提交
177 178
	}

L
Len Brown 已提交
179 180 181
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Found %d possible IRQs\n",
			  link->irq.possible_count));
L
Linus Torvalds 已提交
182

183
	return 0;
L
Linus Torvalds 已提交
184 185
}

186 187
static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
					       void *context)
L
Linus Torvalds 已提交
188
{
189
	int *irq = context;
L
Linus Torvalds 已提交
190

191
	switch (resource->type) {
192 193 194
	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_TAG:
		return AE_OK;
B
Bob Moore 已提交
195
	case ACPI_RESOURCE_TYPE_IRQ:
L
Len Brown 已提交
196 197
		{
			struct acpi_resource_irq *p = &resource->data.irq;
B
Bob Moore 已提交
198
			if (!p || !p->interrupt_count) {
L
Len Brown 已提交
199 200 201 202 203
				/*
				 * IRQ descriptors may have no IRQ# bits set,
				 * particularly those those w/ _STA disabled
				 */
				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
204
						  "Blank _CRS IRQ resource\n"));
205
				return AE_OK;
L
Len Brown 已提交
206 207 208
			}
			*irq = p->interrupts[0];
			break;
L
Linus Torvalds 已提交
209
		}
B
Bob Moore 已提交
210
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
L
Len Brown 已提交
211
		{
B
Bob Moore 已提交
212
			struct acpi_resource_extended_irq *p =
L
Len Brown 已提交
213
			    &resource->data.extended_irq;
B
Bob Moore 已提交
214
			if (!p || !p->interrupt_count) {
L
Len Brown 已提交
215 216 217 218
				/*
				 * extended IRQ descriptors must
				 * return at least 1 IRQ
				 */
219
				printk(KERN_WARNING PREFIX
220
					      "Blank _CRS EXT IRQ resource\n");
221
				return AE_OK;
L
Len Brown 已提交
222 223 224
			}
			*irq = p->interrupts[0];
			break;
L
Linus Torvalds 已提交
225
		}
226
		break;
L
Linus Torvalds 已提交
227
	default:
228 229
		printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ\n",
		       resource->type);
230
		return AE_OK;
L
Linus Torvalds 已提交
231
	}
232

233
	return AE_CTRL_TERMINATE;
L
Linus Torvalds 已提交
234 235 236 237 238 239 240 241 242
}

/*
 * Run _CRS and set link->irq.active
 *
 * return value:
 * 0 - success
 * !0 - failure
 */
L
Len Brown 已提交
243
static int acpi_pci_link_get_current(struct acpi_pci_link *link)
L
Linus Torvalds 已提交
244
{
L
Len Brown 已提交
245
	int result = 0;
246
	acpi_status status;
L
Len Brown 已提交
247
	int irq = 0;
L
Linus Torvalds 已提交
248 249 250 251 252 253 254 255

	link->irq.active = 0;

	/* in practice, status disabled is meaningless, ignore it */
	if (acpi_strict) {
		/* Query _STA, set link->device->status */
		result = acpi_bus_get_status(link->device);
		if (result) {
256
			printk(KERN_ERR PREFIX "Unable to read status\n");
L
Linus Torvalds 已提交
257 258 259 260 261
			goto end;
		}

		if (!link->device->status.enabled) {
			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
262
			return 0;
L
Linus Torvalds 已提交
263 264 265 266 267 268 269
		}
	}

	/* 
	 * Query and parse _CRS to get the current IRQ assignment. 
	 */

270
	status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
L
Len Brown 已提交
271
				     acpi_pci_link_check_current, &irq);
L
Linus Torvalds 已提交
272
	if (ACPI_FAILURE(status)) {
273
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
L
Linus Torvalds 已提交
274 275 276 277 278
		result = -ENODEV;
		goto end;
	}

	if (acpi_strict && !irq) {
279
		printk(KERN_ERR PREFIX "_CRS returned 0\n");
L
Linus Torvalds 已提交
280 281 282 283 284 285 286
		result = -ENODEV;
	}

	link->irq.active = irq;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));

L
Len Brown 已提交
287
      end:
288
	return result;
L
Linus Torvalds 已提交
289 290
}

L
Len Brown 已提交
291
static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
L
Linus Torvalds 已提交
292
{
293 294
	int result;
	acpi_status status;
L
Linus Torvalds 已提交
295
	struct {
L
Len Brown 已提交
296 297 298 299
		struct acpi_resource res;
		struct acpi_resource end;
	} *resource;
	struct acpi_buffer buffer = { 0, NULL };
L
Linus Torvalds 已提交
300

301
	if (!irq)
302
		return -EINVAL;
L
Linus Torvalds 已提交
303

304
	resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
L
Len Brown 已提交
305
	if (!resource)
306
		return -ENOMEM;
L
Linus Torvalds 已提交
307

L
Len Brown 已提交
308
	buffer.length = sizeof(*resource) + 1;
L
Linus Torvalds 已提交
309 310
	buffer.pointer = resource;

L
Len Brown 已提交
311
	switch (link->irq.resource_type) {
B
Bob Moore 已提交
312 313
	case ACPI_RESOURCE_TYPE_IRQ:
		resource->res.type = ACPI_RESOURCE_TYPE_IRQ;
L
Linus Torvalds 已提交
314
		resource->res.length = sizeof(struct acpi_resource);
B
Bob Moore 已提交
315 316 317 318 319
		resource->res.data.irq.triggering = link->irq.triggering;
		resource->res.data.irq.polarity =
		    link->irq.polarity;
		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
			resource->res.data.irq.sharable =
L
Len Brown 已提交
320
			    ACPI_EXCLUSIVE;
L
Linus Torvalds 已提交
321
		else
B
Bob Moore 已提交
322 323
			resource->res.data.irq.sharable = ACPI_SHARED;
		resource->res.data.irq.interrupt_count = 1;
L
Linus Torvalds 已提交
324 325
		resource->res.data.irq.interrupts[0] = irq;
		break;
L
Len Brown 已提交
326

B
Bob Moore 已提交
327 328
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
L
Linus Torvalds 已提交
329
		resource->res.length = sizeof(struct acpi_resource);
L
Len Brown 已提交
330 331
		resource->res.data.extended_irq.producer_consumer =
		    ACPI_CONSUMER;
B
Bob Moore 已提交
332 333 334 335 336 337
		resource->res.data.extended_irq.triggering =
		    link->irq.triggering;
		resource->res.data.extended_irq.polarity =
		    link->irq.polarity;
		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
			resource->res.data.irq.sharable =
L
Len Brown 已提交
338
			    ACPI_EXCLUSIVE;
L
Linus Torvalds 已提交
339
		else
B
Bob Moore 已提交
340 341
			resource->res.data.irq.sharable = ACPI_SHARED;
		resource->res.data.extended_irq.interrupt_count = 1;
L
Linus Torvalds 已提交
342 343 344 345
		resource->res.data.extended_irq.interrupts[0] = irq;
		/* ignore resource_source, it's optional */
		break;
	default:
346
		printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
L
Linus Torvalds 已提交
347 348 349 350
		result = -EINVAL;
		goto end;

	}
B
Bob Moore 已提交
351
	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
352
	resource->end.length = sizeof(struct acpi_resource);
L
Linus Torvalds 已提交
353 354

	/* Attempt to set the resource */
355
	status = acpi_set_current_resources(link->device->handle, &buffer);
L
Linus Torvalds 已提交
356 357 358

	/* check for total failure */
	if (ACPI_FAILURE(status)) {
359
		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
L
Linus Torvalds 已提交
360 361 362 363 364 365 366
		result = -ENODEV;
		goto end;
	}

	/* Query _STA, set device->status */
	result = acpi_bus_get_status(link->device);
	if (result) {
367
		printk(KERN_ERR PREFIX "Unable to read status\n");
L
Linus Torvalds 已提交
368 369 370
		goto end;
	}
	if (!link->device->status.enabled) {
371 372
		printk(KERN_WARNING PREFIX
			      "%s [%s] disabled and referenced, BIOS bug\n",
373
			      acpi_device_name(link->device),
374
			      acpi_device_bid(link->device));
L
Linus Torvalds 已提交
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
	}

	/* Query _CRS, set link->irq.active */
	result = acpi_pci_link_get_current(link);
	if (result) {
		goto end;
	}

	/*
	 * Is current setting not what we set?
	 * set link->irq.active
	 */
	if (link->irq.active != irq) {
		/*
		 * policy: when _CRS doesn't return what we just _SRS
		 * assume _SRS worked and override _CRS value.
		 */
392 393
		printk(KERN_WARNING PREFIX
			      "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
394
			      acpi_device_name(link->device),
395
			      acpi_device_bid(link->device), link->irq.active, irq);
L
Linus Torvalds 已提交
396 397 398 399
		link->irq.active = irq;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
L
Len Brown 已提交
400 401

      end:
L
Linus Torvalds 已提交
402
	kfree(resource);
403
	return result;
L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
}

/* --------------------------------------------------------------------------
                            PCI Link IRQ Management
   -------------------------------------------------------------------------- */

/*
 * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
 * Link Devices to move the PIRQs around to minimize sharing.
 * 
 * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
 * that the BIOS has already set to active.  This is necessary because
 * ACPI has no automatic means of knowing what ISA IRQs are used.  Note that
 * if the BIOS doesn't set a Link Device active, ACPI needs to program it
 * even if acpi_irq_nobalance is set.
 *
 * A tables of penalties avoids directing PCI interrupts to well known
 * ISA IRQs. Boot params are available to over-ride the default table:
 *
 * List interrupts that are free for PCI use.
 * acpi_irq_pci=n[,m]
 *
 * List interrupts that should not be used for PCI:
 * acpi_irq_isa=n[,m]
 *
 * Note that PCI IRQ routers have a list of possible IRQs,
 * which may not include the IRQs this table says are available.
 * 
 * Since this heuristic can't tell the difference between a link
 * that no device will attach to, vs. a link which may be shared
 * by multiple active devices -- it is not optimal.
 *
 * If interrupt performance is that important, get an IO-APIC system
 * with a pin dedicated to each device.  Or for that matter, an MSI
 * enabled system.
 */

#define ACPI_MAX_ISA_IRQ	16

#define PIRQ_PENALTY_PCI_AVAILABLE	(0)
#define PIRQ_PENALTY_PCI_POSSIBLE	(16*16)
#define PIRQ_PENALTY_PCI_USING		(16*16*16)
#define PIRQ_PENALTY_ISA_TYPICAL	(16*16*16*16)
#define PIRQ_PENALTY_ISA_USED		(16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS		(16*16*16*16*16*16)

450
static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = {
L
Linus Torvalds 已提交
451 452 453
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
L
Len Brown 已提交
454 455
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
L
Linus Torvalds 已提交
456 457 458 459 460 461 462
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ5 sometimes SoundBlaster */
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ6 */
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ7 parallel, spurious */
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ8 rtc, sometimes */
	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ9  PCI, often acpi */
	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ10 PCI */
	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ11 PCI */
463 464 465 466
	PIRQ_PENALTY_ISA_USED,		/* IRQ12 mouse */
	PIRQ_PENALTY_ISA_USED,		/* IRQ13 fpe, sometimes */
	PIRQ_PENALTY_ISA_USED,		/* IRQ14 ide0 */
	PIRQ_PENALTY_ISA_USED,		/* IRQ15 ide1 */
L
Linus Torvalds 已提交
467 468
};

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
struct irq_penalty_info {
	int irq;
	int penalty;
	struct list_head node;
};

static LIST_HEAD(acpi_irq_penalty_list);

static int acpi_irq_get_penalty(int irq)
{
	struct irq_penalty_info *irq_info;

	if (irq < ACPI_MAX_ISA_IRQ)
		return acpi_irq_isa_penalty[irq];

	list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
		if (irq_info->irq == irq)
			return irq_info->penalty;
	}

	return 0;
}

static int acpi_irq_set_penalty(int irq, int new_penalty)
{
	struct irq_penalty_info *irq_info;

	/* see if this is a ISA IRQ */
	if (irq < ACPI_MAX_ISA_IRQ) {
		acpi_irq_isa_penalty[irq] = new_penalty;
		return 0;
	}

	/* next, try to locate from the dynamic list */
	list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
		if (irq_info->irq == irq) {
			irq_info->penalty  = new_penalty;
			return 0;
		}
	}

	/* nope, let's allocate a slot for this IRQ */
	irq_info = kzalloc(sizeof(*irq_info), GFP_KERNEL);
	if (!irq_info)
		return -ENOMEM;

	irq_info->irq = irq;
	irq_info->penalty = new_penalty;
	list_add_tail(&irq_info->node, &acpi_irq_penalty_list);

	return 0;
}

static void acpi_irq_add_penalty(int irq, int penalty)
{
	int curpen = acpi_irq_get_penalty(irq);

	acpi_irq_set_penalty(irq, curpen + penalty);
}

L
Len Brown 已提交
529
int __init acpi_irq_penalty_init(void)
L
Linus Torvalds 已提交
530
{
531 532
	struct acpi_pci_link *link;
	int i;
L
Linus Torvalds 已提交
533 534 535 536

	/*
	 * Update penalties to facilitate IRQ balancing.
	 */
537
	list_for_each_entry(link, &acpi_link_list, list) {
L
Linus Torvalds 已提交
538 539 540 541 542 543

		/*
		 * reflect the possible and active irqs in the penalty table --
		 * useful for breaking ties.
		 */
		if (link->irq.possible_count) {
L
Len Brown 已提交
544 545 546
			int penalty =
			    PIRQ_PENALTY_PCI_POSSIBLE /
			    link->irq.possible_count;
L
Linus Torvalds 已提交
547 548

			for (i = 0; i < link->irq.possible_count; i++) {
549 550 551 552 553
				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) {
					int irqpos = link->irq.possible[i];

					acpi_irq_add_penalty(irqpos, penalty);
				}
L
Linus Torvalds 已提交
554 555 556
			}

		} else if (link->irq.active) {
557 558
			acpi_irq_add_penalty(link->irq.active,
					     PIRQ_PENALTY_PCI_POSSIBLE);
L
Linus Torvalds 已提交
559 560
		}
	}
561

562
	return 0;
L
Linus Torvalds 已提交
563 564
}

565
static int acpi_irq_balance = -1;	/* 0: static, 1: balance */
L
Linus Torvalds 已提交
566

L
Len Brown 已提交
567
static int acpi_pci_link_allocate(struct acpi_pci_link *link)
L
Linus Torvalds 已提交
568
{
L
Len Brown 已提交
569 570
	int irq;
	int i;
L
Linus Torvalds 已提交
571

572 573 574 575
	if (link->irq.initialized) {
		if (link->refcnt == 0)
			/* This means the link is disabled but initialized */
			acpi_pci_link_set(link, link->irq.active);
576
		return 0;
577
	}
L
Linus Torvalds 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590

	/*
	 * search for active IRQ in list of possible IRQs.
	 */
	for (i = 0; i < link->irq.possible_count; ++i) {
		if (link->irq.active == link->irq.possible[i])
			break;
	}
	/*
	 * forget active IRQ that is not in possible list
	 */
	if (i == link->irq.possible_count) {
		if (acpi_strict)
591 592
			printk(KERN_WARNING PREFIX "_CRS %d not found"
				      " in _PRS\n", link->irq.active);
L
Linus Torvalds 已提交
593 594 595 596 597 598
		link->irq.active = 0;
	}

	/*
	 * if active found, use it; else pick entry from end of possible list.
	 */
599
	if (link->irq.active)
L
Linus Torvalds 已提交
600
		irq = link->irq.active;
601
	else
L
Linus Torvalds 已提交
602 603 604 605 606 607 608 609
		irq = link->irq.possible[link->irq.possible_count - 1];

	if (acpi_irq_balance || !link->irq.active) {
		/*
		 * Select the best IRQ.  This is done in reverse to promote
		 * the use of IRQs 9, 10, 11, and >15.
		 */
		for (i = (link->irq.possible_count - 1); i >= 0; i--) {
610 611
			if (acpi_irq_get_penalty(irq) >
			    acpi_irq_get_penalty(link->irq.possible[i]))
L
Linus Torvalds 已提交
612 613 614
				irq = link->irq.possible[i];
		}
	}
615
	if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
616 617 618 619 620 621
		printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. "
			    "Try pci=noacpi or acpi=off\n",
			    acpi_device_name(link->device),
			    acpi_device_bid(link->device));
		return -ENODEV;
	}
L
Linus Torvalds 已提交
622 623 624

	/* Attempt to enable the link device at this IRQ. */
	if (acpi_pci_link_set(link, irq)) {
625 626
		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
			    "Try pci=noacpi or acpi=off\n",
627
			    acpi_device_name(link->device),
628
			    acpi_device_bid(link->device));
629
		return -ENODEV;
L
Linus Torvalds 已提交
630
	} else {
631 632
		acpi_irq_add_penalty(link->irq.active, PIRQ_PENALTY_PCI_USING);

633
		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
L
Len Brown 已提交
634 635
		       acpi_device_name(link->device),
		       acpi_device_bid(link->device), link->irq.active);
L
Linus Torvalds 已提交
636 637 638
	}

	link->irq.initialized = 1;
639
	return 0;
L
Linus Torvalds 已提交
640 641 642
}

/*
643
 * acpi_pci_link_allocate_irq
L
Linus Torvalds 已提交
644 645 646
 * success: return IRQ >= 0
 * failure: return -1
 */
647 648
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
			       int *polarity, char **name)
L
Linus Torvalds 已提交
649
{
650 651 652
	int result;
	struct acpi_device *device;
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
653 654 655

	result = acpi_bus_get_device(handle, &device);
	if (result) {
656
		printk(KERN_ERR PREFIX "Invalid link device\n");
657
		return -1;
L
Linus Torvalds 已提交
658 659
	}

660
	link = acpi_driver_data(device);
L
Linus Torvalds 已提交
661
	if (!link) {
662
		printk(KERN_ERR PREFIX "Invalid link context\n");
663
		return -1;
L
Linus Torvalds 已提交
664 665 666 667
	}

	/* TBD: Support multiple index (IRQ) entries per Link Device */
	if (index) {
668
		printk(KERN_ERR PREFIX "Invalid index %d\n", index);
669
		return -1;
L
Linus Torvalds 已提交
670 671
	}

I
Ingo Molnar 已提交
672
	mutex_lock(&acpi_link_lock);
673
	if (acpi_pci_link_allocate(link)) {
I
Ingo Molnar 已提交
674
		mutex_unlock(&acpi_link_lock);
675
		return -1;
676
	}
L
Len Brown 已提交
677

L
Linus Torvalds 已提交
678
	if (!link->irq.active) {
I
Ingo Molnar 已提交
679
		mutex_unlock(&acpi_link_lock);
680
		printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
681
		return -1;
L
Linus Torvalds 已提交
682
	}
L
Len Brown 已提交
683
	link->refcnt++;
I
Ingo Molnar 已提交
684
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
685

B
Bob Moore 已提交
686 687 688 689
	if (triggering)
		*triggering = link->irq.triggering;
	if (polarity)
		*polarity = link->irq.polarity;
L
Len Brown 已提交
690 691
	if (name)
		*name = acpi_device_bid(link->device);
692
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
L
Len Brown 已提交
693 694
			  "Link %s is referenced\n",
			  acpi_device_bid(link->device)));
695
	return (link->irq.active);
L
Linus Torvalds 已提交
696 697
}

698 699 700 701
/*
 * We don't change link's irq information here.  After it is reenabled, we
 * continue use the info
 */
L
Len Brown 已提交
702
int acpi_pci_link_free_irq(acpi_handle handle)
703
{
704 705
	struct acpi_device *device;
	struct acpi_pci_link *link;
L
Len Brown 已提交
706
	acpi_status result;
707 708 709

	result = acpi_bus_get_device(handle, &device);
	if (result) {
710
		printk(KERN_ERR PREFIX "Invalid link device\n");
711
		return -1;
712
	}
L
Linus Torvalds 已提交
713

714
	link = acpi_driver_data(device);
715
	if (!link) {
716
		printk(KERN_ERR PREFIX "Invalid link context\n");
717
		return -1;
718 719
	}

I
Ingo Molnar 已提交
720
	mutex_lock(&acpi_link_lock);
721
	if (!link->irq.initialized) {
I
Ingo Molnar 已提交
722
		mutex_unlock(&acpi_link_lock);
723
		printk(KERN_ERR PREFIX "Link isn't initialized\n");
724
		return -1;
725
	}
726 727 728 729 730 731 732 733 734 735
#ifdef	FUTURE_USE
	/*
	 * The Link reference count allows us to _DISable an unused link
	 * and suspend time, and set it again  on resume.
	 * However, 2.6.12 still has irq_router.resume
	 * which blindly restores the link state.
	 * So we disable the reference count method
	 * to prevent duplicate acpi_pci_link_set()
	 * which would harm some systems
	 */
L
Len Brown 已提交
736
	link->refcnt--;
737
#endif
738
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
L
Len Brown 已提交
739 740
			  "Link %s is dereferenced\n",
			  acpi_device_bid(link->device)));
741

742
	if (link->refcnt == 0)
743
		acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
744

I
Ingo Molnar 已提交
745
	mutex_unlock(&acpi_link_lock);
746
	return (link->irq.active);
747
}
L
Len Brown 已提交
748

L
Linus Torvalds 已提交
749 750 751 752
/* --------------------------------------------------------------------------
                                 Driver Interface
   -------------------------------------------------------------------------- */

753 754
static int acpi_pci_link_add(struct acpi_device *device,
			     const struct acpi_device_id *not_used)
L
Linus Torvalds 已提交
755
{
756 757 758
	int result;
	struct acpi_pci_link *link;
	int i;
L
Len Brown 已提交
759
	int found = 0;
L
Linus Torvalds 已提交
760

761
	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
L
Linus Torvalds 已提交
762
	if (!link)
763
		return -ENOMEM;
L
Linus Torvalds 已提交
764 765 766 767

	link->device = device;
	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
768
	device->driver_data = link;
L
Linus Torvalds 已提交
769

I
Ingo Molnar 已提交
770
	mutex_lock(&acpi_link_lock);
L
Linus Torvalds 已提交
771 772 773 774 775 776 777
	result = acpi_pci_link_get_possible(link);
	if (result)
		goto end;

	/* query and set link->irq.active */
	acpi_pci_link_get_current(link);

778
	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
L
Len Brown 已提交
779
	       acpi_device_bid(device));
L
Linus Torvalds 已提交
780 781
	for (i = 0; i < link->irq.possible_count; i++) {
		if (link->irq.active == link->irq.possible[i]) {
782
			printk(KERN_CONT " *%d", link->irq.possible[i]);
L
Linus Torvalds 已提交
783
			found = 1;
L
Len Brown 已提交
784
		} else
785
			printk(KERN_CONT " %d", link->irq.possible[i]);
L
Linus Torvalds 已提交
786 787
	}

788
	printk(KERN_CONT ")");
L
Linus Torvalds 已提交
789 790

	if (!found)
791
		printk(KERN_CONT " *%d", link->irq.active);
L
Linus Torvalds 已提交
792

L
Len Brown 已提交
793
	if (!link->device->status.enabled)
794
		printk(KERN_CONT ", disabled.");
L
Linus Torvalds 已提交
795

796
	printk(KERN_CONT "\n");
L
Linus Torvalds 已提交
797

798
	list_add_tail(&link->list, &acpi_link_list);
L
Linus Torvalds 已提交
799

L
Len Brown 已提交
800
      end:
L
Linus Torvalds 已提交
801
	/* disable all links -- to be activated on use */
802
	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
I
Ingo Molnar 已提交
803
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
804 805 806 807

	if (result)
		kfree(link);

808
	return result < 0 ? result : 1;
L
Linus Torvalds 已提交
809 810
}

L
Len Brown 已提交
811
static int acpi_pci_link_resume(struct acpi_pci_link *link)
812 813
{
	if (link->refcnt && link->irq.active && link->irq.initialized)
814
		return (acpi_pci_link_set(link, link->irq.active));
815 816

	return 0;
817 818
}

819
static void irqrouter_resume(void)
L
Linus Torvalds 已提交
820
{
821
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
822

823
	list_for_each_entry(link, &acpi_link_list, list) {
824
		acpi_pci_link_resume(link);
L
Linus Torvalds 已提交
825 826 827
	}
}

828
static void acpi_pci_link_remove(struct acpi_device *device)
L
Linus Torvalds 已提交
829
{
830
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
831

832
	link = acpi_driver_data(device);
L
Linus Torvalds 已提交
833

I
Ingo Molnar 已提交
834
	mutex_lock(&acpi_link_lock);
835
	list_del(&link->list);
I
Ingo Molnar 已提交
836
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
837 838 839 840 841

	kfree(link);
}

/*
842
 * modify penalty from cmdline
L
Linus Torvalds 已提交
843 844 845 846 847 848 849 850 851
 */
static int __init acpi_irq_penalty_update(char *str, int used)
{
	int i;

	for (i = 0; i < 16; i++) {
		int retval;
		int irq;

L
Len Brown 已提交
852
		retval = get_option(&str, &irq);
L
Linus Torvalds 已提交
853 854 855 856 857 858

		if (!retval)
			break;	/* no number found */

		if (irq < 0)
			continue;
L
Len Brown 已提交
859

L
Linus Torvalds 已提交
860
		if (used)
861
			acpi_irq_add_penalty(irq, PIRQ_PENALTY_ISA_USED);
L
Linus Torvalds 已提交
862
		else
863
			acpi_irq_set_penalty(irq, PIRQ_PENALTY_PCI_AVAILABLE);
L
Linus Torvalds 已提交
864 865 866 867 868 869 870 871 872 873 874 875 876 877

		if (retval != 2)	/* no next number */
			break;
	}
	return 1;
}

/*
 * We'd like PNP to call this routine for the
 * single ISA_USED value for each legacy device.
 * But instead it calls us with each POSSIBLE setting.
 * There is no ISA_POSSIBLE weight, so we simply use
 * the (small) PCI_USING penalty.
 */
D
David Shaohua Li 已提交
878
void acpi_penalize_isa_irq(int irq, int active)
L
Linus Torvalds 已提交
879
{
880 881 882 883 884 885 886 887 888 889 890
	int penalty;

	if (irq < 0)
		return;

	if (active)
		penalty = PIRQ_PENALTY_ISA_USED;
	else
		penalty = PIRQ_PENALTY_PCI_USING;

	acpi_irq_add_penalty(irq, penalty);
L
Linus Torvalds 已提交
891 892
}

893 894
bool acpi_isa_irq_available(int irq)
{
895 896
	return irq >= 0 &&
		(acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
897 898
}

899 900 901 902 903 904 905
/*
 * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict with
 * PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be use for
 * PCI IRQs.
 */
void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
{
906 907 908 909 910 911 912 913 914 915 916 917
	int penalty;

	if (irq < 0)
		return;

	if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
	    polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
		penalty = PIRQ_PENALTY_ISA_ALWAYS;
	else
		penalty = PIRQ_PENALTY_PCI_USING;

	acpi_irq_add_penalty(irq, penalty);
918 919
}

L
Linus Torvalds 已提交
920 921 922 923 924 925 926 927 928
/*
 * Over-ride default table to reserve additional IRQs for use by ISA
 * e.g. acpi_irq_isa=5
 * Useful for telling ACPI how not to interfere with your ISA sound card.
 */
static int __init acpi_irq_isa(char *str)
{
	return acpi_irq_penalty_update(str, 1);
}
L
Len Brown 已提交
929

L
Linus Torvalds 已提交
930 931 932 933 934 935 936 937 938 939 940
__setup("acpi_irq_isa=", acpi_irq_isa);

/*
 * Over-ride default table to free additional IRQs for use by PCI
 * e.g. acpi_irq_pci=7,15
 * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing.
 */
static int __init acpi_irq_pci(char *str)
{
	return acpi_irq_penalty_update(str, 0);
}
L
Len Brown 已提交
941

L
Linus Torvalds 已提交
942 943 944 945 946 947 948
__setup("acpi_irq_pci=", acpi_irq_pci);

static int __init acpi_irq_nobalance_set(char *str)
{
	acpi_irq_balance = 0;
	return 1;
}
L
Len Brown 已提交
949

L
Linus Torvalds 已提交
950 951
__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);

952
static int __init acpi_irq_balance_set(char *str)
L
Linus Torvalds 已提交
953 954 955 956 957
{
	acpi_irq_balance = 1;
	return 1;
}

L
Len Brown 已提交
958
__setup("acpi_irq_balance", acpi_irq_balance_set);
L
Linus Torvalds 已提交
959

960
static struct syscore_ops irqrouter_syscore_ops = {
L
Len Brown 已提交
961
	.resume = irqrouter_resume,
L
Linus Torvalds 已提交
962 963
};

964
void __init acpi_pci_link_init(void)
L
Linus Torvalds 已提交
965 966
{
	if (acpi_noirq)
967
		return;
L
Linus Torvalds 已提交
968

969 970 971 972 973 974 975
	if (acpi_irq_balance == -1) {
		/* no command line switch: enable balancing in IOAPIC mode */
		if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
			acpi_irq_balance = 1;
		else
			acpi_irq_balance = 0;
	}
976 977
	register_syscore_ops(&irqrouter_syscore_ops);
	acpi_scan_add_handler(&pci_link_handler);
L
Linus Torvalds 已提交
978
}