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