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