Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
io_acpi_init.c
Go to the documentation of this file.
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>
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  */
31  .subtype = 0,
32  .data = { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11,
33  0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
34 };
35 
38  unsigned int devfn;
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 {
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;
77  extern void sn_common_hubdev_init(struct hubdev_info *);
78 
80  &sn_uuid, &buffer);
81  if (ACPI_FAILURE(status)) {
82  acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
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);
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 };
129  struct pcibus_bussoft *prom_bussoft_ptr;
130  struct acpi_resource *resource;
133 
134 
135  handle = PCI_CONTROLLER(bus)->acpi_handle;
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 *)) {
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;
183 
184  /*
185  * The pointer to this device's pcidev_info structure in
186  * the PROM, is in the vendor resource.
187  */
189  &sn_uuid, &buffer);
190  if (ACPI_FAILURE(status)) {
191  acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
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);
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;
244  unsigned int devfn;
245  int function;
247  int slot;
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;
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);
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);
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;
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);
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 
395  find_matching_device, NULL, &pcidev_match, NULL);
396 
397  if (!pcidev_match.handle) {
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
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;
453  }
454  sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
455 }
456 
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
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) {
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
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 }