cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vme_fake.c (30064B)


      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 */
     43struct 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
     52struct 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 */
     62struct 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 */
     82static int geoid;
     83
     84static const char driver_name[] = "vme_fake";
     85
     86static struct vme_bridge *exit_pointer;
     87
     88static struct device *vme_root;
     89
     90/*
     91 * Calling VME bus interrupt callback if provided.
     92 */
     93static 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 */
    107static void fake_irq_set(struct vme_bridge *fake_bridge, int level,
    108		int state, int sync)
    109{
    110	/* Nothing to do */
    111}
    112
    113static void *fake_pci_to_ptr(dma_addr_t addr)
    114{
    115	return (void *)(uintptr_t)addr;
    116}
    117
    118static 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 */
    127static 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 */
    154static 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 */
    223static 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 */
    251static 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
    328err_aspace:
    329err_dwidth:
    330err_window:
    331	return retval;
    332
    333}
    334
    335/*
    336 * Set the attributes of an outbound window.
    337 */
    338static 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
    360static 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
    377static 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
    417static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge,
    418					   unsigned long long addr,
    419					   u32 aspace, u32 cycle)
    420{
    421	u8 retval = 0xff;
    422	int i;
    423	unsigned long long start, end, offset;
    424	u8 *loc;
    425
    426	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    427		start = bridge->slaves[i].vme_base;
    428		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    429
    430		if (aspace != bridge->slaves[i].aspace)
    431			continue;
    432
    433		if (cycle != bridge->slaves[i].cycle)
    434			continue;
    435
    436		if ((addr >= start) && (addr < end)) {
    437			offset = addr - bridge->slaves[i].vme_base;
    438			loc = (u8 *)(bridge->slaves[i].buf_base + offset);
    439			retval = *loc;
    440
    441			break;
    442		}
    443	}
    444
    445	fake_lm_check(bridge, addr, aspace, cycle);
    446
    447	return retval;
    448}
    449
    450static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge,
    451					     unsigned long long addr,
    452					     u32 aspace, u32 cycle)
    453{
    454	u16 retval = 0xffff;
    455	int i;
    456	unsigned long long start, end, offset;
    457	u16 *loc;
    458
    459	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    460		if (aspace != bridge->slaves[i].aspace)
    461			continue;
    462
    463		if (cycle != bridge->slaves[i].cycle)
    464			continue;
    465
    466		start = bridge->slaves[i].vme_base;
    467		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    468
    469		if ((addr >= start) && ((addr + 1) < end)) {
    470			offset = addr - bridge->slaves[i].vme_base;
    471			loc = (u16 *)(bridge->slaves[i].buf_base + offset);
    472			retval = *loc;
    473
    474			break;
    475		}
    476	}
    477
    478	fake_lm_check(bridge, addr, aspace, cycle);
    479
    480	return retval;
    481}
    482
    483static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge,
    484					     unsigned long long addr,
    485					     u32 aspace, u32 cycle)
    486{
    487	u32 retval = 0xffffffff;
    488	int i;
    489	unsigned long long start, end, offset;
    490	u32 *loc;
    491
    492	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    493		if (aspace != bridge->slaves[i].aspace)
    494			continue;
    495
    496		if (cycle != bridge->slaves[i].cycle)
    497			continue;
    498
    499		start = bridge->slaves[i].vme_base;
    500		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    501
    502		if ((addr >= start) && ((addr + 3) < end)) {
    503			offset = addr - bridge->slaves[i].vme_base;
    504			loc = (u32 *)(bridge->slaves[i].buf_base + offset);
    505			retval = *loc;
    506
    507			break;
    508		}
    509	}
    510
    511	fake_lm_check(bridge, addr, aspace, cycle);
    512
    513	return retval;
    514}
    515
    516static ssize_t fake_master_read(struct vme_master_resource *image, void *buf,
    517		size_t count, loff_t offset)
    518{
    519	int retval;
    520	u32 aspace, cycle, dwidth;
    521	struct vme_bridge *fake_bridge;
    522	struct fake_driver *priv;
    523	int i;
    524	unsigned long long addr;
    525	unsigned int done = 0;
    526	unsigned int count32;
    527
    528	fake_bridge = image->parent;
    529
    530	priv = fake_bridge->driver_priv;
    531
    532	i = image->number;
    533
    534	addr = (unsigned long long)priv->masters[i].vme_base + offset;
    535	aspace = priv->masters[i].aspace;
    536	cycle = priv->masters[i].cycle;
    537	dwidth = priv->masters[i].dwidth;
    538
    539	spin_lock(&image->lock);
    540
    541	/* The following code handles VME address alignment. We cannot use
    542	 * memcpy_xxx here because it may cut data transfers in to 8-bit
    543	 * cycles when D16 or D32 cycles are required on the VME bus.
    544	 * On the other hand, the bridge itself assures that the maximum data
    545	 * cycle configured for the transfer is used and splits it
    546	 * automatically for non-aligned addresses, so we don't want the
    547	 * overhead of needlessly forcing small transfers for the entire cycle.
    548	 */
    549	if (addr & 0x1) {
    550		*(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle);
    551		done += 1;
    552		if (done == count)
    553			goto out;
    554	}
    555	if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
    556		if ((addr + done) & 0x2) {
    557			if ((count - done) < 2) {
    558				*(u8 *)(buf + done) = fake_vmeread8(priv,
    559						addr + done, aspace, cycle);
    560				done += 1;
    561				goto out;
    562			} else {
    563				*(u16 *)(buf + done) = fake_vmeread16(priv,
    564						addr + done, aspace, cycle);
    565				done += 2;
    566			}
    567		}
    568	}
    569
    570	if (dwidth == VME_D32) {
    571		count32 = (count - done) & ~0x3;
    572		while (done < count32) {
    573			*(u32 *)(buf + done) = fake_vmeread32(priv, addr + done,
    574					aspace, cycle);
    575			done += 4;
    576		}
    577	} else if (dwidth == VME_D16) {
    578		count32 = (count - done) & ~0x3;
    579		while (done < count32) {
    580			*(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
    581					aspace, cycle);
    582			done += 2;
    583		}
    584	} else if (dwidth == VME_D8) {
    585		count32 = (count - done);
    586		while (done < count32) {
    587			*(u8 *)(buf + done) = fake_vmeread8(priv, addr + done,
    588					aspace, cycle);
    589			done += 1;
    590		}
    591
    592	}
    593
    594	if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
    595		if ((count - done) & 0x2) {
    596			*(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
    597					aspace, cycle);
    598			done += 2;
    599		}
    600	}
    601	if ((count - done) & 0x1) {
    602		*(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace,
    603				cycle);
    604		done += 1;
    605	}
    606
    607out:
    608	retval = count;
    609
    610	spin_unlock(&image->lock);
    611
    612	return retval;
    613}
    614
    615static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge,
    616					      u8 *buf, unsigned long long addr,
    617					      u32 aspace, u32 cycle)
    618{
    619	int i;
    620	unsigned long long start, end, offset;
    621	u8 *loc;
    622
    623	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    624		if (aspace != bridge->slaves[i].aspace)
    625			continue;
    626
    627		if (cycle != bridge->slaves[i].cycle)
    628			continue;
    629
    630		start = bridge->slaves[i].vme_base;
    631		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    632
    633		if ((addr >= start) && (addr < end)) {
    634			offset = addr - bridge->slaves[i].vme_base;
    635			loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
    636			*loc = *buf;
    637
    638			break;
    639		}
    640	}
    641
    642	fake_lm_check(bridge, addr, aspace, cycle);
    643
    644}
    645
    646static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge,
    647					       u16 *buf, unsigned long long addr,
    648					       u32 aspace, u32 cycle)
    649{
    650	int i;
    651	unsigned long long start, end, offset;
    652	u16 *loc;
    653
    654	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    655		if (aspace != bridge->slaves[i].aspace)
    656			continue;
    657
    658		if (cycle != bridge->slaves[i].cycle)
    659			continue;
    660
    661		start = bridge->slaves[i].vme_base;
    662		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    663
    664		if ((addr >= start) && ((addr + 1) < end)) {
    665			offset = addr - bridge->slaves[i].vme_base;
    666			loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset);
    667			*loc = *buf;
    668
    669			break;
    670		}
    671	}
    672
    673	fake_lm_check(bridge, addr, aspace, cycle);
    674
    675}
    676
    677static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge,
    678					       u32 *buf, unsigned long long addr,
    679					       u32 aspace, u32 cycle)
    680{
    681	int i;
    682	unsigned long long start, end, offset;
    683	u32 *loc;
    684
    685	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
    686		if (aspace != bridge->slaves[i].aspace)
    687			continue;
    688
    689		if (cycle != bridge->slaves[i].cycle)
    690			continue;
    691
    692		start = bridge->slaves[i].vme_base;
    693		end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
    694
    695		if ((addr >= start) && ((addr + 3) < end)) {
    696			offset = addr - bridge->slaves[i].vme_base;
    697			loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset);
    698			*loc = *buf;
    699
    700			break;
    701		}
    702	}
    703
    704	fake_lm_check(bridge, addr, aspace, cycle);
    705
    706}
    707
    708static ssize_t fake_master_write(struct vme_master_resource *image, void *buf,
    709		size_t count, loff_t offset)
    710{
    711	int retval = 0;
    712	u32 aspace, cycle, dwidth;
    713	unsigned long long addr;
    714	int i;
    715	unsigned int done = 0;
    716	unsigned int count32;
    717
    718	struct vme_bridge *fake_bridge;
    719	struct fake_driver *bridge;
    720
    721	fake_bridge = image->parent;
    722
    723	bridge = fake_bridge->driver_priv;
    724
    725	i = image->number;
    726
    727	addr = bridge->masters[i].vme_base + offset;
    728	aspace = bridge->masters[i].aspace;
    729	cycle = bridge->masters[i].cycle;
    730	dwidth = bridge->masters[i].dwidth;
    731
    732	spin_lock(&image->lock);
    733
    734	/* Here we apply for the same strategy we do in master_read
    735	 * function in order to assure the correct cycles.
    736	 */
    737	if (addr & 0x1) {
    738		fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle);
    739		done += 1;
    740		if (done == count)
    741			goto out;
    742	}
    743
    744	if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
    745		if ((addr + done) & 0x2) {
    746			if ((count - done) < 2) {
    747				fake_vmewrite8(bridge, (u8 *)(buf + done),
    748						addr + done, aspace, cycle);
    749				done += 1;
    750				goto out;
    751			} else {
    752				fake_vmewrite16(bridge, (u16 *)(buf + done),
    753						addr + done, aspace, cycle);
    754				done += 2;
    755			}
    756		}
    757	}
    758
    759	if (dwidth == VME_D32) {
    760		count32 = (count - done) & ~0x3;
    761		while (done < count32) {
    762			fake_vmewrite32(bridge, (u32 *)(buf + done),
    763					addr + done, aspace, cycle);
    764			done += 4;
    765		}
    766	} else if (dwidth == VME_D16) {
    767		count32 = (count - done) & ~0x3;
    768		while (done < count32) {
    769			fake_vmewrite16(bridge, (u16 *)(buf + done),
    770					addr + done, aspace, cycle);
    771			done += 2;
    772		}
    773	} else if (dwidth == VME_D8) {
    774		count32 = (count - done);
    775		while (done < count32) {
    776			fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done,
    777					aspace, cycle);
    778			done += 1;
    779		}
    780
    781	}
    782
    783	if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
    784		if ((count - done) & 0x2) {
    785			fake_vmewrite16(bridge, (u16 *)(buf + done),
    786					addr + done, aspace, cycle);
    787			done += 2;
    788		}
    789	}
    790
    791	if ((count - done) & 0x1) {
    792		fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace,
    793				cycle);
    794		done += 1;
    795	}
    796
    797out:
    798	retval = count;
    799
    800	spin_unlock(&image->lock);
    801
    802	return retval;
    803}
    804
    805/*
    806 * Perform an RMW cycle on the VME bus.
    807 *
    808 * Requires a previously configured master window, returns final value.
    809 */
    810static unsigned int fake_master_rmw(struct vme_master_resource *image,
    811		unsigned int mask, unsigned int compare, unsigned int swap,
    812		loff_t offset)
    813{
    814	u32 tmp, base;
    815	u32 aspace, cycle;
    816	int i;
    817	struct fake_driver *bridge;
    818
    819	bridge = image->parent->driver_priv;
    820
    821	/* Find the PCI address that maps to the desired VME address */
    822	i = image->number;
    823
    824	base = bridge->masters[i].vme_base;
    825	aspace = bridge->masters[i].aspace;
    826	cycle = bridge->masters[i].cycle;
    827
    828	/* Lock image */
    829	spin_lock(&image->lock);
    830
    831	/* Read existing value */
    832	tmp = fake_vmeread32(bridge, base + offset, aspace, cycle);
    833
    834	/* Perform check */
    835	if ((tmp && mask) == (compare && mask)) {
    836		tmp = tmp | (mask | swap);
    837		tmp = tmp & (~mask | swap);
    838
    839		/* Write back */
    840		fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle);
    841	}
    842
    843	/* Unlock image */
    844	spin_unlock(&image->lock);
    845
    846	return tmp;
    847}
    848
    849/*
    850 * All 4 location monitors reside at the same base - this is therefore a
    851 * system wide configuration.
    852 *
    853 * This does not enable the LM monitor - that should be done when the first
    854 * callback is attached and disabled when the last callback is removed.
    855 */
    856static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
    857		u32 aspace, u32 cycle)
    858{
    859	int i;
    860	struct vme_bridge *fake_bridge;
    861	struct fake_driver *bridge;
    862
    863	fake_bridge = lm->parent;
    864
    865	bridge = fake_bridge->driver_priv;
    866
    867	mutex_lock(&lm->mtx);
    868
    869	/* If we already have a callback attached, we can't move it! */
    870	for (i = 0; i < lm->monitors; i++) {
    871		if (bridge->lm_callback[i]) {
    872			mutex_unlock(&lm->mtx);
    873			pr_err("Location monitor callback attached, can't reset\n");
    874			return -EBUSY;
    875		}
    876	}
    877
    878	switch (aspace) {
    879	case VME_A16:
    880	case VME_A24:
    881	case VME_A32:
    882	case VME_A64:
    883		break;
    884	default:
    885		mutex_unlock(&lm->mtx);
    886		pr_err("Invalid address space\n");
    887		return -EINVAL;
    888	}
    889
    890	bridge->lm_base = lm_base;
    891	bridge->lm_aspace = aspace;
    892	bridge->lm_cycle = cycle;
    893
    894	mutex_unlock(&lm->mtx);
    895
    896	return 0;
    897}
    898
    899/* Get configuration of the callback monitor and return whether it is enabled
    900 * or disabled.
    901 */
    902static int fake_lm_get(struct vme_lm_resource *lm,
    903		unsigned long long *lm_base, u32 *aspace, u32 *cycle)
    904{
    905	struct fake_driver *bridge;
    906
    907	bridge = lm->parent->driver_priv;
    908
    909	mutex_lock(&lm->mtx);
    910
    911	*lm_base = bridge->lm_base;
    912	*aspace = bridge->lm_aspace;
    913	*cycle = bridge->lm_cycle;
    914
    915	mutex_unlock(&lm->mtx);
    916
    917	return bridge->lm_enabled;
    918}
    919
    920/*
    921 * Attach a callback to a specific location monitor.
    922 *
    923 * Callback will be passed the monitor triggered.
    924 */
    925static int fake_lm_attach(struct vme_lm_resource *lm, int monitor,
    926		void (*callback)(void *), void *data)
    927{
    928	struct vme_bridge *fake_bridge;
    929	struct fake_driver *bridge;
    930
    931	fake_bridge = lm->parent;
    932
    933	bridge = fake_bridge->driver_priv;
    934
    935	mutex_lock(&lm->mtx);
    936
    937	/* Ensure that the location monitor is configured - need PGM or DATA */
    938	if (bridge->lm_cycle == 0) {
    939		mutex_unlock(&lm->mtx);
    940		pr_err("Location monitor not properly configured\n");
    941		return -EINVAL;
    942	}
    943
    944	/* Check that a callback isn't already attached */
    945	if (bridge->lm_callback[monitor]) {
    946		mutex_unlock(&lm->mtx);
    947		pr_err("Existing callback attached\n");
    948		return -EBUSY;
    949	}
    950
    951	/* Attach callback */
    952	bridge->lm_callback[monitor] = callback;
    953	bridge->lm_data[monitor] = data;
    954
    955	/* Ensure that global Location Monitor Enable set */
    956	bridge->lm_enabled = 1;
    957
    958	mutex_unlock(&lm->mtx);
    959
    960	return 0;
    961}
    962
    963/*
    964 * Detach a callback function forn a specific location monitor.
    965 */
    966static int fake_lm_detach(struct vme_lm_resource *lm, int monitor)
    967{
    968	u32 tmp;
    969	int i;
    970	struct fake_driver *bridge;
    971
    972	bridge = lm->parent->driver_priv;
    973
    974	mutex_lock(&lm->mtx);
    975
    976	/* Detach callback */
    977	bridge->lm_callback[monitor] = NULL;
    978	bridge->lm_data[monitor] = NULL;
    979
    980	/* If all location monitors disabled, disable global Location Monitor */
    981	tmp = 0;
    982	for (i = 0; i < lm->monitors; i++) {
    983		if (bridge->lm_callback[i])
    984			tmp = 1;
    985	}
    986
    987	if (tmp == 0)
    988		bridge->lm_enabled = 0;
    989
    990	mutex_unlock(&lm->mtx);
    991
    992	return 0;
    993}
    994
    995/*
    996 * Determine Geographical Addressing
    997 */
    998static int fake_slot_get(struct vme_bridge *fake_bridge)
    999{
   1000	return geoid;
   1001}
   1002
   1003static void *fake_alloc_consistent(struct device *parent, size_t size,
   1004		dma_addr_t *dma)
   1005{
   1006	void *alloc = kmalloc(size, GFP_KERNEL);
   1007
   1008	if (alloc)
   1009		*dma = fake_ptr_to_pci(alloc);
   1010
   1011	return alloc;
   1012}
   1013
   1014static void fake_free_consistent(struct device *parent, size_t size,
   1015		void *vaddr, dma_addr_t dma)
   1016{
   1017	kfree(vaddr);
   1018/*
   1019	dma_free_coherent(parent, size, vaddr, dma);
   1020*/
   1021}
   1022
   1023/*
   1024 * Configure CR/CSR space
   1025 *
   1026 * Access to the CR/CSR can be configured at power-up. The location of the
   1027 * CR/CSR registers in the CR/CSR address space is determined by the boards
   1028 * Geographic address.
   1029 *
   1030 * Each board has a 512kB window, with the highest 4kB being used for the
   1031 * boards registers, this means there is a fix length 508kB window which must
   1032 * be mapped onto PCI memory.
   1033 */
   1034static int fake_crcsr_init(struct vme_bridge *fake_bridge)
   1035{
   1036	u32 vstat;
   1037	struct fake_driver *bridge;
   1038
   1039	bridge = fake_bridge->driver_priv;
   1040
   1041	/* Allocate mem for CR/CSR image */
   1042	bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL);
   1043	bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel);
   1044	if (!bridge->crcsr_kernel)
   1045		return -ENOMEM;
   1046
   1047	vstat = fake_slot_get(fake_bridge);
   1048
   1049	pr_info("CR/CSR Offset: %d\n", vstat);
   1050
   1051	return 0;
   1052}
   1053
   1054static void fake_crcsr_exit(struct vme_bridge *fake_bridge)
   1055{
   1056	struct fake_driver *bridge;
   1057
   1058	bridge = fake_bridge->driver_priv;
   1059
   1060	kfree(bridge->crcsr_kernel);
   1061}
   1062
   1063
   1064static int __init fake_init(void)
   1065{
   1066	int retval, i;
   1067	struct list_head *pos = NULL, *n;
   1068	struct vme_bridge *fake_bridge;
   1069	struct fake_driver *fake_device;
   1070	struct vme_master_resource *master_image;
   1071	struct vme_slave_resource *slave_image;
   1072	struct vme_lm_resource *lm;
   1073
   1074	/* We need a fake parent device */
   1075	vme_root = __root_device_register("vme", THIS_MODULE);
   1076
   1077	/* If we want to support more than one bridge at some point, we need to
   1078	 * dynamically allocate this so we get one per device.
   1079	 */
   1080	fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL);
   1081	if (!fake_bridge) {
   1082		retval = -ENOMEM;
   1083		goto err_struct;
   1084	}
   1085
   1086	fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL);
   1087	if (!fake_device) {
   1088		retval = -ENOMEM;
   1089		goto err_driver;
   1090	}
   1091
   1092	fake_bridge->driver_priv = fake_device;
   1093
   1094	fake_bridge->parent = vme_root;
   1095
   1096	fake_device->parent = fake_bridge;
   1097
   1098	/* Initialize wait queues & mutual exclusion flags */
   1099	mutex_init(&fake_device->vme_int);
   1100	mutex_init(&fake_bridge->irq_mtx);
   1101	tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet,
   1102			(unsigned long) fake_bridge);
   1103
   1104	strcpy(fake_bridge->name, driver_name);
   1105
   1106	/* Add master windows to list */
   1107	INIT_LIST_HEAD(&fake_bridge->master_resources);
   1108	for (i = 0; i < FAKE_MAX_MASTER; i++) {
   1109		master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
   1110		if (!master_image) {
   1111			retval = -ENOMEM;
   1112			goto err_master;
   1113		}
   1114		master_image->parent = fake_bridge;
   1115		spin_lock_init(&master_image->lock);
   1116		master_image->locked = 0;
   1117		master_image->number = i;
   1118		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
   1119			VME_A64;
   1120		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
   1121			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
   1122			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
   1123			VME_PROG | VME_DATA;
   1124		master_image->width_attr = VME_D16 | VME_D32;
   1125		memset(&master_image->bus_resource, 0,
   1126				sizeof(struct resource));
   1127		master_image->kern_base  = NULL;
   1128		list_add_tail(&master_image->list,
   1129				&fake_bridge->master_resources);
   1130	}
   1131
   1132	/* Add slave windows to list */
   1133	INIT_LIST_HEAD(&fake_bridge->slave_resources);
   1134	for (i = 0; i < FAKE_MAX_SLAVE; i++) {
   1135		slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
   1136		if (!slave_image) {
   1137			retval = -ENOMEM;
   1138			goto err_slave;
   1139		}
   1140		slave_image->parent = fake_bridge;
   1141		mutex_init(&slave_image->mtx);
   1142		slave_image->locked = 0;
   1143		slave_image->number = i;
   1144		slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
   1145			VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
   1146			VME_USER3 | VME_USER4;
   1147		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
   1148			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
   1149			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
   1150			VME_PROG | VME_DATA;
   1151		list_add_tail(&slave_image->list,
   1152				&fake_bridge->slave_resources);
   1153	}
   1154
   1155	/* Add location monitor to list */
   1156	INIT_LIST_HEAD(&fake_bridge->lm_resources);
   1157	lm = kmalloc(sizeof(*lm), GFP_KERNEL);
   1158	if (!lm) {
   1159		retval = -ENOMEM;
   1160		goto err_lm;
   1161	}
   1162	lm->parent = fake_bridge;
   1163	mutex_init(&lm->mtx);
   1164	lm->locked = 0;
   1165	lm->number = 1;
   1166	lm->monitors = 4;
   1167	list_add_tail(&lm->list, &fake_bridge->lm_resources);
   1168
   1169	fake_bridge->slave_get = fake_slave_get;
   1170	fake_bridge->slave_set = fake_slave_set;
   1171	fake_bridge->master_get = fake_master_get;
   1172	fake_bridge->master_set = fake_master_set;
   1173	fake_bridge->master_read = fake_master_read;
   1174	fake_bridge->master_write = fake_master_write;
   1175	fake_bridge->master_rmw = fake_master_rmw;
   1176	fake_bridge->irq_set = fake_irq_set;
   1177	fake_bridge->irq_generate = fake_irq_generate;
   1178	fake_bridge->lm_set = fake_lm_set;
   1179	fake_bridge->lm_get = fake_lm_get;
   1180	fake_bridge->lm_attach = fake_lm_attach;
   1181	fake_bridge->lm_detach = fake_lm_detach;
   1182	fake_bridge->slot_get = fake_slot_get;
   1183	fake_bridge->alloc_consistent = fake_alloc_consistent;
   1184	fake_bridge->free_consistent = fake_free_consistent;
   1185
   1186	pr_info("Board is%s the VME system controller\n",
   1187			(geoid == 1) ? "" : " not");
   1188
   1189	pr_info("VME geographical address is set to %d\n", geoid);
   1190
   1191	retval = fake_crcsr_init(fake_bridge);
   1192	if (retval) {
   1193		pr_err("CR/CSR configuration failed.\n");
   1194		goto err_crcsr;
   1195	}
   1196
   1197	retval = vme_register_bridge(fake_bridge);
   1198	if (retval != 0) {
   1199		pr_err("Chip Registration failed.\n");
   1200		goto err_reg;
   1201	}
   1202
   1203	exit_pointer = fake_bridge;
   1204
   1205	return 0;
   1206
   1207err_reg:
   1208	fake_crcsr_exit(fake_bridge);
   1209err_crcsr:
   1210err_lm:
   1211	/* resources are stored in link list */
   1212	list_for_each_safe(pos, n, &fake_bridge->lm_resources) {
   1213		lm = list_entry(pos, struct vme_lm_resource, list);
   1214		list_del(pos);
   1215		kfree(lm);
   1216	}
   1217err_slave:
   1218	/* resources are stored in link list */
   1219	list_for_each_safe(pos, n, &fake_bridge->slave_resources) {
   1220		slave_image = list_entry(pos, struct vme_slave_resource, list);
   1221		list_del(pos);
   1222		kfree(slave_image);
   1223	}
   1224err_master:
   1225	/* resources are stored in link list */
   1226	list_for_each_safe(pos, n, &fake_bridge->master_resources) {
   1227		master_image = list_entry(pos, struct vme_master_resource,
   1228				list);
   1229		list_del(pos);
   1230		kfree(master_image);
   1231	}
   1232
   1233	kfree(fake_device);
   1234err_driver:
   1235	kfree(fake_bridge);
   1236err_struct:
   1237	return retval;
   1238
   1239}
   1240
   1241
   1242static void __exit fake_exit(void)
   1243{
   1244	struct list_head *pos = NULL;
   1245	struct list_head *tmplist;
   1246	struct vme_master_resource *master_image;
   1247	struct vme_slave_resource *slave_image;
   1248	int i;
   1249	struct vme_bridge *fake_bridge;
   1250	struct fake_driver *bridge;
   1251
   1252	fake_bridge = exit_pointer;
   1253
   1254	bridge = fake_bridge->driver_priv;
   1255
   1256	pr_debug("Driver is being unloaded.\n");
   1257
   1258	/*
   1259	 *  Shutdown all inbound and outbound windows.
   1260	 */
   1261	for (i = 0; i < FAKE_MAX_MASTER; i++)
   1262		bridge->masters[i].enabled = 0;
   1263
   1264	for (i = 0; i < FAKE_MAX_SLAVE; i++)
   1265		bridge->slaves[i].enabled = 0;
   1266
   1267	/*
   1268	 *  Shutdown Location monitor.
   1269	 */
   1270	bridge->lm_enabled = 0;
   1271
   1272	vme_unregister_bridge(fake_bridge);
   1273
   1274	fake_crcsr_exit(fake_bridge);
   1275	/* resources are stored in link list */
   1276	list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) {
   1277		slave_image = list_entry(pos, struct vme_slave_resource, list);
   1278		list_del(pos);
   1279		kfree(slave_image);
   1280	}
   1281
   1282	/* resources are stored in link list */
   1283	list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) {
   1284		master_image = list_entry(pos, struct vme_master_resource,
   1285				list);
   1286		list_del(pos);
   1287		kfree(master_image);
   1288	}
   1289
   1290	kfree(fake_bridge->driver_priv);
   1291
   1292	kfree(fake_bridge);
   1293
   1294	root_device_unregister(vme_root);
   1295}
   1296
   1297
   1298MODULE_PARM_DESC(geoid, "Set geographical addressing");
   1299module_param(geoid, int, 0);
   1300
   1301MODULE_DESCRIPTION("Fake VME bridge driver");
   1302MODULE_LICENSE("GPL");
   1303
   1304module_init(fake_init);
   1305module_exit(fake_exit);