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