~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/ia64/sn/kernel/io_acpi_init.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp