io_acpi_init.c 15 KB

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