]>
Commit | Line | Data |
---|---|---|
8ea6091f JK |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved. | |
7 | */ | |
8 | ||
9 | #include <asm/sn/types.h> | |
10 | #include <asm/sn/addrs.h> | |
11 | #include <asm/sn/pcidev.h> | |
12 | #include <asm/sn/pcibus_provider_defs.h> | |
13 | #include <asm/sn/sn_sal.h> | |
14 | #include "xtalk/hubdev.h" | |
15 | #include <linux/acpi.h> | |
16 | ||
17 | ||
18 | /* | |
19 | * The code in this file will only be executed when running with | |
20 | * a PROM that has ACPI IO support. (i.e., SN_ACPI_BASE_SUPPORT() == 1) | |
21 | */ | |
22 | ||
23 | ||
24 | /* | |
25 | * This value must match the UUID the PROM uses | |
26 | * (io/acpi/defblk.c) when building a vendor descriptor. | |
27 | */ | |
28 | struct acpi_vendor_uuid sn_uuid = { | |
29 | .subtype = 0, | |
30 | .data = { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11, | |
31 | 0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 }, | |
32 | }; | |
33 | ||
6f09a925 JK |
34 | struct sn_pcidev_match { |
35 | u8 bus; | |
36 | unsigned int devfn; | |
37 | acpi_handle handle; | |
38 | }; | |
39 | ||
8ea6091f JK |
40 | /* |
41 | * Perform the early IO init in PROM. | |
42 | */ | |
e088a4ad | 43 | static long |
8ea6091f JK |
44 | sal_ioif_init(u64 *result) |
45 | { | |
46 | struct ia64_sal_retval isrv = {0,0,0,0}; | |
47 | ||
48 | SAL_CALL_NOLOCK(isrv, | |
49 | SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0); | |
50 | *result = isrv.v0; | |
51 | return isrv.status; | |
52 | } | |
53 | ||
54 | /* | |
690b8d9d JK |
55 | * sn_acpi_hubdev_init() - This function is called by acpi_ns_get_device_callback() |
56 | * for all SGIHUB and SGITIO acpi devices defined in the | |
57 | * DSDT. It obtains the hubdev_info pointer from the | |
58 | * ACPI vendor resource, which the PROM setup, and sets up the | |
59 | * hubdev_info in the pda. | |
8ea6091f | 60 | */ |
690b8d9d JK |
61 | |
62 | static acpi_status __init | |
63 | sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret) | |
8ea6091f JK |
64 | { |
65 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | |
a8ce4471 | 66 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
8ea6091f JK |
67 | u64 addr; |
68 | struct hubdev_info *hubdev; | |
69 | struct hubdev_info *hubdev_ptr; | |
70 | int i; | |
71 | u64 nasid; | |
72 | struct acpi_resource *resource; | |
8ea6091f JK |
73 | acpi_status status; |
74 | struct acpi_resource_vendor_typed *vendor; | |
75 | extern void sn_common_hubdev_init(struct hubdev_info *); | |
76 | ||
690b8d9d | 77 | status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, |
8ea6091f JK |
78 | &sn_uuid, &buffer); |
79 | if (ACPI_FAILURE(status)) { | |
a8ce4471 | 80 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
8ea6091f | 81 | printk(KERN_ERR |
690b8d9d | 82 | "sn_acpi_hubdev_init: acpi_get_vendor_resource() " |
a8ce4471 LM |
83 | "(0x%x) failed for: %s\n", status, |
84 | (char *)name_buffer.pointer); | |
85 | kfree(name_buffer.pointer); | |
690b8d9d | 86 | return AE_OK; /* Continue walking namespace */ |
8ea6091f JK |
87 | } |
88 | ||
89 | resource = buffer.pointer; | |
90 | vendor = &resource->data.vendor_typed; | |
91 | if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != | |
92 | sizeof(struct hubdev_info *)) { | |
a8ce4471 | 93 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
8ea6091f | 94 | printk(KERN_ERR |
a8ce4471 LM |
95 | "sn_acpi_hubdev_init: Invalid vendor data length: " |
96 | "%d for: %s\n", | |
97 | vendor->byte_length, (char *)name_buffer.pointer); | |
98 | kfree(name_buffer.pointer); | |
8ea6091f JK |
99 | goto exit; |
100 | } | |
101 | ||
102 | memcpy(&addr, vendor->byte_data, sizeof(struct hubdev_info *)); | |
103 | hubdev_ptr = __va((struct hubdev_info *) addr); | |
104 | ||
105 | nasid = hubdev_ptr->hdi_nasid; | |
106 | i = nasid_to_cnodeid(nasid); | |
107 | hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); | |
108 | *hubdev = *hubdev_ptr; | |
109 | sn_common_hubdev_init(hubdev); | |
110 | ||
111 | exit: | |
112 | kfree(buffer.pointer); | |
690b8d9d | 113 | return AE_OK; /* Continue walking namespace */ |
8ea6091f JK |
114 | } |
115 | ||
116 | /* | |
117 | * sn_get_bussoft_ptr() - The pcibus_bussoft pointer is found in | |
118 | * the ACPI Vendor resource for this bus. | |
119 | */ | |
120 | static struct pcibus_bussoft * | |
121 | sn_get_bussoft_ptr(struct pci_bus *bus) | |
122 | { | |
123 | u64 addr; | |
124 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | |
a8ce4471 | 125 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
8ea6091f JK |
126 | acpi_handle handle; |
127 | struct pcibus_bussoft *prom_bussoft_ptr; | |
128 | struct acpi_resource *resource; | |
129 | acpi_status status; | |
130 | struct acpi_resource_vendor_typed *vendor; | |
131 | ||
132 | ||
133 | handle = PCI_CONTROLLER(bus)->acpi_handle; | |
134 | status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, | |
135 | &sn_uuid, &buffer); | |
136 | if (ACPI_FAILURE(status)) { | |
a8ce4471 | 137 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
6f09a925 | 138 | printk(KERN_ERR "%s: " |
a8ce4471 LM |
139 | "acpi_get_vendor_resource() failed (0x%x) for: %s\n", |
140 | __func__, status, (char *)name_buffer.pointer); | |
141 | kfree(name_buffer.pointer); | |
8ea6091f JK |
142 | return NULL; |
143 | } | |
144 | resource = buffer.pointer; | |
145 | vendor = &resource->data.vendor_typed; | |
146 | ||
147 | if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != | |
148 | sizeof(struct pcibus_bussoft *)) { | |
149 | printk(KERN_ERR | |
6f09a925 | 150 | "%s: Invalid vendor data length %d\n", |
d4ed8084 | 151 | __func__, vendor->byte_length); |
8ea6091f JK |
152 | kfree(buffer.pointer); |
153 | return NULL; | |
154 | } | |
155 | memcpy(&addr, vendor->byte_data, sizeof(struct pcibus_bussoft *)); | |
156 | prom_bussoft_ptr = __va((struct pcibus_bussoft *) addr); | |
157 | kfree(buffer.pointer); | |
158 | ||
159 | return prom_bussoft_ptr; | |
160 | } | |
161 | ||
162 | /* | |
6f09a925 JK |
163 | * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info |
164 | * pointers from the vendor resource using the | |
165 | * provided acpi handle, and copy the structures | |
166 | * into the argument buffers. | |
8ea6091f | 167 | */ |
6f09a925 JK |
168 | static int |
169 | sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, | |
170 | struct sn_irq_info **sn_irq_info) | |
8ea6091f | 171 | { |
6f09a925 JK |
172 | u64 addr; |
173 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | |
a8ce4471 | 174 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
6f09a925 JK |
175 | struct sn_irq_info *irq_info, *irq_info_prom; |
176 | struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr; | |
177 | struct acpi_resource *resource; | |
178 | int ret = 0; | |
179 | acpi_status status; | |
180 | struct acpi_resource_vendor_typed *vendor; | |
8ea6091f | 181 | |
6f09a925 JK |
182 | /* |
183 | * The pointer to this device's pcidev_info structure in | |
184 | * the PROM, is in the vendor resource. | |
185 | */ | |
186 | status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, | |
187 | &sn_uuid, &buffer); | |
188 | if (ACPI_FAILURE(status)) { | |
a8ce4471 | 189 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
6f09a925 | 190 | printk(KERN_ERR |
a8ce4471 LM |
191 | "%s: acpi_get_vendor_resource() failed (0x%x) for: %s\n", |
192 | __func__, status, (char *)name_buffer.pointer); | |
193 | kfree(name_buffer.pointer); | |
6f09a925 JK |
194 | return 1; |
195 | } | |
196 | ||
197 | resource = buffer.pointer; | |
198 | vendor = &resource->data.vendor_typed; | |
199 | if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != | |
200 | sizeof(struct pci_devdev_info *)) { | |
a8ce4471 | 201 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
6f09a925 | 202 | printk(KERN_ERR |
a8ce4471 LM |
203 | "%s: Invalid vendor data length: %d for: %s\n", |
204 | __func__, vendor->byte_length, | |
205 | (char *)name_buffer.pointer); | |
206 | kfree(name_buffer.pointer); | |
6f09a925 JK |
207 | ret = 1; |
208 | goto exit; | |
209 | } | |
210 | ||
211 | pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); | |
212 | if (!pcidev_ptr) | |
d4ed8084 | 213 | panic("%s: Unable to alloc memory for pcidev_info", __func__); |
6f09a925 JK |
214 | |
215 | memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *)); | |
216 | pcidev_prom_ptr = __va(addr); | |
217 | memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info)); | |
218 | ||
219 | /* Get the IRQ info */ | |
220 | irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | |
221 | if (!irq_info) | |
d4ed8084 | 222 | panic("%s: Unable to alloc memory for sn_irq_info", __func__); |
6f09a925 JK |
223 | |
224 | if (pcidev_ptr->pdi_sn_irq_info) { | |
225 | irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info); | |
226 | memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info)); | |
227 | } | |
228 | ||
229 | *pcidev_info = pcidev_ptr; | |
230 | *sn_irq_info = irq_info; | |
231 | ||
232 | exit: | |
233 | kfree(buffer.pointer); | |
234 | return ret; | |
235 | } | |
236 | ||
237 | static unsigned int | |
238 | get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) | |
239 | { | |
27663c58 | 240 | unsigned long long adr; |
6f09a925 JK |
241 | acpi_handle child; |
242 | unsigned int devfn; | |
243 | int function; | |
244 | acpi_handle parent; | |
245 | int slot; | |
246 | acpi_status status; | |
a8ce4471 LM |
247 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
248 | ||
249 | acpi_get_name(device_handle, ACPI_FULL_PATHNAME, &name_buffer); | |
6f09a925 JK |
250 | |
251 | /* | |
252 | * Do an upward search to find the root bus device, and | |
253 | * obtain the host devfn from the previous child device. | |
254 | */ | |
255 | child = device_handle; | |
256 | while (child) { | |
257 | status = acpi_get_parent(child, &parent); | |
258 | if (ACPI_FAILURE(status)) { | |
259 | printk(KERN_ERR "%s: acpi_get_parent() failed " | |
a8ce4471 LM |
260 | "(0x%x) for: %s\n", __func__, status, |
261 | (char *)name_buffer.pointer); | |
d4ed8084 | 262 | panic("%s: Unable to find host devfn\n", __func__); |
6f09a925 JK |
263 | } |
264 | if (parent == rootbus_handle) | |
265 | break; | |
266 | child = parent; | |
267 | } | |
268 | if (!child) { | |
a8ce4471 LM |
269 | printk(KERN_ERR "%s: Unable to find root bus for: %s\n", |
270 | __func__, (char *)name_buffer.pointer); | |
6f09a925 JK |
271 | BUG(); |
272 | } | |
273 | ||
274 | status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr); | |
275 | if (ACPI_FAILURE(status)) { | |
a8ce4471 LM |
276 | printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: %s\n", |
277 | __func__, status, (char *)name_buffer.pointer); | |
d4ed8084 | 278 | panic("%s: Unable to find host devfn\n", __func__); |
6f09a925 JK |
279 | } |
280 | ||
a8ce4471 LM |
281 | kfree(name_buffer.pointer); |
282 | ||
6f09a925 JK |
283 | slot = (adr >> 16) & 0xffff; |
284 | function = adr & 0xffff; | |
285 | devfn = PCI_DEVFN(slot, function); | |
286 | return devfn; | |
287 | } | |
288 | ||
289 | /* | |
290 | * find_matching_device - Callback routine to find the ACPI device | |
291 | * that matches up with our pci_dev device. | |
292 | * Matching is done on bus number and devfn. | |
293 | * To find the bus number for a particular | |
294 | * ACPI device, we must look at the _BBN method | |
295 | * of its parent. | |
296 | */ | |
297 | static acpi_status | |
298 | find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) | |
299 | { | |
27663c58 MW |
300 | unsigned long long bbn = -1; |
301 | unsigned long long adr; | |
6f09a925 JK |
302 | acpi_handle parent = NULL; |
303 | acpi_status status; | |
304 | unsigned int devfn; | |
305 | int function; | |
306 | int slot; | |
307 | struct sn_pcidev_match *info = context; | |
a8ce4471 | 308 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
6f09a925 JK |
309 | |
310 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, | |
311 | &adr); | |
312 | if (ACPI_SUCCESS(status)) { | |
313 | status = acpi_get_parent(handle, &parent); | |
314 | if (ACPI_FAILURE(status)) { | |
a8ce4471 | 315 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
8ea6091f | 316 | printk(KERN_ERR |
a8ce4471 LM |
317 | "%s: acpi_get_parent() failed (0x%x) for: %s\n", |
318 | __func__, status, (char *)name_buffer.pointer); | |
319 | kfree(name_buffer.pointer); | |
6f09a925 JK |
320 | return AE_OK; |
321 | } | |
322 | status = acpi_evaluate_integer(parent, METHOD_NAME__BBN, | |
323 | NULL, &bbn); | |
324 | if (ACPI_FAILURE(status)) { | |
a8ce4471 | 325 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer); |
6f09a925 | 326 | printk(KERN_ERR |
a8ce4471 LM |
327 | "%s: Failed to find _BBN in parent of: %s\n", |
328 | __func__, (char *)name_buffer.pointer); | |
329 | kfree(name_buffer.pointer); | |
6f09a925 JK |
330 | return AE_OK; |
331 | } | |
332 | ||
333 | slot = (adr >> 16) & 0xffff; | |
334 | function = adr & 0xffff; | |
335 | devfn = PCI_DEVFN(slot, function); | |
336 | if ((info->devfn == devfn) && (info->bus == bbn)) { | |
337 | /* We have a match! */ | |
338 | info->handle = handle; | |
339 | return 1; | |
8ea6091f | 340 | } |
8ea6091f | 341 | } |
6f09a925 JK |
342 | return AE_OK; |
343 | } | |
344 | ||
345 | /* | |
346 | * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi | |
347 | * device matching the specified pci_dev, | |
348 | * and return the pcidev info and irq info. | |
349 | */ | |
350 | int | |
351 | sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, | |
352 | struct sn_irq_info **sn_irq_info) | |
353 | { | |
354 | unsigned int host_devfn; | |
355 | struct sn_pcidev_match pcidev_match; | |
356 | acpi_handle rootbus_handle; | |
27663c58 | 357 | unsigned long long segment; |
6f09a925 | 358 | acpi_status status; |
a8ce4471 | 359 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
6f09a925 JK |
360 | |
361 | rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle; | |
362 | status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL, | |
363 | &segment); | |
364 | if (ACPI_SUCCESS(status)) { | |
365 | if (segment != pci_domain_nr(dev)) { | |
a8ce4471 LM |
366 | acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, |
367 | &name_buffer); | |
6f09a925 | 368 | printk(KERN_ERR |
a8ce4471 LM |
369 | "%s: Segment number mismatch, 0x%llx vs 0x%x for: %s\n", |
370 | __func__, segment, pci_domain_nr(dev), | |
371 | (char *)name_buffer.pointer); | |
372 | kfree(name_buffer.pointer); | |
6f09a925 JK |
373 | return 1; |
374 | } | |
375 | } else { | |
a8ce4471 LM |
376 | acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, &name_buffer); |
377 | printk(KERN_ERR "%s: Unable to get __SEG from: %s\n", | |
378 | __func__, (char *)name_buffer.pointer); | |
379 | kfree(name_buffer.pointer); | |
6f09a925 JK |
380 | return 1; |
381 | } | |
382 | ||
383 | /* | |
384 | * We want to search all devices in this segment/domain | |
385 | * of the ACPI namespace for the matching ACPI device, | |
386 | * which holds the pcidev_info pointer in its vendor resource. | |
387 | */ | |
388 | pcidev_match.bus = dev->bus->number; | |
389 | pcidev_match.devfn = dev->devfn; | |
390 | pcidev_match.handle = NULL; | |
391 | ||
392 | acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX, | |
2263576c | 393 | find_matching_device, NULL, &pcidev_match, NULL); |
6f09a925 JK |
394 | |
395 | if (!pcidev_match.handle) { | |
396 | printk(KERN_ERR | |
397 | "%s: Could not find matching ACPI device for %s.\n", | |
d4ed8084 | 398 | __func__, pci_name(dev)); |
6f09a925 | 399 | return 1; |
8ea6091f | 400 | } |
6f09a925 JK |
401 | |
402 | if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info)) | |
403 | return 1; | |
404 | ||
405 | /* Build up the pcidev_info.pdi_slot_host_handle */ | |
406 | host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle); | |
407 | (*pcidev_info)->pdi_slot_host_handle = | |
408 | ((unsigned long) pci_domain_nr(dev) << 40) | | |
409 | /* bus == 0 */ | |
410 | host_devfn; | |
411 | return 0; | |
8ea6091f JK |
412 | } |
413 | ||
a2302c68 | 414 | /* |
6f09a925 JK |
415 | * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info. |
416 | * Perform any SN specific slot fixup. | |
a2302c68 JK |
417 | * At present there does not appear to be |
418 | * any generic way to handle a ROM image | |
419 | * that has been shadowed by the PROM, so | |
420 | * we pass a pointer to it within the | |
421 | * pcidev_info structure. | |
422 | */ | |
423 | ||
424 | void | |
6f09a925 | 425 | sn_acpi_slot_fixup(struct pci_dev *dev) |
a2302c68 JK |
426 | { |
427 | void __iomem *addr; | |
6f09a925 JK |
428 | struct pcidev_info *pcidev_info = NULL; |
429 | struct sn_irq_info *sn_irq_info = NULL; | |
d7ad2254 | 430 | size_t image_size, size; |
a2302c68 | 431 | |
6f09a925 JK |
432 | if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { |
433 | panic("%s: Failure obtaining pcidev_info for %s\n", | |
d4ed8084 | 434 | __func__, pci_name(dev)); |
6f09a925 JK |
435 | } |
436 | ||
a2302c68 JK |
437 | if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { |
438 | /* | |
439 | * A valid ROM image exists and has been shadowed by the | |
d7ad2254 JK |
440 | * PROM. Setup the pci_dev ROM resource with the address |
441 | * of the shadowed copy, and the actual length of the ROM image. | |
a2302c68 | 442 | */ |
d7ad2254 JK |
443 | size = pci_resource_len(dev, PCI_ROM_RESOURCE); |
444 | addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], | |
445 | size); | |
97c44836 | 446 | image_size = pci_get_rom_size(dev, addr, size); |
a2302c68 JK |
447 | dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; |
448 | dev->resource[PCI_ROM_RESOURCE].end = | |
d7ad2254 | 449 | (unsigned long) addr + image_size - 1; |
a2302c68 JK |
450 | dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; |
451 | } | |
6f09a925 | 452 | sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); |
a2302c68 JK |
453 | } |
454 | ||
6f09a925 JK |
455 | EXPORT_SYMBOL(sn_acpi_slot_fixup); |
456 | ||
8ea6091f | 457 | |
6f09a925 JK |
458 | /* |
459 | * sn_acpi_bus_fixup - Perform SN specific setup of software structs | |
460 | * (pcibus_bussoft, pcidev_info) and hardware | |
461 | * registers, for the specified bus and devices under it. | |
462 | */ | |
463 | void | |
464 | sn_acpi_bus_fixup(struct pci_bus *bus) | |
465 | { | |
466 | struct pci_dev *pci_dev = NULL; | |
467 | struct pcibus_bussoft *prom_bussoft_ptr; | |
468 | ||
469 | if (!bus->parent) { /* If root bus */ | |
470 | prom_bussoft_ptr = sn_get_bussoft_ptr(bus); | |
471 | if (prom_bussoft_ptr == NULL) { | |
472 | printk(KERN_ERR | |
473 | "%s: 0x%04x:0x%02x Unable to " | |
474 | "obtain prom_bussoft_ptr\n", | |
d4ed8084 | 475 | __func__, pci_domain_nr(bus), bus->number); |
6f09a925 JK |
476 | return; |
477 | } | |
478 | sn_common_bus_fixup(bus, prom_bussoft_ptr); | |
479 | } | |
480 | list_for_each_entry(pci_dev, &bus->devices, bus_list) { | |
481 | sn_acpi_slot_fixup(pci_dev); | |
482 | } | |
483 | } | |
484 | ||
8ea6091f JK |
485 | /* |
486 | * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the | |
487 | * nodes and root buses in the DSDT. As a result, bus scanning | |
488 | * will be initiated by the Linux ACPI code. | |
489 | */ | |
490 | ||
491 | void __init | |
492 | sn_io_acpi_init(void) | |
493 | { | |
494 | u64 result; | |
e088a4ad | 495 | long status; |
8ea6091f | 496 | |
3948ec94 JK |
497 | /* SN Altix does not follow the IOSAPIC IRQ routing model */ |
498 | acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM; | |
499 | ||
690b8d9d JK |
500 | /* Setup hubdev_info for all SGIHUB/SGITIO devices */ |
501 | acpi_get_devices("SGIHUB", sn_acpi_hubdev_init, NULL, NULL); | |
502 | acpi_get_devices("SGITIO", sn_acpi_hubdev_init, NULL, NULL); | |
503 | ||
8ea6091f JK |
504 | status = sal_ioif_init(&result); |
505 | if (status || result) | |
506 | panic("sal_ioif_init failed: [%lx] %s\n", | |
507 | status, ia64_sal_strerror(status)); | |
508 | } |