linux-old/arch/ia64/sn/io/drivers/pciba.c
<<
>>
Prefs
   1/*
   2 * arch/ia64/sn/io/pciba.c
   3 *
   4 * IRIX PCIBA-inspired user mode PCI interface
   5 *
   6 * requires: devfs
   7 *
   8 * device nodes show up in /dev/pci/BB/SS.F (where BB is the bus the
   9 * device is on, SS is the slot the device is in, and F is the
  10 * device's function on a multi-function card).
  11 *
  12 * when compiled into the kernel, it will only be initialized by the
  13 * sgi sn1 specific initialization code.  in this case, device nodes
  14 * are under /dev/hw/..../
  15 *
  16 * This file is subject to the terms and conditions of the GNU General
  17 * Public License.  See the file "COPYING" in the main directory of
  18 * this archive for more details.
  19 *
  20 * Copyright (C) 2001-2003 Silicon Graphics, Inc.  All rights reserved.
  21 *
  22 * 03262001 - Initial version by Chad Talbott
  23 */
  24
  25
  26/* jesse's beefs:
  27
  28   register_pci_device should be documented
  29   
  30   grossness with do_swap should be documented
  31   
  32   big, gross union'ized node_data should be replaced with independent
  33   structures
  34
  35   replace global list of nodes with global lists of resources.  could
  36   use object oriented approach of allocating and cleaning up
  37   resources.
  38   
  39*/
  40
  41
  42#include <linux/config.h>
  43#include <linux/module.h>
  44#include <asm/sn/sgi.h>
  45#include <asm/sn/iograph.h>
  46#include <asm/sn/invent.h>
  47#include <asm/sn/hcl.h>
  48#include <asm/sn/labelcl.h>
  49#include <linux/pci.h>
  50#include <linux/list.h>
  51
  52#include <linux/mm.h>
  53#include <linux/slab.h>
  54#include <linux/vmalloc.h>
  55#include <linux/mman.h>
  56#include <linux/init.h>
  57#include <linux/raw.h>
  58#include <linux/capability.h>
  59
  60#include <asm/uaccess.h>
  61#include <asm/sn/sgi.h>
  62#include <asm/io.h>
  63#include <asm/pgalloc.h>
  64#include <asm/page.h>
  65#include <asm/system.h>
  66
  67#include <asm/sn/pci/pciba.h>
  68
  69
  70MODULE_DESCRIPTION("User mode PCI interface");
  71MODULE_AUTHOR("Chad Talbott");
  72
  73
  74#undef DEBUG_PCIBA
  75/* #define DEBUG_PCIBA */
  76
  77#undef TRACE_PCIBA
  78/* #define TRACE_PCIBA */
  79
  80#if defined(DEBUG_PCIBA)
  81#  define DPRINTF(x...) printk(KERN_DEBUG x)
  82#else
  83#  define DPRINTF(x...)
  84#endif
  85
  86#if defined(TRACE_PCIBA)
  87#  if defined(__GNUC__)
  88#    define TRACE()     printk(KERN_DEBUG "%s:%d:%s\n", \
  89                               __FILE__, __LINE__, __FUNCTION__)
  90#  else
  91#    define TRACE()     printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__)
  92#  endif
  93#else
  94#  define TRACE()
  95#endif
  96
  97
  98typedef enum { failure, success } status;
  99typedef enum { false, true } boolean;
 100
 101
 102/* major data structures:
 103
 104   struct node_data -
 105   
 106        one for each file registered with devfs.  contains everything
 107        that any file's fops would need to know about.
 108
 109   struct dma_allocation -
 110
 111        a single DMA allocation.  only the 'dma' nodes care about
 112        these.  they are there primarily to allow the driver to look
 113        up the kernel virtual address of dma buffers allocated by
 114        pci_alloc_consistent, as the application is only given the
 115        physical address (to program the device's dma, presumably) and
 116        cannot supply the kernel virtual address when freeing the
 117        buffer.
 118
 119        it's also useful to maintain a list of buffers allocated
 120        through a specific node to allow some sanity checking by this
 121        driver.  this prevents (for example) a broken application from
 122        freeing buffers that it didn't allocate, or buffers allocated
 123        on another node.
 124   
 125   global_node_list -
 126
 127        a list of all nodes allocated.  this allows the driver to free
 128        all the memory it has 'kmalloc'd in case of an error, or on
 129        module removal.
 130
 131   global_dma_list -
 132
 133        a list of all dma buffers allocated by this driver.  this
 134        allows the driver to 'pci_free_consistent' all buffers on
 135        module removal or error.
 136
 137*/
 138
 139
 140struct node_data {
 141        /* flat list of all the device nodes.  makes it easy to free
 142           them all when we're unregistered */
 143        struct list_head global_node_list;
 144        vertex_hdl_t devfs_handle;
 145
 146        void (* cleanup)(struct node_data *);
 147
 148        union {
 149                struct {
 150                        struct pci_dev * dev;
 151                        struct list_head dma_allocs;
 152                        boolean mmapped;
 153                } dma;
 154                struct {
 155                        struct pci_dev * dev;
 156                        u32 saved_rom_base_reg;
 157                        boolean mmapped;
 158                } rom;
 159                struct {
 160                        struct resource * res;
 161                } base;
 162                struct {
 163                        struct pci_dev * dev;
 164                } config;
 165        } u;
 166};
 167
 168struct dma_allocation {
 169        struct list_head list;
 170
 171        dma_addr_t handle;
 172        void * va;
 173        size_t size;
 174};
 175
 176
 177static LIST_HEAD(global_node_list);
 178static LIST_HEAD(global_dma_list);
 179
 180
 181/* module entry points */
 182int __init pciba_init(void);
 183void __exit pciba_exit(void);
 184
 185static status __init register_with_devfs(void);
 186static void __exit unregister_with_devfs(void);
 187
 188static status __init register_pci_device(vertex_hdl_t device_dir_handle,
 189                                         struct pci_dev * dev);
 190
 191/* file operations */
 192static int generic_open(struct inode * inode, struct file * file);
 193static int rom_mmap(struct file * file, struct vm_area_struct * vma);
 194static int rom_release(struct inode * inode, struct file * file);
 195static int base_mmap(struct file * file, struct vm_area_struct * vma);
 196static int config_ioctl(struct inode * inode, struct file * file, 
 197                        unsigned int cmd, 
 198                        unsigned long arg);
 199static int dma_ioctl(struct inode * inode, struct file * file, 
 200                     unsigned int cmd, 
 201                     unsigned long arg);
 202static int dma_mmap(struct file * file, struct vm_area_struct * vma);
 203
 204/* support routines */
 205static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va);
 206static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va);
 207
 208#ifdef DEBUG_PCIBA
 209static void dump_nodes(struct list_head * nodes);
 210static void dump_allocations(struct list_head * dalp);
 211#endif
 212
 213/* file operations for each type of node */
 214static struct file_operations rom_fops = {
 215        owner:          THIS_MODULE,
 216        mmap:           rom_mmap,
 217        open:           generic_open,
 218        release:        rom_release
 219};
 220 
 221
 222static struct file_operations base_fops = {
 223        owner:          THIS_MODULE,
 224        mmap:           base_mmap,
 225        open:           generic_open
 226};
 227
 228
 229static struct file_operations config_fops = {
 230        owner:          THIS_MODULE,
 231        ioctl:          config_ioctl,
 232        open:           generic_open
 233};      
 234
 235static struct file_operations dma_fops = {
 236        owner:          THIS_MODULE,
 237        ioctl:          dma_ioctl,
 238        mmap:           dma_mmap,
 239        open:           generic_open
 240};      
 241
 242
 243module_init(pciba_init);
 244module_exit(pciba_exit);
 245
 246
 247int __init
 248pciba_init(void)
 249{
 250        if (!ia64_platform_is("sn2"))
 251                return -ENODEV;
 252
 253        TRACE();
 254
 255        if (register_with_devfs() == failure)
 256                return 1; /* failure */
 257
 258        printk("PCIBA (a user mode PCI interface) initialized.\n");
 259
 260        return 0; /* success */
 261}
 262
 263
 264void __exit
 265pciba_exit(void)
 266{
 267        TRACE();
 268
 269        /* FIXME: should also free all that memory that we allocated
 270           ;) */
 271        unregister_with_devfs();
 272}
 273
 274
 275# if 0
 276static void __exit
 277free_nodes(void)
 278{
 279        struct node_data * nd;
 280        
 281        TRACE();
 282
 283        list_for_each(nd, &node_list) {
 284                kfree(list_entry(nd, struct nd, node_list));
 285        }
 286}
 287#endif
 288
 289
 290static vertex_hdl_t pciba_devfs_handle;
 291
 292
 293extern vertex_hdl_t
 294devfn_to_vertex(unsigned char busnum, unsigned int devfn);
 295
 296static status __init
 297register_with_devfs(void)
 298{
 299        struct pci_dev * dev;
 300        vertex_hdl_t device_dir_handle;
 301
 302        TRACE();
 303
 304        /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */
 305
 306        pci_for_each_dev(dev) {
 307                device_dir_handle = devfn_to_vertex(dev->bus->number,
 308                                                    dev->devfn);
 309                if (device_dir_handle == NULL)
 310                        return failure;
 311        
 312                if (register_pci_device(device_dir_handle, dev) == failure) {
 313                        hwgraph_vertex_destroy(pciba_devfs_handle);
 314                        return failure;
 315                }
 316        }
 317
 318        return success;
 319}
 320
 321static void __exit
 322unregister_with_devfs(void)
 323{
 324        struct list_head * lhp;
 325        struct node_data * nd;
 326        
 327        TRACE();
 328
 329        list_for_each(lhp, &global_node_list) {
 330                nd = list_entry(lhp, struct node_data, global_node_list);
 331                hwgraph_vertex_destroy(nd->devfs_handle);
 332        }
 333
 334}
 335
 336
 337struct node_data * new_node(void)
 338{
 339        struct node_data * node;
 340        
 341        TRACE();
 342        
 343        node = kmalloc(sizeof(struct node_data), GFP_KERNEL);
 344        if (node <= 0)
 345                return node;
 346        list_add(&node->global_node_list, &global_node_list);
 347        return node;
 348}
 349
 350
 351void dma_cleanup(struct node_data * dma_node)
 352{
 353        TRACE();
 354
 355        /* FIXME: should free these allocations */
 356#ifdef DEBUG_PCIBA
 357        dump_allocations(&dma_node->u.dma.dma_allocs);
 358#endif
 359        hwgraph_vertex_destroy(dma_node->devfs_handle);
 360}
 361
 362
 363void init_dma_node(struct node_data * node,
 364                   struct pci_dev * dev, vertex_hdl_t dh)
 365{
 366        TRACE();
 367
 368        node->devfs_handle = dh;
 369        node->u.dma.dev = dev;
 370        node->cleanup = dma_cleanup;
 371        INIT_LIST_HEAD(&node->u.dma.dma_allocs);
 372}
 373
 374
 375void rom_cleanup(struct node_data * rom_node)
 376{
 377        TRACE();
 378
 379        if (rom_node->u.rom.mmapped)
 380                pci_write_config_dword(rom_node->u.rom.dev,
 381                                       PCI_ROM_ADDRESS,
 382                                       rom_node->u.rom.saved_rom_base_reg);
 383        hwgraph_vertex_destroy(rom_node->devfs_handle);
 384}
 385
 386
 387void init_rom_node(struct node_data * node,
 388                   struct pci_dev * dev, vertex_hdl_t dh)
 389{
 390        TRACE();
 391
 392        node->devfs_handle = dh;
 393        node->u.rom.dev = dev;
 394        node->cleanup = rom_cleanup;
 395        node->u.rom.mmapped = false;
 396}
 397
 398
 399static status __init
 400register_pci_device(vertex_hdl_t device_dir_handle, struct pci_dev * dev)
 401{
 402        struct node_data * nd;
 403        char devfs_path[20];
 404        vertex_hdl_t node_devfs_handle;
 405        int ri;
 406
 407        TRACE();
 408
 409
 410        /* register nodes for all the device's base address registers */
 411        for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
 412                if (pci_resource_len(dev, ri) != 0) {
 413                        sprintf(devfs_path, "base/%d", ri);
 414                        if (hwgraph_register(device_dir_handle, devfs_path,
 415                                           0, DEVFS_FL_NONE,
 416                                           0, 0,
 417                                           S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
 418                                           &base_fops, 
 419                                           &dev->resource[ri]) == NULL)
 420                                return failure;
 421                }
 422        }
 423        
 424        /* register a node corresponding to the first MEM resource on
 425           the device */
 426        for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
 427                if (dev->resource[ri].flags & IORESOURCE_MEM &&
 428                    pci_resource_len(dev, ri) != 0) {
 429                        if (hwgraph_register(device_dir_handle, "mem",
 430                                           0, DEVFS_FL_NONE, 0, 0,
 431                                           S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
 432                                           &base_fops, 
 433                                           &dev->resource[ri]) == NULL)
 434                                return failure;
 435                        break;
 436                }
 437        }
 438
 439        /* also register a node corresponding to the first IO resource
 440           on the device */
 441        for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
 442                if (dev->resource[ri].flags & IORESOURCE_IO &&
 443                    pci_resource_len(dev, ri) != 0) {
 444                        if (hwgraph_register(device_dir_handle, "io",
 445                                           0, DEVFS_FL_NONE, 0, 0,
 446                                           S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
 447                                           &base_fops, 
 448                                           &dev->resource[ri]) == NULL)
 449                                return failure;
 450                        break;
 451                }
 452        }
 453
 454        /* register a node corresponding to the device's ROM resource,
 455           if present */
 456        if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) {
 457                nd = new_node();
 458                if (nd <= 0)
 459                        return failure;
 460                node_devfs_handle = hwgraph_register(device_dir_handle, "rom",
 461                                                   0, DEVFS_FL_NONE, 0, 0,
 462                                                   S_IFCHR | S_IRUSR, 0, 0,
 463                                                   &rom_fops, nd);
 464                if (node_devfs_handle == NULL)
 465                        return failure;
 466                init_rom_node(nd, dev, node_devfs_handle);
 467        }
 468
 469        /* register a node that allows ioctl's to read and write to
 470           the device's config space */
 471        if (hwgraph_register(device_dir_handle, "config", 0, DEVFS_FL_NONE,
 472                           0, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
 473                           &config_fops, dev) == NULL)
 474                return failure;
 475
 476
 477        /* finally, register a node that allows ioctl's to allocate
 478           and free DMA buffers, as well as memory map those
 479           buffers. */
 480        nd = new_node();
 481        if (nd <= 0)
 482                return failure;
 483        node_devfs_handle =
 484                hwgraph_register(device_dir_handle, "dma", 0, DEVFS_FL_NONE,
 485                               0, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
 486                               &dma_fops, nd);
 487        if (node_devfs_handle == NULL)
 488                return failure;
 489        init_dma_node(nd, dev, node_devfs_handle);
 490
 491#ifdef DEBUG_PCIBA
 492        dump_nodes(&global_node_list);
 493#endif
 494        
 495        return success;
 496}
 497
 498
 499static int
 500generic_open(struct inode * inode, struct file * file)
 501{
 502        TRACE();
 503
 504        /* FIXME: should check that they're not trying to open the ROM
 505           writable */
 506
 507        return 0; /* success */
 508}
 509
 510
 511static int
 512rom_mmap(struct file * file, struct vm_area_struct * vma)
 513{
 514        unsigned long pci_pa;
 515        struct node_data * nd;
 516
 517        TRACE();
 518
 519#ifdef CONFIG_HWGFS_FS
 520        nd = (struct node_data * )file->f_dentry->d_fsdata;
 521#else
 522        nd = (struct node_data * )file->private_data;
 523#endif
 524
 525        pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE);
 526
 527        if (!nd->u.rom.mmapped) {
 528                nd->u.rom.mmapped = true;
 529                DPRINTF("Enabling ROM address decoder.\n");
 530                DPRINTF(
 531"rom_mmap: FIXME: some cards do not allow both ROM and memory addresses to\n"
 532"rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.\n");
 533                pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
 534                                      &nd->u.rom.saved_rom_base_reg);
 535                DPRINTF("ROM base address contains %x\n",
 536                        nd->u.rom.saved_rom_base_reg);
 537                pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
 538                                       nd->u.rom.saved_rom_base_reg |
 539                                       PCI_ROM_ADDRESS_ENABLE);
 540        }
 541        
 542        return mmap_pci_address(vma, pci_pa);
 543}
 544
 545
 546static int
 547rom_release(struct inode * inode, struct file * file)
 548{
 549        struct node_data * nd;
 550
 551        TRACE();
 552
 553#ifdef CONFIG_HWGFS_FS
 554        nd = (struct node_data * )file->f_dentry->d_fsdata;
 555#else
 556        nd = (struct node_data * )file->private_data;
 557#endif
 558
 559        if (nd->u.rom.mmapped) {
 560                nd->u.rom.mmapped = false;
 561                DPRINTF("Disabling ROM address decoder.\n");
 562                pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
 563                                       nd->u.rom.saved_rom_base_reg);
 564        }
 565        return 0; /* indicate success */
 566}
 567
 568
 569static int
 570base_mmap(struct file * file, struct vm_area_struct * vma)
 571{
 572        struct resource * resource;
 573
 574        TRACE();
 575
 576#ifdef CONFIG_HWGFS_FS
 577        resource = (struct resource *)file->f_dentry->d_fsdata;
 578#else
 579        resource = (struct resource *)file->private_data;
 580#endif
 581
 582        return mmap_pci_address(vma, resource->start);
 583}
 584
 585
 586static int
 587config_ioctl(struct inode * inode, struct file * file, 
 588             unsigned int cmd, 
 589             unsigned long arg)
 590{
 591        struct pci_dev * dev;
 592
 593        union cfg_data {
 594                uint8_t byte;
 595                uint16_t word;
 596                uint32_t dword;
 597        } read_data, write_data;
 598
 599        int dir, size, offset;
 600
 601        TRACE();
 602
 603        DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)\n", 
 604                cmd, 
 605                _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
 606        DPRINTF("arg = %lx\n", arg);
 607
 608#ifdef CONFIG_HWGFS_FS
 609        dev = (struct pci_dev *)file->f_dentry->d_fsdata;
 610#else
 611        dev = (struct pci_dev *)file->private_data;
 612#endif
 613
 614        /* PCIIOCCFG{RD,WR}: read and/or write PCI configuration
 615           space. If both, the read happens first (this becomes a swap
 616           operation, atomic with respect to other updates through
 617           this path).  */
 618
 619        dir = _IOC_DIR(cmd);
 620
 621#define do_swap(suffix, type)                                           \
 622        do {                                                            \
 623                if (dir & _IOC_READ) {                                  \
 624                        pci_read_config_##suffix(dev, _IOC_NR(cmd),     \
 625                                                 &read_data.suffix);    \
 626                }                                                       \
 627                if (dir & _IOC_WRITE) {                                 \
 628                        get_user(write_data.suffix, (type)arg);         \
 629                        pci_write_config_##suffix(dev, _IOC_NR(cmd),    \
 630                                                  write_data.suffix);   \
 631                }                                                       \
 632                if (dir & _IOC_READ) {                                  \
 633                        put_user(read_data.suffix, (type)arg);          \
 634                }                                                       \
 635        } while (0)
 636
 637        size = _IOC_SIZE(cmd);
 638        offset = _IOC_NR(cmd);
 639
 640        DPRINTF("sanity check\n");
 641        if (((size > 0) || (size <= 4)) &&
 642            ((offset + size) <= 256) &&
 643            (dir & (_IOC_READ | _IOC_WRITE))) {
 644
 645                switch (size)
 646                {
 647                case 1:
 648                        do_swap(byte, uint8_t *);
 649                        break;
 650                case 2:
 651                        do_swap(word, uint16_t *);
 652                        break;
 653                case 4:
 654                        do_swap(dword, uint32_t *);
 655                        break;
 656                default:
 657                        DPRINTF("invalid ioctl\n");
 658                        return -EINVAL;
 659                }
 660        } else
 661                return -EINVAL;
 662                
 663        return 0;
 664}
 665
 666
 667#ifdef DEBUG_PCIBA
 668static void
 669dump_allocations(struct list_head * dalp)
 670{
 671        struct dma_allocation * dap;
 672        struct list_head * p;
 673        
 674        printk("{\n");
 675        list_for_each(p, dalp) {
 676                dap = list_entry(p, struct dma_allocation, 
 677                                 list);
 678                printk("  handle = %lx, va = %p\n",
 679                       dap->handle, dap->va);
 680        }
 681        printk("}\n");
 682}
 683
 684static void
 685dump_nodes(struct list_head * nodes)
 686{
 687        struct node_data * ndp;
 688        struct list_head * p;
 689        
 690        printk("{\n");
 691        list_for_each(p, nodes) {
 692                ndp = list_entry(p, struct node_data, 
 693                                 global_node_list);
 694                printk("  %p\n", (void *)ndp);
 695        }
 696        printk("}\n");
 697}
 698
 699
 700#if 0
 701#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
 702
 703static void
 704test_list(void)
 705{
 706        u64 i;
 707        LIST_HEAD(the_list);
 708
 709        for (i = 0; i < 5; i++) {
 710                struct dma_allocation * new_alloc;
 711                NEW(new_alloc);
 712                new_alloc->va = (void *)i;
 713                new_alloc->handle = 5*i;
 714                printk("%d - the_list->next = %lx\n", i, the_list.next);
 715                list_add(&new_alloc->list, &the_list);
 716        }
 717        dump_allocations(&the_list);
 718}
 719#endif
 720#endif
 721
 722
 723static LIST_HEAD(dma_buffer_list);
 724
 725
 726static int
 727dma_ioctl(struct inode * inode, struct file * file, 
 728          unsigned int cmd, 
 729          unsigned long arg)
 730{
 731        struct node_data * nd;
 732        uint64_t argv;
 733        int result;
 734        struct dma_allocation * dma_alloc;
 735        struct list_head * iterp;
 736
 737        TRACE();
 738
 739        DPRINTF("cmd = %x\n", cmd);
 740        DPRINTF("arg = %lx\n", arg);
 741
 742#ifdef CONFIG_HWGFS_FS
 743        nd = (struct node_data *)file->f_dentry->d_fsdata;
 744#else
 745        nd = (struct node_data *)file->private_data;
 746#endif
 747
 748#ifdef DEBUG_PCIBA
 749        DPRINTF("at dma_ioctl entry\n");
 750        dump_allocations(&nd->u.dma.dma_allocs);
 751#endif
 752
 753        switch (cmd) {
 754        case PCIIOCDMAALLOC:
 755                /* PCIIOCDMAALLOC: allocate a chunk of physical memory
 756                   and set it up for DMA. Return the PCI address that
 757                   gets to it.  */
 758                DPRINTF("case PCIIOCDMAALLOC (%lx)\n", PCIIOCDMAALLOC);
 759                
 760                if ( (result = get_user(argv, (uint64_t *)arg)) )
 761                        return result;
 762                DPRINTF("argv (size of buffer) = %lx\n", argv);
 763
 764                dma_alloc = (struct dma_allocation *)
 765                        kmalloc(sizeof(struct dma_allocation), GFP_KERNEL);
 766                if (dma_alloc <= 0)
 767                        return -ENOMEM;
 768
 769                dma_alloc->size = (size_t)argv;
 770                dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev,
 771                                                     dma_alloc->size,
 772                                                     &dma_alloc->handle);
 773                DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lx\n",
 774                        dma_alloc->va, dma_alloc->handle);
 775                if (dma_alloc->va == NULL) {
 776                        kfree(dma_alloc);
 777                        return -ENOMEM;
 778                }
 779
 780                list_add(&dma_alloc->list, &nd->u.dma.dma_allocs);
 781                if ( (result = put_user((uint64_t)dma_alloc->handle, 
 782                                      (uint64_t *)arg)) ) {
 783                        DPRINTF("put_user failed\n");
 784                        pci_free_consistent(nd->u.dma.dev, (size_t)argv,
 785                                            dma_alloc->va, dma_alloc->handle);
 786                        kfree(dma_alloc);
 787                        return result;
 788                }
 789
 790#ifdef DEBUG_PCIBA
 791                DPRINTF("after insertion\n");
 792                dump_allocations(&nd->u.dma.dma_allocs);
 793#endif
 794                break;
 795
 796        case PCIIOCDMAFREE:
 797                DPRINTF("case PCIIOCDMAFREE (%lx)\n", PCIIOCDMAFREE);
 798
 799                if ( (result = get_user(argv, (uint64_t *)arg)) ) {
 800                        DPRINTF("get_user failed\n");
 801                        return result;
 802                }
 803
 804                DPRINTF("argv (physical address of DMA buffer) = %lx\n", argv);
 805                list_for_each(iterp, &nd->u.dma.dma_allocs) {
 806                        struct dma_allocation * da =
 807                                list_entry(iterp, struct dma_allocation, list);
 808                        if (da->handle == argv) {
 809                                pci_free_consistent(nd->u.dma.dev, da->size,
 810                                                    da->va, da->handle);
 811                                list_del(&da->list);
 812                                kfree(da);
 813#ifdef DEBUG_PCIBA
 814                                DPRINTF("after deletion\n");
 815                                dump_allocations(&nd->u.dma.dma_allocs);
 816#endif
 817                                return 0; /* success */
 818                        }
 819                }
 820                /* previously allocated dma buffer wasn't found */
 821                DPRINTF("attempt to free invalid dma handle\n");
 822                return -EINVAL;
 823
 824        default:
 825                DPRINTF("undefined ioctl\n");
 826                return -EINVAL;
 827        }
 828
 829        DPRINTF("success\n");
 830        return 0;
 831}
 832                
 833
 834static int
 835dma_mmap(struct file * file, struct vm_area_struct * vma)
 836{
 837        struct node_data * nd;
 838        struct list_head * iterp;
 839        int result;
 840        
 841        TRACE();
 842
 843#ifdef CONFIG_HWGFS_FS
 844        nd = (struct node_data *)file->f_dentry->d_fsdata;
 845#else
 846        nd = (struct node_data *)file->private_data;
 847#endif
 848        
 849        DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
 850        DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
 851        DPRINTF("offset = %lx\n", vma->vm_pgoff);
 852
 853        /* get kernel virtual address for the dma buffer (necessary
 854         * for the mmap). */
 855        list_for_each(iterp, &nd->u.dma.dma_allocs) {
 856                struct dma_allocation * da =
 857                        list_entry(iterp, struct dma_allocation, list);
 858                /* why does mmap shift its offset argument? */
 859                if (da->handle == vma->vm_pgoff << PAGE_SHIFT) {
 860                        DPRINTF("found dma handle\n");
 861                        if ( (result = mmap_kernel_address(vma,
 862                                                           da->va)) ) {
 863                                return result; /* failure */
 864                        } else {
 865                                /* it seems like at least one of these
 866                                   should show up in user land....
 867                                   I'm missing something */
 868                                *(char *)da->va = 0xaa;
 869                                strncpy(da->va, "        Toastie!", da->size);
 870                                if (put_user(0x18badbeeful,
 871                                             (u64 *)vma->vm_start))
 872                                        DPRINTF("put_user failed?!\n");
 873                                return 0; /* success */
 874                        }
 875
 876                }
 877        }
 878        DPRINTF("attempt to mmap an invalid dma handle\n");
 879        return -EINVAL;
 880}
 881
 882
 883static int
 884mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va)
 885{
 886        unsigned long pci_pa;
 887
 888        TRACE();
 889
 890        DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
 891        DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
 892
 893        /* the size of the vma doesn't necessarily correspond to the
 894           size specified in the mmap call.  So we can't really do any
 895           kind of sanity check here.  This is a dangerous driver, and
 896           it's very easy for a user process to kill the machine.  */
 897
 898        DPRINTF("PCI base at virtual address %lx\n", pci_va);
 899        /* the __pa macro is intended for region 7 on IA64, so it
 900           doesn't work for region 6 */
 901        /* pci_pa = __pa(pci_va); */
 902        /* should be replaced by ia64_tpa or equivalent (preferably a
 903           generic equivalent) */
 904        pci_pa = pci_va & ~0xe000000000000000ul;
 905        DPRINTF("PCI base at physical address %lx\n", pci_pa);
 906
 907        /* there are various arch-specific versions of this function
 908           defined in linux/drivers/char/mem.c, but it would be nice
 909           if all architectures put it in pgtable.h.  it's defined
 910           there for ia64.... */
 911        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 912
 913        vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
 914
 915        return io_remap_page_range(vma->vm_start, pci_pa, 
 916                                   vma->vm_end-vma->vm_start,
 917                                   vma->vm_page_prot);
 918}
 919
 920
 921static int
 922mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va)
 923{
 924        unsigned long kernel_pa;
 925
 926        TRACE();
 927
 928        DPRINTF("vma->vm_start is %lx\n", vma->vm_start);
 929        DPRINTF("vma->vm_end is %lx\n", vma->vm_end);
 930
 931        /* the size of the vma doesn't necessarily correspond to the
 932           size specified in the mmap call.  So we can't really do any
 933           kind of sanity check here.  This is a dangerous driver, and
 934           it's very easy for a user process to kill the machine.  */
 935
 936        DPRINTF("mapping virtual address %p\n", kernel_va);
 937        kernel_pa = __pa(kernel_va);
 938        DPRINTF("mapping physical address %lx\n", kernel_pa);
 939
 940        vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
 941
 942        return remap_page_range(vma->vm_start, kernel_pa, 
 943                                vma->vm_end-vma->vm_start,
 944                                vma->vm_page_prot);
 945}       
 946
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.