Blame view

drivers/acpi/pci_link.c 24.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  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.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * 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).
   */
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
27
  #include <linux/syscore_ops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
  #include <linux/spinlock.h>
  #include <linux/pm.h>
  #include <linux/pci.h>
36e430951   Ingo Molnar   sem2mutex: acpi, ...
35
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
8b48463f8   Lv Zheng   ACPI: Clean up in...
37
  #include <linux/acpi.h>
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
38
  #include <linux/irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

c071b6040   Rashika   ACPI / PCI: Inclu...
40
  #include "internal.h"
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
41
  #define _COMPONENT			ACPI_PCI_COMPONENT
f52fd66d2   Len Brown   ACPI: clean up AC...
42
  ACPI_MODULE_NAME("pci_link");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
  #define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
  #define ACPI_PCI_LINK_FILE_INFO		"info"
  #define ACPI_PCI_LINK_FILE_STATUS	"state"
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
47
  #define ACPI_PCI_LINK_MAX_POSSIBLE	16
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
48
49
50
  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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

c97adf9e7   Márton Németh   acpi: make ACPI d...
52
  static const struct acpi_device_id link_device_ids[] = {
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
53
54
55
  	{"PNP0C0F", 0},
  	{"", 0},
  };
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
56

4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
57
  static struct acpi_scan_handler pci_link_handler = {
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
58
  	.ids = link_device_ids,
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
59
60
  	.attach = acpi_pci_link_add,
  	.detach = acpi_pci_link_remove,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  };
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
62
63
64
65
  /*
   * 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
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  struct acpi_pci_link_irq {
37c593913   Sinan Kaya   ACPI, PCI, irq: r...
67
  	u32 active;		/* Current IRQ */
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
68
  	u8 triggering;		/* All IRQs */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
69
  	u8 polarity;		/* All IRQs */
4be44fcd3   Len Brown   [ACPI] Lindent al...
70
71
  	u8 resource_type;
  	u8 possible_count;
37c593913   Sinan Kaya   ACPI, PCI, irq: r...
72
  	u32 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
4be44fcd3   Len Brown   [ACPI] Lindent al...
73
74
  	u8 initialized:1;
  	u8 reserved:7;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  };
  
  struct acpi_pci_link {
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
78
  	struct list_head		list;
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
79
80
81
  	struct acpi_device		*device;
  	struct acpi_pci_link_irq	irq;
  	int				refcnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  };
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
83
  static LIST_HEAD(acpi_link_list);
e5685b9d3   Adrian Bunk   ACPI: misc cleanups
84
  static DEFINE_MUTEX(acpi_link_lock);
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
85
  static int sci_irq = -1, sci_penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
  /* --------------------------------------------------------------------------
                              PCI Link Device Management
     -------------------------------------------------------------------------- */
  
  /*
   * set context (link) possible list from resource list
   */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
94
95
  static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
  						void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  {
50dd09697   Jan Engelhardt   ACPI: Remove unne...
97
  	struct acpi_pci_link *link = context;
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
98
  	u32 i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99

eca008c81   Len Brown   [ACPI] handle ACP...
100
  	switch (resource->type) {
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
101
  	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
102
  	case ACPI_RESOURCE_TYPE_END_TAG:
d550d98d3   Patrick Mochel   ACPI: delete trac...
103
  		return AE_OK;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
104
  	case ACPI_RESOURCE_TYPE_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
105
106
  		{
  			struct acpi_resource_irq *p = &resource->data.irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
107
  			if (!p || !p->interrupt_count) {
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
108
109
110
  				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  						  "Blank _PRS IRQ resource
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
111
  				return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  			}
4be44fcd3   Len Brown   [ACPI] Lindent al...
113
  			for (i = 0;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
114
  			     (i < p->interrupt_count
4be44fcd3   Len Brown   [ACPI] Lindent al...
115
116
  			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
  				if (!p->interrupts[i]) {
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
117
118
119
120
  					printk(KERN_WARNING PREFIX
  					       "Invalid _PRS IRQ %d
  ",
  					       p->interrupts[i]);
4be44fcd3   Len Brown   [ACPI] Lindent al...
121
122
123
124
125
  					continue;
  				}
  				link->irq.possible[i] = p->interrupts[i];
  				link->irq.possible_count++;
  			}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
126
127
128
  			link->irq.triggering = p->triggering;
  			link->irq.polarity = p->polarity;
  			link->irq.resource_type = ACPI_RESOURCE_TYPE_IRQ;
4be44fcd3   Len Brown   [ACPI] Lindent al...
129
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  		}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
131
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
132
  		{
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
133
  			struct acpi_resource_extended_irq *p =
4be44fcd3   Len Brown   [ACPI] Lindent al...
134
  			    &resource->data.extended_irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
135
  			if (!p || !p->interrupt_count) {
cece92969   Len Brown   ACPI: un-export A...
136
  				printk(KERN_WARNING PREFIX
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
137
138
  					      "Blank _PRS EXT IRQ resource
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
139
  				return AE_OK;
4be44fcd3   Len Brown   [ACPI] Lindent al...
140
141
  			}
  			for (i = 0;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
142
  			     (i < p->interrupt_count
4be44fcd3   Len Brown   [ACPI] Lindent al...
143
144
  			      && i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
  				if (!p->interrupts[i]) {
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
145
146
147
148
  					printk(KERN_WARNING PREFIX
  					       "Invalid _PRS IRQ %d
  ",
  					       p->interrupts[i]);
4be44fcd3   Len Brown   [ACPI] Lindent al...
149
150
151
152
  					continue;
  				}
  				link->irq.possible[i] = p->interrupts[i];
  				link->irq.possible_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  			}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
154
155
156
  			link->irq.triggering = p->triggering;
  			link->irq.polarity = p->polarity;
  			link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
4be44fcd3   Len Brown   [ACPI] Lindent al...
157
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	default:
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
160
161
162
  		printk(KERN_ERR PREFIX "_PRS resource type 0x%x isn't an IRQ
  ",
  		       resource->type);
d550d98d3   Patrick Mochel   ACPI: delete trac...
163
  		return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
165
  	return AE_CTRL_TERMINATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
167
  static int acpi_pci_link_get_possible(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
169
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

67a713657   Patrick Mochel   ACPI: pci_link: U...
171
  	status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
4be44fcd3   Len Brown   [ACPI] Lindent al...
172
  				     acpi_pci_link_check_possible, link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
174
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
175
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
177
178
179
180
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			  "Found %d possible IRQs
  ",
  			  link->irq.possible_count));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

d550d98d3   Patrick Mochel   ACPI: delete trac...
182
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  }
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
184
185
  static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
  					       void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
187
  	int *irq = context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

eca008c81   Len Brown   [ACPI] handle ACP...
189
  	switch (resource->type) {
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
190
191
192
  	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
  	case ACPI_RESOURCE_TYPE_END_TAG:
  		return AE_OK;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
193
  	case ACPI_RESOURCE_TYPE_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
194
195
  		{
  			struct acpi_resource_irq *p = &resource->data.irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
196
  			if (!p || !p->interrupt_count) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
197
198
199
200
201
  				/*
  				 * IRQ descriptors may have no IRQ# bits set,
  				 * particularly those those w/ _STA disabled
  				 */
  				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
202
203
  						  "Blank _CRS IRQ resource
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
204
  				return AE_OK;
4be44fcd3   Len Brown   [ACPI] Lindent al...
205
206
207
  			}
  			*irq = p->interrupts[0];
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  		}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
209
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
210
  		{
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
211
  			struct acpi_resource_extended_irq *p =
4be44fcd3   Len Brown   [ACPI] Lindent al...
212
  			    &resource->data.extended_irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
213
  			if (!p || !p->interrupt_count) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
214
215
216
217
  				/*
  				 * extended IRQ descriptors must
  				 * return at least 1 IRQ
  				 */
cece92969   Len Brown   ACPI: un-export A...
218
  				printk(KERN_WARNING PREFIX
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
219
220
  					      "Blank _CRS EXT IRQ resource
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
221
  				return AE_OK;
4be44fcd3   Len Brown   [ACPI] Lindent al...
222
223
224
  			}
  			*irq = p->interrupts[0];
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  		}
d4ec6c7cc   Len Brown   [ACPI] remove "Re...
226
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	default:
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
228
229
230
  		printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ
  ",
  		       resource->type);
d550d98d3   Patrick Mochel   ACPI: delete trac...
231
  		return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	}
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
233

d550d98d3   Patrick Mochel   ACPI: delete trac...
234
  	return AE_CTRL_TERMINATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
242
243
  }
  
  /*
   * Run _CRS and set link->irq.active
   *
   * return value:
   * 0 - success
   * !0 - failure
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
244
  static int acpi_pci_link_get_current(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
246
  	int result = 0;
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
247
  	acpi_status status;
4be44fcd3   Len Brown   [ACPI] Lindent al...
248
  	int irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
  	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) {
6468463ab   Len Brown   ACPI: un-export A...
257
258
  			printk(KERN_ERR PREFIX "Unable to read status
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
  			goto end;
  		}
  
  		if (!link->device->status.enabled) {
  			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
265
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
  		}
  	}
  
  	/* 
  	 * Query and parse _CRS to get the current IRQ assignment. 
  	 */
67a713657   Patrick Mochel   ACPI: pci_link: U...
272
  	status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
4be44fcd3   Len Brown   [ACPI] Lindent al...
273
  				     acpi_pci_link_check_current, &irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
275
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
  		result = -ENODEV;
  		goto end;
  	}
  
  	if (acpi_strict && !irq) {
6468463ab   Len Brown   ACPI: un-export A...
281
282
  		printk(KERN_ERR PREFIX "_CRS returned 0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
  		result = -ENODEV;
  	}
  
  	link->irq.active = irq;
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d 
  ", link->irq.active));
4be44fcd3   Len Brown   [ACPI] Lindent al...
290
        end:
d550d98d3   Patrick Mochel   ACPI: delete trac...
291
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
293
  static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
295
296
  	int result;
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	struct {
4be44fcd3   Len Brown   [ACPI] Lindent al...
298
299
300
301
  		struct acpi_resource res;
  		struct acpi_resource end;
  	} *resource;
  	struct acpi_buffer buffer = { 0, NULL };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302

6eca4b4ca   Bjorn Helgaas   ACPI: pci_link: r...
303
  	if (!irq)
d550d98d3   Patrick Mochel   ACPI: delete trac...
304
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

36bcbec7c   Burman Yan   ACPI: replace kma...
306
  	resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
4be44fcd3   Len Brown   [ACPI] Lindent al...
307
  	if (!resource)
d550d98d3   Patrick Mochel   ACPI: delete trac...
308
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309

4be44fcd3   Len Brown   [ACPI] Lindent al...
310
  	buffer.length = sizeof(*resource) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  	buffer.pointer = resource;
4be44fcd3   Len Brown   [ACPI] Lindent al...
312
  	switch (link->irq.resource_type) {
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
313
314
  	case ACPI_RESOURCE_TYPE_IRQ:
  		resource->res.type = ACPI_RESOURCE_TYPE_IRQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  		resource->res.length = sizeof(struct acpi_resource);
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
316
317
318
319
320
  		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 =
4be44fcd3   Len Brown   [ACPI] Lindent al...
321
  			    ACPI_EXCLUSIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  		else
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
323
324
  			resource->res.data.irq.sharable = ACPI_SHARED;
  		resource->res.data.irq.interrupt_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
  		resource->res.data.irq.interrupts[0] = irq;
  		break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
327

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
328
329
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  		resource->res.length = sizeof(struct acpi_resource);
4be44fcd3   Len Brown   [ACPI] Lindent al...
331
332
  		resource->res.data.extended_irq.producer_consumer =
  		    ACPI_CONSUMER;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
333
334
335
336
337
338
  		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 =
4be44fcd3   Len Brown   [ACPI] Lindent al...
339
  			    ACPI_EXCLUSIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  		else
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
341
342
  			resource->res.data.irq.sharable = ACPI_SHARED;
  		resource->res.data.extended_irq.interrupt_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
  		resource->res.data.extended_irq.interrupts[0] = irq;
  		/* ignore resource_source, it's optional */
  		break;
  	default:
6468463ab   Len Brown   ACPI: un-export A...
347
348
  		printk(KERN_ERR PREFIX "Invalid Resource_type %d
  ", link->irq.resource_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
  		result = -EINVAL;
  		goto end;
  
  	}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
353
  	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
f084dbb93   Yinghai Lu   ACPI: Set length ...
354
  	resource->end.length = sizeof(struct acpi_resource);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  
  	/* Attempt to set the resource */
67a713657   Patrick Mochel   ACPI: pci_link: U...
357
  	status = acpi_set_current_resources(link->device->handle, &buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  
  	/* check for total failure */
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
361
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
  		result = -ENODEV;
  		goto end;
  	}
  
  	/* Query _STA, set device->status */
  	result = acpi_bus_get_status(link->device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
369
370
  		printk(KERN_ERR PREFIX "Unable to read status
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
  		goto end;
  	}
  	if (!link->device->status.enabled) {
cece92969   Len Brown   ACPI: un-export A...
374
375
376
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] disabled and referenced, BIOS bug
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
377
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
378
  			      acpi_device_bid(link->device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  	}
  
  	/* 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.
  		 */
cece92969   Len Brown   ACPI: un-export A...
396
397
398
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] BIOS reported IRQ %d, using IRQ %d
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
399
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
400
  			      acpi_device_bid(link->device), link->irq.active, irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
404
405
  		link->irq.active = irq;
  	}
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d
  ", link->irq.active));
4be44fcd3   Len Brown   [ACPI] Lindent al...
406
407
  
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  	kfree(resource);
d550d98d3   Patrick Mochel   ACPI: delete trac...
409
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  /* --------------------------------------------------------------------------
                              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.
   */
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
445
  #define ACPI_MAX_ISA_IRQS	16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
450
451
  #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)
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
452
  static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
4be44fcd3   Len Brown   [ACPI] Lindent al...
456
457
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
  	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 */
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
462
463
464
  	0,				/* IRQ9  PCI, often acpi */
  	0,				/* IRQ10 PCI */
  	0,				/* IRQ11 PCI */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
465
466
467
468
  	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 */
e24971457   Rafael J. Wysocki   Revert "ACPI, PCI...
469
  	/* >IRQ15 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  };
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
471
472
473
474
  static int acpi_irq_pci_sharing_penalty(int irq)
  {
  	struct acpi_pci_link *link;
  	int penalty = 0;
4a6e68bf9   Sinan Kaya   ACPI,PCI,IRQ: fac...
475
  	int i;
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
476
477
478
479
480
481
482
483
  
  	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;
4a6e68bf9   Sinan Kaya   ACPI,PCI,IRQ: fac...
484
485
486
487
488
489
490
491
  
  		/*
  		 * penalize the IRQs PCI 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;
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
492
493
494
495
496
497
498
499
  	}
  
  	return penalty;
  }
  
  static int acpi_irq_get_penalty(int irq)
  {
  	int penalty = 0;
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
500
501
  	if (irq == sci_irq)
  		penalty += sci_penalty;
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
502

f7eca374f   Sinan Kaya   ACPI,PCI,IRQ: sep...
503
504
  	if (irq < ACPI_MAX_ISA_IRQS)
  		return penalty + acpi_isa_irq_penalty[irq];
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
505
  	return penalty + acpi_irq_pci_sharing_penalty(irq);
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
506
  }
487cf917e   Sinan Kaya   Revert "ACPI, PCI...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  int __init acpi_irq_penalty_init(void)
  {
  	struct acpi_pci_link *link;
  	int i;
  
  	/*
  	 * Update penalties to facilitate IRQ balancing.
  	 */
  	list_for_each_entry(link, &acpi_link_list, list) {
  
  		/*
  		 * reflect the possible and active irqs in the penalty table --
  		 * useful for breaking ties.
  		 */
  		if (link->irq.possible_count) {
  			int penalty =
  			    PIRQ_PENALTY_PCI_POSSIBLE /
  			    link->irq.possible_count;
  
  			for (i = 0; i < link->irq.possible_count; i++) {
  				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQS)
  					acpi_isa_irq_penalty[link->irq.
  							 possible[i]] +=
  					    penalty;
  			}
  
  		} else if (link->irq.active &&
  				(link->irq.active < ACPI_MAX_ISA_IRQS)) {
  			acpi_isa_irq_penalty[link->irq.active] +=
  			    PIRQ_PENALTY_PCI_POSSIBLE;
  		}
  	}
  
  	return 0;
  }
32836259f   Bjorn Helgaas   ACPI: pci_link: r...
542
  static int acpi_irq_balance = -1;	/* 0: static, 1: balance */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543

4be44fcd3   Len Brown   [ACPI] Lindent al...
544
  static int acpi_pci_link_allocate(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
546
547
  	int irq;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
549
550
551
552
  	if (link->irq.initialized) {
  		if (link->refcnt == 0)
  			/* This means the link is disabled but initialized */
  			acpi_pci_link_set(link, link->irq.active);
d550d98d3   Patrick Mochel   ACPI: delete trac...
553
  		return 0;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
554
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
561
562
563
564
565
566
567
  
  	/*
  	 * 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)
cece92969   Len Brown   ACPI: un-export A...
568
569
570
  			printk(KERN_WARNING PREFIX "_CRS %d not found"
  				      " in _PRS
  ", link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
  		link->irq.active = 0;
  	}
  
  	/*
  	 * if active found, use it; else pick entry from end of possible list.
  	 */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
577
  	if (link->irq.active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  		irq = link->irq.active;
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
579
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  		irq = link->irq.possible[link->irq.possible_count - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
584
585
586
587
  
  	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--) {
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
588
589
  			if (acpi_irq_get_penalty(irq) >
  			    acpi_irq_get_penalty(link->irq.possible[i]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
  				irq = link->irq.possible[i];
  		}
  	}
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
593
  	if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
594
595
596
597
598
599
600
  		printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. "
  			    "Try pci=noacpi or acpi=off
  ",
  			    acpi_device_name(link->device),
  			    acpi_device_bid(link->device));
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
  
  	/* Attempt to enable the link device at this IRQ. */
  	if (acpi_pci_link_set(link, irq)) {
6468463ab   Len Brown   ACPI: un-export A...
604
605
606
  		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
  			    "Try pci=noacpi or acpi=off
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
607
  			    acpi_device_name(link->device),
6468463ab   Len Brown   ACPI: un-export A...
608
  			    acpi_device_bid(link->device));
d550d98d3   Patrick Mochel   ACPI: delete trac...
609
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  	} else {
98756f531   Sinan Kaya   ACPI/PCI: pci_lin...
611
612
613
  		if (link->irq.active < ACPI_MAX_ISA_IRQS)
  			acpi_isa_irq_penalty[link->irq.active] +=
  				PIRQ_PENALTY_PCI_USING;
4d9391557   Frank Seidel   ACPI: add missing...
614
615
  		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d
  ",
4be44fcd3   Len Brown   [ACPI] Lindent al...
616
617
  		       acpi_device_name(link->device),
  		       acpi_device_bid(link->device), link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
  	}
  
  	link->irq.initialized = 1;
d550d98d3   Patrick Mochel   ACPI: delete trac...
621
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
  }
  
  /*
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
625
   * acpi_pci_link_allocate_irq
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
   * success: return IRQ >= 0
   * failure: return -1
   */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
629
630
  int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
  			       int *polarity, char **name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
632
633
634
  	int result;
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
638
639
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
640
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	}
50dd09697   Jan Engelhardt   ACPI: Remove unne...
642
  	link = acpi_driver_data(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
644
645
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
646
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
  	}
  
  	/* TBD: Support multiple index (IRQ) entries per Link Device */
  	if (index) {
6468463ab   Len Brown   ACPI: un-export A...
651
652
  		printk(KERN_ERR PREFIX "Invalid index %d
  ", index);
d550d98d3   Patrick Mochel   ACPI: delete trac...
653
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
655
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
656
  	if (acpi_pci_link_allocate(link)) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
657
  		mutex_unlock(&acpi_link_lock);
d550d98d3   Patrick Mochel   ACPI: delete trac...
658
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
659
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
660

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	if (!link->irq.active) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
662
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
663
664
  		printk(KERN_ERR PREFIX "Link active IRQ is 0!
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
665
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
667
  	link->refcnt++;
36e430951   Ingo Molnar   sem2mutex: acpi, ...
668
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
670
671
672
673
  	if (triggering)
  		*triggering = link->irq.triggering;
  	if (polarity)
  		*polarity = link->irq.polarity;
4be44fcd3   Len Brown   [ACPI] Lindent al...
674
675
  	if (name)
  		*name = acpi_device_bid(link->device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
676
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
677
678
679
  			  "Link %s is referenced
  ",
  			  acpi_device_bid(link->device)));
d550d98d3   Patrick Mochel   ACPI: delete trac...
680
  	return (link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  }
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
682
683
684
685
  /*
   * We don't change link's irq information here.  After it is reenabled, we
   * continue use the info
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
686
  int acpi_pci_link_free_irq(acpi_handle handle)
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
687
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
688
689
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
4be44fcd3   Len Brown   [ACPI] Lindent al...
690
  	acpi_status result;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
691

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
692
693
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
694
695
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
696
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
697
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698

50dd09697   Jan Engelhardt   ACPI: Remove unne...
699
  	link = acpi_driver_data(device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
700
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
701
702
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
703
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
704
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
705
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
706
  	if (!link->irq.initialized) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
707
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
708
709
  		printk(KERN_ERR PREFIX "Link isn't initialized
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
710
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
711
  	}
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
712
713
714
715
716
717
718
719
720
721
  #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
  	 */
4be44fcd3   Len Brown   [ACPI] Lindent al...
722
  	link->refcnt--;
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
723
  #endif
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
724
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
725
726
727
  			  "Link %s is dereferenced
  ",
  			  acpi_device_bid(link->device)));
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
728

1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
729
  	if (link->refcnt == 0)
383d7a11c   donald.d.dugger@intel.com   ACPI: Fix possibl...
730
  		acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
731

36e430951   Ingo Molnar   sem2mutex: acpi, ...
732
  	mutex_unlock(&acpi_link_lock);
d550d98d3   Patrick Mochel   ACPI: delete trac...
733
  	return (link->irq.active);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
734
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
735

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
  /* --------------------------------------------------------------------------
                                   Driver Interface
     -------------------------------------------------------------------------- */
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
739
740
  static int acpi_pci_link_add(struct acpi_device *device,
  			     const struct acpi_device_id *not_used)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
742
743
744
  	int result;
  	struct acpi_pci_link *link;
  	int i;
4be44fcd3   Len Brown   [ACPI] Lindent al...
745
  	int found = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746

36bcbec7c   Burman Yan   ACPI: replace kma...
747
  	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	if (!link)
d550d98d3   Patrick Mochel   ACPI: delete trac...
749
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  
  	link->device = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
  	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
  	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
db89b4f0d   Pavel Machek   ACPI: catch calls...
754
  	device->driver_data = link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755

36e430951   Ingo Molnar   sem2mutex: acpi, ...
756
  	mutex_lock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
  	result = acpi_pci_link_get_possible(link);
  	if (result)
  		goto end;
  
  	/* query and set link->irq.active */
  	acpi_pci_link_get_current(link);
0dc070bb0   Dan Aloni   ACPI: drivers/acp...
763
  	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
4be44fcd3   Len Brown   [ACPI] Lindent al...
764
  	       acpi_device_bid(device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
  	for (i = 0; i < link->irq.possible_count; i++) {
  		if (link->irq.active == link->irq.possible[i]) {
be96447e0   Kay Sievers   acpi: use KERN_CO...
767
  			printk(KERN_CONT " *%d", link->irq.possible[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  			found = 1;
4be44fcd3   Len Brown   [ACPI] Lindent al...
769
  		} else
be96447e0   Kay Sievers   acpi: use KERN_CO...
770
  			printk(KERN_CONT " %d", link->irq.possible[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	}
be96447e0   Kay Sievers   acpi: use KERN_CO...
772
  	printk(KERN_CONT ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  
  	if (!found)
be96447e0   Kay Sievers   acpi: use KERN_CO...
775
  		printk(KERN_CONT " *%d", link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

4be44fcd3   Len Brown   [ACPI] Lindent al...
777
  	if (!link->device->status.enabled)
be96447e0   Kay Sievers   acpi: use KERN_CO...
778
  		printk(KERN_CONT ", disabled.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779

be96447e0   Kay Sievers   acpi: use KERN_CO...
780
781
  	printk(KERN_CONT "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
783
  	list_add_tail(&link->list, &acpi_link_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784

4be44fcd3   Len Brown   [ACPI] Lindent al...
785
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  	/* disable all links -- to be activated on use */
383d7a11c   donald.d.dugger@intel.com   ACPI: Fix possibl...
787
  	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
788
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
  
  	if (result)
  		kfree(link);
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
792
  	return result < 0 ? result : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
794
  static int acpi_pci_link_resume(struct acpi_pci_link *link)
697a2d63a   Linus Torvalds   Revert ACPI inter...
795
  {
697a2d63a   Linus Torvalds   Revert ACPI inter...
796
  	if (link->refcnt && link->irq.active && link->irq.initialized)
d550d98d3   Patrick Mochel   ACPI: delete trac...
797
  		return (acpi_pci_link_set(link, link->irq.active));
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
798
799
  
  	return 0;
697a2d63a   Linus Torvalds   Revert ACPI inter...
800
  }
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
801
  static void irqrouter_resume(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
803
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804

5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
805
  	list_for_each_entry(link, &acpi_link_list, list) {
697a2d63a   Linus Torvalds   Revert ACPI inter...
806
  		acpi_pci_link_resume(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  }
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
809
  static void acpi_pci_link_remove(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
811
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812

50dd09697   Jan Engelhardt   ACPI: Remove unne...
813
  	link = acpi_driver_data(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

36e430951   Ingo Molnar   sem2mutex: acpi, ...
815
  	mutex_lock(&acpi_link_lock);
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
816
  	list_del(&link->list);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
817
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
  
  	kfree(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
  }
  
  /*
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
823
   * modify acpi_isa_irq_penalty[] from cmdline
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
826
827
828
829
830
831
   */
  static int __init acpi_irq_penalty_update(char *str, int used)
  {
  	int i;
  
  	for (i = 0; i < 16; i++) {
  		int retval;
  		int irq;
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
832
  		int new_penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833

4be44fcd3   Len Brown   [ACPI] Lindent al...
834
  		retval = get_option(&str, &irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
  
  		if (!retval)
  			break;	/* no number found */
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
838
839
  		/* see if this is a ISA IRQ */
  		if ((irq < 0) || (irq >= ACPI_MAX_ISA_IRQS))
e24971457   Rafael J. Wysocki   Revert "ACPI, PCI...
840
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  		if (used)
eeaed4bb5   Sinan Kaya   ACPI/PCI/IRQ: ass...
842
  			new_penalty = acpi_isa_irq_penalty[irq] +
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
843
  					PIRQ_PENALTY_ISA_USED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  		else
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
845
  			new_penalty = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
847
  		acpi_isa_irq_penalty[irq] = new_penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
852
853
854
855
856
857
858
859
860
  		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.
   */
c9c3e457d   David Shaohua Li   [ACPI] PNPACPI vs...
861
  void acpi_penalize_isa_irq(int irq, int active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
  {
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
863
  	if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
eeaed4bb5   Sinan Kaya   ACPI/PCI/IRQ: ass...
864
  		acpi_isa_irq_penalty[irq] +=
54794580f   Sinan Kaya   ACPI,PCI,IRQ: cor...
865
  		  (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  }
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
867
868
  bool acpi_isa_irq_available(int irq)
  {
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
869
  	return irq >= 0 && (irq >= ARRAY_SIZE(acpi_isa_irq_penalty) ||
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
870
  		    acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
871
  }
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
872
873
874
875
876
877
878
879
880
881
  void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
  {
  	sci_irq = irq;
  
  	if (trigger == ACPI_MADT_TRIGGER_LEVEL &&
  	    polarity == ACPI_MADT_POLARITY_ACTIVE_LOW)
  		sci_penalty = PIRQ_PENALTY_PCI_USING;
  	else
  		sci_penalty = PIRQ_PENALTY_ISA_ALWAYS;
  }
5d0ddfebb   Jiang Liu   ACPI, PCI: Penali...
882
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
885
886
887
888
889
890
   * 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);
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
891

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
894
895
896
897
898
899
900
901
902
  __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);
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
903

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
905
906
907
908
909
910
  __setup("acpi_irq_pci=", acpi_irq_pci);
  
  static int __init acpi_irq_nobalance_set(char *str)
  {
  	acpi_irq_balance = 0;
  	return 1;
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
911

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  __setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
8a383ef0b   Roel Kluin   ACPI: ec.c, pci_l...
913
  static int __init acpi_irq_balance_set(char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
  {
  	acpi_irq_balance = 1;
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918

4be44fcd3   Len Brown   [ACPI] Lindent al...
919
  __setup("acpi_irq_balance", acpi_irq_balance_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920

c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
921
  static struct syscore_ops irqrouter_syscore_ops = {
4be44fcd3   Len Brown   [ACPI] Lindent al...
922
  	.resume = irqrouter_resume,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  };
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
924
  void __init acpi_pci_link_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  	if (acpi_noirq)
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
927
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

32836259f   Bjorn Helgaas   ACPI: pci_link: r...
929
930
931
932
933
934
935
  	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;
  	}
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
936
937
  	register_syscore_ops(&irqrouter_syscore_ops);
  	acpi_scan_add_handler(&pci_link_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  }