linux-old/arch/ppc64/kernel/vio.c
<<
>>
Prefs
   1/*
   2 * IBM PowerPC Virtual I/O Infrastructure Support.
   3 *
   4 * Dave Engebretsen engebret@us.ibm.com
   5 *    Copyright (c) 2003 Dave Engebretsen
   6 *
   7 *      This program is free software; you can redistribute it and/or
   8 *      modify it under the terms of the GNU General Public License
   9 *      as published by the Free Software Foundation; either version
  10 *      2 of the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/init.h>
  14#include <linux/console.h>
  15#include <linux/pci.h>
  16#include <linux/version.h>
  17#include <linux/module.h>
  18#include <asm/rtas.h>
  19#include <asm/pci_dma.h>
  20#include <asm/dma.h>
  21#include <asm/ppcdebug.h>
  22#include <asm/vio.h>
  23#include <asm/hvcall.h>
  24
  25extern struct TceTable *build_tce_table(struct TceTable *tbl);
  26
  27extern dma_addr_t get_tces(struct TceTable *, unsigned order,
  28                           void *page, unsigned numPages, int direction);
  29extern void tce_free(struct TceTable *tbl, dma_addr_t dma_addr,
  30                     unsigned order, unsigned num_pages);
  31
  32
  33static struct vio_bus vio_bus;
  34static LIST_HEAD(registered_vio_drivers);
  35int vio_num_address_cells;
  36EXPORT_SYMBOL(vio_num_address_cells);
  37
  38/**
  39 * vio_register_driver: - Register a new vio driver
  40 * @drv:        The vio_driver structure to be registered.
  41 *
  42 * Adds the driver structure to the list of registered drivers
  43 * Returns the number of vio devices which were claimed by the driver
  44 * during registration.  The driver remains registered even if the
  45 * return value is zero.
  46 */
  47int vio_register_driver(struct vio_driver *drv)
  48{
  49        int count = 0;
  50        struct vio_dev *dev;
  51        const struct vio_device_id* id;
  52        /*
  53         * Walk the vio_bus, find devices for this driver, and
  54         * call back into the driver probe interface.
  55         */
  56
  57        list_for_each_entry(dev, &vio_bus.devices, devices_list) {
  58                id = vio_match_device(drv->id_table, dev);
  59                if(drv && id) {
  60                        if (0 == drv->probe(dev, id)) {
  61                                dev->driver = drv;
  62                                count++;
  63                        }
  64                }
  65        }
  66
  67        list_add_tail(&drv->node, &registered_vio_drivers);
  68
  69        return count;
  70}
  71EXPORT_SYMBOL(vio_register_driver);
  72
  73/**
  74 * vio_unregister_driver - Remove registration of vio driver.
  75 * @driver:     The vio_driver struct to be removed form registration
  76 *
  77 * Searches for devices that are assigned to the driver and calls
  78 * driver->remove() for each one.  Removes the driver from the list
  79 * of registered drivers.  Returns the number of devices that were
  80 * assigned to that driver.
  81 */
  82int vio_unregister_driver(struct vio_driver *driver)
  83{
  84        struct vio_dev *dev;
  85        int devices_found = 0;
  86
  87        list_for_each_entry(dev, &vio_bus.devices, devices_list) {
  88                if (dev->driver == driver) {
  89                        driver->remove(dev);
  90                        dev->driver = NULL;
  91                        devices_found++;
  92                }
  93        }
  94
  95        list_del(&driver->node);
  96
  97        return devices_found;
  98}
  99EXPORT_SYMBOL(vio_unregister_driver);
 100
 101/**
 102 * vio_match_device: - Tell if a VIO device has a matching VIO device id structure.
 103 * @ids:        array of VIO device id structures to search in
 104 * @dev:        the VIO device structure to match against
 105 *
 106 * Used by a driver to check whether a VIO device present in the
 107 * system is in its list of supported devices. Returns the matching
 108 * vio_device_id structure or NULL if there is no match.
 109 */
 110const struct vio_device_id *
 111vio_match_device(const struct vio_device_id *ids, const struct vio_dev *dev)
 112{
 113        while (ids->type) {
 114                if ((strncmp(dev->archdata->type, ids->type, strlen(ids->type)) == 0) &&
 115                        device_is_compatible((struct device_node*)dev->archdata, ids->compat))
 116                        return ids;
 117                ids++;
 118        }
 119        return NULL;
 120}
 121
 122/**
 123 * vio_bus_init: - Initialize the virtual IO bus
 124 */
 125int __init
 126vio_bus_init(void)
 127{
 128        struct device_node *node_vroot, *node_vdev;
 129
 130        printk("vio_bus_init: start\n");
 131
 132        INIT_LIST_HEAD(&vio_bus.devices);
 133
 134        /*
 135         * Create device node entries for each virtual device
 136         * identified in the device tree.
 137         * Functionally takes the place of pci_scan_bus
 138         */
 139        node_vroot = find_devices("vdevice");
 140        if (!node_vroot) {
 141                printk(KERN_WARNING "vio_bus_init: no /vdevice node\n");
 142                return 0;
 143        }
 144
 145        vio_num_address_cells = prom_n_addr_cells(node_vroot->child);
 146
 147        for (node_vdev = node_vroot->child;
 148                        node_vdev != NULL;
 149                        node_vdev = node_vdev->sibling) {
 150                printk(KERN_INFO "vio_bus_init: processing %p\n", node_vdev);
 151
 152                vio_register_device(node_vdev);
 153        }
 154
 155        printk(KERN_INFO "vio_bus_init: done\n");
 156
 157        return 0;
 158}
 159
 160__initcall(vio_bus_init);
 161
 162
 163/**
 164 * vio_register_device: - Register a new vio device.
 165 * @archdata:   The OF node for this device.
 166 *
 167 * Creates and initializes a vio_dev structure from the data in
 168 * node_vdev (archdata) and adds it to the list of virtual devices.
 169 * Returns a pointer to the created vio_dev or NULL if node has
 170 * NULL device_type or compatible fields.
 171*/
 172struct vio_dev * __devinit vio_register_device(struct device_node *node_vdev)
 173{
 174        struct vio_dev *dev;
 175        unsigned int *unit_address;
 176        unsigned int *irq_p;
 177
 178        /* guarantee all vio_devs have 'device_type' field*/
 179        if ((NULL == node_vdev->type)) {
 180                printk(KERN_WARNING "vio_register_device: node %s missing 'device_type' "
 181                        , node_vdev->name?node_vdev->name:"UNKNOWN");
 182                return NULL;
 183        }
 184
 185        unit_address = (unsigned int *)get_property(node_vdev, "reg", NULL);
 186        if(!unit_address) {
 187                printk(KERN_WARNING "Can't find %s reg property\n", node_vdev->name?node_vdev->name:"UNKNOWN_DEVICE");
 188                return NULL;
 189        }
 190
 191        /* allocate a vio_dev for this node */
 192        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 193        memset(dev, 0, sizeof(*dev));
 194
 195        dev->archdata = (void*)node_vdev; /* to become of_get_node(node_vdev); */
 196        dev->bus = &vio_bus;
 197        dev->unit_address = *unit_address;
 198        dev->tce_table = vio_build_tce_table(dev);
 199
 200        irq_p = (unsigned int *) get_property(node_vdev, "interrupts", 0);
 201        if(irq_p) {
 202                dev->irq = irq_offset_up(*irq_p);
 203        } else {
 204                dev->irq = (unsigned int) -1;
 205        }
 206
 207        list_add_tail(&dev->devices_list, &vio_bus.devices);
 208
 209        return dev;
 210}
 211
 212/**
 213 * vio_find_driver: - Find driver for vio_dev.
 214 * @dev:        Device to search for a driver.
 215 *
 216 * Walks the registered_vio_drivers list calling vio_match_device()
 217 * for every driver in the list. If there is a match, calls the
 218 * driver's probe().
 219 * Returns a pointer to the matched driver or NULL if driver is not
 220 * found.
 221*/
 222struct vio_driver * vio_find_driver(struct vio_dev* dev)
 223{
 224        struct vio_driver *driver;
 225        list_for_each_entry(driver, &registered_vio_drivers, node) {
 226                if(driver && vio_match_device(driver->id_table, dev)) {
 227                        if (0 < driver->probe(dev, NULL)) {
 228                                dev->driver = driver;
 229                                return driver;
 230                        }
 231                }
 232        }
 233
 234        return NULL;
 235}
 236
 237/**
 238 * vio_get_attribute: - get attribute for virtual device
 239 * @vdev:       The vio device to get property.
 240 * @which:      The property/attribute to be extracted.
 241 * @length:     Pointer to length of returned data size (unused if NULL).
 242 *
 243 * Calls prom.c's get_property() to return the value of the
 244 * attribute specified by the preprocessor constant @which
 245*/
 246const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
 247{
 248        return get_property((struct device_node *)vdev->archdata, (char*)which, length);
 249}
 250EXPORT_SYMBOL(vio_get_attribute);
 251
 252/**
 253 * vio_build_tce_table: - gets the dma information from OF and builds the TCE tree.
 254 * @dev: the virtual device.
 255 *
 256 * Returns a pointer to the built tce tree, or NULL if it can't
 257 * find property.
 258*/
 259struct TceTable * vio_build_tce_table(struct vio_dev *dev)
 260{
 261        unsigned int *dma_window;
 262        struct TceTable *newTceTable;
 263        unsigned long offset;
 264        unsigned long size;
 265        int dma_window_property_size;
 266
 267        dma_window = (unsigned int *) get_property((struct device_node *)dev->archdata, "ibm,my-dma-window", &dma_window_property_size);
 268        if(!dma_window) {
 269                return NULL;
 270        }
 271
 272        newTceTable = (struct TceTable *) kmalloc(sizeof(struct TceTable), GFP_KERNEL);
 273
 274        /* RPA docs say that #address-cells is always 1 for virtual
 275                devices, but some older boxes' OF returns 2.  This should
 276                be removed by GA, unless there is legacy OFs that still
 277                have 2 for #address-cells */
 278        size = ((dma_window[1+vio_num_address_cells]
 279                >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
 280
 281        /* This is just an ugly kludge. Remove as soon as the OF for all
 282        machines actually follow the spec and encodes the offset field
 283        as phys-encode (that is, #address-cells wide)*/
 284        if (dma_window_property_size == 12) {
 285                size = ((dma_window[1] >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
 286        } else if (dma_window_property_size == 20) {
 287                size = ((dma_window[4] >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
 288        } else {
 289                printk(KERN_WARNING "vio_build_tce_table: Invalid size of ibm,my-dma-window=%i, using 0x80 for size\n", dma_window_property_size);
 290                size = 0x80;
 291        }
 292
 293        /*  There should be some code to extract the phys-encoded offset
 294                using prom_n_addr_cells(). However, according to a comment
 295                on earlier versions, it's always zero, so we don't bother */
 296        offset = dma_window[1] >>  PAGE_SHIFT;
 297
 298        /* TCE table size - measured in units of pages of tce table */
 299        newTceTable->size = size;
 300        /* offset for VIO should always be 0 */
 301        newTceTable->startOffset = offset;
 302        newTceTable->busNumber   = 0;
 303        newTceTable->index       = (unsigned long)dma_window[0];
 304        newTceTable->tceType     = TCE_VB;
 305
 306        return build_tce_table(newTceTable);
 307}
 308
 309int vio_enable_interrupts(struct vio_dev *dev)
 310{
 311        int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
 312        if (rc != H_Success) {
 313                printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
 314        }
 315        return rc;
 316}
 317EXPORT_SYMBOL(vio_enable_interrupts);
 318
 319int vio_disable_interrupts(struct vio_dev *dev)
 320{
 321        int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
 322        if (rc != H_Success) {
 323        printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
 324        }
 325        return rc;
 326}
 327EXPORT_SYMBOL(vio_disable_interrupts);
 328
 329dma_addr_t vio_map_single(struct vio_dev *dev, void *vaddr,
 330                          size_t size, int direction )
 331{
 332        struct TceTable * tbl;
 333        dma_addr_t dma_handle = NO_TCE;
 334        unsigned long uaddr;
 335        unsigned order, nPages;
 336
 337        if(direction == PCI_DMA_NONE) BUG();
 338
 339        uaddr = (unsigned long)vaddr;
 340        nPages = PAGE_ALIGN( uaddr + size ) - ( uaddr & PAGE_MASK );
 341        order = get_order( nPages & PAGE_MASK );
 342        nPages >>= PAGE_SHIFT;
 343
 344        /* Client asked for way to much space.  This is checked later anyway */
 345        /* It is easier to debug here for the drivers than in the tce tables.*/
 346        if(order >= NUM_TCE_LEVELS) {
 347                printk("VIO_DMA: vio_map_single size to large: 0x%lx \n",size);
 348                return NO_TCE;
 349        }
 350
 351        tbl = dev->tce_table;
 352
 353        if(tbl) {
 354                dma_handle = get_tces(tbl, order, vaddr, nPages, direction);
 355                dma_handle |= (uaddr & ~PAGE_MASK);
 356        }
 357
 358        return dma_handle;
 359}
 360EXPORT_SYMBOL(vio_map_single);
 361
 362void vio_unmap_single(struct vio_dev *dev, dma_addr_t dma_handle,
 363                      size_t size, int direction)
 364{
 365        struct TceTable * tbl;
 366        unsigned order, nPages;
 367
 368        if (direction == PCI_DMA_NONE) BUG();
 369
 370        nPages = PAGE_ALIGN( dma_handle + size ) - ( dma_handle & PAGE_MASK );
 371        order = get_order( nPages & PAGE_MASK );
 372        nPages >>= PAGE_SHIFT;
 373
 374        /* Client asked for way to much space.  This is checked later anyway */
 375        /* It is easier to debug here for the drivers than in the tce tables.*/
 376        if(order >= NUM_TCE_LEVELS) {
 377                printk("VIO_DMA: vio_unmap_single 0x%lx size to large: 0x%lx \n",(unsigned long)dma_handle,(unsigned long)size);
 378                return;
 379        }
 380
 381        tbl = dev->tce_table;
 382        if(tbl) tce_free(tbl, dma_handle, order, nPages);
 383}
 384EXPORT_SYMBOL(vio_unmap_single);
 385
 386int vio_map_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
 387               int direction)
 388{
 389        int i;
 390
 391        for (i = 0; i < nelems; i++) {
 392
 393                /* 2.4 scsi scatterlists use address field.
 394                   Not sure about other subsystems. */
 395                void *vaddr;
 396                if (sglist->address)
 397                        vaddr = sglist->address;
 398                else
 399                        vaddr = page_address(sglist->page) + sglist->offset;
 400
 401                sglist->dma_address = vio_map_single(vdev, vaddr,
 402                                                     sglist->length,
 403                                                     direction);
 404                sglist->dma_length = sglist->length;
 405                sglist++;
 406        }
 407
 408        return nelems;
 409}
 410EXPORT_SYMBOL(vio_map_sg);
 411
 412void vio_unmap_sg(struct vio_dev *vdev, struct scatterlist *sglist, int nelems,
 413                  int direction)
 414{
 415        while (nelems--) {
 416                vio_unmap_single(vdev, sglist->dma_address,
 417                                 sglist->dma_length, direction);
 418                sglist++;
 419        }
 420}
 421
 422void *vio_alloc_consistent(struct vio_dev *dev, size_t size,
 423                           dma_addr_t *dma_handle)
 424{
 425        struct TceTable * tbl;
 426        void *ret = NULL;
 427        unsigned order, nPages;
 428        dma_addr_t tce;
 429
 430        size = PAGE_ALIGN(size);
 431        order = get_order(size);
 432        nPages = 1 << order;
 433
 434        /* Client asked for way to much space.  This is checked later anyway */
 435        /* It is easier to debug here for the drivers than in the tce tables.*/
 436        if(order >= NUM_TCE_LEVELS) {
 437                printk("VIO_DMA: vio_alloc_consistent size to large: 0x%lx \n",size);
 438                return (void *)NO_TCE;
 439        }
 440
 441        tbl = dev->tce_table;
 442
 443        if ( tbl ) {
 444                /* Alloc enough pages (and possibly more) */
 445                ret = (void *)__get_free_pages( GFP_ATOMIC, order );
 446                if ( ret ) {
 447                        /* Page allocation succeeded */
 448                        memset(ret, 0, nPages << PAGE_SHIFT);
 449                        /* Set up tces to cover the allocated range */
 450                        tce = get_tces( tbl, order, ret, nPages, PCI_DMA_BIDIRECTIONAL );
 451                        if ( tce == NO_TCE ) {
 452                                PPCDBG(PPCDBG_TCE, "vio_alloc_consistent: get_tces failed\n" );
 453                                free_pages( (unsigned long)ret, order );
 454                                ret = NULL;
 455                        }
 456                        else
 457                                {
 458                                        *dma_handle = tce;
 459                                }
 460                }
 461                else PPCDBG(PPCDBG_TCE, "vio_alloc_consistent: __get_free_pages failed for order = %d\n", order);
 462        }
 463        else PPCDBG(PPCDBG_TCE, "vio_alloc_consistent: get_tce_table failed for 0x%016lx\n", dev);
 464
 465        PPCDBG(PPCDBG_TCE, "\tvio_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle);
 466        PPCDBG(PPCDBG_TCE, "\tvio_alloc_consistent: return     = 0x%16.16lx\n", ret);
 467        return ret;
 468}
 469EXPORT_SYMBOL(vio_alloc_consistent);
 470
 471void vio_free_consistent(struct vio_dev *dev, size_t size,
 472                         void *vaddr, dma_addr_t dma_handle)
 473{
 474        struct TceTable * tbl;
 475        unsigned order, nPages;
 476
 477        PPCDBG(PPCDBG_TCE, "vio_free_consistent:\n");
 478        PPCDBG(PPCDBG_TCE, "\tdev = 0x%16.16lx, size = 0x%16.16lx, dma_handle = 0x%16.16lx, vaddr = 0x%16.16lx\n", dev, size, dma_handle, vaddr);
 479
 480        size = PAGE_ALIGN(size);
 481        order = get_order(size);
 482        nPages = 1 << order;
 483
 484        /* Client asked for way to much space.  This is checked later anyway */
 485        /* It is easier to debug here for the drivers than in the tce tables.*/
 486        if(order >= NUM_TCE_LEVELS) {
 487                printk("PCI_DMA: pci_free_consistent size to large: 0x%lx \n",size);
 488                return;
 489        }
 490
 491        tbl = dev->tce_table;
 492
 493        if ( tbl ) {
 494                tce_free(tbl, dma_handle, order, nPages);
 495                free_pages( (unsigned long)vaddr, order );
 496        }
 497}
 498EXPORT_SYMBOL(vio_free_consistent);
 499
 500EXPORT_SYMBOL(plpar_hcall_norets);
 501EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
 502
 503
 504
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.