Blame view

drivers/acpi/pci_link.c 23.1 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
20
21
22
23
24
25
26
27
28
29
30
  /*
   *  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.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * 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...
31
  #include <linux/syscore_ops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
  #include <linux/spinlock.h>
  #include <linux/pm.h>
  #include <linux/pci.h>
36e430951   Ingo Molnar   sem2mutex: acpi, ...
39
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
40
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  
  #include <acpi/acpi_bus.h>
  #include <acpi/acpi_drivers.h>
a192a9580   Len Brown   ACPI: Move defini...
44
  #define PREFIX "ACPI: "
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
45
  #define _COMPONENT			ACPI_PCI_COMPONENT
f52fd66d2   Len Brown   ACPI: clean up AC...
46
  ACPI_MODULE_NAME("pci_link");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  #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...
51
  #define ACPI_PCI_LINK_MAX_POSSIBLE	16
4be44fcd3   Len Brown   [ACPI] Lindent al...
52
53
  static int acpi_pci_link_add(struct acpi_device *device);
  static int acpi_pci_link_remove(struct acpi_device *device, int type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

c97adf9e7   Márton Németh   acpi: make ACPI d...
55
  static const struct acpi_device_id link_device_ids[] = {
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
56
57
58
59
  	{"PNP0C0F", 0},
  	{"", 0},
  };
  MODULE_DEVICE_TABLE(acpi, link_device_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  static struct acpi_driver acpi_pci_link_driver = {
c2b6705b7   Len Brown   ACPI: fix acpi_dr...
61
  	.name = "pci_link",
4be44fcd3   Len Brown   [ACPI] Lindent al...
62
  	.class = ACPI_PCI_LINK_CLASS,
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
63
  	.ids = link_device_ids,
4be44fcd3   Len Brown   [ACPI] Lindent al...
64
65
66
  	.ops = {
  		.add = acpi_pci_link_add,
  		.remove = acpi_pci_link_remove,
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
67
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  };
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
69
70
71
72
  /*
   * 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
73
  struct acpi_pci_link_irq {
4be44fcd3   Len Brown   [ACPI] Lindent al...
74
  	u8 active;		/* Current IRQ */
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
75
  	u8 triggering;		/* All IRQs */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
76
  	u8 polarity;		/* All IRQs */
4be44fcd3   Len Brown   [ACPI] Lindent al...
77
78
79
80
81
  	u8 resource_type;
  	u8 possible_count;
  	u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
  	u8 initialized:1;
  	u8 reserved:7;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
  };
  
  struct acpi_pci_link {
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
85
  	struct list_head		list;
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
86
87
88
  	struct acpi_device		*device;
  	struct acpi_pci_link_irq	irq;
  	int				refcnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  };
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
90
  static LIST_HEAD(acpi_link_list);
e5685b9d3   Adrian Bunk   ACPI: misc cleanups
91
  static DEFINE_MUTEX(acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

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

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

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

d550d98d3   Patrick Mochel   ACPI: delete trac...
188
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  }
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
190
191
  static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
  					       void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
193
  	int *irq = context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

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

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

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

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

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

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

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
334
335
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  		resource->res.length = sizeof(struct acpi_resource);
4be44fcd3   Len Brown   [ACPI] Lindent al...
337
338
  		resource->res.data.extended_irq.producer_consumer =
  		    ACPI_CONSUMER;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
339
340
341
342
343
344
  		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...
345
  			    ACPI_EXCLUSIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  		else
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
347
348
  			resource->res.data.irq.sharable = ACPI_SHARED;
  		resource->res.data.extended_irq.interrupt_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
  		resource->res.data.extended_irq.interrupts[0] = irq;
  		/* ignore resource_source, it's optional */
  		break;
  	default:
6468463ab   Len Brown   ACPI: un-export A...
353
354
  		printk(KERN_ERR PREFIX "Invalid Resource_type %d
  ", link->irq.resource_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
  		result = -EINVAL;
  		goto end;
  
  	}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
359
  	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  
  	/* Attempt to set the resource */
67a713657   Patrick Mochel   ACPI: pci_link: U...
362
  	status = acpi_set_current_resources(link->device->handle, &buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
  
  	/* check for total failure */
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
366
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
  		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...
374
375
  		printk(KERN_ERR PREFIX "Unable to read status
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
  		goto end;
  	}
  	if (!link->device->status.enabled) {
cece92969   Len Brown   ACPI: un-export A...
379
380
381
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] disabled and referenced, BIOS bug
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
382
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
383
  			      acpi_device_bid(link->device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  	}
  
  	/* 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...
401
402
403
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] BIOS reported IRQ %d, using IRQ %d
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
404
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
405
  			      acpi_device_bid(link->device), link->irq.active, irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
  		link->irq.active = irq;
  	}
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d
  ", link->irq.active));
4be44fcd3   Len Brown   [ACPI] Lindent al...
411
412
  
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  	kfree(resource);
d550d98d3   Patrick Mochel   ACPI: delete trac...
414
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  /* --------------------------------------------------------------------------
                              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_IRQS		256
  #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)
  
  static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
4be44fcd3   Len Brown   [ACPI] Lindent al...
465
466
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
472
473
  	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 */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
474
475
476
477
  	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 */
4be44fcd3   Len Brown   [ACPI] Lindent al...
478
  	/* >IRQ15 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  };
4be44fcd3   Len Brown   [ACPI] Lindent al...
480
  int __init acpi_irq_penalty_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
482
483
  	struct acpi_pci_link *link;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  	/*
  	 * Update penalties to facilitate IRQ balancing.
  	 */
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
488
  	list_for_each_entry(link, &acpi_link_list, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
492
493
494
  
  		/*
  		 * reflect the possible and active irqs in the penalty table --
  		 * useful for breaking ties.
  		 */
  		if (link->irq.possible_count) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
495
496
497
  			int penalty =
  			    PIRQ_PENALTY_PCI_POSSIBLE /
  			    link->irq.possible_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
  
  			for (i = 0; i < link->irq.possible_count; i++) {
  				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
4be44fcd3   Len Brown   [ACPI] Lindent al...
501
502
503
  					acpi_irq_penalty[link->irq.
  							 possible[i]] +=
  					    penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  			}
  
  		} else if (link->irq.active) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
507
508
  			acpi_irq_penalty[link->irq.active] +=
  			    PIRQ_PENALTY_PCI_POSSIBLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
  		}
  	}
  	/* Add a penalty for the SCI */
cee324b14   Alexey Starikovskiy   ACPICA: use new A...
512
  	acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
d550d98d3   Patrick Mochel   ACPI: delete trac...
513
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  }
32836259f   Bjorn Helgaas   ACPI: pci_link: r...
515
  static int acpi_irq_balance = -1;	/* 0: static, 1: balance */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

4be44fcd3   Len Brown   [ACPI] Lindent al...
517
  static int acpi_pci_link_allocate(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
519
520
  	int irq;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
522
523
524
525
  	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...
526
  		return 0;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
527
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
535
536
537
538
539
540
  
  	/*
  	 * 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...
541
542
543
  			printk(KERN_WARNING PREFIX "_CRS %d not found"
  				      " in _PRS
  ", link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
  		link->irq.active = 0;
  	}
  
  	/*
  	 * if active found, use it; else pick entry from end of possible list.
  	 */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
550
  	if (link->irq.active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  		irq = link->irq.active;
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
552
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  		irq = link->irq.possible[link->irq.possible_count - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
559
560
  
  	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--) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
561
562
  			if (acpi_irq_penalty[irq] >
  			    acpi_irq_penalty[link->irq.possible[i]])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
  				irq = link->irq.possible[i];
  		}
  	}
  
  	/* Attempt to enable the link device at this IRQ. */
  	if (acpi_pci_link_set(link, irq)) {
6468463ab   Len Brown   ACPI: un-export A...
569
570
571
  		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
  			    "Try pci=noacpi or acpi=off
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
572
  			    acpi_device_name(link->device),
6468463ab   Len Brown   ACPI: un-export A...
573
  			    acpi_device_bid(link->device));
d550d98d3   Patrick Mochel   ACPI: delete trac...
574
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  	} else {
  		acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
4d9391557   Frank Seidel   ACPI: add missing...
577
578
  		printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d
  ",
4be44fcd3   Len Brown   [ACPI] Lindent al...
579
580
  		       acpi_device_name(link->device),
  		       acpi_device_bid(link->device), link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
  	}
  
  	link->irq.initialized = 1;
d550d98d3   Patrick Mochel   ACPI: delete trac...
584
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
  }
  
  /*
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
588
   * acpi_pci_link_allocate_irq
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
   * success: return IRQ >= 0
   * failure: return -1
   */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
592
593
  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
594
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
595
596
597
  	int result;
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
601
602
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
603
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  	}
50dd09697   Jan Engelhardt   ACPI: Remove unne...
605
  	link = acpi_driver_data(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
607
608
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
609
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
  	}
  
  	/* TBD: Support multiple index (IRQ) entries per Link Device */
  	if (index) {
6468463ab   Len Brown   ACPI: un-export A...
614
615
  		printk(KERN_ERR PREFIX "Invalid index %d
  ", index);
d550d98d3   Patrick Mochel   ACPI: delete trac...
616
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
618
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
619
  	if (acpi_pci_link_allocate(link)) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
620
  		mutex_unlock(&acpi_link_lock);
d550d98d3   Patrick Mochel   ACPI: delete trac...
621
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
622
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
623

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  	if (!link->irq.active) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
625
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
626
627
  		printk(KERN_ERR PREFIX "Link active IRQ is 0!
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
628
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
630
  	link->refcnt++;
36e430951   Ingo Molnar   sem2mutex: acpi, ...
631
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
633
634
635
636
  	if (triggering)
  		*triggering = link->irq.triggering;
  	if (polarity)
  		*polarity = link->irq.polarity;
4be44fcd3   Len Brown   [ACPI] Lindent al...
637
638
  	if (name)
  		*name = acpi_device_bid(link->device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
639
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
640
641
642
  			  "Link %s is referenced
  ",
  			  acpi_device_bid(link->device)));
d550d98d3   Patrick Mochel   ACPI: delete trac...
643
  	return (link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  }
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
645
646
647
648
  /*
   * We don't change link's irq information here.  After it is reenabled, we
   * continue use the info
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
649
  int acpi_pci_link_free_irq(acpi_handle handle)
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
650
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
651
652
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
4be44fcd3   Len Brown   [ACPI] Lindent al...
653
  	acpi_status result;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
654

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
655
656
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
657
658
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
659
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
660
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661

50dd09697   Jan Engelhardt   ACPI: Remove unne...
662
  	link = acpi_driver_data(device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
663
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
664
665
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
666
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
667
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
668
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
669
  	if (!link->irq.initialized) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
670
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
671
672
  		printk(KERN_ERR PREFIX "Link isn't initialized
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
673
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
674
  	}
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
675
676
677
678
679
680
681
682
683
684
  #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...
685
  	link->refcnt--;
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
686
  #endif
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
687
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
688
689
690
  			  "Link %s is dereferenced
  ",
  			  acpi_device_bid(link->device)));
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
691

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  /* --------------------------------------------------------------------------
                                   Driver Interface
     -------------------------------------------------------------------------- */
4be44fcd3   Len Brown   [ACPI] Lindent al...
702
  static int acpi_pci_link_add(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
704
705
706
  	int result;
  	struct acpi_pci_link *link;
  	int i;
4be44fcd3   Len Brown   [ACPI] Lindent al...
707
  	int found = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708

36bcbec7c   Burman Yan   ACPI: replace kma...
709
  	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
  	if (!link)
d550d98d3   Patrick Mochel   ACPI: delete trac...
711
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  
  	link->device = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
  	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...
716
  	device->driver_data = link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717

36e430951   Ingo Molnar   sem2mutex: acpi, ...
718
  	mutex_lock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
724
  	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...
725
  	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
4be44fcd3   Len Brown   [ACPI] Lindent al...
726
  	       acpi_device_bid(device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
  	for (i = 0; i < link->irq.possible_count; i++) {
  		if (link->irq.active == link->irq.possible[i]) {
  			printk(" *%d", link->irq.possible[i]);
  			found = 1;
4be44fcd3   Len Brown   [ACPI] Lindent al...
731
  		} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
736
737
738
  			printk(" %d", link->irq.possible[i]);
  	}
  
  	printk(")");
  
  	if (!found)
  		printk(" *%d", link->irq.active);
4be44fcd3   Len Brown   [ACPI] Lindent al...
739
  	if (!link->device->status.enabled)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
  		printk(", disabled.");
  
  	printk("
  ");
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
744
  	list_add_tail(&link->list, &acpi_link_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745

4be44fcd3   Len Brown   [ACPI] Lindent al...
746
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	/* disable all links -- to be activated on use */
383d7a11c   donald.d.dugger@intel.com   ACPI: Fix possibl...
748
  	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
749
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
  
  	if (result)
  		kfree(link);
d550d98d3   Patrick Mochel   ACPI: delete trac...
753
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
755
  static int acpi_pci_link_resume(struct acpi_pci_link *link)
697a2d63a   Linus Torvalds   Revert ACPI inter...
756
  {
697a2d63a   Linus Torvalds   Revert ACPI inter...
757
  	if (link->refcnt && link->irq.active && link->irq.initialized)
d550d98d3   Patrick Mochel   ACPI: delete trac...
758
  		return (acpi_pci_link_set(link, link->irq.active));
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
759
760
  
  	return 0;
697a2d63a   Linus Torvalds   Revert ACPI inter...
761
  }
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
762
  static void irqrouter_resume(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
764
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765

5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
766
  	list_for_each_entry(link, &acpi_link_list, list) {
697a2d63a   Linus Torvalds   Revert ACPI inter...
767
  		acpi_pci_link_resume(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
770
  static int acpi_pci_link_remove(struct acpi_device *device, int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
772
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773

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

36e430951   Ingo Molnar   sem2mutex: acpi, ...
776
  	mutex_lock(&acpi_link_lock);
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
777
  	list_del(&link->list);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
778
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
  
  	kfree(link);
d550d98d3   Patrick Mochel   ACPI: delete trac...
781
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
784
785
786
787
788
789
790
791
792
793
  }
  
  /*
   * modify acpi_irq_penalty[] from cmdline
   */
  static int __init acpi_irq_penalty_update(char *str, int used)
  {
  	int i;
  
  	for (i = 0; i < 16; i++) {
  		int retval;
  		int irq;
4be44fcd3   Len Brown   [ACPI] Lindent al...
794
  		retval = get_option(&str, &irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
  
  		if (!retval)
  			break;	/* no number found */
  
  		if (irq < 0)
  			continue;
4be44fcd3   Len Brown   [ACPI] Lindent al...
801

fa46d3526   Bjorn Helgaas   ACPI: bounds chec...
802
  		if (irq >= ARRAY_SIZE(acpi_irq_penalty))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
  			continue;
  
  		if (used)
  			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
  		else
  			acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
  
  		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...
823
  void acpi_penalize_isa_irq(int irq, int active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  {
fa46d3526   Bjorn Helgaas   ACPI: bounds chec...
825
826
827
828
829
830
  	if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
  		if (active)
  			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
  		else
  			acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
836
837
838
839
840
841
  }
  
  /*
   * 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...
842

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
850
851
852
853
  __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...
854

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
858
859
860
861
  __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...
862

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  __setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
8a383ef0b   Roel Kluin   ACPI: ec.c, pci_l...
864
  static int __init acpi_irq_balance_set(char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
  {
  	acpi_irq_balance = 1;
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869

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

c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
872
  static struct syscore_ops irqrouter_syscore_ops = {
4be44fcd3   Len Brown   [ACPI] Lindent al...
873
  	.resume = irqrouter_resume,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  };
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
875
  static int __init irqrouter_init_ops(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  {
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
877
878
  	if (!acpi_disabled && !acpi_noirq)
  		register_syscore_ops(&irqrouter_syscore_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879

c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
880
  	return 0;
4be44fcd3   Len Brown   [ACPI] Lindent al...
881
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882

c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
883
  device_initcall(irqrouter_init_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884

4be44fcd3   Len Brown   [ACPI] Lindent al...
885
  static int __init acpi_pci_link_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  	if (acpi_noirq)
d550d98d3   Patrick Mochel   ACPI: delete trac...
888
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

32836259f   Bjorn Helgaas   ACPI: pci_link: r...
890
891
892
893
894
895
896
  	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;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  	if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
d550d98d3   Patrick Mochel   ACPI: delete trac...
898
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899

d550d98d3   Patrick Mochel   ACPI: delete trac...
900
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
903
  }
  
  subsys_initcall(acpi_pci_link_init);