Blame view

drivers/acpi/pci_link.c 23.5 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
  /*
   *  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>
   *
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
9
10
   * TBD:
   *	1. Support more than one IRQ resource entry per link device (index).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
   *	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...
14
  #include <linux/syscore_ops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
  #include <linux/spinlock.h>
  #include <linux/pm.h>
  #include <linux/pci.h>
36e430951   Ingo Molnar   sem2mutex: acpi, ...
22
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
8b48463f8   Lv Zheng   ACPI: Clean up in...
24
  #include <linux/acpi.h>
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
25
  #include <linux/irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

c071b6040   Rashika   ACPI / PCI: Inclu...
27
  #include "internal.h"
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
28
  #define _COMPONENT			ACPI_PCI_COMPONENT
f52fd66d2   Len Brown   ACPI: clean up AC...
29
  ACPI_MODULE_NAME("pci_link");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
32
  #define ACPI_PCI_LINK_MAX_POSSIBLE	16
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
33
34
35
  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
36

c97adf9e7   Márton Németh   acpi: make ACPI d...
37
  static const struct acpi_device_id link_device_ids[] = {
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
38
39
40
  	{"PNP0C0F", 0},
  	{"", 0},
  };
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
41

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
  /* --------------------------------------------------------------------------
                              PCI Link Device Management
     -------------------------------------------------------------------------- */
  
  /*
   * set context (link) possible list from resource list
   */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
79
80
  static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
  						void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  {
50dd09697   Jan Engelhardt   ACPI: Remove unne...
82
  	struct acpi_pci_link *link = context;
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
83
  	u32 i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

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

67a713657   Patrick Mochel   ACPI: pci_link: U...
156
  	status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
4be44fcd3   Len Brown   [ACPI] Lindent al...
157
  				     acpi_pci_link_check_possible, link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	if (ACPI_FAILURE(status)) {
92d1b381f   Alex Hung   ACPI / PCI: pci_l...
159
160
  		acpi_handle_debug(link->device->handle, "_PRS not present or invalid");
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
162
163
164
165
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			  "Found %d possible IRQs
  ",
  			  link->irq.possible_count));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

d550d98d3   Patrick Mochel   ACPI: delete trac...
167
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  }
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
169
170
  static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
  					       void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
172
  	int *irq = context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173

eca008c81   Len Brown   [ACPI] handle ACP...
174
  	switch (resource->type) {
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
175
176
177
  	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
  	case ACPI_RESOURCE_TYPE_END_TAG:
  		return AE_OK;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
178
  	case ACPI_RESOURCE_TYPE_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
179
180
  		{
  			struct acpi_resource_irq *p = &resource->data.irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
181
  			if (!p || !p->interrupt_count) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
182
183
184
185
186
  				/*
  				 * 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...
187
188
  						  "Blank _CRS IRQ resource
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
189
  				return AE_OK;
4be44fcd3   Len Brown   [ACPI] Lindent al...
190
191
192
  			}
  			*irq = p->interrupts[0];
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  		}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
194
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
4be44fcd3   Len Brown   [ACPI] Lindent al...
195
  		{
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
196
  			struct acpi_resource_extended_irq *p =
4be44fcd3   Len Brown   [ACPI] Lindent al...
197
  			    &resource->data.extended_irq;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
198
  			if (!p || !p->interrupt_count) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
199
200
201
202
  				/*
  				 * extended IRQ descriptors must
  				 * return at least 1 IRQ
  				 */
cece92969   Len Brown   ACPI: un-export A...
203
  				printk(KERN_WARNING PREFIX
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
204
205
  					      "Blank _CRS EXT IRQ resource
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
206
  				return AE_OK;
4be44fcd3   Len Brown   [ACPI] Lindent al...
207
208
209
  			}
  			*irq = p->interrupts[0];
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  		}
d4ec6c7cc   Len Brown   [ACPI] remove "Re...
211
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	default:
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
213
214
215
  		printk(KERN_ERR PREFIX "_CRS resource type 0x%x isn't an IRQ
  ",
  		       resource->type);
d550d98d3   Patrick Mochel   ACPI: delete trac...
216
  		return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	}
4a5e3638b   Bjorn Helgaas   ACPI: stop compla...
218

d550d98d3   Patrick Mochel   ACPI: delete trac...
219
  	return AE_CTRL_TERMINATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
227
228
  }
  
  /*
   * Run _CRS and set link->irq.active
   *
   * return value:
   * 0 - success
   * !0 - failure
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
229
  static int acpi_pci_link_get_current(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
231
  	int result = 0;
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
232
  	acpi_status status;
4be44fcd3   Len Brown   [ACPI] Lindent al...
233
  	int irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
  	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...
242
243
  			printk(KERN_ERR PREFIX "Unable to read status
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
  			goto end;
  		}
  
  		if (!link->device->status.enabled) {
  			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
250
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
  		}
  	}
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
253
254
  	/*
  	 * Query and parse _CRS to get the current IRQ assignment.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  	 */
67a713657   Patrick Mochel   ACPI: pci_link: U...
256
  	status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
4be44fcd3   Len Brown   [ACPI] Lindent al...
257
  				     acpi_pci_link_check_current, &irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
259
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
  		result = -ENODEV;
  		goto end;
  	}
  
  	if (acpi_strict && !irq) {
6468463ab   Len Brown   ACPI: un-export A...
265
266
  		printk(KERN_ERR PREFIX "_CRS returned 0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
  		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...
274
        end:
d550d98d3   Patrick Mochel   ACPI: delete trac...
275
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
277
  static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
279
280
  	int result;
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	struct {
4be44fcd3   Len Brown   [ACPI] Lindent al...
282
283
284
285
  		struct acpi_resource res;
  		struct acpi_resource end;
  	} *resource;
  	struct acpi_buffer buffer = { 0, NULL };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

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

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

4be44fcd3   Len Brown   [ACPI] Lindent al...
294
  	buffer.length = sizeof(*resource) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	buffer.pointer = resource;
4be44fcd3   Len Brown   [ACPI] Lindent al...
296
  	switch (link->irq.resource_type) {
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
297
298
  	case ACPI_RESOURCE_TYPE_IRQ:
  		resource->res.type = ACPI_RESOURCE_TYPE_IRQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  		resource->res.length = sizeof(struct acpi_resource);
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
300
301
302
303
  		resource->res.data.irq.triggering = link->irq.triggering;
  		resource->res.data.irq.polarity =
  		    link->irq.polarity;
  		if (link->irq.triggering == ACPI_EDGE_SENSITIVE)
c163f90cc   Erik Schmauss   ACPI/ACPICA: Triv...
304
  			resource->res.data.irq.shareable =
4be44fcd3   Len Brown   [ACPI] Lindent al...
305
  			    ACPI_EXCLUSIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  		else
c163f90cc   Erik Schmauss   ACPI/ACPICA: Triv...
307
  			resource->res.data.irq.shareable = ACPI_SHARED;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
308
  		resource->res.data.irq.interrupt_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
  		resource->res.data.irq.interrupts[0] = irq;
  		break;
4be44fcd3   Len Brown   [ACPI] Lindent al...
311

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
312
313
  	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
  		resource->res.type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  		resource->res.length = sizeof(struct acpi_resource);
4be44fcd3   Len Brown   [ACPI] Lindent al...
315
316
  		resource->res.data.extended_irq.producer_consumer =
  		    ACPI_CONSUMER;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
317
318
319
320
321
  		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)
1c5e1cdd7   Hans de Goede   ACPI/PCI: pci_lin...
322
  			resource->res.data.extended_irq.shareable =
4be44fcd3   Len Brown   [ACPI] Lindent al...
323
  			    ACPI_EXCLUSIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  		else
1c5e1cdd7   Hans de Goede   ACPI/PCI: pci_lin...
325
  			resource->res.data.extended_irq.shareable = ACPI_SHARED;
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
326
  		resource->res.data.extended_irq.interrupt_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
  		resource->res.data.extended_irq.interrupts[0] = irq;
  		/* ignore resource_source, it's optional */
  		break;
  	default:
6468463ab   Len Brown   ACPI: un-export A...
331
332
  		printk(KERN_ERR PREFIX "Invalid Resource_type %d
  ", link->irq.resource_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
  		result = -EINVAL;
  		goto end;
  
  	}
50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
337
  	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
f084dbb93   Yinghai Lu   ACPI: Set length ...
338
  	resource->end.length = sizeof(struct acpi_resource);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
  
  	/* Attempt to set the resource */
67a713657   Patrick Mochel   ACPI: pci_link: U...
341
  	status = acpi_set_current_resources(link->device->handle, &buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
  
  	/* check for total failure */
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
345
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
349
350
351
352
  		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...
353
354
  		printk(KERN_ERR PREFIX "Unable to read status
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
  		goto end;
  	}
  	if (!link->device->status.enabled) {
cece92969   Len Brown   ACPI: un-export A...
358
359
360
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] disabled and referenced, BIOS bug
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
361
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
362
  			      acpi_device_bid(link->device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  	}
  
  	/* 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...
380
381
382
  		printk(KERN_WARNING PREFIX
  			      "%s [%s] BIOS reported IRQ %d, using IRQ %d
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
383
  			      acpi_device_name(link->device),
cece92969   Len Brown   ACPI: un-export A...
384
  			      acpi_device_bid(link->device), link->irq.active, irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
  		link->irq.active = irq;
  	}
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d
  ", link->irq.active));
4be44fcd3   Len Brown   [ACPI] Lindent al...
390
391
  
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  	kfree(resource);
d550d98d3   Patrick Mochel   ACPI: delete trac...
393
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
  /* --------------------------------------------------------------------------
                              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.
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
402
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
   * "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.
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
420
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
   * 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...
429
  #define ACPI_MAX_ISA_IRQS	16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
435
  #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...
436
  static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
  	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
4be44fcd3   Len Brown   [ACPI] Lindent al...
440
441
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3 serial */
  	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4 serial */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
  	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...
446
447
448
  	0,				/* IRQ9  PCI, often acpi */
  	0,				/* IRQ10 PCI */
  	0,				/* IRQ11 PCI */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
449
450
451
452
  	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...
453
  	/* >IRQ15 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  };
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
455
456
457
458
  static int acpi_irq_pci_sharing_penalty(int irq)
  {
  	struct acpi_pci_link *link;
  	int penalty = 0;
4a6e68bf9   Sinan Kaya   ACPI,PCI,IRQ: fac...
459
  	int i;
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
460
461
462
463
464
465
466
467
  
  	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...
468
469
470
471
472
473
474
475
  
  		/*
  		 * 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...
476
477
478
479
480
481
482
483
  	}
  
  	return penalty;
  }
  
  static int acpi_irq_get_penalty(int irq)
  {
  	int penalty = 0;
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
484
485
  	if (irq == sci_irq)
  		penalty += sci_penalty;
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
486

f7eca374f   Sinan Kaya   ACPI,PCI,IRQ: sep...
487
488
  	if (irq < ACPI_MAX_ISA_IRQS)
  		return penalty + acpi_isa_irq_penalty[irq];
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
489
  	return penalty + acpi_irq_pci_sharing_penalty(irq);
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
490
  }
487cf917e   Sinan Kaya   Revert "ACPI, PCI...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  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...
526
  static int acpi_irq_balance = -1;	/* 0: static, 1: balance */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

4be44fcd3   Len Brown   [ACPI] Lindent al...
528
  static int acpi_pci_link_allocate(struct acpi_pci_link *link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
530
531
  	int irq;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
533
534
535
536
  	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...
537
  		return 0;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
538
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
544
545
546
547
548
549
550
551
  
  	/*
  	 * 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...
552
553
554
  			printk(KERN_WARNING PREFIX "_CRS %d not found"
  				      " in _PRS
  ", link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
  		link->irq.active = 0;
  	}
  
  	/*
  	 * if active found, use it; else pick entry from end of possible list.
  	 */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
561
  	if (link->irq.active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  		irq = link->irq.active;
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
563
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  		irq = link->irq.possible[link->irq.possible_count - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
  
  	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...
572
573
  			if (acpi_irq_get_penalty(irq) >
  			    acpi_irq_get_penalty(link->irq.possible[i]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
  				irq = link->irq.possible[i];
  		}
  	}
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
577
  	if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
578
579
580
581
582
583
584
  		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
585
586
587
  
  	/* Attempt to enable the link device at this IRQ. */
  	if (acpi_pci_link_set(link, irq)) {
6468463ab   Len Brown   ACPI: un-export A...
588
589
590
  		printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
  			    "Try pci=noacpi or acpi=off
  ",
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
591
  			    acpi_device_name(link->device),
6468463ab   Len Brown   ACPI: un-export A...
592
  			    acpi_device_bid(link->device));
d550d98d3   Patrick Mochel   ACPI: delete trac...
593
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  	} else {
98756f531   Sinan Kaya   ACPI/PCI: pci_lin...
595
596
597
  		if (link->irq.active < ACPI_MAX_ISA_IRQS)
  			acpi_isa_irq_penalty[link->irq.active] +=
  				PIRQ_PENALTY_PCI_USING;
90fd94e4a   Sinan Kaya   ACPI/PCI: pci_lin...
598
599
  		pr_info("%s [%s] enabled at IRQ %d
  ",
4be44fcd3   Len Brown   [ACPI] Lindent al...
600
601
  		       acpi_device_name(link->device),
  		       acpi_device_bid(link->device), link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  	}
  
  	link->irq.initialized = 1;
d550d98d3   Patrick Mochel   ACPI: delete trac...
605
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
  }
  
  /*
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
609
   * acpi_pci_link_allocate_irq
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
   * success: return IRQ >= 0
   * failure: return -1
   */
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
613
614
  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
615
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
616
617
618
  	int result;
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
622
623
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
624
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  	}
50dd09697   Jan Engelhardt   ACPI: Remove unne...
626
  	link = acpi_driver_data(device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
628
629
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
630
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
  	}
  
  	/* TBD: Support multiple index (IRQ) entries per Link Device */
  	if (index) {
6468463ab   Len Brown   ACPI: un-export A...
635
636
  		printk(KERN_ERR PREFIX "Invalid index %d
  ", index);
d550d98d3   Patrick Mochel   ACPI: delete trac...
637
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
639
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
640
  	if (acpi_pci_link_allocate(link)) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
641
  		mutex_unlock(&acpi_link_lock);
d550d98d3   Patrick Mochel   ACPI: delete trac...
642
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
643
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
644

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  	if (!link->irq.active) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
646
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
647
648
  		printk(KERN_ERR PREFIX "Link active IRQ is 0!
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
649
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
651
  	link->refcnt++;
36e430951   Ingo Molnar   sem2mutex: acpi, ...
652
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

50eca3eb8   Bob Moore   [ACPI] ACPICA 200...
654
655
656
657
  	if (triggering)
  		*triggering = link->irq.triggering;
  	if (polarity)
  		*polarity = link->irq.polarity;
4be44fcd3   Len Brown   [ACPI] Lindent al...
658
659
  	if (name)
  		*name = acpi_device_bid(link->device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
660
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
661
662
663
  			  "Link %s is referenced
  ",
  			  acpi_device_bid(link->device)));
8698fab1c   Krzysztof Wilczynski   ACPI/PCI: Remove ...
664
  	return link->irq.active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  }
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
666
667
668
669
  /*
   * We don't change link's irq information here.  After it is reenabled, we
   * continue use the info
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
670
  int acpi_pci_link_free_irq(acpi_handle handle)
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
671
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
672
673
  	struct acpi_device *device;
  	struct acpi_pci_link *link;
4be44fcd3   Len Brown   [ACPI] Lindent al...
674
  	acpi_status result;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
675

87bec66b9   David Shaohua Li   [ACPI] suspend/re...
676
677
  	result = acpi_bus_get_device(handle, &device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
678
679
  		printk(KERN_ERR PREFIX "Invalid link device
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
680
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
681
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682

50dd09697   Jan Engelhardt   ACPI: Remove unne...
683
  	link = acpi_driver_data(device);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
684
  	if (!link) {
6468463ab   Len Brown   ACPI: un-export A...
685
686
  		printk(KERN_ERR PREFIX "Invalid link context
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
687
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
688
  	}
36e430951   Ingo Molnar   sem2mutex: acpi, ...
689
  	mutex_lock(&acpi_link_lock);
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
690
  	if (!link->irq.initialized) {
36e430951   Ingo Molnar   sem2mutex: acpi, ...
691
  		mutex_unlock(&acpi_link_lock);
6468463ab   Len Brown   ACPI: un-export A...
692
693
  		printk(KERN_ERR PREFIX "Link isn't initialized
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
694
  		return -1;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
695
  	}
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
696
697
698
699
700
701
702
703
704
705
  #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...
706
  	link->refcnt--;
ecc21ebe6   David Shaohua Li   [ACPI] PCI interr...
707
  #endif
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
708
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
709
710
711
  			  "Link %s is dereferenced
  ",
  			  acpi_device_bid(link->device)));
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
712

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

36e430951   Ingo Molnar   sem2mutex: acpi, ...
716
  	mutex_unlock(&acpi_link_lock);
8698fab1c   Krzysztof Wilczynski   ACPI/PCI: Remove ...
717
  	return link->irq.active;
87bec66b9   David Shaohua Li   [ACPI] suspend/re...
718
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
719

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
  /* --------------------------------------------------------------------------
                                   Driver Interface
     -------------------------------------------------------------------------- */
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
723
724
  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
725
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
726
727
728
  	int result;
  	struct acpi_pci_link *link;
  	int i;
4be44fcd3   Len Brown   [ACPI] Lindent al...
729
  	int found = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

36bcbec7c   Burman Yan   ACPI: replace kma...
731
  	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  	if (!link)
d550d98d3   Patrick Mochel   ACPI: delete trac...
733
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  
  	link->device = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
  	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...
738
  	device->driver_data = link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739

36e430951   Ingo Molnar   sem2mutex: acpi, ...
740
  	mutex_lock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
744
745
746
  	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...
747
  	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
4be44fcd3   Len Brown   [ACPI] Lindent al...
748
  	       acpi_device_bid(device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
  	for (i = 0; i < link->irq.possible_count; i++) {
  		if (link->irq.active == link->irq.possible[i]) {
be96447e0   Kay Sievers   acpi: use KERN_CO...
751
  			printk(KERN_CONT " *%d", link->irq.possible[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  			found = 1;
4be44fcd3   Len Brown   [ACPI] Lindent al...
753
  		} else
be96447e0   Kay Sievers   acpi: use KERN_CO...
754
  			printk(KERN_CONT " %d", link->irq.possible[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  	}
be96447e0   Kay Sievers   acpi: use KERN_CO...
756
  	printk(KERN_CONT ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  
  	if (!found)
be96447e0   Kay Sievers   acpi: use KERN_CO...
759
  		printk(KERN_CONT " *%d", link->irq.active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

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

be96447e0   Kay Sievers   acpi: use KERN_CO...
764
765
  	printk(KERN_CONT "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766

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

4be44fcd3   Len Brown   [ACPI] Lindent al...
769
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	/* disable all links -- to be activated on use */
383d7a11c   donald.d.dugger@intel.com   ACPI: Fix possibl...
771
  	acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
772
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
  
  	if (result)
  		kfree(link);
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
776
  	return result < 0 ? result : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
778
  static int acpi_pci_link_resume(struct acpi_pci_link *link)
697a2d63a   Linus Torvalds   Revert ACPI inter...
779
  {
697a2d63a   Linus Torvalds   Revert ACPI inter...
780
  	if (link->refcnt && link->irq.active && link->irq.initialized)
d550d98d3   Patrick Mochel   ACPI: delete trac...
781
  		return (acpi_pci_link_set(link, link->irq.active));
1c9ca3a7d   Bjorn Helgaas   ACPI: pci_link: c...
782
783
  
  	return 0;
697a2d63a   Linus Torvalds   Revert ACPI inter...
784
  }
c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
785
  static void irqrouter_resume(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
787
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
789
  	list_for_each_entry(link, &acpi_link_list, list) {
697a2d63a   Linus Torvalds   Revert ACPI inter...
790
  		acpi_pci_link_resume(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  }
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
793
  static void acpi_pci_link_remove(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  {
c9d624432   Bjorn Helgaas   ACPI: pci_link: r...
795
  	struct acpi_pci_link *link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796

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

36e430951   Ingo Molnar   sem2mutex: acpi, ...
799
  	mutex_lock(&acpi_link_lock);
5f0dccaa8   Bjorn Helgaas   ACPI: pci_link: s...
800
  	list_del(&link->list);
36e430951   Ingo Molnar   sem2mutex: acpi, ...
801
  	mutex_unlock(&acpi_link_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  
  	kfree(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
  }
  
  /*
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
807
   * modify acpi_isa_irq_penalty[] from cmdline
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
815
   */
  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...
816
  		int new_penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817

4be44fcd3   Len Brown   [ACPI] Lindent al...
818
  		retval = get_option(&str, &irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
  
  		if (!retval)
  			break;	/* no number found */
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
822
823
  		/* see if this is a ISA IRQ */
  		if ((irq < 0) || (irq >= ACPI_MAX_ISA_IRQS))
e24971457   Rafael J. Wysocki   Revert "ACPI, PCI...
824
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  		if (used)
eeaed4bb5   Sinan Kaya   ACPI/PCI/IRQ: ass...
826
  			new_penalty = acpi_isa_irq_penalty[irq] +
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
827
  					PIRQ_PENALTY_ISA_USED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  		else
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
829
  			new_penalty = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830

5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
831
  		acpi_isa_irq_penalty[irq] = new_penalty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
834
835
836
837
838
839
840
841
842
843
844
  		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...
845
  void acpi_penalize_isa_irq(int irq, int active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
  {
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
847
  	if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
eeaed4bb5   Sinan Kaya   ACPI/PCI/IRQ: ass...
848
  		acpi_isa_irq_penalty[irq] +=
54794580f   Sinan Kaya   ACPI,PCI,IRQ: cor...
849
  		  (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  }
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
851
852
  bool acpi_isa_irq_available(int irq)
  {
5c5087a55   Sinan Kaya   ACPI,PCI,IRQ: red...
853
  	return irq >= 0 && (irq >= ARRAY_SIZE(acpi_isa_irq_penalty) ||
103544d86   Sinan Kaya   ACPI,PCI,IRQ: red...
854
  		    acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
5ebc76035   Jiang Liu   ACPI, PCI, irq: D...
855
  }
f1caa61df   Sinan Kaya   ACPI/PCI: pci_lin...
856
857
858
859
860
861
862
863
864
865
  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...
866
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
872
873
874
   * 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...
875

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
881
882
883
884
885
886
  __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...
887

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
892
893
894
  __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...
895

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  __setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
8a383ef0b   Roel Kluin   ACPI: ec.c, pci_l...
897
  static int __init acpi_irq_balance_set(char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
  {
  	acpi_irq_balance = 1;
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902

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

c3146df2b   Rafael J. Wysocki   ACPI: Use syscore...
905
  static struct syscore_ops irqrouter_syscore_ops = {
4be44fcd3   Len Brown   [ACPI] Lindent al...
906
  	.resume = irqrouter_resume,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  };
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
908
  void __init acpi_pci_link_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  	if (acpi_noirq)
4daeaf683   Rafael J. Wysocki   ACPI / PCI: Make ...
911
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912

32836259f   Bjorn Helgaas   ACPI: pci_link: r...
913
914
915
916
917
918
919
  	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 ...
920
921
  	register_syscore_ops(&irqrouter_syscore_ops);
  	acpi_scan_add_handler(&pci_link_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  }