Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vme: Adding Fake VME driver

This patch introduces a fake VME bridge driver. This driver currently
emulates a subset of the VME bridge functionality. This allows some VME
subsystem development and even some VME device driver development to be
carried out in the absence of a proper VME bus.

Signed-off-by: Martyn Welch <martyn@welchs.me.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Martyn Welch and committed by
Greg Kroah-Hartman
658bcdae 050c3d52

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