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