mfd: kempld-core: Constify variables that point to const structure
[linux-2.6-block.git] / 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         void *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 static void *fake_pci_to_ptr(dma_addr_t addr)
118 {
119         return (void *)(uintptr_t)addr;
120 }
121
122 static dma_addr_t fake_ptr_to_pci(void *addr)
123 {
124         return (dma_addr_t)(uintptr_t)addr;
125 }
126
127 /*
128  * Generate a VME bus interrupt at the requested level & vector. Wait for
129  * interrupt to be acked.
130  */
131 static 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  */
158 static 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;
215         bridge->slaves[i].buf_base = fake_pci_to_ptr(buf_base);
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  */
227 static 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;
243         *buf_base = fake_ptr_to_pci(bridge->slaves[i].buf_base);
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  */
255 static 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) {
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:
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:
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
332 err_aspace:
333 err_dwidth:
334 err_window:
335         return retval;
336
337 }
338
339 /*
340  * Set the attributes of an outbound window.
341  */
342 static 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
364 static 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
381 static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr,
382                           u32 aspace, u32 cycle)
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)) {
412                                         if (bridge->lm_callback[i])
413                                                 bridge->lm_callback[i](
414                                                         bridge->lm_data[i]);
415                                 }
416                         }
417                 }
418         }
419 }
420
421 static 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;
441                         loc = (u8 *)(bridge->slaves[i].buf_base + offset);
442                         retval = *loc;
443
444                         break;
445                 }
446         }
447
448         fake_lm_check(bridge, addr, aspace, cycle);
449
450         return retval;
451 }
452
453 static 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;
473                         loc = (u16 *)(bridge->slaves[i].buf_base + offset);
474                         retval = *loc;
475
476                         break;
477                 }
478         }
479
480         fake_lm_check(bridge, addr, aspace, cycle);
481
482         return retval;
483 }
484
485 static 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;
505                         loc = (u32 *)(bridge->slaves[i].buf_base + offset);
506                         retval = *loc;
507
508                         break;
509                 }
510         }
511
512         fake_lm_check(bridge, addr, aspace, cycle);
513
514         return retval;
515 }
516
517 static 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
608 out:
609         retval = count;
610
611         spin_unlock(&image->lock);
612
613         return retval;
614 }
615
616 static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
617                            unsigned long long addr, u32 aspace, u32 cycle)
618 {
619         int i;
620         unsigned long long start, end, offset;
621         u8 *loc;
622
623         for (i = 0; i < FAKE_MAX_SLAVE; i++) {
624                 if (aspace != bridge->slaves[i].aspace)
625                         continue;
626
627                 if (cycle != bridge->slaves[i].cycle)
628                         continue;
629
630                 start = bridge->slaves[i].vme_base;
631                 end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
632
633                 if ((addr >= start) && (addr < end)) {
634                         offset = addr - bridge->slaves[i].vme_base;
635                         loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
636                         *loc = *buf;
637
638                         break;
639                 }
640         }
641
642         fake_lm_check(bridge, addr, aspace, cycle);
643
644 }
645
646 static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
647                             unsigned long long addr, u32 aspace, u32 cycle)
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
676 static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
677                             unsigned long long addr, u32 aspace, u32 cycle)
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
706 static 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
795 out:
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  */
808 static 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  */
854 static 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++) {
869                 if (bridge->lm_callback[i]) {
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  */
900 static 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  */
923 static 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 */
943         if (bridge->lm_callback[monitor]) {
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  */
964 static 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++) {
981                 if (bridge->lm_callback[i])
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  */
996 static int fake_slot_get(struct vme_bridge *fake_bridge)
997 {
998         return geoid;
999 }
1000
1001 static void *fake_alloc_consistent(struct device *parent, size_t size,
1002                 dma_addr_t *dma)
1003 {
1004         void *alloc = kmalloc(size, GFP_KERNEL);
1005
1006         if (alloc)
1007                 *dma = fake_ptr_to_pci(alloc);
1008
1009         return alloc;
1010 }
1011
1012 static 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  */
1032 static 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);
1041         bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel);
1042         if (!bridge->crcsr_kernel)
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
1052 static 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
1062 static 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          */
1078         fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL);
1079         if (!fake_bridge) {
1080                 retval = -ENOMEM;
1081                 goto err_struct;
1082         }
1083
1084         fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL);
1085         if (!fake_device) {
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++) {
1107                 master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
1108                 if (!master_image) {
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++) {
1133                 slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
1134                 if (!slave_image) {
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);
1155         lm = kmalloc(sizeof(*lm), GFP_KERNEL);
1156         if (!lm) {
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
1205 err_reg:
1206         fake_crcsr_exit(fake_bridge);
1207 err_crcsr:
1208 err_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         }
1215 err_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         }
1222 err_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);
1232 err_driver:
1233         kfree(fake_bridge);
1234 err_struct:
1235         return retval;
1236
1237 }
1238
1239
1240 static 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
1296 MODULE_PARM_DESC(geoid, "Set geographical addressing");
1297 module_param(geoid, int, 0);
1298
1299 MODULE_DESCRIPTION("Fake VME bridge driver");
1300 MODULE_LICENSE("GPL");
1301
1302 module_init(fake_init);
1303 module_exit(fake_exit);