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