root/drivers/vme/bridges/vme_fake.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fake_VIRQ_tasklet
  2. fake_irq_set
  3. fake_pci_to_ptr
  4. fake_ptr_to_pci
  5. fake_irq_generate
  6. fake_slave_set
  7. fake_slave_get
  8. fake_master_set
  9. __fake_master_get
  10. fake_master_get
  11. fake_lm_check
  12. fake_vmeread8
  13. fake_vmeread16
  14. fake_vmeread32
  15. fake_master_read
  16. fake_vmewrite8
  17. fake_vmewrite16
  18. fake_vmewrite32
  19. fake_master_write
  20. fake_master_rmw
  21. fake_lm_set
  22. fake_lm_get
  23. fake_lm_attach
  24. fake_lm_detach
  25. fake_slot_get
  26. fake_alloc_consistent
  27. fake_free_consistent
  28. fake_crcsr_init
  29. fake_crcsr_exit
  30. fake_init
  31. fake_exit

   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 */
  43 struct 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 
  52 struct 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 */
  62 struct 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 */
  82 static int geoid;
  83 
  84 static const char driver_name[] = "vme_fake";
  85 
  86 static struct vme_bridge *exit_pointer;
  87 
  88 static struct device *vme_root;
  89 
  90 /*
  91  * Calling VME bus interrupt callback if provided.
  92  */
  93 static 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  */
 107 static void fake_irq_set(struct vme_bridge *fake_bridge, int level,
 108                 int state, int sync)
 109 {
 110         /* Nothing to do */
 111 }
 112 
 113 static void *fake_pci_to_ptr(dma_addr_t addr)
 114 {
 115         return (void *)(uintptr_t)addr;
 116 }
 117 
 118 static 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  */
 127 static 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  */
 154 static 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  */
 223 static 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  */
 251 static 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 
 328 err_aspace:
 329 err_dwidth:
 330 err_window:
 331         return retval;
 332 
 333 }
 334 
 335 /*
 336  * Set the attributes of an outbound window.
 337  */
 338 static 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 
 360 static 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 
 377 static 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 
 417 static 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 
 450 static 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 
 483 static 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 
 516 static 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 
 607 out:
 608         retval = count;
 609 
 610         spin_unlock(&image->lock);
 611 
 612         return retval;
 613 }
 614 
 615 static 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 
 646 static 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 
 677 static 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 
 708 static 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 
 797 out:
 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  */
 810 static 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  */
 856 static 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  */
 902 static 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  */
 925 static 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  */
 966 static 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  */
 998 static int fake_slot_get(struct vme_bridge *fake_bridge)
 999 {
1000         return geoid;
1001 }
1002 
1003 static 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 
1014 static 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  */
1034 static 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 
1054 static 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 
1064 static 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 
1207 err_reg:
1208         fake_crcsr_exit(fake_bridge);
1209 err_crcsr:
1210 err_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         }
1217 err_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         }
1224 err_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);
1234 err_driver:
1235         kfree(fake_bridge);
1236 err_struct:
1237         return retval;
1238 
1239 }
1240 
1241 
1242 static 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 
1298 MODULE_PARM_DESC(geoid, "Set geographical addressing");
1299 module_param(geoid, int, 0);
1300 
1301 MODULE_DESCRIPTION("Fake VME bridge driver");
1302 MODULE_LICENSE("GPL");
1303 
1304 module_init(fake_init);
1305 module_exit(fake_exit);

/* [<][>][^][v][top][bottom][index][help] */