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#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/proc_fs.h>
31#include <linux/spinlock.h>
32#include <linux/pm.h>
33#include <linux/pci.h>
34#include <linux/acpi.h>
35#include <acpi/acpi_bus.h>
36#include <acpi/acpi_drivers.h>
37
38#define _COMPONENT ACPI_PCI_COMPONENT
39ACPI_MODULE_NAME("pci_bind");
40
41struct acpi_pci_data {
42 struct acpi_pci_id id;
43 struct pci_bus *bus;
44 struct pci_dev *dev;
45};
46
47static int acpi_pci_unbind(struct acpi_device *device);
48
49static void acpi_pci_data_handler(acpi_handle handle, u32 function,
50 void *context)
51{
52
53
54
55 return;
56}
57
58
59
60
61
62
63
64
65acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
66{
67 int result = 0;
68 acpi_status status = AE_OK;
69 struct acpi_device *device = NULL;
70 struct acpi_pci_data *data = NULL;
71
72
73 if (!id)
74 return AE_BAD_PARAMETER;
75
76 result = acpi_bus_get_device(handle, &device);
77 if (result) {
78 printk(KERN_ERR PREFIX
79 "Invalid ACPI Bus context for device %s\n",
80 acpi_device_bid(device));
81 return AE_NOT_EXIST;
82 }
83
84 status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data);
85 if (ACPI_FAILURE(status) || !data) {
86 ACPI_EXCEPTION((AE_INFO, status,
87 "Invalid ACPI-PCI context for device %s",
88 acpi_device_bid(device)));
89 return status;
90 }
91
92 *id = data->id;
93
94
95
96
97
98
99
100
101 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
102 "Device %s has PCI address %04x:%02x:%02x.%d\n",
103 acpi_device_bid(device), id->segment, id->bus,
104 id->device, id->function));
105
106 return AE_OK;
107}
108
109EXPORT_SYMBOL(acpi_get_pci_id);
110
111int acpi_pci_bind(struct acpi_device *device)
112{
113 int result = 0;
114 acpi_status status;
115 struct acpi_pci_data *data;
116 struct acpi_pci_data *pdata;
117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
118 acpi_handle handle;
119
120 if (!device || !device->parent)
121 return -EINVAL;
122
123 data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
124 if (!data)
125 return -ENOMEM;
126
127 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
128 if (ACPI_FAILURE(status)) {
129 kfree(data);
130 return -ENODEV;
131 }
132
133 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
134 (char *)buffer.pointer));
135
136
137
138
139
140
141 status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
142 (void **)&pdata);
143 if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
144 ACPI_EXCEPTION((AE_INFO, status,
145 "Invalid ACPI-PCI context for parent device %s",
146 acpi_device_bid(device->parent)));
147 result = -ENODEV;
148 goto end;
149 }
150 data->id.segment = pdata->id.segment;
151 data->id.bus = pdata->bus->number;
152
153
154
155
156
157
158
159 data->id.device = device->pnp.bus_address >> 16;
160 data->id.function = device->pnp.bus_address & 0xFFFF;
161
162 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n",
163 data->id.segment, data->id.bus, data->id.device,
164 data->id.function));
165
166
167
168
169
170
171
172
173
174
175
176
177 data->dev = pci_get_slot(pdata->bus,
178 PCI_DEVFN(data->id.device, data->id.function));
179 if (!data->dev) {
180 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
181 "Device %04x:%02x:%02x.%d not present in PCI namespace\n",
182 data->id.segment, data->id.bus,
183 data->id.device, data->id.function));
184 result = -ENODEV;
185 goto end;
186 }
187 if (!data->dev->bus) {
188 printk(KERN_ERR PREFIX
189 "Device %04x:%02x:%02x.%d has invalid 'bus' field\n",
190 data->id.segment, data->id.bus,
191 data->id.device, data->id.function);
192 result = -ENODEV;
193 goto end;
194 }
195
196
197
198
199
200
201
202 if (data->dev->subordinate) {
203 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
204 "Device %04x:%02x:%02x.%d is a PCI bridge\n",
205 data->id.segment, data->id.bus,
206 data->id.device, data->id.function));
207 data->bus = data->dev->subordinate;
208 device->ops.bind = acpi_pci_bind;
209 device->ops.unbind = acpi_pci_unbind;
210 }
211
212
213
214
215
216
217 status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
218 if (ACPI_FAILURE(status)) {
219 ACPI_EXCEPTION((AE_INFO, status,
220 "Unable to attach ACPI-PCI context to device %s",
221 acpi_device_bid(device)));
222 result = -ENODEV;
223 goto end;
224 }
225
226
227
228
229
230
231
232
233
234
235
236 status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
237 if (ACPI_SUCCESS(status)) {
238 if (data->bus)
239 acpi_pci_irq_add_prt(device->handle, data->id.segment,
240 data->bus->number);
241 else
242 acpi_pci_irq_add_prt(device->handle, data->id.segment,
243 data->id.bus);
244 }
245
246 end:
247 kfree(buffer.pointer);
248 if (result) {
249 pci_dev_put(data->dev);
250 kfree(data);
251 }
252 return result;
253}
254
255static int acpi_pci_unbind(struct acpi_device *device)
256{
257 int result = 0;
258 acpi_status status;
259 struct acpi_pci_data *data;
260 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
261
262
263 if (!device || !device->parent)
264 return -EINVAL;
265
266 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
267 if (ACPI_FAILURE(status))
268 return -ENODEV;
269
270 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
271 (char *) buffer.pointer));
272 kfree(buffer.pointer);
273
274 status =
275 acpi_get_data(device->handle, acpi_pci_data_handler,
276 (void **)&data);
277 if (ACPI_FAILURE(status)) {
278 result = -ENODEV;
279 goto end;
280 }
281
282 status = acpi_detach_data(device->handle, acpi_pci_data_handler);
283 if (ACPI_FAILURE(status)) {
284 ACPI_EXCEPTION((AE_INFO, status,
285 "Unable to detach data from device %s",
286 acpi_device_bid(device)));
287 result = -ENODEV;
288 goto end;
289 }
290 if (data->dev->subordinate) {
291 acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
292 }
293 pci_dev_put(data->dev);
294 kfree(data);
295
296 end:
297 return result;
298}
299
300int
301acpi_pci_bind_root(struct acpi_device *device,
302 struct acpi_pci_id *id, struct pci_bus *bus)
303{
304 int result = 0;
305 acpi_status status;
306 struct acpi_pci_data *data = NULL;
307 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
308
309 if (!device || !id || !bus) {
310 return -EINVAL;
311 }
312
313 data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
314 if (!data)
315 return -ENOMEM;
316
317 data->id = *id;
318 data->bus = bus;
319 device->ops.bind = acpi_pci_bind;
320 device->ops.unbind = acpi_pci_unbind;
321
322 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
323 if (ACPI_FAILURE(status)) {
324 kfree (data);
325 return -ENODEV;
326 }
327
328 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to "
329 "%04x:%02x\n", (char *)buffer.pointer,
330 id->segment, id->bus));
331
332 status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
333 if (ACPI_FAILURE(status)) {
334 ACPI_EXCEPTION((AE_INFO, status,
335 "Unable to attach ACPI-PCI context to device %s",
336 (char *)buffer.pointer));
337 result = -ENODEV;
338 goto end;
339 }
340
341 end:
342 kfree(buffer.pointer);
343 if (result != 0)
344 kfree(data);
345
346 return result;
347}
348