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