File Index
Files and directories
Sign in
FILE

vme_fake.c

File preview with syntax highlighting.

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