linux/arch/ia64/sn/kernel/io_acpi_init.c
<<
>>
Prefs
   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 */
  30struct 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
  36struct 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 */
  45static long
  46sal_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
  64static acpi_status __init
  65sn_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
 113exit:
 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 */
 122static struct pcibus_bussoft *
 123sn_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 = acpi_device_handle(PCI_CONTROLLER(bus)->companion);
 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 */
 170static int
 171sn_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
 234exit:
 235        kfree(buffer.pointer);
 236        return ret;
 237}
 238
 239static unsigned int
 240get_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 */
 299static acpi_status
 300find_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 */
 352int
 353sn_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 = acpi_device_handle(PCI_CONTROLLER(dev)->companion);
 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
 426void
 427sn_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        struct resource *res;
 433        size_t size;
 434
 435        if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
 436                panic("%s:  Failure obtaining pcidev_info for %s\n",
 437                      __func__, pci_name(dev));
 438        }
 439
 440        if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
 441                /*
 442                 * A valid ROM image exists and has been shadowed by the
 443                 * PROM. Setup the pci_dev ROM resource with the address
 444                 * of the shadowed copy, and the actual length of the ROM image.
 445                 */
 446                size = pci_resource_len(dev, PCI_ROM_RESOURCE);
 447
 448                res = &dev->resource[PCI_ROM_RESOURCE];
 449
 450                pci_disable_rom(dev);
 451                if (res->parent)
 452                        release_resource(res);
 453
 454                res->start = pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE];
 455                res->end = res->start + size - 1;
 456                res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW |
 457                             IORESOURCE_PCI_FIXED;
 458        }
 459        sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 460}
 461EXPORT_SYMBOL(sn_acpi_slot_fixup);
 462
 463
 464/*
 465 * sn_acpi_bus_fixup -  Perform SN specific setup of software structs
 466 *                      (pcibus_bussoft, pcidev_info) and hardware
 467 *                      registers, for the specified bus and devices under it.
 468 */
 469void
 470sn_acpi_bus_fixup(struct pci_bus *bus)
 471{
 472        struct pci_dev *pci_dev = NULL;
 473        struct pcibus_bussoft *prom_bussoft_ptr;
 474
 475        if (!bus->parent) {     /* If root bus */
 476                prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
 477                if (prom_bussoft_ptr == NULL) {
 478                        printk(KERN_ERR
 479                               "%s: 0x%04x:0x%02x Unable to "
 480                               "obtain prom_bussoft_ptr\n",
 481                               __func__, pci_domain_nr(bus), bus->number);
 482                        return;
 483                }
 484                sn_common_bus_fixup(bus, prom_bussoft_ptr);
 485        }
 486        list_for_each_entry(pci_dev, &bus->devices, bus_list) {
 487                sn_acpi_slot_fixup(pci_dev);
 488        }
 489}
 490
 491/*
 492 * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
 493 *                   nodes and root buses in the DSDT. As a result, bus scanning
 494 *                   will be initiated by the Linux ACPI code.
 495 */
 496
 497void __init
 498sn_io_acpi_init(void)
 499{
 500        u64 result;
 501        long status;
 502
 503        /* SN Altix does not follow the IOSAPIC IRQ routing model */
 504        acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
 505
 506        /* Setup hubdev_info for all SGIHUB/SGITIO devices */
 507        acpi_get_devices("SGIHUB", sn_acpi_hubdev_init, NULL, NULL);
 508        acpi_get_devices("SGITIO", sn_acpi_hubdev_init, NULL, NULL);
 509
 510        status = sal_ioif_init(&result);
 511        if (status || result)
 512                panic("sal_ioif_init failed: [%lx] %s\n",
 513                      status, ia64_sal_strerror(status));
 514}
 515