pci_link.c 23.5 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_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>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  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).
 */

28
#include <linux/syscore_ops.h>
L
Linus Torvalds 已提交
29 30 31 32 33 34 35
#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 已提交
36
#include <linux/mutex.h>
37
#include <linux/slab.h>
38
#include <linux/acpi.h>
39
#include <linux/irq.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
}

/* --------------------------------------------------------------------------
                            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.
 */

441
#define ACPI_MAX_ISA_IRQS	16
L
Linus Torvalds 已提交
442 443 444 445 446 447 448

#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)

449
static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
L
Linus Torvalds 已提交
450 451 452
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
L
Len Brown 已提交
453 454
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
L
Linus Torvalds 已提交
455 456 457 458
	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 */
459 460 461
	0,				/* IRQ9  PCI, often acpi */
	0,				/* IRQ10 PCI */
	0,				/* IRQ11 PCI */
462 463 464 465
	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 */
466
	/* >IRQ15 */
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
static int acpi_irq_pci_sharing_penalty(int irq)
{
	struct acpi_pci_link *link;
	int penalty = 0;

	list_for_each_entry(link, &acpi_link_list, list) {
		/*
		 * If a link is active, penalize its IRQ heavily
		 * so we try to choose a different IRQ.
		 */
		if (link->irq.active && link->irq.active == irq)
			penalty += PIRQ_PENALTY_PCI_USING;
		else {
			int i;

			/*
			 * If a link is inactive, penalize the IRQs it
			 * might use, but not as severely.
			 */
			for (i = 0; i < link->irq.possible_count; i++)
				if (link->irq.possible[i] == irq)
					penalty += PIRQ_PENALTY_PCI_POSSIBLE /
						link->irq.possible_count;
		}
	}

	return penalty;
}

static int acpi_irq_get_penalty(int irq)
{
	int penalty = 0;

502 503
	if (irq < ACPI_MAX_ISA_IRQS)
		penalty += acpi_isa_irq_penalty[irq];
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

	/*
	* 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.
	*/
	if (irq == acpi_gbl_FADT.sci_interrupt) {
		u32 type = irq_get_trigger_type(irq) & IRQ_TYPE_SENSE_MASK;

		if (type != IRQ_TYPE_LEVEL_LOW)
			penalty += PIRQ_PENALTY_ISA_ALWAYS;
		else
			penalty += PIRQ_PENALTY_PCI_USING;
	}

	penalty += acpi_irq_pci_sharing_penalty(irq);
	return penalty;
}

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

L
Len Brown 已提交
525
static int acpi_pci_link_allocate(struct acpi_pci_link *link)
L
Linus Torvalds 已提交
526
{
L
Len Brown 已提交
527 528
	int irq;
	int i;
L
Linus Torvalds 已提交
529

530 531 532 533
	if (link->irq.initialized) {
		if (link->refcnt == 0)
			/* This means the link is disabled but initialized */
			acpi_pci_link_set(link, link->irq.active);
534
		return 0;
535
	}
L
Linus Torvalds 已提交
536 537 538 539 540 541 542 543 544 545 546 547 548

	/*
	 * 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)
549 550
			printk(KERN_WARNING PREFIX "_CRS %d not found"
				      " in _PRS\n", link->irq.active);
L
Linus Torvalds 已提交
551 552 553 554 555 556
		link->irq.active = 0;
	}

	/*
	 * if active found, use it; else pick entry from end of possible list.
	 */
557
	if (link->irq.active)
L
Linus Torvalds 已提交
558
		irq = link->irq.active;
559
	else
L
Linus Torvalds 已提交
560 561 562 563 564 565 566 567
		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--) {
568 569
			if (acpi_irq_get_penalty(irq) >
			    acpi_irq_get_penalty(link->irq.possible[i]))
L
Linus Torvalds 已提交
570 571 572
				irq = link->irq.possible[i];
		}
	}
573
	if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
574 575 576 577 578 579
		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 已提交
580 581 582

	/* Attempt to enable the link device at this IRQ. */
	if (acpi_pci_link_set(link, irq)) {
583 584
		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
			    "Try pci=noacpi or acpi=off\n",
585
			    acpi_device_name(link->device),
586
			    acpi_device_bid(link->device));
587
		return -ENODEV;
L
Linus Torvalds 已提交
588
	} else {
589
		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
L
Len Brown 已提交
590 591
		       acpi_device_name(link->device),
		       acpi_device_bid(link->device), link->irq.active);
L
Linus Torvalds 已提交
592 593 594
	}

	link->irq.initialized = 1;
595
	return 0;
L
Linus Torvalds 已提交
596 597 598
}

/*
599
 * acpi_pci_link_allocate_irq
L
Linus Torvalds 已提交
600 601 602
 * success: return IRQ >= 0
 * failure: return -1
 */
603 604
int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
			       int *polarity, char **name)
L
Linus Torvalds 已提交
605
{
606 607 608
	int result;
	struct acpi_device *device;
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
609 610 611

	result = acpi_bus_get_device(handle, &device);
	if (result) {
612
		printk(KERN_ERR PREFIX "Invalid link device\n");
613
		return -1;
L
Linus Torvalds 已提交
614 615
	}

616
	link = acpi_driver_data(device);
L
Linus Torvalds 已提交
617
	if (!link) {
618
		printk(KERN_ERR PREFIX "Invalid link context\n");
619
		return -1;
L
Linus Torvalds 已提交
620 621 622 623
	}

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

I
Ingo Molnar 已提交
628
	mutex_lock(&acpi_link_lock);
629
	if (acpi_pci_link_allocate(link)) {
I
Ingo Molnar 已提交
630
		mutex_unlock(&acpi_link_lock);
631
		return -1;
632
	}
L
Len Brown 已提交
633

L
Linus Torvalds 已提交
634
	if (!link->irq.active) {
I
Ingo Molnar 已提交
635
		mutex_unlock(&acpi_link_lock);
636
		printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
637
		return -1;
L
Linus Torvalds 已提交
638
	}
L
Len Brown 已提交
639
	link->refcnt++;
I
Ingo Molnar 已提交
640
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
641

B
Bob Moore 已提交
642 643 644 645
	if (triggering)
		*triggering = link->irq.triggering;
	if (polarity)
		*polarity = link->irq.polarity;
L
Len Brown 已提交
646 647
	if (name)
		*name = acpi_device_bid(link->device);
648
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
L
Len Brown 已提交
649 650
			  "Link %s is referenced\n",
			  acpi_device_bid(link->device)));
651
	return (link->irq.active);
L
Linus Torvalds 已提交
652 653
}

654 655 656 657
/*
 * We don't change link's irq information here.  After it is reenabled, we
 * continue use the info
 */
L
Len Brown 已提交
658
int acpi_pci_link_free_irq(acpi_handle handle)
659
{
660 661
	struct acpi_device *device;
	struct acpi_pci_link *link;
L
Len Brown 已提交
662
	acpi_status result;
663 664 665

	result = acpi_bus_get_device(handle, &device);
	if (result) {
666
		printk(KERN_ERR PREFIX "Invalid link device\n");
667
		return -1;
668
	}
L
Linus Torvalds 已提交
669

670
	link = acpi_driver_data(device);
671
	if (!link) {
672
		printk(KERN_ERR PREFIX "Invalid link context\n");
673
		return -1;
674 675
	}

I
Ingo Molnar 已提交
676
	mutex_lock(&acpi_link_lock);
677
	if (!link->irq.initialized) {
I
Ingo Molnar 已提交
678
		mutex_unlock(&acpi_link_lock);
679
		printk(KERN_ERR PREFIX "Link isn't initialized\n");
680
		return -1;
681
	}
682 683 684 685 686 687 688 689 690 691
#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 已提交
692
	link->refcnt--;
693
#endif
694
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
L
Len Brown 已提交
695 696
			  "Link %s is dereferenced\n",
			  acpi_device_bid(link->device)));
697

698
	if (link->refcnt == 0)
699
		acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
700

I
Ingo Molnar 已提交
701
	mutex_unlock(&acpi_link_lock);
702
	return (link->irq.active);
703
}
L
Len Brown 已提交
704

L
Linus Torvalds 已提交
705 706 707 708
/* --------------------------------------------------------------------------
                                 Driver Interface
   -------------------------------------------------------------------------- */

709 710
static int acpi_pci_link_add(struct acpi_device *device,
			     const struct acpi_device_id *not_used)
L
Linus Torvalds 已提交
711
{
712 713 714
	int result;
	struct acpi_pci_link *link;
	int i;
L
Len Brown 已提交
715
	int found = 0;
L
Linus Torvalds 已提交
716

717
	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
L
Linus Torvalds 已提交
718
	if (!link)
719
		return -ENOMEM;
L
Linus Torvalds 已提交
720 721 722 723

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

I
Ingo Molnar 已提交
726
	mutex_lock(&acpi_link_lock);
L
Linus Torvalds 已提交
727 728 729 730 731 732 733
	result = acpi_pci_link_get_possible(link);
	if (result)
		goto end;

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

734
	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
L
Len Brown 已提交
735
	       acpi_device_bid(device));
L
Linus Torvalds 已提交
736 737
	for (i = 0; i < link->irq.possible_count; i++) {
		if (link->irq.active == link->irq.possible[i]) {
738
			printk(KERN_CONT " *%d", link->irq.possible[i]);
L
Linus Torvalds 已提交
739
			found = 1;
L
Len Brown 已提交
740
		} else
741
			printk(KERN_CONT " %d", link->irq.possible[i]);
L
Linus Torvalds 已提交
742 743
	}

744
	printk(KERN_CONT ")");
L
Linus Torvalds 已提交
745 746

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

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

752
	printk(KERN_CONT "\n");
L
Linus Torvalds 已提交
753

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

L
Len Brown 已提交
756
      end:
L
Linus Torvalds 已提交
757
	/* disable all links -- to be activated on use */
758
	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
I
Ingo Molnar 已提交
759
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
760 761 762 763

	if (result)
		kfree(link);

764
	return result < 0 ? result : 1;
L
Linus Torvalds 已提交
765 766
}

L
Len Brown 已提交
767
static int acpi_pci_link_resume(struct acpi_pci_link *link)
768 769
{
	if (link->refcnt && link->irq.active && link->irq.initialized)
770
		return (acpi_pci_link_set(link, link->irq.active));
771 772

	return 0;
773 774
}

775
static void irqrouter_resume(void)
L
Linus Torvalds 已提交
776
{
777
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
778

779
	list_for_each_entry(link, &acpi_link_list, list) {
780
		acpi_pci_link_resume(link);
L
Linus Torvalds 已提交
781 782 783
	}
}

784
static void acpi_pci_link_remove(struct acpi_device *device)
L
Linus Torvalds 已提交
785
{
786
	struct acpi_pci_link *link;
L
Linus Torvalds 已提交
787

788
	link = acpi_driver_data(device);
L
Linus Torvalds 已提交
789

I
Ingo Molnar 已提交
790
	mutex_lock(&acpi_link_lock);
791
	list_del(&link->list);
I
Ingo Molnar 已提交
792
	mutex_unlock(&acpi_link_lock);
L
Linus Torvalds 已提交
793 794 795 796 797

	kfree(link);
}

/*
798
 * modify acpi_isa_irq_penalty[] from cmdline
L
Linus Torvalds 已提交
799 800 801 802 803 804 805 806
 */
static int __init acpi_irq_penalty_update(char *str, int used)
{
	int i;

	for (i = 0; i < 16; i++) {
		int retval;
		int irq;
807
		int new_penalty;
L
Linus Torvalds 已提交
808

L
Len Brown 已提交
809
		retval = get_option(&str, &irq);
L
Linus Torvalds 已提交
810 811 812 813

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

814 815
		/* see if this is a ISA IRQ */
		if ((irq < 0) || (irq >= ACPI_MAX_ISA_IRQS))
816 817
			continue;

L
Linus Torvalds 已提交
818
		if (used)
819 820
			new_penalty = acpi_irq_get_penalty(irq) +
					PIRQ_PENALTY_ISA_USED;
L
Linus Torvalds 已提交
821
		else
822
			new_penalty = 0;
L
Linus Torvalds 已提交
823

824
		acpi_isa_irq_penalty[irq] = new_penalty;
L
Linus Torvalds 已提交
825 826 827 828 829 830 831 832 833 834 835 836 837
		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 已提交
838
void acpi_penalize_isa_irq(int irq, int active)
L
Linus Torvalds 已提交
839
{
840 841
	if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
		acpi_isa_irq_penalty[irq] = acpi_irq_get_penalty(irq) +
842
			active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING;
L
Linus Torvalds 已提交
843 844
}

845 846
bool acpi_isa_irq_available(int irq)
{
847
	return irq >= 0 && (irq >= ARRAY_SIZE(acpi_isa_irq_penalty) ||
848
		    acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
849 850
}

L
Linus Torvalds 已提交
851 852 853 854 855 856 857 858 859
/*
 * 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 已提交
860

L
Linus Torvalds 已提交
861 862 863 864 865 866 867 868 869 870 871
__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 已提交
872

L
Linus Torvalds 已提交
873 874 875 876 877 878 879
__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 已提交
880

L
Linus Torvalds 已提交
881 882
__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);

883
static int __init acpi_irq_balance_set(char *str)
L
Linus Torvalds 已提交
884 885 886 887 888
{
	acpi_irq_balance = 1;
	return 1;
}

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

891
static struct syscore_ops irqrouter_syscore_ops = {
L
Len Brown 已提交
892
	.resume = irqrouter_resume,
L
Linus Torvalds 已提交
893 894
};

895
void __init acpi_pci_link_init(void)
L
Linus Torvalds 已提交
896 897
{
	if (acpi_noirq)
898
		return;
L
Linus Torvalds 已提交
899

900 901 902 903 904 905 906
	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;
	}
907 908
	register_syscore_ops(&irqrouter_syscore_ops);
	acpi_scan_add_handler(&pci_link_handler);
L
Linus Torvalds 已提交
909
}