linux/drivers/vme/bridges/vme_fake.c
<<
>>
Prefs
   1/*
   2 * Fake VME bridge support.
   3 *
   4 * This drive provides a fake VME bridge chip, this enables debugging of the
   5 * VME framework in the absence of a VME system.
   6 *
   7 * This driver has to do a number of things in software that would be driven
   8 * by hardware if it was available, it will also result in extra overhead at
   9 * times when compared with driving actual hardware.
  10 *
  11 * Author: Martyn Welch <martyn@welches.me.uk>
  12 * Copyright (c) 2014 Martyn Welch
  13 *
  14 * Based on vme_tsi148.c:
  15 *
  16 * Author: Martyn Welch <martyn.welch@ge.com>
  17 * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
  18 *
  19 * Based on work by Tom Armistead and Ajit Prem
  20 * Copyright 2004 Motorola Inc.
  21 *
  22 * This program is free software; you can redistribute  it and/or modify it
  23 * under  the terms of  the GNU General  Public License as published by the
  24 * Free Software Foundation;  either version 2 of the  License, or (at your
  25 * option) any later version.
  26 */
  27
  28#include <linux/device.h>
  29#include <linux/errno.h>
  30#include <linux/interrupt.h>
  31#include <linux/module.h>
  32#include <linux/moduleparam.h>
  33#include <linux/slab.h>
  34#include <linux/spinlock.h>
  35#include <linux/types.h>
  36#include <linux/vme.h>
  37
  38#include "../vme_bridge.h"
  39
  40/*
  41 *  Define the number of each that the fake driver supports.
  42 */
  43#define FAKE_MAX_MASTER         8       /* Max Master Windows */
  44#define FAKE_MAX_SLAVE          8       /* Max Slave Windows */
  45
  46/* Structures to hold information normally held in device registers */
  47struct fake_slave_window {
  48        int enabled;
  49        unsigned long long vme_base;
  50        unsigned long long size;
  51        void *buf_base;
  52        u32 aspace;
  53        u32 cycle;
  54};
  55
  56struct fake_master_window {
  57        int enabled;
  58        unsigned long long vme_base;
  59        unsigned long long size;
  60        u32 aspace;
  61        u32 cycle;
  62        u32 dwidth;
  63};
  64
  65/* Structure used to hold driver specific information */
  66struct fake_driver {
  67        struct vme_bridge *parent;
  68        struct fake_slave_window slaves[FAKE_MAX_SLAVE];
  69        struct fake_master_window masters[FAKE_MAX_MASTER];
  70        u32 lm_enabled;
  71        unsigned long long lm_base;
  72        u32 lm_aspace;
  73        u32 lm_cycle;
  74        void (*lm_callback[4])(void *);
  75        void *lm_data[4];
  76        struct tasklet_struct int_tasklet;
  77        int int_level;
  78        int int_statid;
  79        void *crcsr_kernel;
  80        dma_addr_t crcsr_bus;
  81        /* Only one VME interrupt can be generated at a time, provide locking */
  82        struct mutex vme_int;
  83};
  84
  85/* Module parameter */
  86static int geoid;
  87
  88static const char driver_name[] = "vme_fake";
  89
  90static struct vme_bridge *exit_pointer;
  91
  92static struct device *vme_root;
  93
  94/*
  95 * Calling VME bus interrupt callback if provided.
  96 */
  97static void fake_VIRQ_tasklet(unsigned long data)
  98{
  99        struct vme_bridge *fake_bridge;
 100        struct fake_driver *bridge;
 101
 102        fake_bridge = (struct vme_bridge *) data;
 103        bridge = fake_bridge->driver_priv;
 104
 105        vme_irq_handler(fake_bridge, bridge->int_level, bridge->int_statid);
 106}
 107
 108/*
 109 * Configure VME interrupt
 110 */
 111static void fake_irq_set(struct vme_bridge *fake_bridge, int level,
 112                int state, int sync)
 113{
 114        /* Nothing to do */
 115}
 116
 117static void *fake_pci_to_ptr(dma_addr_t addr)
 118{
 119        return (void *)(uintptr_t)addr;
 120}
 121
 122static dma_addr_t fake_ptr_to_pci(void *addr)
 123{
 124        return (dma_addr_t)(uintptr_t)addr;
 125}
 126
 127/*
 128 * Generate a VME bus interrupt at the requested level & vector. Wait for
 129 * interrupt to be acked.
 130 */
 131static int fake_irq_generate(struct vme_bridge *fake_bridge, int level,
 132                int statid)
 133{
 134        struct fake_driver *bridge;
 135
 136        bridge = fake_bridge->driver_priv;
 137
 138        mutex_lock(&bridge->vme_int);
 139
 140        bridge->int_level = level;
 141
 142        bridge->int_statid = statid;
 143
 144        /*
 145         * Schedule tasklet to run VME handler to emulate normal VME interrupt
 146         * handler behaviour.
 147         */
 148        tasklet_schedule(&bridge->int_tasklet);
 149
 150        mutex_unlock(&bridge->vme_int);
 151
 152        return 0;
 153}
 154
 155/*
 156 * Initialize a slave window with the requested attributes.
 157 */
 158static int fake_slave_set(struct vme_slave_resource *image, int enabled,
 159                unsigned long long vme_base, unsigned long long size,
 160                dma_addr_t buf_base, u32 aspace, u32 cycle)
 161{
 162        unsigned int i, granularity = 0;
 163        unsigned long long vme_bound;
 164        struct vme_bridge *fake_bridge;
 165        struct fake_driver *bridge;
 166
 167        fake_bridge = image->parent;
 168        bridge = fake_bridge->driver_priv;
 169
 170        i = image->number;
 171
 172        switch (aspace) {
 173        case VME_A16:
 174                granularity = 0x10;
 175                break;
 176        case VME_A24:
 177                granularity = 0x1000;
 178                break;
 179        case VME_A32:
 180                granularity = 0x10000;
 181                break;
 182        case VME_A64:
 183                granularity = 0x10000;
 184                break;
 185        case VME_CRCSR:
 186        case VME_USER1:
 187        case VME_USER2:
 188        case VME_USER3:
 189        case VME_USER4:
 190        default:
 191                pr_err("Invalid address space\n");
 192                return -EINVAL;
 193        }
 194
 195        /*
 196         * Bound address is a valid address for the window, adjust
 197         * accordingly
 198         */
 199        vme_bound = vme_base + size - granularity;
 200
 201        if (vme_base & (granularity - 1)) {
 202                pr_err("Invalid VME base alignment\n");
 203                return -EINVAL;
 204        }
 205        if (vme_bound & (granularity - 1)) {
 206                pr_err("Invalid VME bound alignment\n");
 207                return -EINVAL;
 208        }
 209
 210        mutex_lock(&image->mtx);
 211
 212        bridge->slaves[i].enabled = enabled;
 213        bridge->slaves[i].vme_base = vme_base;
 214        bridge->slaves[i].size = size;
 215        bridge->slaves[i].buf_base = fake_pci_to_ptr(buf_base);
 216        bridge->slaves[i].aspace = aspace;
 217        bridge->slaves[i].cycle = cycle;
 218
 219        mutex_unlock(&image->mtx);
 220
 221        return 0;
 222}
 223
 224/*
 225 * Get slave window configuration.
 226 */
 227static int fake_slave_get(struct vme_slave_resource *image, int *enabled,
 228                unsigned long long *vme_base, unsigned long long *size,
 229                dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
 230{
 231        unsigned int i;
 232        struct fake_driver *bridge;
 233
 234        bridge = image->parent->driver_priv;
 235
 236        i = image->number;
 237
 238        mutex_lock(&image->mtx);
 239
 240        *enabled = bridge->slaves[i].enabled;
 241        *vme_base = bridge->slaves[i].vme_base;
 242        *size = bridge->slaves[i].size;
 243        *buf_base = fake_ptr_to_pci(bridge->slaves[i].buf_base);
 244        *aspace = bridge->slaves[i].aspace;
 245        *cycle = bridge->slaves[i].cycle;
 246
 247        mutex_unlock(&image->mtx);
 248
 249        return 0;
 250}
 251
 252/*
 253 * Set the attributes of an outbound window.
 254 */
 255static int fake_master_set(struct vme_master_resource *image, int enabled,
 256                unsigned long long vme_base, unsigned long long size,
 257                u32 aspace, u32 cycle, u32 dwidth)
 258{
 259        int retval = 0;
 260        unsigned int i;
 261        struct vme_bridge *fake_bridge;
 262        struct fake_driver *bridge;
 263
 264        fake_bridge = image->parent;
 265
 266        bridge = fake_bridge->driver_priv;
 267
 268        /* Verify input data */
 269        if (vme_base & 0xFFFF) {
 270                pr_err("Invalid VME Window alignment\n");
 271                retval = -EINVAL;
 272                goto err_window;
 273        }
 274
 275        if (size & 0xFFFF) {
 276                pr_err("Invalid size alignment\n");
 277                retval = -EINVAL;
 278                goto err_window;
 279        }
 280
 281        if ((size == 0) && (enabled != 0)) {
 282                pr_err("Size must be non-zero for enabled windows\n");
 283                retval = -EINVAL;
 284                goto err_window;
 285        }
 286
 287        /* Setup data width */
 288        switch (dwidth) {
 289        case VME_D8:
 290        case VME_D16:
 291        case VME_D32:
 292                break;
 293        default:
 294                pr_err("Invalid data width\n");
 295                retval = -EINVAL;
 296                goto err_dwidth;
 297        }
 298
 299        /* Setup address space */
 300        switch (aspace) {
 301        case VME_A16:
 302        case VME_A24:
 303        case VME_A32:
 304        case VME_A64:
 305        case VME_CRCSR:
 306        case VME_USER1:
 307        case VME_USER2:
 308        case VME_USER3:
 309        case VME_USER4:
 310                break;
 311        default:
 312                pr_err("Invalid address space\n");
 313                retval = -EINVAL;
 314                goto err_aspace;
 315        }
 316
 317        spin_lock(&image->lock);
 318
 319        i = image->number;
 320
 321        bridge->masters[i].enabled = enabled;
 322        bridge->masters[i].vme_base = vme_base;
 323        bridge->masters[i].size = size;
 324        bridge->masters[i].aspace = aspace;
 325        bridge->masters[i].cycle = cycle;
 326        bridge->masters[i].dwidth = dwidth;
 327
 328        spin_unlock(&image->lock);
 329
 330        return 0;
 331
 332err_aspace:
 333err_dwidth:
 334err_window:
 335        return retval;
 336
 337}
 338
 339/*
 340 * Set the attributes of an outbound window.
 341 */
 342static int __fake_master_get(struct vme_master_resource *image, int *enabled,
 343                unsigned long long *vme_base, unsigned long long *size,
 344                u32 *aspace, u32 *cycle, u32 *dwidth)
 345{
 346        unsigned int i;
 347        struct fake_driver *bridge;
 348
 349        bridge = image->parent->driver_priv;
 350
 351        i = image->number;
 352
 353        *enabled = bridge->masters[i].enabled;
 354        *vme_base = bridge->masters[i].vme_base;
 355        *size = bridge->masters[i].size;
 356        *aspace = bridge->masters[i].aspace;
 357        *cycle = bridge->masters[i].cycle;
 358        *dwidth = bridge->masters[i].dwidth;
 359
 360        return 0;
 361}
 362
 363
 364static int fake_master_get(struct vme_master_resource *image, int *enabled,
 365                unsigned long long *vme_base, unsigned long long *size,
 366                u32 *aspace, u32 *cycle, u32 *dwidth)
 367{
 368        int retval;
 369
 370        spin_lock(&image->lock);
 371
 372        retval = __fake_master_get(image, enabled, vme_base, size, aspace,
 373                        cycle, dwidth);
 374
 375        spin_unlock(&image->lock);
 376
 377        return retval;
 378}
 379
 380
 381static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr,
 382                          u32 aspace, u32 cycle)
 383{
 384        struct vme_bridge *fake_bridge;
 385        unsigned long long lm_base;
 386        u32 lm_aspace, lm_cycle;
 387        int i;
 388        struct vme_lm_resource *lm;
 389        struct list_head *pos = NULL, *n;
 390
 391        /* Get vme_bridge */
 392        fake_bridge = bridge->parent;
 393
 394        /* Loop through each location monitor resource */
 395        list_for_each_safe(pos, n, &fake_bridge->lm_resources) {
 396                lm = list_entry(pos, struct vme_lm_resource, list);
 397
 398                /* If disabled, we're done */
 399                if (bridge->lm_enabled == 0)
 400                        return;
 401
 402                lm_base = bridge->lm_base;
 403                lm_aspace = bridge->lm_aspace;
 404                lm_cycle = bridge->lm_cycle;
 405
 406                /* First make sure that the cycle and address space match */
 407                if ((lm_aspace == aspace) && (lm_cycle == cycle)) {
 408                        for (i = 0; i < lm->monitors; i++) {
 409                                /* Each location monitor covers 8 bytes */
 410                                if (((lm_base + (8 * i)) <= addr) &&
 411                                    ((lm_base + (8 * i) + 8) > addr)) {
 412                                        if (bridge->lm_callback[i])
 413                                                bridge->lm_callback[i](
 414                                                        bridge->lm_data[i]);
 415                                }
 416                        }
 417                }
 418        }
 419}
 420
 421static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
 422                u32 aspace, u32 cycle)
 423{
 424        u8 retval = 0xff;
 425        int i;
 426        unsigned long long start, end, offset;
 427        u8 *loc;
 428
 429        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 430                start = bridge->slaves[i].vme_base;
 431                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 432
 433                if (aspace != bridge->slaves[i].aspace)
 434                        continue;
 435
 436                if (cycle != bridge->slaves[i].cycle)
 437                        continue;
 438
 439                if ((addr >= start) && (addr < end)) {
 440                        offset = addr - bridge->slaves[i].vme_base;
 441                        loc = (u8 *)(bridge->slaves[i].buf_base + offset);
 442                        retval = *loc;
 443
 444                        break;
 445                }
 446        }
 447
 448        fake_lm_check(bridge, addr, aspace, cycle);
 449
 450        return retval;
 451}
 452
 453static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
 454                u32 aspace, u32 cycle)
 455{
 456        u16 retval = 0xffff;
 457        int i;
 458        unsigned long long start, end, offset;
 459        u16 *loc;
 460
 461        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 462                if (aspace != bridge->slaves[i].aspace)
 463                        continue;
 464
 465                if (cycle != bridge->slaves[i].cycle)
 466                        continue;
 467
 468                start = bridge->slaves[i].vme_base;
 469                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 470
 471                if ((addr >= start) && ((addr + 1) < end)) {
 472                        offset = addr - bridge->slaves[i].vme_base;
 473                        loc = (u16 *)(bridge->slaves[i].buf_base + offset);
 474                        retval = *loc;
 475
 476                        break;
 477                }
 478        }
 479
 480        fake_lm_check(bridge, addr, aspace, cycle);
 481
 482        return retval;
 483}
 484
 485static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr,
 486                u32 aspace, u32 cycle)
 487{
 488        u32 retval = 0xffffffff;
 489        int i;
 490        unsigned long long start, end, offset;
 491        u32 *loc;
 492
 493        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 494                if (aspace != bridge->slaves[i].aspace)
 495                        continue;
 496
 497                if (cycle != bridge->slaves[i].cycle)
 498                        continue;
 499
 500                start = bridge->slaves[i].vme_base;
 501                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 502
 503                if ((addr >= start) && ((addr + 3) < end)) {
 504                        offset = addr - bridge->slaves[i].vme_base;
 505                        loc = (u32 *)(bridge->slaves[i].buf_base + offset);
 506                        retval = *loc;
 507
 508                        break;
 509                }
 510        }
 511
 512        fake_lm_check(bridge, addr, aspace, cycle);
 513
 514        return retval;
 515}
 516
 517static ssize_t fake_master_read(struct vme_master_resource *image, void *buf,
 518                size_t count, loff_t offset)
 519{
 520        int retval;
 521        u32 aspace, cycle, dwidth;
 522        struct vme_bridge *fake_bridge;
 523        struct fake_driver *priv;
 524        int i;
 525        unsigned long long addr;
 526        unsigned int done = 0;
 527        unsigned int count32;
 528
 529        fake_bridge = image->parent;
 530
 531        priv = fake_bridge->driver_priv;
 532
 533        i = image->number;
 534
 535        addr = (unsigned long long)priv->masters[i].vme_base + offset;
 536        aspace = priv->masters[i].aspace;
 537        cycle = priv->masters[i].cycle;
 538        dwidth = priv->masters[i].dwidth;
 539
 540        spin_lock(&image->lock);
 541
 542        /* The following code handles VME address alignment. We cannot use
 543         * memcpy_xxx here because it may cut data transfers in to 8-bit
 544         * cycles when D16 or D32 cycles are required on the VME bus.
 545         * On the other hand, the bridge itself assures that the maximum data
 546         * cycle configured for the transfer is used and splits it
 547         * automatically for non-aligned addresses, so we don't want the
 548         * overhead of needlessly forcing small transfers for the entire cycle.
 549         */
 550        if (addr & 0x1) {
 551                *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle);
 552                done += 1;
 553                if (done == count)
 554                        goto out;
 555        }
 556        if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
 557                if ((addr + done) & 0x2) {
 558                        if ((count - done) < 2) {
 559                                *(u8 *)(buf + done) = fake_vmeread8(priv,
 560                                                addr + done, aspace, cycle);
 561                                done += 1;
 562                                goto out;
 563                        } else {
 564                                *(u16 *)(buf + done) = fake_vmeread16(priv,
 565                                                addr + done, aspace, cycle);
 566                                done += 2;
 567                        }
 568                }
 569        }
 570
 571        if (dwidth == VME_D32) {
 572                count32 = (count - done) & ~0x3;
 573                while (done < count32) {
 574                        *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done,
 575                                        aspace, cycle);
 576                        done += 4;
 577                }
 578        } else if (dwidth == VME_D16) {
 579                count32 = (count - done) & ~0x3;
 580                while (done < count32) {
 581                        *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
 582                                        aspace, cycle);
 583                        done += 2;
 584                }
 585        } else if (dwidth == VME_D8) {
 586                count32 = (count - done);
 587                while (done < count32) {
 588                        *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done,
 589                                        aspace, cycle);
 590                        done += 1;
 591                }
 592
 593        }
 594
 595        if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
 596                if ((count - done) & 0x2) {
 597                        *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
 598                                        aspace, cycle);
 599                        done += 2;
 600                }
 601        }
 602        if ((count - done) & 0x1) {
 603                *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace,
 604                                cycle);
 605                done += 1;
 606        }
 607
 608out:
 609        retval = count;
 610
 611        spin_unlock(&image->lock);
 612
 613        return retval;
 614}
 615
 616static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
 617                           unsigned long long addr, u32 aspace, u32 cycle)
 618{
 619        int i;
 620        unsigned long long start, end, offset;
 621        u8 *loc;
 622
 623        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 624                if (aspace != bridge->slaves[i].aspace)
 625                        continue;
 626
 627                if (cycle != bridge->slaves[i].cycle)
 628                        continue;
 629
 630                start = bridge->slaves[i].vme_base;
 631                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 632
 633                if ((addr >= start) && (addr < end)) {
 634                        offset = addr - bridge->slaves[i].vme_base;
 635                        loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
 636                        *loc = *buf;
 637
 638                        break;
 639                }
 640        }
 641
 642        fake_lm_check(bridge, addr, aspace, cycle);
 643
 644}
 645
 646static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
 647                            unsigned long long addr, u32 aspace, u32 cycle)
 648{
 649        int i;
 650        unsigned long long start, end, offset;
 651        u16 *loc;
 652
 653        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 654                if (aspace != bridge->slaves[i].aspace)
 655                        continue;
 656
 657                if (cycle != bridge->slaves[i].cycle)
 658                        continue;
 659
 660                start = bridge->slaves[i].vme_base;
 661                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 662
 663                if ((addr >= start) && ((addr + 1) < end)) {
 664                        offset = addr - bridge->slaves[i].vme_base;
 665                        loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset);
 666                        *loc = *buf;
 667
 668                        break;
 669                }
 670        }
 671
 672        fake_lm_check(bridge, addr, aspace, cycle);
 673
 674}
 675
 676static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
 677                            unsigned long long addr, u32 aspace, u32 cycle)
 678{
 679        int i;
 680        unsigned long long start, end, offset;
 681        u32 *loc;
 682
 683        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
 684                if (aspace != bridge->slaves[i].aspace)
 685                        continue;
 686
 687                if (cycle != bridge->slaves[i].cycle)
 688                        continue;
 689
 690                start = bridge->slaves[i].vme_base;
 691                end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
 692
 693                if ((addr >= start) && ((addr + 3) < end)) {
 694                        offset = addr - bridge->slaves[i].vme_base;
 695                        loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset);
 696                        *loc = *buf;
 697
 698                        break;
 699                }
 700        }
 701
 702        fake_lm_check(bridge, addr, aspace, cycle);
 703
 704}
 705
 706static ssize_t fake_master_write(struct vme_master_resource *image, void *buf,
 707                size_t count, loff_t offset)
 708{
 709        int retval = 0;
 710        u32 aspace, cycle, dwidth;
 711        unsigned long long addr;
 712        int i;
 713        unsigned int done = 0;
 714        unsigned int count32;
 715
 716        struct vme_bridge *fake_bridge;
 717        struct fake_driver *bridge;
 718
 719        fake_bridge = image->parent;
 720
 721        bridge = fake_bridge->driver_priv;
 722
 723        i = image->number;
 724
 725        addr = bridge->masters[i].vme_base + offset;
 726        aspace = bridge->masters[i].aspace;
 727        cycle = bridge->masters[i].cycle;
 728        dwidth = bridge->masters[i].dwidth;
 729
 730        spin_lock(&image->lock);
 731
 732        /* Here we apply for the same strategy we do in master_read
 733         * function in order to assure the correct cycles.
 734         */
 735        if (addr & 0x1) {
 736                fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle);
 737                done += 1;
 738                if (done == count)
 739                        goto out;
 740        }
 741
 742        if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
 743                if ((addr + done) & 0x2) {
 744                        if ((count - done) < 2) {
 745                                fake_vmewrite8(bridge, (u8 *)(buf + done),
 746                                                addr + done, aspace, cycle);
 747                                done += 1;
 748                                goto out;
 749                        } else {
 750                                fake_vmewrite16(bridge, (u16 *)(buf + done),
 751                                                addr + done, aspace, cycle);
 752                                done += 2;
 753                        }
 754                }
 755        }
 756
 757        if (dwidth == VME_D32) {
 758                count32 = (count - done) & ~0x3;
 759                while (done < count32) {
 760                        fake_vmewrite32(bridge, (u32 *)(buf + done),
 761                                        addr + done, aspace, cycle);
 762                        done += 4;
 763                }
 764        } else if (dwidth == VME_D16) {
 765                count32 = (count - done) & ~0x3;
 766                while (done < count32) {
 767                        fake_vmewrite16(bridge, (u16 *)(buf + done),
 768                                        addr + done, aspace, cycle);
 769                        done += 2;
 770                }
 771        } else if (dwidth == VME_D8) {
 772                count32 = (count - done);
 773                while (done < count32) {
 774                        fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done,
 775                                        aspace, cycle);
 776                        done += 1;
 777                }
 778
 779        }
 780
 781        if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
 782                if ((count - done) & 0x2) {
 783                        fake_vmewrite16(bridge, (u16 *)(buf + done),
 784                                        addr + done, aspace, cycle);
 785                        done += 2;
 786                }
 787        }
 788
 789        if ((count - done) & 0x1) {
 790                fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace,
 791                                cycle);
 792                done += 1;
 793        }
 794
 795out:
 796        retval = count;
 797
 798        spin_unlock(&image->lock);
 799
 800        return retval;
 801}
 802
 803/*
 804 * Perform an RMW cycle on the VME bus.
 805 *
 806 * Requires a previously configured master window, returns final value.
 807 */
 808static unsigned int fake_master_rmw(struct vme_master_resource *image,
 809                unsigned int mask, unsigned int compare, unsigned int swap,
 810                loff_t offset)
 811{
 812        u32 tmp, base;
 813        u32 aspace, cycle;
 814        int i;
 815        struct fake_driver *bridge;
 816
 817        bridge = image->parent->driver_priv;
 818
 819        /* Find the PCI address that maps to the desired VME address */
 820        i = image->number;
 821
 822        base = bridge->masters[i].vme_base;
 823        aspace = bridge->masters[i].aspace;
 824        cycle = bridge->masters[i].cycle;
 825
 826        /* Lock image */
 827        spin_lock(&image->lock);
 828
 829        /* Read existing value */
 830        tmp = fake_vmeread32(bridge, base + offset, aspace, cycle);
 831
 832        /* Perform check */
 833        if ((tmp && mask) == (compare && mask)) {
 834                tmp = tmp | (mask | swap);
 835                tmp = tmp & (~mask | swap);
 836
 837                /* Write back */
 838                fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle);
 839        }
 840
 841        /* Unlock image */
 842        spin_unlock(&image->lock);
 843
 844        return tmp;
 845}
 846
 847/*
 848 * All 4 location monitors reside at the same base - this is therefore a
 849 * system wide configuration.
 850 *
 851 * This does not enable the LM monitor - that should be done when the first
 852 * callback is attached and disabled when the last callback is removed.
 853 */
 854static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
 855                u32 aspace, u32 cycle)
 856{
 857        int i;
 858        struct vme_bridge *fake_bridge;
 859        struct fake_driver *bridge;
 860
 861        fake_bridge = lm->parent;
 862
 863        bridge = fake_bridge->driver_priv;
 864
 865        mutex_lock(&lm->mtx);
 866
 867        /* If we already have a callback attached, we can't move it! */
 868        for (i = 0; i < lm->monitors; i++) {
 869                if (bridge->lm_callback[i]) {
 870                        mutex_unlock(&lm->mtx);
 871                        pr_err("Location monitor callback attached, can't reset\n");
 872                        return -EBUSY;
 873                }
 874        }
 875
 876        switch (aspace) {
 877        case VME_A16:
 878        case VME_A24:
 879        case VME_A32:
 880        case VME_A64:
 881                break;
 882        default:
 883                mutex_unlock(&lm->mtx);
 884                pr_err("Invalid address space\n");
 885                return -EINVAL;
 886        }
 887
 888        bridge->lm_base = lm_base;
 889        bridge->lm_aspace = aspace;
 890        bridge->lm_cycle = cycle;
 891
 892        mutex_unlock(&lm->mtx);
 893
 894        return 0;
 895}
 896
 897/* Get configuration of the callback monitor and return whether it is enabled
 898 * or disabled.
 899 */
 900static int fake_lm_get(struct vme_lm_resource *lm,
 901                unsigned long long *lm_base, u32 *aspace, u32 *cycle)
 902{
 903        struct fake_driver *bridge;
 904
 905        bridge = lm->parent->driver_priv;
 906
 907        mutex_lock(&lm->mtx);
 908
 909        *lm_base = bridge->lm_base;
 910        *aspace = bridge->lm_aspace;
 911        *cycle = bridge->lm_cycle;
 912
 913        mutex_unlock(&lm->mtx);
 914
 915        return bridge->lm_enabled;
 916}
 917
 918/*
 919 * Attach a callback to a specific location monitor.
 920 *
 921 * Callback will be passed the monitor triggered.
 922 */
 923static int fake_lm_attach(struct vme_lm_resource *lm, int monitor,
 924                void (*callback)(void *), void *data)
 925{
 926        struct vme_bridge *fake_bridge;
 927        struct fake_driver *bridge;
 928
 929        fake_bridge = lm->parent;
 930
 931        bridge = fake_bridge->driver_priv;
 932
 933        mutex_lock(&lm->mtx);
 934
 935        /* Ensure that the location monitor is configured - need PGM or DATA */
 936        if (bridge->lm_cycle == 0) {
 937                mutex_unlock(&lm->mtx);
 938                pr_err("Location monitor not properly configured\n");
 939                return -EINVAL;
 940        }
 941
 942        /* Check that a callback isn't already attached */
 943        if (bridge->lm_callback[monitor]) {
 944                mutex_unlock(&lm->mtx);
 945                pr_err("Existing callback attached\n");
 946                return -EBUSY;
 947        }
 948
 949        /* Attach callback */
 950        bridge->lm_callback[monitor] = callback;
 951        bridge->lm_data[monitor] = data;
 952
 953        /* Ensure that global Location Monitor Enable set */
 954        bridge->lm_enabled = 1;
 955
 956        mutex_unlock(&lm->mtx);
 957
 958        return 0;
 959}
 960
 961/*
 962 * Detach a callback function forn a specific location monitor.
 963 */
 964static int fake_lm_detach(struct vme_lm_resource *lm, int monitor)
 965{
 966        u32 tmp;
 967        int i;
 968        struct fake_driver *bridge;
 969
 970        bridge = lm->parent->driver_priv;
 971
 972        mutex_lock(&lm->mtx);
 973
 974        /* Detach callback */
 975        bridge->lm_callback[monitor] = NULL;
 976        bridge->lm_data[monitor] = NULL;
 977
 978        /* If all location monitors disabled, disable global Location Monitor */
 979        tmp = 0;
 980        for (i = 0; i < lm->monitors; i++) {
 981                if (bridge->lm_callback[i])
 982                        tmp = 1;
 983        }
 984
 985        if (tmp == 0)
 986                bridge->lm_enabled = 0;
 987
 988        mutex_unlock(&lm->mtx);
 989
 990        return 0;
 991}
 992
 993/*
 994 * Determine Geographical Addressing
 995 */
 996static int fake_slot_get(struct vme_bridge *fake_bridge)
 997{
 998        return geoid;
 999}
1000
1001static void *fake_alloc_consistent(struct device *parent, size_t size,
1002                dma_addr_t *dma)
1003{
1004        void *alloc = kmalloc(size, GFP_KERNEL);
1005
1006        if (alloc)
1007                *dma = fake_ptr_to_pci(alloc);
1008
1009        return alloc;
1010}
1011
1012static void fake_free_consistent(struct device *parent, size_t size,
1013                void *vaddr, dma_addr_t dma)
1014{
1015        kfree(vaddr);
1016/*
1017        dma_free_coherent(parent, size, vaddr, dma);
1018*/
1019}
1020
1021/*
1022 * Configure CR/CSR space
1023 *
1024 * Access to the CR/CSR can be configured at power-up. The location of the
1025 * CR/CSR registers in the CR/CSR address space is determined by the boards
1026 * Geographic address.
1027 *
1028 * Each board has a 512kB window, with the highest 4kB being used for the
1029 * boards registers, this means there is a fix length 508kB window which must
1030 * be mapped onto PCI memory.
1031 */
1032static int fake_crcsr_init(struct vme_bridge *fake_bridge)
1033{
1034        u32 vstat;
1035        struct fake_driver *bridge;
1036
1037        bridge = fake_bridge->driver_priv;
1038
1039        /* Allocate mem for CR/CSR image */
1040        bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL);
1041        bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel);
1042        if (!bridge->crcsr_kernel)
1043                return -ENOMEM;
1044
1045        vstat = fake_slot_get(fake_bridge);
1046
1047        pr_info("CR/CSR Offset: %d\n", vstat);
1048
1049        return 0;
1050}
1051
1052static void fake_crcsr_exit(struct vme_bridge *fake_bridge)
1053{
1054        struct fake_driver *bridge;
1055
1056        bridge = fake_bridge->driver_priv;
1057
1058        kfree(bridge->crcsr_kernel);
1059}
1060
1061
1062static int __init fake_init(void)
1063{
1064        int retval, i;
1065        struct list_head *pos = NULL, *n;
1066        struct vme_bridge *fake_bridge;
1067        struct fake_driver *fake_device;
1068        struct vme_master_resource *master_image;
1069        struct vme_slave_resource *slave_image;
1070        struct vme_lm_resource *lm;
1071
1072        /* We need a fake parent device */
1073        vme_root = __root_device_register("vme", THIS_MODULE);
1074
1075        /* If we want to support more than one bridge at some point, we need to
1076         * dynamically allocate this so we get one per device.
1077         */
1078        fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL);
1079        if (!fake_bridge) {
1080                retval = -ENOMEM;
1081                goto err_struct;
1082        }
1083
1084        fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL);
1085        if (!fake_device) {
1086                retval = -ENOMEM;
1087                goto err_driver;
1088        }
1089
1090        fake_bridge->driver_priv = fake_device;
1091
1092        fake_bridge->parent = vme_root;
1093
1094        fake_device->parent = fake_bridge;
1095
1096        /* Initialize wait queues & mutual exclusion flags */
1097        mutex_init(&fake_device->vme_int);
1098        mutex_init(&fake_bridge->irq_mtx);
1099        tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet,
1100                        (unsigned long) fake_bridge);
1101
1102        strcpy(fake_bridge->name, driver_name);
1103
1104        /* Add master windows to list */
1105        INIT_LIST_HEAD(&fake_bridge->master_resources);
1106        for (i = 0; i < FAKE_MAX_MASTER; i++) {
1107                master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
1108                if (!master_image) {
1109                        retval = -ENOMEM;
1110                        goto err_master;
1111                }
1112                master_image->parent = fake_bridge;
1113                spin_lock_init(&master_image->lock);
1114                master_image->locked = 0;
1115                master_image->number = i;
1116                master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
1117                        VME_A64;
1118                master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
1119                        VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
1120                        VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
1121                        VME_PROG | VME_DATA;
1122                master_image->width_attr = VME_D16 | VME_D32;
1123                memset(&master_image->bus_resource, 0,
1124                                sizeof(struct resource));
1125                master_image->kern_base  = NULL;
1126                list_add_tail(&master_image->list,
1127                                &fake_bridge->master_resources);
1128        }
1129
1130        /* Add slave windows to list */
1131        INIT_LIST_HEAD(&fake_bridge->slave_resources);
1132        for (i = 0; i < FAKE_MAX_SLAVE; i++) {
1133                slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
1134                if (!slave_image) {
1135                        retval = -ENOMEM;
1136                        goto err_slave;
1137                }
1138                slave_image->parent = fake_bridge;
1139                mutex_init(&slave_image->mtx);
1140                slave_image->locked = 0;
1141                slave_image->number = i;
1142                slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
1143                        VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
1144                        VME_USER3 | VME_USER4;
1145                slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
1146                        VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
1147                        VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
1148                        VME_PROG | VME_DATA;
1149                list_add_tail(&slave_image->list,
1150                                &fake_bridge->slave_resources);
1151        }
1152
1153        /* Add location monitor to list */
1154        INIT_LIST_HEAD(&fake_bridge->lm_resources);
1155        lm = kmalloc(sizeof(*lm), GFP_KERNEL);
1156        if (!lm) {
1157                retval = -ENOMEM;
1158                goto err_lm;
1159        }
1160        lm->parent = fake_bridge;
1161        mutex_init(&lm->mtx);
1162        lm->locked = 0;
1163        lm->number = 1;
1164        lm->monitors = 4;
1165        list_add_tail(&lm->list, &fake_bridge->lm_resources);
1166
1167        fake_bridge->slave_get = fake_slave_get;
1168        fake_bridge->slave_set = fake_slave_set;
1169        fake_bridge->master_get = fake_master_get;
1170        fake_bridge->master_set = fake_master_set;
1171        fake_bridge->master_read = fake_master_read;
1172        fake_bridge->master_write = fake_master_write;
1173        fake_bridge->master_rmw = fake_master_rmw;
1174        fake_bridge->irq_set = fake_irq_set;
1175        fake_bridge->irq_generate = fake_irq_generate;
1176        fake_bridge->lm_set = fake_lm_set;
1177        fake_bridge->lm_get = fake_lm_get;
1178        fake_bridge->lm_attach = fake_lm_attach;
1179        fake_bridge->lm_detach = fake_lm_detach;
1180        fake_bridge->slot_get = fake_slot_get;
1181        fake_bridge->alloc_consistent = fake_alloc_consistent;
1182        fake_bridge->free_consistent = fake_free_consistent;
1183
1184        pr_info("Board is%s the VME system controller\n",
1185                        (geoid == 1) ? "" : " not");
1186
1187        pr_info("VME geographical address is set to %d\n", geoid);
1188
1189        retval = fake_crcsr_init(fake_bridge);
1190        if (retval) {
1191                pr_err("CR/CSR configuration failed.\n");
1192                goto err_crcsr;
1193        }
1194
1195        retval = vme_register_bridge(fake_bridge);
1196        if (retval != 0) {
1197                pr_err("Chip Registration failed.\n");
1198                goto err_reg;
1199        }
1200
1201        exit_pointer = fake_bridge;
1202
1203        return 0;
1204
1205err_reg:
1206        fake_crcsr_exit(fake_bridge);
1207err_crcsr:
1208err_lm:
1209        /* resources are stored in link list */
1210        list_for_each_safe(pos, n, &fake_bridge->lm_resources) {
1211                lm = list_entry(pos, struct vme_lm_resource, list);
1212                list_del(pos);
1213                kfree(lm);
1214        }
1215err_slave:
1216        /* resources are stored in link list */
1217        list_for_each_safe(pos, n, &fake_bridge->slave_resources) {
1218                slave_image = list_entry(pos, struct vme_slave_resource, list);
1219                list_del(pos);
1220                kfree(slave_image);
1221        }
1222err_master:
1223        /* resources are stored in link list */
1224        list_for_each_safe(pos, n, &fake_bridge->master_resources) {
1225                master_image = list_entry(pos, struct vme_master_resource,
1226                                list);
1227                list_del(pos);
1228                kfree(master_image);
1229        }
1230
1231        kfree(fake_device);
1232err_driver:
1233        kfree(fake_bridge);
1234err_struct:
1235        return retval;
1236
1237}
1238
1239
1240static void __exit fake_exit(void)
1241{
1242        struct list_head *pos = NULL;
1243        struct list_head *tmplist;
1244        struct vme_master_resource *master_image;
1245        struct vme_slave_resource *slave_image;
1246        int i;
1247        struct vme_bridge *fake_bridge;
1248        struct fake_driver *bridge;
1249
1250        fake_bridge = exit_pointer;
1251
1252        bridge = fake_bridge->driver_priv;
1253
1254        pr_debug("Driver is being unloaded.\n");
1255
1256        /*
1257         *  Shutdown all inbound and outbound windows.
1258         */
1259        for (i = 0; i < FAKE_MAX_MASTER; i++)
1260                bridge->masters[i].enabled = 0;
1261
1262        for (i = 0; i < FAKE_MAX_SLAVE; i++)
1263                bridge->slaves[i].enabled = 0;
1264
1265        /*
1266         *  Shutdown Location monitor.
1267         */
1268        bridge->lm_enabled = 0;
1269
1270        vme_unregister_bridge(fake_bridge);
1271
1272        fake_crcsr_exit(fake_bridge);
1273        /* resources are stored in link list */
1274        list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) {
1275                slave_image = list_entry(pos, struct vme_slave_resource, list);
1276                list_del(pos);
1277                kfree(slave_image);
1278        }
1279
1280        /* resources are stored in link list */
1281        list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) {
1282                master_image = list_entry(pos, struct vme_master_resource,
1283                                list);
1284                list_del(pos);
1285                kfree(master_image);
1286        }
1287
1288        kfree(fake_bridge->driver_priv);
1289
1290        kfree(fake_bridge);
1291
1292        root_device_unregister(vme_root);
1293}
1294
1295
1296MODULE_PARM_DESC(geoid, "Set geographical addressing");
1297module_param(geoid, int, 0);
1298
1299MODULE_DESCRIPTION("Fake VME bridge driver");
1300MODULE_LICENSE("GPL");
1301
1302module_init(fake_init);
1303module_exit(fake_exit);
1304