]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/vme/bridges/vme_fake.c
iommu/amd: Lock dev_data in attach/detach code paths
[linux.git] / drivers / vme / bridges / vme_fake.c
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 u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
418                 u32 aspace, u32 cycle)
419 {
420         u8 retval = 0xff;
421         int i;
422         unsigned long long start, end, offset;
423         u8 *loc;
424
425         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
426                 start = bridge->slaves[i].vme_base;
427                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
428
429                 if (aspace != bridge->slaves[i].aspace)
430                         continue;
431
432                 if (cycle != bridge->slaves[i].cycle)
433                         continue;
434
435                 if ((addr >= start) && (addr < end)) {
436                         offset = addr - bridge->slaves[i].vme_base;
437                         loc = (u8 *)(bridge->slaves[i].buf_base + offset);
438                         retval = *loc;
439
440                         break;
441                 }
442         }
443
444         fake_lm_check(bridge, addr, aspace, cycle);
445
446         return retval;
447 }
448
449 static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
450                 u32 aspace, u32 cycle)
451 {
452         u16 retval = 0xffff;
453         int i;
454         unsigned long long start, end, offset;
455         u16 *loc;
456
457         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
458                 if (aspace != bridge->slaves[i].aspace)
459                         continue;
460
461                 if (cycle != bridge->slaves[i].cycle)
462                         continue;
463
464                 start = bridge->slaves[i].vme_base;
465                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
466
467                 if ((addr >= start) && ((addr + 1) < end)) {
468                         offset = addr - bridge->slaves[i].vme_base;
469                         loc = (u16 *)(bridge->slaves[i].buf_base + offset);
470                         retval = *loc;
471
472                         break;
473                 }
474         }
475
476         fake_lm_check(bridge, addr, aspace, cycle);
477
478         return retval;
479 }
480
481 static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr,
482                 u32 aspace, u32 cycle)
483 {
484         u32 retval = 0xffffffff;
485         int i;
486         unsigned long long start, end, offset;
487         u32 *loc;
488
489         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
490                 if (aspace != bridge->slaves[i].aspace)
491                         continue;
492
493                 if (cycle != bridge->slaves[i].cycle)
494                         continue;
495
496                 start = bridge->slaves[i].vme_base;
497                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
498
499                 if ((addr >= start) && ((addr + 3) < end)) {
500                         offset = addr - bridge->slaves[i].vme_base;
501                         loc = (u32 *)(bridge->slaves[i].buf_base + offset);
502                         retval = *loc;
503
504                         break;
505                 }
506         }
507
508         fake_lm_check(bridge, addr, aspace, cycle);
509
510         return retval;
511 }
512
513 static ssize_t fake_master_read(struct vme_master_resource *image, void *buf,
514                 size_t count, loff_t offset)
515 {
516         int retval;
517         u32 aspace, cycle, dwidth;
518         struct vme_bridge *fake_bridge;
519         struct fake_driver *priv;
520         int i;
521         unsigned long long addr;
522         unsigned int done = 0;
523         unsigned int count32;
524
525         fake_bridge = image->parent;
526
527         priv = fake_bridge->driver_priv;
528
529         i = image->number;
530
531         addr = (unsigned long long)priv->masters[i].vme_base + offset;
532         aspace = priv->masters[i].aspace;
533         cycle = priv->masters[i].cycle;
534         dwidth = priv->masters[i].dwidth;
535
536         spin_lock(&image->lock);
537
538         /* The following code handles VME address alignment. We cannot use
539          * memcpy_xxx here because it may cut data transfers in to 8-bit
540          * cycles when D16 or D32 cycles are required on the VME bus.
541          * On the other hand, the bridge itself assures that the maximum data
542          * cycle configured for the transfer is used and splits it
543          * automatically for non-aligned addresses, so we don't want the
544          * overhead of needlessly forcing small transfers for the entire cycle.
545          */
546         if (addr & 0x1) {
547                 *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle);
548                 done += 1;
549                 if (done == count)
550                         goto out;
551         }
552         if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
553                 if ((addr + done) & 0x2) {
554                         if ((count - done) < 2) {
555                                 *(u8 *)(buf + done) = fake_vmeread8(priv,
556                                                 addr + done, aspace, cycle);
557                                 done += 1;
558                                 goto out;
559                         } else {
560                                 *(u16 *)(buf + done) = fake_vmeread16(priv,
561                                                 addr + done, aspace, cycle);
562                                 done += 2;
563                         }
564                 }
565         }
566
567         if (dwidth == VME_D32) {
568                 count32 = (count - done) & ~0x3;
569                 while (done < count32) {
570                         *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done,
571                                         aspace, cycle);
572                         done += 4;
573                 }
574         } else if (dwidth == VME_D16) {
575                 count32 = (count - done) & ~0x3;
576                 while (done < count32) {
577                         *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
578                                         aspace, cycle);
579                         done += 2;
580                 }
581         } else if (dwidth == VME_D8) {
582                 count32 = (count - done);
583                 while (done < count32) {
584                         *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done,
585                                         aspace, cycle);
586                         done += 1;
587                 }
588
589         }
590
591         if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
592                 if ((count - done) & 0x2) {
593                         *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
594                                         aspace, cycle);
595                         done += 2;
596                 }
597         }
598         if ((count - done) & 0x1) {
599                 *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace,
600                                 cycle);
601                 done += 1;
602         }
603
604 out:
605         retval = count;
606
607         spin_unlock(&image->lock);
608
609         return retval;
610 }
611
612 static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
613                            unsigned long long addr, u32 aspace, u32 cycle)
614 {
615         int i;
616         unsigned long long start, end, offset;
617         u8 *loc;
618
619         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
620                 if (aspace != bridge->slaves[i].aspace)
621                         continue;
622
623                 if (cycle != bridge->slaves[i].cycle)
624                         continue;
625
626                 start = bridge->slaves[i].vme_base;
627                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
628
629                 if ((addr >= start) && (addr < end)) {
630                         offset = addr - bridge->slaves[i].vme_base;
631                         loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
632                         *loc = *buf;
633
634                         break;
635                 }
636         }
637
638         fake_lm_check(bridge, addr, aspace, cycle);
639
640 }
641
642 static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
643                             unsigned long long addr, u32 aspace, u32 cycle)
644 {
645         int i;
646         unsigned long long start, end, offset;
647         u16 *loc;
648
649         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
650                 if (aspace != bridge->slaves[i].aspace)
651                         continue;
652
653                 if (cycle != bridge->slaves[i].cycle)
654                         continue;
655
656                 start = bridge->slaves[i].vme_base;
657                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
658
659                 if ((addr >= start) && ((addr + 1) < end)) {
660                         offset = addr - bridge->slaves[i].vme_base;
661                         loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset);
662                         *loc = *buf;
663
664                         break;
665                 }
666         }
667
668         fake_lm_check(bridge, addr, aspace, cycle);
669
670 }
671
672 static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
673                             unsigned long long addr, u32 aspace, u32 cycle)
674 {
675         int i;
676         unsigned long long start, end, offset;
677         u32 *loc;
678
679         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
680                 if (aspace != bridge->slaves[i].aspace)
681                         continue;
682
683                 if (cycle != bridge->slaves[i].cycle)
684                         continue;
685
686                 start = bridge->slaves[i].vme_base;
687                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
688
689                 if ((addr >= start) && ((addr + 3) < end)) {
690                         offset = addr - bridge->slaves[i].vme_base;
691                         loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset);
692                         *loc = *buf;
693
694                         break;
695                 }
696         }
697
698         fake_lm_check(bridge, addr, aspace, cycle);
699
700 }
701
702 static ssize_t fake_master_write(struct vme_master_resource *image, void *buf,
703                 size_t count, loff_t offset)
704 {
705         int retval = 0;
706         u32 aspace, cycle, dwidth;
707         unsigned long long addr;
708         int i;
709         unsigned int done = 0;
710         unsigned int count32;
711
712         struct vme_bridge *fake_bridge;
713         struct fake_driver *bridge;
714
715         fake_bridge = image->parent;
716
717         bridge = fake_bridge->driver_priv;
718
719         i = image->number;
720
721         addr = bridge->masters[i].vme_base + offset;
722         aspace = bridge->masters[i].aspace;
723         cycle = bridge->masters[i].cycle;
724         dwidth = bridge->masters[i].dwidth;
725
726         spin_lock(&image->lock);
727
728         /* Here we apply for the same strategy we do in master_read
729          * function in order to assure the correct cycles.
730          */
731         if (addr & 0x1) {
732                 fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle);
733                 done += 1;
734                 if (done == count)
735                         goto out;
736         }
737
738         if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
739                 if ((addr + done) & 0x2) {
740                         if ((count - done) < 2) {
741                                 fake_vmewrite8(bridge, (u8 *)(buf + done),
742                                                 addr + done, aspace, cycle);
743                                 done += 1;
744                                 goto out;
745                         } else {
746                                 fake_vmewrite16(bridge, (u16 *)(buf + done),
747                                                 addr + done, aspace, cycle);
748                                 done += 2;
749                         }
750                 }
751         }
752
753         if (dwidth == VME_D32) {
754                 count32 = (count - done) & ~0x3;
755                 while (done < count32) {
756                         fake_vmewrite32(bridge, (u32 *)(buf + done),
757                                         addr + done, aspace, cycle);
758                         done += 4;
759                 }
760         } else if (dwidth == VME_D16) {
761                 count32 = (count - done) & ~0x3;
762                 while (done < count32) {
763                         fake_vmewrite16(bridge, (u16 *)(buf + done),
764                                         addr + done, aspace, cycle);
765                         done += 2;
766                 }
767         } else if (dwidth == VME_D8) {
768                 count32 = (count - done);
769                 while (done < count32) {
770                         fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done,
771                                         aspace, cycle);
772                         done += 1;
773                 }
774
775         }
776
777         if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
778                 if ((count - done) & 0x2) {
779                         fake_vmewrite16(bridge, (u16 *)(buf + done),
780                                         addr + done, aspace, cycle);
781                         done += 2;
782                 }
783         }
784
785         if ((count - done) & 0x1) {
786                 fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace,
787                                 cycle);
788                 done += 1;
789         }
790
791 out:
792         retval = count;
793
794         spin_unlock(&image->lock);
795
796         return retval;
797 }
798
799 /*
800  * Perform an RMW cycle on the VME bus.
801  *
802  * Requires a previously configured master window, returns final value.
803  */
804 static unsigned int fake_master_rmw(struct vme_master_resource *image,
805                 unsigned int mask, unsigned int compare, unsigned int swap,
806                 loff_t offset)
807 {
808         u32 tmp, base;
809         u32 aspace, cycle;
810         int i;
811         struct fake_driver *bridge;
812
813         bridge = image->parent->driver_priv;
814
815         /* Find the PCI address that maps to the desired VME address */
816         i = image->number;
817
818         base = bridge->masters[i].vme_base;
819         aspace = bridge->masters[i].aspace;
820         cycle = bridge->masters[i].cycle;
821
822         /* Lock image */
823         spin_lock(&image->lock);
824
825         /* Read existing value */
826         tmp = fake_vmeread32(bridge, base + offset, aspace, cycle);
827
828         /* Perform check */
829         if ((tmp && mask) == (compare && mask)) {
830                 tmp = tmp | (mask | swap);
831                 tmp = tmp & (~mask | swap);
832
833                 /* Write back */
834                 fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle);
835         }
836
837         /* Unlock image */
838         spin_unlock(&image->lock);
839
840         return tmp;
841 }
842
843 /*
844  * All 4 location monitors reside at the same base - this is therefore a
845  * system wide configuration.
846  *
847  * This does not enable the LM monitor - that should be done when the first
848  * callback is attached and disabled when the last callback is removed.
849  */
850 static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
851                 u32 aspace, u32 cycle)
852 {
853         int i;
854         struct vme_bridge *fake_bridge;
855         struct fake_driver *bridge;
856
857         fake_bridge = lm->parent;
858
859         bridge = fake_bridge->driver_priv;
860
861         mutex_lock(&lm->mtx);
862
863         /* If we already have a callback attached, we can't move it! */
864         for (i = 0; i < lm->monitors; i++) {
865                 if (bridge->lm_callback[i]) {
866                         mutex_unlock(&lm->mtx);
867                         pr_err("Location monitor callback attached, can't reset\n");
868                         return -EBUSY;
869                 }
870         }
871
872         switch (aspace) {
873         case VME_A16:
874         case VME_A24:
875         case VME_A32:
876         case VME_A64:
877                 break;
878         default:
879                 mutex_unlock(&lm->mtx);
880                 pr_err("Invalid address space\n");
881                 return -EINVAL;
882         }
883
884         bridge->lm_base = lm_base;
885         bridge->lm_aspace = aspace;
886         bridge->lm_cycle = cycle;
887
888         mutex_unlock(&lm->mtx);
889
890         return 0;
891 }
892
893 /* Get configuration of the callback monitor and return whether it is enabled
894  * or disabled.
895  */
896 static int fake_lm_get(struct vme_lm_resource *lm,
897                 unsigned long long *lm_base, u32 *aspace, u32 *cycle)
898 {
899         struct fake_driver *bridge;
900
901         bridge = lm->parent->driver_priv;
902
903         mutex_lock(&lm->mtx);
904
905         *lm_base = bridge->lm_base;
906         *aspace = bridge->lm_aspace;
907         *cycle = bridge->lm_cycle;
908
909         mutex_unlock(&lm->mtx);
910
911         return bridge->lm_enabled;
912 }
913
914 /*
915  * Attach a callback to a specific location monitor.
916  *
917  * Callback will be passed the monitor triggered.
918  */
919 static int fake_lm_attach(struct vme_lm_resource *lm, int monitor,
920                 void (*callback)(void *), void *data)
921 {
922         struct vme_bridge *fake_bridge;
923         struct fake_driver *bridge;
924
925         fake_bridge = lm->parent;
926
927         bridge = fake_bridge->driver_priv;
928
929         mutex_lock(&lm->mtx);
930
931         /* Ensure that the location monitor is configured - need PGM or DATA */
932         if (bridge->lm_cycle == 0) {
933                 mutex_unlock(&lm->mtx);
934                 pr_err("Location monitor not properly configured\n");
935                 return -EINVAL;
936         }
937
938         /* Check that a callback isn't already attached */
939         if (bridge->lm_callback[monitor]) {
940                 mutex_unlock(&lm->mtx);
941                 pr_err("Existing callback attached\n");
942                 return -EBUSY;
943         }
944
945         /* Attach callback */
946         bridge->lm_callback[monitor] = callback;
947         bridge->lm_data[monitor] = data;
948
949         /* Ensure that global Location Monitor Enable set */
950         bridge->lm_enabled = 1;
951
952         mutex_unlock(&lm->mtx);
953
954         return 0;
955 }
956
957 /*
958  * Detach a callback function forn a specific location monitor.
959  */
960 static int fake_lm_detach(struct vme_lm_resource *lm, int monitor)
961 {
962         u32 tmp;
963         int i;
964         struct fake_driver *bridge;
965
966         bridge = lm->parent->driver_priv;
967
968         mutex_lock(&lm->mtx);
969
970         /* Detach callback */
971         bridge->lm_callback[monitor] = NULL;
972         bridge->lm_data[monitor] = NULL;
973
974         /* If all location monitors disabled, disable global Location Monitor */
975         tmp = 0;
976         for (i = 0; i < lm->monitors; i++) {
977                 if (bridge->lm_callback[i])
978                         tmp = 1;
979         }
980
981         if (tmp == 0)
982                 bridge->lm_enabled = 0;
983
984         mutex_unlock(&lm->mtx);
985
986         return 0;
987 }
988
989 /*
990  * Determine Geographical Addressing
991  */
992 static int fake_slot_get(struct vme_bridge *fake_bridge)
993 {
994         return geoid;
995 }
996
997 static void *fake_alloc_consistent(struct device *parent, size_t size,
998                 dma_addr_t *dma)
999 {
1000         void *alloc = kmalloc(size, GFP_KERNEL);
1001
1002         if (alloc)
1003                 *dma = fake_ptr_to_pci(alloc);
1004
1005         return alloc;
1006 }
1007
1008 static void fake_free_consistent(struct device *parent, size_t size,
1009                 void *vaddr, dma_addr_t dma)
1010 {
1011         kfree(vaddr);
1012 /*
1013         dma_free_coherent(parent, size, vaddr, dma);
1014 */
1015 }
1016
1017 /*
1018  * Configure CR/CSR space
1019  *
1020  * Access to the CR/CSR can be configured at power-up. The location of the
1021  * CR/CSR registers in the CR/CSR address space is determined by the boards
1022  * Geographic address.
1023  *
1024  * Each board has a 512kB window, with the highest 4kB being used for the
1025  * boards registers, this means there is a fix length 508kB window which must
1026  * be mapped onto PCI memory.
1027  */
1028 static int fake_crcsr_init(struct vme_bridge *fake_bridge)
1029 {
1030         u32 vstat;
1031         struct fake_driver *bridge;
1032
1033         bridge = fake_bridge->driver_priv;
1034
1035         /* Allocate mem for CR/CSR image */
1036         bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL);
1037         bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel);
1038         if (!bridge->crcsr_kernel)
1039                 return -ENOMEM;
1040
1041         vstat = fake_slot_get(fake_bridge);
1042
1043         pr_info("CR/CSR Offset: %d\n", vstat);
1044
1045         return 0;
1046 }
1047
1048 static void fake_crcsr_exit(struct vme_bridge *fake_bridge)
1049 {
1050         struct fake_driver *bridge;
1051
1052         bridge = fake_bridge->driver_priv;
1053
1054         kfree(bridge->crcsr_kernel);
1055 }
1056
1057
1058 static int __init fake_init(void)
1059 {
1060         int retval, i;
1061         struct list_head *pos = NULL, *n;
1062         struct vme_bridge *fake_bridge;
1063         struct fake_driver *fake_device;
1064         struct vme_master_resource *master_image;
1065         struct vme_slave_resource *slave_image;
1066         struct vme_lm_resource *lm;
1067
1068         /* We need a fake parent device */
1069         vme_root = __root_device_register("vme", THIS_MODULE);
1070
1071         /* If we want to support more than one bridge at some point, we need to
1072          * dynamically allocate this so we get one per device.
1073          */
1074         fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL);
1075         if (!fake_bridge) {
1076                 retval = -ENOMEM;
1077                 goto err_struct;
1078         }
1079
1080         fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL);
1081         if (!fake_device) {
1082                 retval = -ENOMEM;
1083                 goto err_driver;
1084         }
1085
1086         fake_bridge->driver_priv = fake_device;
1087
1088         fake_bridge->parent = vme_root;
1089
1090         fake_device->parent = fake_bridge;
1091
1092         /* Initialize wait queues & mutual exclusion flags */
1093         mutex_init(&fake_device->vme_int);
1094         mutex_init(&fake_bridge->irq_mtx);
1095         tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet,
1096                         (unsigned long) fake_bridge);
1097
1098         strcpy(fake_bridge->name, driver_name);
1099
1100         /* Add master windows to list */
1101         INIT_LIST_HEAD(&fake_bridge->master_resources);
1102         for (i = 0; i < FAKE_MAX_MASTER; i++) {
1103                 master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
1104                 if (!master_image) {
1105                         retval = -ENOMEM;
1106                         goto err_master;
1107                 }
1108                 master_image->parent = fake_bridge;
1109                 spin_lock_init(&master_image->lock);
1110                 master_image->locked = 0;
1111                 master_image->number = i;
1112                 master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
1113                         VME_A64;
1114                 master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
1115                         VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
1116                         VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
1117                         VME_PROG | VME_DATA;
1118                 master_image->width_attr = VME_D16 | VME_D32;
1119                 memset(&master_image->bus_resource, 0,
1120                                 sizeof(struct resource));
1121                 master_image->kern_base  = NULL;
1122                 list_add_tail(&master_image->list,
1123                                 &fake_bridge->master_resources);
1124         }
1125
1126         /* Add slave windows to list */
1127         INIT_LIST_HEAD(&fake_bridge->slave_resources);
1128         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
1129                 slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
1130                 if (!slave_image) {
1131                         retval = -ENOMEM;
1132                         goto err_slave;
1133                 }
1134                 slave_image->parent = fake_bridge;
1135                 mutex_init(&slave_image->mtx);
1136                 slave_image->locked = 0;
1137                 slave_image->number = i;
1138                 slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
1139                         VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
1140                         VME_USER3 | VME_USER4;
1141                 slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
1142                         VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
1143                         VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
1144                         VME_PROG | VME_DATA;
1145                 list_add_tail(&slave_image->list,
1146                                 &fake_bridge->slave_resources);
1147         }
1148
1149         /* Add location monitor to list */
1150         INIT_LIST_HEAD(&fake_bridge->lm_resources);
1151         lm = kmalloc(sizeof(*lm), GFP_KERNEL);
1152         if (!lm) {
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);