linux/arch/ppc64/kernel/vio.c
<<
>>
Prefs
   1/*
   2 * IBM PowerPC Virtual I/O Infrastructure Support.
   3 *
   4 *    Copyright (c) 2003 IBM Corp.
   5 *     Dave Engebretsen engebret@us.ibm.com
   6 *     Santiago Leon santil@us.ibm.com
   7 *     Hollis Blanchard <hollisb@us.ibm.com>
   8 *
   9 *      This program is free software; you can redistribute it and/or
  10 *      modify it under the terms of the GNU General Public License
  11 *      as published by the Free Software Foundation; either version
  12 *      2 of the License, or (at your option) any later version.
  13 */
  14
  15#include <linux/init.h>
  16#include <linux/console.h>
  17#include <linux/version.h>
  18#include <linux/module.h>
  19#include <linux/kobject.h>
  20#include <linux/mm.h>
  21#include <linux/dma-mapping.h>
  22#include <asm/rtas.h>
  23#include <asm/iommu.h>
  24#include <asm/dma.h>
  25#include <asm/ppcdebug.h>
  26#include <asm/vio.h>
  27#include <asm/hvcall.h>
  28#include <asm/iSeries/vio.h>
  29#include <asm/iSeries/HvTypes.h>
  30#include <asm/iSeries/HvCallXm.h>
  31#include <asm/iSeries/HvLpConfig.h>
  32
  33#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__)
  34
  35extern struct subsystem devices_subsys; /* needed for vio_find_name() */
  36
  37static const struct vio_device_id *vio_match_device(
  38                const struct vio_device_id *, const struct vio_dev *);
  39
  40#ifdef CONFIG_PPC_PSERIES
  41static struct iommu_table *vio_build_iommu_table(struct vio_dev *);
  42static int vio_num_address_cells;
  43#endif
  44static struct vio_dev *vio_bus_device; /* fake "parent" device */
  45
  46#ifdef CONFIG_PPC_ISERIES
  47static struct vio_dev *__init vio_register_device_iseries(char *type,
  48                uint32_t unit_num);
  49
  50static struct iommu_table veth_iommu_table;
  51static struct iommu_table vio_iommu_table;
  52
  53static struct vio_dev _vio_dev  = {
  54        .iommu_table = &vio_iommu_table,
  55        .dev.bus = &vio_bus_type
  56};
  57struct device *iSeries_vio_dev = &_vio_dev.dev;
  58EXPORT_SYMBOL(iSeries_vio_dev);
  59
  60#define device_is_compatible(a, b)      1
  61
  62#endif
  63
  64/* convert from struct device to struct vio_dev and pass to driver.
  65 * dev->driver has already been set by generic code because vio_bus_match
  66 * succeeded. */
  67static int vio_bus_probe(struct device *dev)
  68{
  69        struct vio_dev *viodev = to_vio_dev(dev);
  70        struct vio_driver *viodrv = to_vio_driver(dev->driver);
  71        const struct vio_device_id *id;
  72        int error = -ENODEV;
  73
  74        DBGENTER();
  75
  76        if (!viodrv->probe)
  77                return error;
  78
  79        id = vio_match_device(viodrv->id_table, viodev);
  80        if (id) {
  81                error = viodrv->probe(viodev, id);
  82        }
  83
  84        return error;
  85}
  86
  87/* convert from struct device to struct vio_dev and pass to driver. */
  88static int vio_bus_remove(struct device *dev)
  89{
  90        struct vio_dev *viodev = to_vio_dev(dev);
  91        struct vio_driver *viodrv = to_vio_driver(dev->driver);
  92
  93        DBGENTER();
  94
  95        if (viodrv->remove) {
  96                return viodrv->remove(viodev);
  97        }
  98
  99        /* driver can't remove */
 100        return 1;
 101}
 102
 103/**
 104 * vio_register_driver: - Register a new vio driver
 105 * @drv:        The vio_driver structure to be registered.
 106 */
 107int vio_register_driver(struct vio_driver *viodrv)
 108{
 109        printk(KERN_DEBUG "%s: driver %s registering\n", __FUNCTION__,
 110                viodrv->name);
 111
 112        /* fill in 'struct driver' fields */
 113        viodrv->driver.name = viodrv->name;
 114        viodrv->driver.bus = &vio_bus_type;
 115        viodrv->driver.probe = vio_bus_probe;
 116        viodrv->driver.remove = vio_bus_remove;
 117
 118        return driver_register(&viodrv->driver);
 119}
 120EXPORT_SYMBOL(vio_register_driver);
 121
 122/**
 123 * vio_unregister_driver - Remove registration of vio driver.
 124 * @driver:     The vio_driver struct to be removed form registration
 125 */
 126void vio_unregister_driver(struct vio_driver *viodrv)
 127{
 128        driver_unregister(&viodrv->driver);
 129}
 130EXPORT_SYMBOL(vio_unregister_driver);
 131
 132/**
 133 * vio_match_device: - Tell if a VIO device has a matching VIO device id structure.
 134 * @ids:        array of VIO device id structures to search in
 135 * @dev:        the VIO device structure to match against
 136 *
 137 * Used by a driver to check whether a VIO device present in the
 138 * system is in its list of supported devices. Returns the matching
 139 * vio_device_id structure or NULL if there is no match.
 140 */
 141static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
 142        const struct vio_dev *dev)
 143{
 144        DBGENTER();
 145
 146        while (ids->type) {
 147                if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
 148                        device_is_compatible(dev->dev.platform_data, ids->compat))
 149                        return ids;
 150                ids++;
 151        }
 152        return NULL;
 153}
 154
 155#ifdef CONFIG_PPC_ISERIES
 156void __init iommu_vio_init(void)
 157{
 158        struct iommu_table *t;
 159        struct iommu_table_cb cb;
 160        unsigned long cbp;
 161        unsigned long itc_entries;
 162
 163        cb.itc_busno = 255;    /* Bus 255 is the virtual bus */
 164        cb.itc_virtbus = 0xff; /* Ask for virtual bus */
 165
 166        cbp = virt_to_abs(&cb);
 167        HvCallXm_getTceTableParms(cbp);
 168
 169        itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
 170        veth_iommu_table.it_size        = itc_entries / 2;
 171        veth_iommu_table.it_busno       = cb.itc_busno;
 172        veth_iommu_table.it_offset      = cb.itc_offset;
 173        veth_iommu_table.it_index       = cb.itc_index;
 174        veth_iommu_table.it_type        = TCE_VB;
 175        veth_iommu_table.it_blocksize   = 1;
 176
 177        t = iommu_init_table(&veth_iommu_table);
 178
 179        if (!t)
 180                printk("Virtual Bus VETH TCE table failed.\n");
 181
 182        vio_iommu_table.it_size         = itc_entries - veth_iommu_table.it_size;
 183        vio_iommu_table.it_busno        = cb.itc_busno;
 184        vio_iommu_table.it_offset       = cb.itc_offset +
 185                                          veth_iommu_table.it_size;
 186        vio_iommu_table.it_index        = cb.itc_index;
 187        vio_iommu_table.it_type         = TCE_VB;
 188        vio_iommu_table.it_blocksize    = 1;
 189
 190        t = iommu_init_table(&vio_iommu_table);
 191
 192        if (!t)
 193                printk("Virtual Bus VIO TCE table failed.\n");
 194}
 195#endif
 196
 197#ifdef CONFIG_PPC_PSERIES
 198static void probe_bus_pseries(void)
 199{
 200        struct device_node *node_vroot, *of_node;
 201
 202        node_vroot = find_devices("vdevice");
 203        if ((node_vroot == NULL) || (node_vroot->child == NULL))
 204                /* this machine doesn't do virtual IO, and that's ok */
 205                return;
 206
 207        vio_num_address_cells = prom_n_addr_cells(node_vroot->child);
 208
 209        /*
 210         * Create struct vio_devices for each virtual device in the device tree.
 211         * Drivers will associate with them later.
 212         */
 213        for (of_node = node_vroot->child; of_node != NULL;
 214                        of_node = of_node->sibling) {
 215                printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
 216                vio_register_device_node(of_node);
 217        }
 218}
 219#endif
 220
 221#ifdef CONFIG_PPC_ISERIES
 222static void probe_bus_iseries(void)
 223{
 224        HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap();
 225        struct vio_dev *viodev;
 226        int i;
 227
 228        /* there is only one of each of these */
 229        vio_register_device_iseries("viocons", 0);
 230        vio_register_device_iseries("vscsi", 0);
 231
 232        vlan_map = HvLpConfig_getVirtualLanIndexMap();
 233        for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
 234                if ((vlan_map & (0x8000 >> i)) == 0)
 235                        continue;
 236                viodev = vio_register_device_iseries("vlan", i);
 237                /* veth is special and has it own iommu_table */
 238                viodev->iommu_table = &veth_iommu_table;
 239        }
 240        for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
 241                vio_register_device_iseries("viodasd", i);
 242        for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
 243                vio_register_device_iseries("viocd", i);
 244        for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
 245                vio_register_device_iseries("viotape", i);
 246}
 247#endif
 248
 249/**
 250 * vio_bus_init: - Initialize the virtual IO bus
 251 */
 252static int __init vio_bus_init(void)
 253{
 254        int err;
 255
 256        err = bus_register(&vio_bus_type);
 257        if (err) {
 258                printk(KERN_ERR "failed to register VIO bus\n");
 259                return err;
 260        }
 261
 262        /* the fake parent of all vio devices, just to give us a nice directory */
 263        vio_bus_device = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
 264        if (!vio_bus_device) {
 265                return 1;
 266        }
 267        memset(vio_bus_device, 0, sizeof(struct vio_dev));
 268        strcpy(vio_bus_device->dev.bus_id, "vio");
 269
 270        err = device_register(&vio_bus_device->dev);
 271        if (err) {
 272                printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__,
 273                        err);
 274                kfree(vio_bus_device);
 275                return err;
 276        }
 277
 278#ifdef CONFIG_PPC_PSERIES
 279        probe_bus_pseries();
 280#endif
 281#ifdef CONFIG_PPC_ISERIES
 282        probe_bus_iseries();
 283#endif
 284
 285        return 0;
 286}
 287
 288__initcall(vio_bus_init);
 289
 290/* vio_dev refcount hit 0 */
 291static void __devinit vio_dev_release(struct device *dev)
 292{
 293        DBGENTER();
 294
 295#ifdef CONFIG_PPC_PSERIES
 296        /* XXX free TCE table */
 297        of_node_put(dev->platform_data);
 298#endif
 299        kfree(to_vio_dev(dev));
 300}
 301
 302#ifdef CONFIG_PPC_PSERIES
 303static ssize_t viodev_show_devspec(struct device *dev, char *buf)
 304{
 305        struct device_node *of_node = dev->platform_data;
 306
 307        return sprintf(buf, "%s\n", of_node->full_name);
 308}
 309DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
 310#endif
 311
 312static ssize_t viodev_show_name(struct device *dev, char *buf)
 313{
 314        return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
 315}
 316DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);
 317
 318static struct vio_dev * __devinit vio_register_device_common(
 319                struct vio_dev *viodev, char *name, char *type,
 320                uint32_t unit_address, struct iommu_table *iommu_table)
 321{
 322        DBGENTER();
 323
 324        viodev->name = name;
 325        viodev->type = type;
 326        viodev->unit_address = unit_address;
 327        viodev->iommu_table = iommu_table;
 328        /* init generic 'struct device' fields: */
 329        viodev->dev.parent = &vio_bus_device->dev;
 330        viodev->dev.bus = &vio_bus_type;
 331        viodev->dev.release = vio_dev_release;
 332
 333        /* register with generic device framework */
 334        if (device_register(&viodev->dev)) {
 335                printk(KERN_ERR "%s: failed to register device %s\n",
 336                                __FUNCTION__, viodev->dev.bus_id);
 337                return NULL;
 338        }
 339        device_create_file(&viodev->dev, &dev_attr_name);
 340
 341        return viodev;
 342}
 343
 344#ifdef CONFIG_PPC_PSERIES
 345/**
 346 * vio_register_device_node: - Register a new vio device.
 347 * @of_node:    The OF node for this device.
 348 *
 349 * Creates and initializes a vio_dev structure from the data in
 350 * of_node (dev.platform_data) and adds it to the list of virtual devices.
 351 * Returns a pointer to the created vio_dev or NULL if node has
 352 * NULL device_type or compatible fields.
 353 */
 354struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
 355{
 356        struct vio_dev *viodev;
 357        unsigned int *unit_address;
 358        unsigned int *irq_p;
 359
 360        DBGENTER();
 361
 362        /* we need the 'device_type' property, in order to match with drivers */
 363        if ((NULL == of_node->type)) {
 364                printk(KERN_WARNING
 365                        "%s: node %s missing 'device_type'\n", __FUNCTION__,
 366                        of_node->name ? of_node->name : "<unknown>");
 367                return NULL;
 368        }
 369
 370        unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
 371        if (!unit_address) {
 372                printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
 373                        of_node->name ? of_node->name : "<unknown>");
 374                return NULL;
 375        }
 376
 377        /* allocate a vio_dev for this node */
 378        viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
 379        if (!viodev) {
 380                return NULL;
 381        }
 382        memset(viodev, 0, sizeof(struct vio_dev));
 383
 384        viodev->dev.platform_data = of_node_get(of_node);
 385
 386        viodev->irq = NO_IRQ;
 387        irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
 388        if (irq_p) {
 389                int virq = virt_irq_create_mapping(*irq_p);
 390                if (virq == NO_IRQ) {
 391                        printk(KERN_ERR "Unable to allocate interrupt "
 392                               "number for %s\n", of_node->full_name);
 393                } else
 394                        viodev->irq = irq_offset_up(virq);
 395        }
 396
 397        snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
 398
 399        /* register with generic device framework */
 400        if (vio_register_device_common(viodev, of_node->name, of_node->type,
 401                                *unit_address, vio_build_iommu_table(viodev))
 402                        == NULL) {
 403                /* XXX free TCE table */
 404                kfree(viodev);
 405                return NULL;
 406        }
 407        device_create_file(&viodev->dev, &dev_attr_devspec);
 408
 409        return viodev;
 410}
 411EXPORT_SYMBOL(vio_register_device_node);
 412#endif
 413
 414#ifdef CONFIG_PPC_ISERIES
 415/**
 416 * vio_register_device: - Register a new vio device.
 417 * @voidev:     The device to register.
 418 */
 419static struct vio_dev *__init vio_register_device_iseries(char *type,
 420                uint32_t unit_num)
 421{
 422        struct vio_dev *viodev;
 423
 424        DBGENTER();
 425
 426        /* allocate a vio_dev for this node */
 427        viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
 428        if (!viodev)
 429                return NULL;
 430        memset(viodev, 0, sizeof(struct vio_dev));
 431
 432        snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
 433
 434        return vio_register_device_common(viodev, viodev->dev.bus_id, type,
 435                        unit_num, &vio_iommu_table);
 436}
 437#endif
 438
 439void __devinit vio_unregister_device(struct vio_dev *viodev)
 440{
 441        DBGENTER();
 442#ifdef CONFIG_PPC_PSERIES
 443        device_remove_file(&viodev->dev, &dev_attr_devspec);
 444#endif
 445        device_remove_file(&viodev->dev, &dev_attr_name);
 446        device_unregister(&viodev->dev);
 447}
 448EXPORT_SYMBOL(vio_unregister_device);
 449
 450#ifdef CONFIG_PPC_PSERIES
 451/**
 452 * vio_get_attribute: - get attribute for virtual device
 453 * @vdev:       The vio device to get property.
 454 * @which:      The property/attribute to be extracted.
 455 * @length:     Pointer to length of returned data size (unused if NULL).
 456 *
 457 * Calls prom.c's get_property() to return the value of the
 458 * attribute specified by the preprocessor constant @which
 459*/
 460const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
 461{
 462        return get_property(vdev->dev.platform_data, (char*)which, length);
 463}
 464EXPORT_SYMBOL(vio_get_attribute);
 465
 466/* vio_find_name() - internal because only vio.c knows how we formatted the
 467 * kobject name
 468 * XXX once vio_bus_type.devices is actually used as a kset in
 469 * drivers/base/bus.c, this function should be removed in favor of
 470 * "device_find(kobj_name, &vio_bus_type)"
 471 */
 472static struct vio_dev *vio_find_name(const char *kobj_name)
 473{
 474        struct kobject *found;
 475
 476        found = kset_find_obj(&devices_subsys.kset, kobj_name);
 477        if (!found)
 478                return NULL;
 479
 480        return to_vio_dev(container_of(found, struct device, kobj));
 481}
 482
 483/**
 484 * vio_find_node - find an already-registered vio_dev
 485 * @vnode: device_node of the virtual device we're looking for
 486 */
 487struct vio_dev *vio_find_node(struct device_node *vnode)
 488{
 489        uint32_t *unit_address;
 490        char kobj_name[BUS_ID_SIZE];
 491
 492        /* construct the kobject name from the device node */
 493        unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
 494        if (!unit_address)
 495                return NULL;
 496        snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
 497
 498        return vio_find_name(kobj_name);
 499}
 500EXPORT_SYMBOL(vio_find_node);
 501
 502/**
 503 * vio_build_iommu_table: - gets the dma information from OF and builds the TCE tree.
 504 * @dev: the virtual device.
 505 *
 506 * Returns a pointer to the built tce tree, or NULL if it can't
 507 * find property.
 508*/
 509static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
 510{
 511        unsigned int *dma_window;
 512        struct iommu_table *newTceTable;
 513        unsigned long offset;
 514        int dma_window_property_size;
 515
 516        dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
 517        if(!dma_window) {
 518                return NULL;
 519        }
 520
 521        newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
 522
 523        /*  There should be some code to extract the phys-encoded offset
 524                using prom_n_addr_cells(). However, according to a comment
 525                on earlier versions, it's always zero, so we don't bother */
 526        offset = dma_window[1] >>  PAGE_SHIFT;
 527
 528        /* TCE table size - measured in tce entries */
 529        newTceTable->it_size            = dma_window[4] >> PAGE_SHIFT;
 530        /* offset for VIO should always be 0 */
 531        newTceTable->it_offset          = offset;
 532        newTceTable->it_busno           = 0;
 533        newTceTable->it_index           = (unsigned long)dma_window[0];
 534        newTceTable->it_type            = TCE_VB;
 535
 536        return iommu_init_table(newTceTable);
 537}
 538
 539int vio_enable_interrupts(struct vio_dev *dev)
 540{
 541        int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
 542        if (rc != H_Success) {
 543                printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
 544        }
 545        return rc;
 546}
 547EXPORT_SYMBOL(vio_enable_interrupts);
 548
 549int vio_disable_interrupts(struct vio_dev *dev)
 550{
 551        int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
 552        if (rc != H_Success) {
 553                printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
 554        }
 555        return rc;
 556}
 557EXPORT_SYMBOL(vio_disable_interrupts);
 558#endif
 559
 560dma_addr_t vio_map_single(struct vio_dev *dev, void *vaddr,
 561                          size_t size, enum dma_data_direction direction)
 562{
 563        return iommu_map_single(dev->iommu_table, vaddr, size, direction);
 564}
 565EXPORT_SYMBOL(vio_map_single);
 566
 567void vio_unmap_single(struct vio_dev *dev, dma_addr_t dma_handle,
 568                      size_t size, enum dma_data_direction direction)
 569{
 570        iommu_unmap_single(dev->iommu_table, dma_handle, size, direction);
 571}
 572EXPORT_SYMBOL(vio_unmap_single);
 573
 574int vio_map_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
 575               enum dma_data_direction direction)
 576{
 577        return iommu_map_sg(&vdev->dev, vdev->iommu_table, sglist,
 578                        nelems, direction);
 579}
 580EXPORT_SYMBOL(vio_map_sg);
 581
 582void vio_unmap_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
 583                  enum dma_data_direction direction)
 584{
 585        iommu_unmap_sg(vdev->iommu_table, sglist, nelems, direction);
 586}
 587EXPORT_SYMBOL(vio_unmap_sg);
 588
 589void *vio_alloc_consistent(struct vio_dev *dev, size_t size,
 590                           dma_addr_t *dma_handle)
 591{
 592        return iommu_alloc_consistent(dev->iommu_table, size, dma_handle);
 593}
 594EXPORT_SYMBOL(vio_alloc_consistent);
 595
 596void vio_free_consistent(struct vio_dev *dev, size_t size,
 597                         void *vaddr, dma_addr_t dma_handle)
 598{
 599        iommu_free_consistent(dev->iommu_table, size, vaddr, dma_handle);
 600}
 601EXPORT_SYMBOL(vio_free_consistent);
 602
 603static int vio_bus_match(struct device *dev, struct device_driver *drv)
 604{
 605        const struct vio_dev *vio_dev = to_vio_dev(dev);
 606        struct vio_driver *vio_drv = to_vio_driver(drv);
 607        const struct vio_device_id *ids = vio_drv->id_table;
 608        const struct vio_device_id *found_id;
 609
 610        DBGENTER();
 611
 612        if (!ids)
 613                return 0;
 614
 615        found_id = vio_match_device(ids, vio_dev);
 616        if (found_id)
 617                return 1;
 618
 619        return 0;
 620}
 621
 622struct bus_type vio_bus_type = {
 623        .name = "vio",
 624        .match = vio_bus_match,
 625};
 626
 627EXPORT_SYMBOL(vio_bus_type);
 628
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.