aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vme
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vme')
-rw-r--r--drivers/staging/vme/Kconfig17
-rw-r--r--drivers/staging/vme/Makefile7
-rw-r--r--drivers/staging/vme/TODO98
-rw-r--r--drivers/staging/vme/bridges/Kconfig13
-rw-r--r--drivers/staging/vme/bridges/Makefile2
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c1933
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.h505
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c2925
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.h1387
-rw-r--r--drivers/staging/vme/devices/Kconfig8
-rw-r--r--drivers/staging/vme/devices/Makefile5
-rw-r--r--drivers/staging/vme/devices/vme_user.c826
-rw-r--r--drivers/staging/vme/devices/vme_user.h52
-rw-r--r--drivers/staging/vme/vme.c1497
-rw-r--r--drivers/staging/vme/vme.h161
-rw-r--r--drivers/staging/vme/vme_api.txt372
-rw-r--r--drivers/staging/vme/vme_bridge.h261
17 files changed, 10069 insertions, 0 deletions
diff --git a/drivers/staging/vme/Kconfig b/drivers/staging/vme/Kconfig
new file mode 100644
index 000000000000..ae628a58b0c6
--- /dev/null
+++ b/drivers/staging/vme/Kconfig
@@ -0,0 +1,17 @@
+#
+# VME configuration.
+#
+
+menuconfig VME_BUS
+ tristate "VME bridge support"
+ depends on PCI
+ ---help---
+ If you say Y here you get support for the VME bridge Framework.
+
+if VME_BUS
+
+source "drivers/staging/vme/bridges/Kconfig"
+
+source "drivers/staging/vme/devices/Kconfig"
+
+endif # VME
diff --git a/drivers/staging/vme/Makefile b/drivers/staging/vme/Makefile
new file mode 100644
index 000000000000..8c3b90ee5853
--- /dev/null
+++ b/drivers/staging/vme/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the VME bridge device drivers.
+#
+obj-$(CONFIG_VME_BUS) += vme.o
+
+obj-y += bridges/
+obj-y += devices/
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
new file mode 100644
index 000000000000..adc5fca42afd
--- /dev/null
+++ b/drivers/staging/vme/TODO
@@ -0,0 +1,98 @@
+ TODO
+ ====
+
+API
+===
+
+DMA Resource Allocation incomplete
+----------------------------------
+
+The current DMA resource Allocation provides no means of selecting the
+suitability of a DMA controller based on it's supported modes of operation, as
+opposed to the resource allocation mechanisms for master and slave windows:
+
+ struct vme_resource *vme_request_dma(struct device *dev);
+
+As opposed to:
+
+ struct vme_resource * vme_master_request(struct device *dev,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t width);
+
+The TSI148 can perform, VME-to-PCI, PCI-to-VME, PATTERN-to-VME, PATTERN-to-PCI,
+VME-to-VME and PCI-to-PCI transfers. The CA91C142 can only provide VME-to-PCI
+and PCI-to-VME.
+
+Add a mechanism to select a VME controller based on source/target type,
+required aspace, cycle and width requirements.
+
+
+Master window broadcast select mask
+-----------------------------------
+
+API currently provides no method to set or get Broadcast Select mask. Suggest
+somthing like:
+
+ int vme_master_bmsk_set (struct vme_resource *res, int mask);
+ int vme_master_bmsk_get (struct vme_resource *res, int *mask);
+
+
+Interrupt Generation
+--------------------
+
+Add optional timeout when waiting for an IACK.
+
+
+CR/CSR Buffer
+-------------
+
+The VME API provides no functions to access the buffer mapped into the CR/CSR
+space.
+
+
+Mailboxes
+---------
+
+Whilst not part of the VME specification, they are provided by a number of
+chips. They are currently not supported at all by the API.
+
+
+Core
+====
+
+- Rename vme_master_resource's "pci_resource" to be bus agnostic.
+- Improve generic sanity checks (Such as does an offset and size fit within a
+ window and parameter checking).
+
+Bridge Support
+==============
+
+Tempe (tsi148)
+--------------
+
+- Driver can currently only support a single bridge.
+- 2eSST Broadcast mode.
+- Mailboxes unsupported.
+- Improve error detection.
+- Control of prefetch size, threshold.
+- Arbiter control
+- Requestor control
+
+Universe II (ca91c142)
+----------------------
+
+- Driver can currently only support a single bridge.
+- DMA unsupported.
+- RMW transactions unsupported.
+- Location Monitors unsupported.
+- Mailboxes unsupported.
+- Error Detection.
+- Control of prefetch size, threshold.
+- Arbiter control
+- Requestor control
+- Slot detection
+
+Universe I (ca91x042)
+---------------------
+
+Currently completely unsupported.
+
diff --git a/drivers/staging/vme/bridges/Kconfig b/drivers/staging/vme/bridges/Kconfig
new file mode 100644
index 000000000000..023cceba0c59
--- /dev/null
+++ b/drivers/staging/vme/bridges/Kconfig
@@ -0,0 +1,13 @@
+comment "VME Bridge Drivers"
+
+config VME_CA91CX42
+ tristate "Universe II"
+ help
+ If you say Y here you get support for the Tundra CA91C142
+ (Universe II) VME bridge chip.
+
+config VME_TSI148
+ tristate "Tempe"
+ help
+ If you say Y here you get support for the Tundra TSI148 VME bridge
+ chip.
diff --git a/drivers/staging/vme/bridges/Makefile b/drivers/staging/vme/bridges/Makefile
new file mode 100644
index 000000000000..59638afcd502
--- /dev/null
+++ b/drivers/staging/vme/bridges/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VME_CA91CX42) += vme_ca91cx42.o
+obj-$(CONFIG_VME_TSI148) += vme_tsi148.o
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
new file mode 100644
index 000000000000..3d2a84c45829
--- /dev/null
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -0,0 +1,1933 @@
+/*
+ * Support for the Tundra Universe I/II VME-PCI Bridge Chips
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * Derived from ca91c042.c by Michael Wyrick
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "../vme.h"
+#include "../vme_bridge.h"
+#include "vme_ca91cx42.h"
+
+static int __init ca91cx42_init(void);
+static int ca91cx42_probe(struct pci_dev *, const struct pci_device_id *);
+static void ca91cx42_remove(struct pci_dev *);
+static void __exit ca91cx42_exit(void);
+
+struct vme_bridge *ca91cx42_bridge;
+wait_queue_head_t dma_queue;
+wait_queue_head_t iack_queue;
+wait_queue_head_t lm_queue;
+wait_queue_head_t mbox_queue;
+
+void (*lm_callback[4])(int); /* Called in interrupt handler, be careful! */
+void *crcsr_kernel;
+dma_addr_t crcsr_bus;
+
+struct mutex vme_rmw; /* Only one RMW cycle at a time */
+struct mutex vme_int; /*
+ * Only one VME interrupt can be
+ * generated at a time, provide locking
+ */
+struct mutex vme_irq; /* Locking for VME irq callback configuration */
+
+
+
+static char driver_name[] = "vme_ca91cx42";
+
+static struct pci_device_id ca91cx42_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) },
+ { },
+};
+
+static struct pci_driver ca91cx42_driver = {
+ .name = driver_name,
+ .id_table = ca91cx42_ids,
+ .probe = ca91cx42_probe,
+ .remove = ca91cx42_remove,
+};
+
+static u32 ca91cx42_DMA_irqhandler(void)
+{
+ wake_up(&dma_queue);
+
+ return CA91CX42_LINT_DMA;
+}
+
+static u32 ca91cx42_LM_irqhandler(u32 stat)
+{
+ int i;
+ u32 serviced = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (stat & CA91CX42_LINT_LM[i]) {
+ /* We only enable interrupts if the callback is set */
+ lm_callback[i](i);
+ serviced |= CA91CX42_LINT_LM[i];
+ }
+ }
+
+ return serviced;
+}
+
+/* XXX This needs to be split into 4 queues */
+static u32 ca91cx42_MB_irqhandler(int mbox_mask)
+{
+ wake_up(&mbox_queue);
+
+ return CA91CX42_LINT_MBOX;
+}
+
+static u32 ca91cx42_IACK_irqhandler(void)
+{
+ wake_up(&iack_queue);
+
+ return CA91CX42_LINT_SW_IACK;
+}
+
+#if 0
+int ca91cx42_bus_error_chk(int clrflag)
+{
+ int tmp;
+ tmp = ioread32(ca91cx42_bridge->base + PCI_COMMAND);
+ if (tmp & 0x08000000) { /* S_TA is Set */
+ if (clrflag)
+ iowrite32(tmp | 0x08000000,
+ ca91cx42_bridge->base + PCI_COMMAND);
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static u32 ca91cx42_VERR_irqhandler(void)
+{
+ int val;
+
+ val = ioread32(ca91cx42_bridge->base + DGCS);
+
+ if (!(val & 0x00000800)) {
+ printk(KERN_ERR "ca91c042: ca91cx42_VERR_irqhandler DMA Read "
+ "Error DGCS=%08X\n", val);
+ }
+
+ return CA91CX42_LINT_VERR;
+}
+
+static u32 ca91cx42_LERR_irqhandler(void)
+{
+ int val;
+
+ val = ioread32(ca91cx42_bridge->base + DGCS);
+
+ if (!(val & 0x00000800)) {
+ printk(KERN_ERR "ca91c042: ca91cx42_LERR_irqhandler DMA Read "
+ "Error DGCS=%08X\n", val);
+
+ }
+
+ return CA91CX42_LINT_LERR;
+}
+
+
+static u32 ca91cx42_VIRQ_irqhandler(int stat)
+{
+ int vec, i, serviced = 0;
+ void (*call)(int, int, void *);
+ void *priv_data;
+
+ for (i = 7; i > 0; i--) {
+ if (stat & (1 << i)) {
+ vec = ioread32(ca91cx42_bridge->base +
+ CA91CX42_V_STATID[i]) & 0xff;
+
+ call = ca91cx42_bridge->irq[i - 1].callback[vec].func;
+ priv_data =
+ ca91cx42_bridge->irq[i - 1].callback[vec].priv_data;
+
+ if (call != NULL)
+ call(i, vec, priv_data);
+ else
+ printk("Spurilous VME interrupt, level:%x, "
+ "vector:%x\n", i, vec);
+
+ serviced |= (1 << i);
+ }
+ }
+
+ return serviced;
+}
+
+static irqreturn_t ca91cx42_irqhandler(int irq, void *dev_id)
+{
+ u32 stat, enable, serviced = 0;
+
+ if (dev_id != ca91cx42_bridge->base)
+ return IRQ_NONE;
+
+ enable = ioread32(ca91cx42_bridge->base + LINT_EN);
+ stat = ioread32(ca91cx42_bridge->base + LINT_STAT);
+
+ /* Only look at unmasked interrupts */
+ stat &= enable;
+
+ if (unlikely(!stat))
+ return IRQ_NONE;
+
+ if (stat & CA91CX42_LINT_DMA)
+ serviced |= ca91cx42_DMA_irqhandler();
+ if (stat & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
+ CA91CX42_LINT_LM3))
+ serviced |= ca91cx42_LM_irqhandler(stat);
+ if (stat & CA91CX42_LINT_MBOX)
+ serviced |= ca91cx42_MB_irqhandler(stat);
+ if (stat & CA91CX42_LINT_SW_IACK)
+ serviced |= ca91cx42_IACK_irqhandler();
+ if (stat & CA91CX42_LINT_VERR)
+ serviced |= ca91cx42_VERR_irqhandler();
+ if (stat & CA91CX42_LINT_LERR)
+ serviced |= ca91cx42_LERR_irqhandler();
+ if (stat & (CA91CX42_LINT_VIRQ1 | CA91CX42_LINT_VIRQ2 |
+ CA91CX42_LINT_VIRQ3 | CA91CX42_LINT_VIRQ4 |
+ CA91CX42_LINT_VIRQ5 | CA91CX42_LINT_VIRQ6 |
+ CA91CX42_LINT_VIRQ7))
+ serviced |= ca91cx42_VIRQ_irqhandler(stat);
+
+ /* Clear serviced interrupts */
+ iowrite32(stat, ca91cx42_bridge->base + LINT_STAT);
+
+ return IRQ_HANDLED;
+}
+
+static int ca91cx42_irq_init(struct vme_bridge *bridge)
+{
+ int result, tmp;
+ struct pci_dev *pdev;
+
+ /* Need pdev */
+ pdev = container_of(bridge->parent, struct pci_dev, dev);
+
+ /* Initialise list for VME bus errors */
+ INIT_LIST_HEAD(&(bridge->vme_errors));
+
+ /* Disable interrupts from PCI to VME */
+ iowrite32(0, bridge->base + VINT_EN);
+
+ /* Disable PCI interrupts */
+ iowrite32(0, bridge->base + LINT_EN);
+ /* Clear Any Pending PCI Interrupts */
+ iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
+
+ result = request_irq(pdev->irq, ca91cx42_irqhandler, IRQF_SHARED,
+ driver_name, pdev);
+ if (result) {
+ dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
+ pdev->irq);
+ return result;
+ }
+
+ /* Ensure all interrupts are mapped to PCI Interrupt 0 */
+ iowrite32(0, bridge->base + LINT_MAP0);
+ iowrite32(0, bridge->base + LINT_MAP1);
+ iowrite32(0, bridge->base + LINT_MAP2);
+
+ /* Enable DMA, mailbox & LM Interrupts */
+ tmp = CA91CX42_LINT_MBOX3 | CA91CX42_LINT_MBOX2 | CA91CX42_LINT_MBOX1 |
+ CA91CX42_LINT_MBOX0 | CA91CX42_LINT_SW_IACK |
+ CA91CX42_LINT_VERR | CA91CX42_LINT_LERR | CA91CX42_LINT_DMA;
+
+ iowrite32(tmp, bridge->base + LINT_EN);
+
+ return 0;
+}
+
+static void ca91cx42_irq_exit(struct pci_dev *pdev)
+{
+ /* Disable interrupts from PCI to VME */
+ iowrite32(0, ca91cx42_bridge->base + VINT_EN);
+
+ /* Disable PCI interrupts */
+ iowrite32(0, ca91cx42_bridge->base + LINT_EN);
+ /* Clear Any Pending PCI Interrupts */
+ iowrite32(0x00FFFFFF, ca91cx42_bridge->base + LINT_STAT);
+
+ free_irq(pdev->irq, pdev);
+}
+
+/*
+ * Set up an VME interrupt
+ */
+int ca91cx42_request_irq(int level, int statid,
+ void (*callback)(int level, int vector, void *priv_data),
+ void *priv_data)
+{
+ u32 tmp;
+
+ mutex_lock(&(vme_irq));
+
+ if (ca91cx42_bridge->irq[level - 1].callback[statid].func) {
+ mutex_unlock(&(vme_irq));
+ printk("VME Interrupt already taken\n");
+ return -EBUSY;
+ }
+
+
+ ca91cx42_bridge->irq[level - 1].count++;
+ ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
+ ca91cx42_bridge->irq[level - 1].callback[statid].func = callback;
+
+ /* Enable IRQ level */
+ tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
+ tmp |= CA91CX42_LINT_VIRQ[level];
+ iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+
+ mutex_unlock(&(vme_irq));
+
+ return 0;
+}
+
+/*
+ * Free VME interrupt
+ */
+void ca91cx42_free_irq(int level, int statid)
+{
+ u32 tmp;
+ struct pci_dev *pdev;
+
+ mutex_lock(&(vme_irq));
+
+ ca91cx42_bridge->irq[level - 1].count--;
+
+ /* Disable IRQ level if no more interrupts attached at this level*/
+ if (ca91cx42_bridge->irq[level - 1].count == 0) {
+ tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
+ tmp &= ~CA91CX42_LINT_VIRQ[level];
+ iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+
+ pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
+ dev);
+
+ synchronize_irq(pdev->irq);
+ }
+
+ ca91cx42_bridge->irq[level - 1].callback[statid].func = NULL;
+ ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = NULL;
+
+ mutex_unlock(&(vme_irq));
+}
+
+int ca91cx42_generate_irq(int level, int statid)
+{
+ u32 tmp;
+
+ /* Universe can only generate even vectors */
+ if (statid & 1)
+ return -EINVAL;
+
+ mutex_lock(&(vme_int));
+
+ tmp = ioread32(ca91cx42_bridge->base + VINT_EN);
+
+ /* Set Status/ID */
+ iowrite32(statid << 24, ca91cx42_bridge->base + STATID);
+
+ /* Assert VMEbus IRQ */
+ tmp = tmp | (1 << (level + 24));
+ iowrite32(tmp, ca91cx42_bridge->base + VINT_EN);
+
+ /* Wait for IACK */
+ wait_event_interruptible(iack_queue, 0);
+
+ /* Return interrupt to low state */
+ tmp = ioread32(ca91cx42_bridge->base + VINT_EN);
+ tmp = tmp & ~(1 << (level + 24));
+ iowrite32(tmp, ca91cx42_bridge->base + VINT_EN);
+
+ mutex_unlock(&(vme_int));
+
+ return 0;
+}
+
+int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle)
+{
+ unsigned int i, addr = 0, granularity = 0;
+ unsigned int temp_ctl = 0;
+ unsigned int vme_bound, pci_offset;
+
+ i = image->number;
+
+ switch (aspace) {
+ case VME_A16:
+ addr |= CA91CX42_VSI_CTL_VAS_A16;
+ break;
+ case VME_A24:
+ addr |= CA91CX42_VSI_CTL_VAS_A24;
+ break;
+ case VME_A32:
+ addr |= CA91CX42_VSI_CTL_VAS_A32;
+ break;
+ case VME_USER1:
+ addr |= CA91CX42_VSI_CTL_VAS_USER1;
+ break;
+ case VME_USER2:
+ addr |= CA91CX42_VSI_CTL_VAS_USER2;
+ break;
+ case VME_A64:
+ case VME_CRCSR:
+ case VME_USER3:
+ case VME_USER4:
+ default:
+ printk(KERN_ERR "Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ /*
+ * Bound address is a valid address for the window, adjust
+ * accordingly
+ */
+ vme_bound = vme_base + size - granularity;
+ pci_offset = pci_base - vme_base;
+
+ /* XXX Need to check that vme_base, vme_bound and pci_offset aren't
+ * too big for registers
+ */
+
+ if ((i == 0) || (i == 4))
+ granularity = 0x1000;
+ else
+ granularity = 0x10000;
+
+ if (vme_base & (granularity - 1)) {
+ printk(KERN_ERR "Invalid VME base alignment\n");
+ return -EINVAL;
+ }
+ if (vme_bound & (granularity - 1)) {
+ printk(KERN_ERR "Invalid VME bound alignment\n");
+ return -EINVAL;
+ }
+ if (pci_offset & (granularity - 1)) {
+ printk(KERN_ERR "Invalid PCI Offset alignment\n");
+ return -EINVAL;
+ }
+
+ /* Disable while we are mucking around */
+ temp_ctl = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+ temp_ctl &= ~CA91CX42_VSI_CTL_EN;
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+
+ /* Setup mapping */
+ iowrite32(vme_base, ca91cx42_bridge->base + CA91CX42_VSI_BS[i]);
+ iowrite32(vme_bound, ca91cx42_bridge->base + CA91CX42_VSI_BD[i]);
+ iowrite32(pci_offset, ca91cx42_bridge->base + CA91CX42_VSI_TO[i]);
+
+/* XXX Prefetch stuff currently unsupported */
+#if 0
+ if (vmeIn->wrPostEnable)
+ temp_ctl |= CA91CX42_VSI_CTL_PWEN;
+ if (vmeIn->prefetchEnable)
+ temp_ctl |= CA91CX42_VSI_CTL_PREN;
+ if (vmeIn->rmwLock)
+ temp_ctl |= CA91CX42_VSI_CTL_LLRMW;
+ if (vmeIn->data64BitCapable)
+ temp_ctl |= CA91CX42_VSI_CTL_LD64EN;
+#endif
+
+ /* Setup address space */
+ temp_ctl &= ~CA91CX42_VSI_CTL_VAS_M;
+ temp_ctl |= addr;
+
+ /* Setup cycle types */
+ temp_ctl &= ~(CA91CX42_VSI_CTL_PGM_M | CA91CX42_VSI_CTL_SUPER_M);
+ if (cycle & VME_SUPER)
+ temp_ctl |= CA91CX42_VSI_CTL_SUPER_SUPR;
+ if (cycle & VME_USER)
+ temp_ctl |= CA91CX42_VSI_CTL_SUPER_NPRIV;
+ if (cycle & VME_PROG)
+ temp_ctl |= CA91CX42_VSI_CTL_PGM_PGM;
+ if (cycle & VME_DATA)
+ temp_ctl |= CA91CX42_VSI_CTL_PGM_DATA;
+
+ /* Write ctl reg without enable */
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+
+ if (enabled)
+ temp_ctl |= CA91CX42_VSI_CTL_EN;
+
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+
+ return 0;
+}
+
+int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ unsigned int i, granularity = 0, ctl = 0;
+ unsigned long long vme_bound, pci_offset;
+
+ i = image->number;
+
+ if ((i == 0) || (i == 4))
+ granularity = 0x1000;
+ else
+ granularity = 0x10000;
+
+ /* Read Registers */
+ ctl = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_CTL[i]);
+
+ *vme_base = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_BS[i]);
+ vme_bound = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_BD[i]);
+ pci_offset = ioread32(ca91cx42_bridge->base + CA91CX42_VSI_TO[i]);
+
+ *pci_base = (dma_addr_t)vme_base + pci_offset;
+ *size = (unsigned long long)((vme_bound - *vme_base) + granularity);
+
+ *enabled = 0;
+ *aspace = 0;
+ *cycle = 0;
+
+ if (ctl & CA91CX42_VSI_CTL_EN)
+ *enabled = 1;
+
+ if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A16)
+ *aspace = VME_A16;
+ if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A24)
+ *aspace = VME_A24;
+ if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A32)
+ *aspace = VME_A32;
+ if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER1)
+ *aspace = VME_USER1;
+ if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER2)
+ *aspace = VME_USER2;
+
+ if (ctl & CA91CX42_VSI_CTL_SUPER_SUPR)
+ *cycle |= VME_SUPER;
+ if (ctl & CA91CX42_VSI_CTL_SUPER_NPRIV)
+ *cycle |= VME_USER;
+ if (ctl & CA91CX42_VSI_CTL_PGM_PGM)
+ *cycle |= VME_PROG;
+ if (ctl & CA91CX42_VSI_CTL_PGM_DATA)
+ *cycle |= VME_DATA;
+
+ return 0;
+}
+
+/*
+ * Allocate and map PCI Resource
+ */
+static int ca91cx42_alloc_resource(struct vme_master_resource *image,
+ unsigned long long size)
+{
+ unsigned long long existing_size;
+ int retval = 0;
+ struct pci_dev *pdev;
+
+ /* Find pci_dev container of dev */
+ if (ca91cx42_bridge->parent == NULL) {
+ printk(KERN_ERR "Dev entry NULL\n");
+ return -EINVAL;
+ }
+ pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev);
+
+ existing_size = (unsigned long long)(image->pci_resource.end -
+ image->pci_resource.start);
+
+ /* If the existing size is OK, return */
+ if (existing_size == (size - 1))
+ return 0;
+
+ if (existing_size != 0) {
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+ if (image->pci_resource.name != NULL)
+ kfree(image->pci_resource.name);
+ release_resource(&(image->pci_resource));
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+ }
+
+ if (image->pci_resource.name == NULL) {
+ image->pci_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ if (image->pci_resource.name == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for resource"
+ " name\n");
+ retval = -ENOMEM;
+ goto err_name;
+ }
+ }
+
+ sprintf((char *)image->pci_resource.name, "%s.%d",
+ ca91cx42_bridge->name, image->number);
+
+ image->pci_resource.start = 0;
+ image->pci_resource.end = (unsigned long)size;
+ image->pci_resource.flags = IORESOURCE_MEM;
+
+ retval = pci_bus_alloc_resource(pdev->bus,
+ &(image->pci_resource), size, size, PCIBIOS_MIN_MEM,
+ 0, NULL, NULL);
+ if (retval) {
+ printk(KERN_ERR "Failed to allocate mem resource for "
+ "window %d size 0x%lx start 0x%lx\n",
+ image->number, (unsigned long)size,
+ (unsigned long)image->pci_resource.start);
+ goto err_resource;
+ }
+
+ image->kern_base = ioremap_nocache(
+ image->pci_resource.start, size);
+ if (image->kern_base == NULL) {
+ printk(KERN_ERR "Failed to remap resource\n");
+ retval = -ENOMEM;
+ goto err_remap;
+ }
+
+ return 0;
+
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+err_remap:
+ release_resource(&(image->pci_resource));
+err_resource:
+ kfree(image->pci_resource.name);
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+err_name:
+ return retval;
+}
+
+/*
+ * * Free and unmap PCI Resource
+ * */
+static void ca91cx42_free_resource(struct vme_master_resource *image)
+{
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+ release_resource(&(image->pci_resource));
+ kfree(image->pci_resource.name);
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+}
+
+
+int ca91cx42_master_set(struct vme_master_resource *image, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
+{
+ int retval = 0;
+ unsigned int i;
+ unsigned int temp_ctl = 0;
+ unsigned long long pci_bound, vme_offset, pci_base;
+
+ /* Verify input data */
+ if (vme_base & 0xFFF) {
+ printk(KERN_ERR "Invalid VME Window alignment\n");
+ retval = -EINVAL;
+ goto err_window;
+ }
+ if (size & 0xFFF) {
+ printk(KERN_ERR "Invalid VME Window alignment\n");
+ retval = -EINVAL;
+ goto err_window;
+ }
+
+ spin_lock(&(image->lock));
+
+ /* XXX We should do this much later, so that we can exit without
+ * needing to redo the mapping...
+ */
+ /*
+ * Let's allocate the resource here rather than further up the stack as
+ * it avoids pushing loads of bus dependant stuff up the stack
+ */
+ retval = ca91cx42_alloc_resource(image, size);
+ if (retval) {
+ spin_unlock(&(image->lock));
+ printk(KERN_ERR "Unable to allocate memory for resource "
+ "name\n");
+ retval = -ENOMEM;
+ goto err_res;
+ }
+
+ pci_base = (unsigned long long)image->pci_resource.start;
+
+ /*
+ * Bound address is a valid address for the window, adjust
+ * according to window granularity.
+ */
+ pci_bound = pci_base + (size - 0x1000);
+ vme_offset = vme_base - pci_base;
+
+ i = image->number;
+
+ /* Disable while we are mucking around */
+ temp_ctl = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+ temp_ctl &= ~CA91CX42_LSI_CTL_EN;
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+
+/* XXX Prefetch stuff currently unsupported */
+#if 0
+ if (vmeOut->wrPostEnable)
+ temp_ctl |= 0x40000000;
+#endif
+
+ /* Setup cycle types */
+ temp_ctl &= ~CA91CX42_LSI_CTL_VCT_M;
+ if (cycle & VME_BLT)
+ temp_ctl |= CA91CX42_LSI_CTL_VCT_BLT;
+ if (cycle & VME_MBLT)
+ temp_ctl |= CA91CX42_LSI_CTL_VCT_MBLT;
+
+ /* Setup data width */
+ temp_ctl &= ~CA91CX42_LSI_CTL_VDW_M;
+ switch (dwidth) {
+ case VME_D8:
+ temp_ctl |= CA91CX42_LSI_CTL_VDW_D8;
+ break;
+ case VME_D16:
+ temp_ctl |= CA91CX42_LSI_CTL_VDW_D16;
+ break;
+ case VME_D32:
+ temp_ctl |= CA91CX42_LSI_CTL_VDW_D32;
+ break;
+ case VME_D64:
+ temp_ctl |= CA91CX42_LSI_CTL_VDW_D64;
+ break;
+ default:
+ spin_unlock(&(image->lock));
+ printk(KERN_ERR "Invalid data width\n");
+ retval = -EINVAL;
+ goto err_dwidth;
+ break;
+ }
+
+ /* Setup address space */
+ temp_ctl &= ~CA91CX42_LSI_CTL_VAS_M;
+ switch (aspace) {
+ case VME_A16:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_A16;
+ break;
+ case VME_A24:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_A24;
+ break;
+ case VME_A32:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_A32;
+ break;
+ case VME_CRCSR:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_CRCSR;
+ break;
+ case VME_USER1:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_USER1;
+ break;
+ case VME_USER2:
+ temp_ctl |= CA91CX42_LSI_CTL_VAS_USER2;
+ break;
+ case VME_A64:
+ case VME_USER3:
+ case VME_USER4:
+ default:
+ spin_unlock(&(image->lock));
+ printk(KERN_ERR "Invalid address space\n");
+ retval = -EINVAL;
+ goto err_aspace;
+ break;
+ }
+
+ temp_ctl &= ~(CA91CX42_LSI_CTL_PGM_M | CA91CX42_LSI_CTL_SUPER_M);
+ if (cycle & VME_SUPER)
+ temp_ctl |= CA91CX42_LSI_CTL_SUPER_SUPR;
+ if (cycle & VME_PROG)
+ temp_ctl |= CA91CX42_LSI_CTL_PGM_PGM;
+
+ /* Setup mapping */
+ iowrite32(pci_base, ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
+ iowrite32(pci_bound, ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
+ iowrite32(vme_offset, ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
+
+ /* Write ctl reg without enable */
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+
+ if (enabled)
+ temp_ctl |= CA91CX42_LSI_CTL_EN;
+
+ iowrite32(temp_ctl, ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+
+ spin_unlock(&(image->lock));
+ return 0;
+
+err_aspace:
+err_dwidth:
+ ca91cx42_free_resource(image);
+err_res:
+err_window:
+ return retval;
+}
+
+int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
+{
+ unsigned int i, ctl;
+ unsigned long long pci_base, pci_bound, vme_offset;
+
+ i = image->number;
+
+ ctl = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_CTL[i]);
+
+ pci_base = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
+ vme_offset = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
+ pci_bound = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
+
+ *vme_base = pci_base + vme_offset;
+ *size = (pci_bound - pci_base) + 0x1000;
+
+ *enabled = 0;
+ *aspace = 0;
+ *cycle = 0;
+ *dwidth = 0;
+
+ if (ctl & CA91CX42_LSI_CTL_EN)
+ *enabled = 1;
+
+ /* Setup address space */
+ switch (ctl & CA91CX42_LSI_CTL_VAS_M) {
+ case CA91CX42_LSI_CTL_VAS_A16:
+ *aspace = VME_A16;
+ break;
+ case CA91CX42_LSI_CTL_VAS_A24:
+ *aspace = VME_A24;
+ break;
+ case CA91CX42_LSI_CTL_VAS_A32:
+ *aspace = VME_A32;
+ break;
+ case CA91CX42_LSI_CTL_VAS_CRCSR:
+ *aspace = VME_CRCSR;
+ break;
+ case CA91CX42_LSI_CTL_VAS_USER1:
+ *aspace = VME_USER1;
+ break;
+ case CA91CX42_LSI_CTL_VAS_USER2:
+ *aspace = VME_USER2;
+ break;
+ }
+
+ /* XXX Not sure howto check for MBLT */
+ /* Setup cycle types */
+ if (ctl & CA91CX42_LSI_CTL_VCT_BLT)
+ *cycle |= VME_BLT;
+ else
+ *cycle |= VME_SCT;
+
+ if (ctl & CA91CX42_LSI_CTL_SUPER_SUPR)
+ *cycle |= VME_SUPER;
+ else
+ *cycle |= VME_USER;
+
+ if (ctl & CA91CX42_LSI_CTL_PGM_PGM)
+ *cycle = VME_PROG;
+ else
+ *cycle = VME_DATA;
+
+ /* Setup data width */
+ switch (ctl & CA91CX42_LSI_CTL_VDW_M) {
+ case CA91CX42_LSI_CTL_VDW_D8:
+ *dwidth = VME_D8;
+ break;
+ case CA91CX42_LSI_CTL_VDW_D16:
+ *dwidth = VME_D16;
+ break;
+ case CA91CX42_LSI_CTL_VDW_D32:
+ *dwidth = VME_D32;
+ break;
+ case CA91CX42_LSI_CTL_VDW_D64:
+ *dwidth = VME_D64;
+ break;
+ }
+
+/* XXX Prefetch stuff currently unsupported */
+#if 0
+ if (ctl & 0x40000000)
+ vmeOut->wrPostEnable = 1;
+#endif
+
+ return 0;
+}
+
+int ca91cx42_master_get(struct vme_master_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
+{
+ int retval;
+
+ spin_lock(&(image->lock));
+
+ retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace,
+ cycle, dwidth);
+
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf,
+ size_t count, loff_t offset)
+{
+ int retval;
+
+ spin_lock(&(image->lock));
+
+ memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
+ retval = count;
+
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
+ size_t count, loff_t offset)
+{
+ int retval = 0;
+
+ spin_lock(&(image->lock));
+
+ memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
+ retval = count;
+
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+int ca91cx42_slot_get(void)
+{
+ u32 slot = 0;
+
+ slot = ioread32(ca91cx42_bridge->base + VCSR_BS);
+ slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27);
+ return (int)slot;
+
+}
+
+static int __init ca91cx42_init(void)
+{
+ return pci_register_driver(&ca91cx42_driver);
+}
+
+/*
+ * Configure CR/CSR space
+ *
+ * Access to the CR/CSR can be configured at power-up. The location of the
+ * CR/CSR registers in the CR/CSR address space is determined by the boards
+ * Auto-ID or Geographic address. This function ensures that the window is
+ * enabled at an offset consistent with the boards geopgraphic address.
+ */
+static int ca91cx42_crcsr_init(struct pci_dev *pdev)
+{
+ unsigned int crcsr_addr;
+ int tmp, slot;
+
+/* XXX We may need to set this somehow as the Universe II does not support
+ * geographical addressing.
+ */
+#if 0
+ if (vme_slotnum != -1)
+ iowrite32(vme_slotnum << 27, ca91cx42_bridge->base + VCSR_BS);
+#endif
+ slot = ca91cx42_slot_get();
+ dev_info(&pdev->dev, "CR/CSR Offset: %d\n", slot);
+ if (slot == 0) {
+ dev_err(&pdev->dev, "Slot number is unset, not configuring "
+ "CR/CSR space\n");
+ return -EINVAL;
+ }
+
+ /* Allocate mem for CR/CSR image */
+ crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+ &crcsr_bus);
+ if (crcsr_kernel == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
+ "image\n");
+ return -ENOMEM;
+ }
+
+ memset(crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+
+ crcsr_addr = slot * (512 * 1024);
+ iowrite32(crcsr_bus - crcsr_addr, ca91cx42_bridge->base + VCSR_TO);
+
+ tmp = ioread32(ca91cx42_bridge->base + VCSR_CTL);
+ tmp |= CA91CX42_VCSR_CTL_EN;
+ iowrite32(tmp, ca91cx42_bridge->base + VCSR_CTL);
+
+ return 0;
+}
+
+static void ca91cx42_crcsr_exit(struct pci_dev *pdev)
+{
+ u32 tmp;
+
+ /* Turn off CR/CSR space */
+ tmp = ioread32(ca91cx42_bridge->base + VCSR_CTL);
+ tmp &= ~CA91CX42_VCSR_CTL_EN;
+ iowrite32(tmp, ca91cx42_bridge->base + VCSR_CTL);
+
+ /* Free image */
+ iowrite32(0, ca91cx42_bridge->base + VCSR_TO);
+
+ pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, crcsr_kernel, crcsr_bus);
+}
+
+static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int retval, i;
+ u32 data;
+ struct list_head *pos = NULL;
+ struct vme_master_resource *master_image;
+ struct vme_slave_resource *slave_image;
+#if 0
+ struct vme_dma_resource *dma_ctrlr;
+#endif
+ struct vme_lm_resource *lm;
+
+ /* We want to support more than one of each bridge so we need to
+ * dynamically allocate the bridge structure
+ */
+ ca91cx42_bridge = kmalloc(sizeof(struct vme_bridge), GFP_KERNEL);
+
+ if (ca91cx42_bridge == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for device "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_struct;
+ }
+
+ memset(ca91cx42_bridge, 0, sizeof(struct vme_bridge));
+
+ /* Enable the device */
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to enable device\n");
+ goto err_enable;
+ }
+
+ /* Map Registers */
+ retval = pci_request_regions(pdev, driver_name);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to reserve resources\n");
+ goto err_resource;
+ }
+
+ /* map registers in BAR 0 */
+ ca91cx42_bridge->base = ioremap_nocache(pci_resource_start(pdev, 0),
+ 4096);
+ if (!ca91cx42_bridge->base) {
+ dev_err(&pdev->dev, "Unable to remap CRG region\n");
+ retval = -EIO;
+ goto err_remap;
+ }
+
+ /* Check to see if the mapping worked out */
+ data = ioread32(ca91cx42_bridge->base + CA91CX42_PCI_ID) & 0x0000FFFF;
+ if (data != PCI_VENDOR_ID_TUNDRA) {
+ dev_err(&pdev->dev, "PCI_ID check failed\n");
+ retval = -EIO;
+ goto err_test;
+ }
+
+ /* Initialize wait queues & mutual exclusion flags */
+ /* XXX These need to be moved to the vme_bridge structure */
+ init_waitqueue_head(&dma_queue);
+ init_waitqueue_head(&iack_queue);
+ mutex_init(&(vme_int));
+ mutex_init(&(vme_irq));
+ mutex_init(&(vme_rmw));
+
+ ca91cx42_bridge->parent = &(pdev->dev);
+ strcpy(ca91cx42_bridge->name, driver_name);
+
+ /* Setup IRQ */
+ retval = ca91cx42_irq_init(ca91cx42_bridge);
+ if (retval != 0) {
+ dev_err(&pdev->dev, "Chip Initialization failed.\n");
+ goto err_irq;
+ }
+
+ /* Add master windows to list */
+ INIT_LIST_HEAD(&(ca91cx42_bridge->master_resources));
+ for (i = 0; i < CA91C142_MAX_MASTER; i++) {
+ master_image = kmalloc(sizeof(struct vme_master_resource),
+ GFP_KERNEL);
+ if (master_image == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "master resource structure\n");
+ retval = -ENOMEM;
+ goto err_master;
+ }
+ master_image->parent = ca91cx42_bridge;
+ spin_lock_init(&(master_image->lock));
+ master_image->locked = 0;
+ master_image->number = i;
+ master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+ VME_CRCSR | VME_USER1 | VME_USER2;
+ master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+ VME_SUPER | VME_USER | VME_PROG | VME_DATA;
+ master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
+ memset(&(master_image->pci_resource), 0,
+ sizeof(struct resource));
+ master_image->kern_base = NULL;
+ list_add_tail(&(master_image->list),
+ &(ca91cx42_bridge->master_resources));
+ }
+
+ /* Add slave windows to list */
+ INIT_LIST_HEAD(&(ca91cx42_bridge->slave_resources));
+ for (i = 0; i < CA91C142_MAX_SLAVE; i++) {
+ slave_image = kmalloc(sizeof(struct vme_slave_resource),
+ GFP_KERNEL);
+ if (slave_image == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "slave resource structure\n");
+ retval = -ENOMEM;
+ goto err_slave;
+ }
+ slave_image->parent = ca91cx42_bridge;
+ mutex_init(&(slave_image->mtx));
+ slave_image->locked = 0;
+ slave_image->number = i;
+ slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 |
+ VME_USER2;
+
+ /* Only windows 0 and 4 support A16 */
+ if (i == 0 || i == 4)
+ slave_image->address_attr |= VME_A16;
+
+ slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+ VME_SUPER | VME_USER | VME_PROG | VME_DATA;
+ list_add_tail(&(slave_image->list),
+ &(ca91cx42_bridge->slave_resources));
+ }
+#if 0
+ /* Add dma engines to list */
+ INIT_LIST_HEAD(&(ca91cx42_bridge->dma_resources));
+ for (i = 0; i < CA91C142_MAX_DMA; i++) {
+ dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
+ GFP_KERNEL);
+ if (dma_ctrlr == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "dma resource structure\n");
+ retval = -ENOMEM;
+ goto err_dma;
+ }
+ dma_ctrlr->parent = ca91cx42_bridge;
+ mutex_init(&(dma_ctrlr->mtx));
+ dma_ctrlr->locked = 0;
+ dma_ctrlr->number = i;
+ INIT_LIST_HEAD(&(dma_ctrlr->pending));
+ INIT_LIST_HEAD(&(dma_ctrlr->running));
+ list_add_tail(&(dma_ctrlr->list),
+ &(ca91cx42_bridge->dma_resources));
+ }
+#endif
+ /* Add location monitor to list */
+ INIT_LIST_HEAD(&(ca91cx42_bridge->lm_resources));
+ lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
+ if (lm == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "location monitor resource structure\n");
+ retval = -ENOMEM;
+ goto err_lm;
+ }
+ lm->parent = ca91cx42_bridge;
+ mutex_init(&(lm->mtx));
+ lm->locked = 0;
+ lm->number = 1;
+ lm->monitors = 4;
+ list_add_tail(&(lm->list), &(ca91cx42_bridge->lm_resources));
+
+ ca91cx42_bridge->slave_get = ca91cx42_slave_get;
+ ca91cx42_bridge->slave_set = ca91cx42_slave_set;
+ ca91cx42_bridge->master_get = ca91cx42_master_get;
+ ca91cx42_bridge->master_set = ca91cx42_master_set;
+ ca91cx42_bridge->master_read = ca91cx42_master_read;
+ ca91cx42_bridge->master_write = ca91cx42_master_write;
+#if 0
+ ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
+ ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
+ ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
+ ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
+#endif
+ ca91cx42_bridge->request_irq = ca91cx42_request_irq;
+ ca91cx42_bridge->free_irq = ca91cx42_free_irq;
+ ca91cx42_bridge->generate_irq = ca91cx42_generate_irq;
+#if 0
+ ca91cx42_bridge->lm_set = ca91cx42_lm_set;
+ ca91cx42_bridge->lm_get = ca91cx42_lm_get;
+ ca91cx42_bridge->lm_attach = ca91cx42_lm_attach;
+ ca91cx42_bridge->lm_detach = ca91cx42_lm_detach;
+#endif
+ ca91cx42_bridge->slot_get = ca91cx42_slot_get;
+
+ data = ioread32(ca91cx42_bridge->base + MISC_CTL);
+ dev_info(&pdev->dev, "Board is%s the VME system controller\n",
+ (data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not");
+ dev_info(&pdev->dev, "Slot ID is %d\n", ca91cx42_slot_get());
+
+ if (ca91cx42_crcsr_init(pdev)) {
+ dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
+ retval = -EINVAL;
+#if 0
+ goto err_crcsr;
+#endif
+ }
+
+ /* Need to save ca91cx42_bridge pointer locally in link list for use in
+ * ca91cx42_remove()
+ */
+ retval = vme_register_bridge(ca91cx42_bridge);
+ if (retval != 0) {
+ dev_err(&pdev->dev, "Chip Registration failed.\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+ vme_unregister_bridge(ca91cx42_bridge);
+err_reg:
+ ca91cx42_crcsr_exit(pdev);
+err_crcsr:
+err_lm:
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
+ lm = list_entry(pos, struct vme_lm_resource, list);
+ list_del(pos);
+ kfree(lm);
+ }
+#if 0
+err_dma:
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
+ dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+ list_del(pos);
+ kfree(dma_ctrlr);
+ }
+#endif
+err_slave:
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
+ slave_image = list_entry(pos, struct vme_slave_resource, list);
+ list_del(pos);
+ kfree(slave_image);
+ }
+err_master:
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->master_resources)) {
+ master_image = list_entry(pos, struct vme_master_resource,
+ list);
+ list_del(pos);
+ kfree(master_image);
+ }
+
+ ca91cx42_irq_exit(pdev);
+err_irq:
+err_test:
+ iounmap(ca91cx42_bridge->base);
+err_remap:
+ pci_release_regions(pdev);
+err_resource:
+ pci_disable_device(pdev);
+err_enable:
+ kfree(ca91cx42_bridge);
+err_struct:
+ return retval;
+
+}
+
+void ca91cx42_remove(struct pci_dev *pdev)
+{
+ struct list_head *pos = NULL;
+ struct vme_master_resource *master_image;
+ struct vme_slave_resource *slave_image;
+ struct vme_dma_resource *dma_ctrlr;
+ struct vme_lm_resource *lm;
+ int i;
+
+ /* Turn off Ints */
+ iowrite32(0, ca91cx42_bridge->base + LINT_EN);
+
+ /* Turn off the windows */
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI0_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI1_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI2_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI3_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI4_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI5_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI6_CTL);
+ iowrite32(0x00800000, ca91cx42_bridge->base + LSI7_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI0_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI1_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI2_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI3_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI4_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI5_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI6_CTL);
+ iowrite32(0x00F00000, ca91cx42_bridge->base + VSI7_CTL);
+
+ vme_unregister_bridge(ca91cx42_bridge);
+#if 0
+ ca91cx42_crcsr_exit(pdev);
+#endif
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
+ lm = list_entry(pos, struct vme_lm_resource, list);
+ list_del(pos);
+ kfree(lm);
+ }
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
+ dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+ list_del(pos);
+ kfree(dma_ctrlr);
+ }
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
+ slave_image = list_entry(pos, struct vme_slave_resource, list);
+ list_del(pos);
+ kfree(slave_image);
+ }
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(ca91cx42_bridge->master_resources)) {
+ master_image = list_entry(pos, struct vme_master_resource,
+ list);
+ list_del(pos);
+ kfree(master_image);
+ }
+
+ ca91cx42_irq_exit(pdev);
+
+ iounmap(ca91cx42_bridge->base);
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+
+ kfree(ca91cx42_bridge);
+}
+
+static void __exit ca91cx42_exit(void)
+{
+ pci_unregister_driver(&ca91cx42_driver);
+}
+
+MODULE_DESCRIPTION("VME driver for the Tundra Universe II VME bridge");
+MODULE_LICENSE("GPL");
+
+module_init(ca91cx42_init);
+module_exit(ca91cx42_exit);
+
+/*----------------------------------------------------------------------------
+ * STAGING
+ *--------------------------------------------------------------------------*/
+
+#if 0
+#define SWIZZLE(X) ( ((X & 0xFF000000) >> 24) | ((X & 0x00FF0000) >> 8) | ((X & 0x0000FF00) << 8) | ((X & 0x000000FF) << 24))
+
+int ca91cx42_master_rmw(vmeRmwCfg_t *vmeRmw)
+{
+ int temp_ctl = 0;
+ int tempBS = 0;
+ int tempBD = 0;
+ int tempTO = 0;
+ int vmeBS = 0;
+ int vmeBD = 0;
+ int *rmw_pci_data_ptr = NULL;
+ int *vaDataPtr = NULL;
+ int i;
+ vmeOutWindowCfg_t vmeOut;
+ if (vmeRmw->maxAttempts < 1) {
+ return -EINVAL;
+ }
+ if (vmeRmw->targetAddrU) {
+ return -EINVAL;
+ }
+ /* Find the PCI address that maps to the desired VME address */
+ for (i = 0; i < 8; i++) {
+ temp_ctl = ioread32(ca91cx42_bridge->base +
+ CA91CX42_LSI_CTL[i]);
+ if ((temp_ctl & 0x80000000) == 0) {
+ continue;
+ }
+ memset(&vmeOut, 0, sizeof(vmeOut));
+ vmeOut.windowNbr = i;
+ ca91cx42_get_out_bound(&vmeOut);
+ if (vmeOut.addrSpace != vmeRmw->addrSpace) {
+ continue;
+ }
+ tempBS = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BS[i]);
+ tempBD = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_BD[i]);
+ tempTO = ioread32(ca91cx42_bridge->base + CA91CX42_LSI_TO[i]);
+ vmeBS = tempBS + tempTO;
+ vmeBD = tempBD + tempTO;
+ if ((vmeRmw->targetAddr >= vmeBS) &&
+ (vmeRmw->targetAddr < vmeBD)) {
+ rmw_pci_data_ptr =
+ (int *)(tempBS + (vmeRmw->targetAddr - vmeBS));
+ vaDataPtr =
+ (int *)(out_image_va[i] +
+ (vmeRmw->targetAddr - vmeBS));
+ break;
+ }
+ }
+
+ /* If no window - fail. */
+ if (rmw_pci_data_ptr == NULL) {
+ return -EINVAL;
+ }
+ /* Setup the RMW registers. */
+ iowrite32(0, ca91cx42_bridge->base + SCYC_CTL);
+ iowrite32(SWIZZLE(vmeRmw->enableMask), ca91cx42_bridge->base + SCYC_EN);
+ iowrite32(SWIZZLE(vmeRmw->compareData), ca91cx42_bridge->base +
+ SCYC_CMP);
+ iowrite32(SWIZZLE(vmeRmw->swapData), ca91cx42_bridge->base + SCYC_SWP);
+ iowrite32((int)rmw_pci_data_ptr, ca91cx42_bridge->base + SCYC_ADDR);
+ iowrite32(1, ca91cx42_bridge->base + SCYC_CTL);
+
+ /* Run the RMW cycle until either success or max attempts. */
+ vmeRmw->numAttempts = 1;
+ while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) {
+
+ if ((ioread32(vaDataPtr) & vmeRmw->enableMask) ==
+ (vmeRmw->swapData & vmeRmw->enableMask)) {
+
+ iowrite32(0, ca91cx42_bridge->base + SCYC_CTL);
+ break;
+
+ }
+ vmeRmw->numAttempts++;
+ }
+
+ /* If no success, set num Attempts to be greater than max attempts */
+ if (vmeRmw->numAttempts > vmeRmw->maxAttempts) {
+ vmeRmw->numAttempts = vmeRmw->maxAttempts + 1;
+ }
+
+ return 0;
+}
+
+int uniSetupDctlReg(vmeDmaPacket_t * vmeDma, int *dctlregreturn)
+{
+ unsigned int dctlreg = 0x80;
+ struct vmeAttr *vmeAttr;
+
+ if (vmeDma->srcBus == VME_DMA_VME) {
+ dctlreg = 0;
+ vmeAttr = &vmeDma->srcVmeAttr;
+ } else {
+ dctlreg = 0x80000000;
+ vmeAttr = &vmeDma->dstVmeAttr;
+ }
+
+ switch (vmeAttr->maxDataWidth) {
+ case VME_D8:
+ break;
+ case VME_D16:
+ dctlreg |= 0x00400000;
+ break;
+ case VME_D32:
+ dctlreg |= 0x00800000;
+ break;
+ case VME_D64:
+ dctlreg |= 0x00C00000;
+ break;
+ }
+
+ switch (vmeAttr->addrSpace) {
+ case VME_A16:
+ break;
+ case VME_A24:
+ dctlreg |= 0x00010000;
+ break;
+ case VME_A32:
+ dctlreg |= 0x00020000;
+ break;
+ case VME_USER1:
+ dctlreg |= 0x00060000;
+ break;
+ case VME_USER2:
+ dctlreg |= 0x00070000;
+ break;
+
+ case VME_A64: /* not supported in Universe DMA */
+ case VME_CRCSR:
+ case VME_USER3:
+ case VME_USER4:
+ return -EINVAL;
+ break;
+ }
+ if (vmeAttr->userAccessType == VME_PROG) {
+ dctlreg |= 0x00004000;
+ }
+ if (vmeAttr->dataAccessType == VME_SUPER) {
+ dctlreg |= 0x00001000;
+ }
+ if (vmeAttr->xferProtocol != VME_SCT) {
+ dctlreg |= 0x00000100;
+ }
+ *dctlregreturn = dctlreg;
+ return 0;
+}
+
+unsigned int
+ca91cx42_start_dma(int channel, unsigned int dgcsreg, TDMA_Cmd_Packet *vmeLL)
+{
+ unsigned int val;
+
+ /* Setup registers as needed for direct or chained. */
+ if (dgcsreg & 0x8000000) {
+ iowrite32(0, ca91cx42_bridge->base + DTBC);
+ iowrite32((unsigned int)vmeLL, ca91cx42_bridge->base + DCPP);
+ } else {
+#if 0
+ printk(KERN_ERR "Starting: DGCS = %08x\n", dgcsreg);
+ printk(KERN_ERR "Starting: DVA = %08x\n",
+ ioread32(&vmeLL->dva));
+ printk(KERN_ERR "Starting: DLV = %08x\n",
+ ioread32(&vmeLL->dlv));
+ printk(KERN_ERR "Starting: DTBC = %08x\n",
+ ioread32(&vmeLL->dtbc));
+ printk(KERN_ERR "Starting: DCTL = %08x\n",
+ ioread32(&vmeLL->dctl));
+#endif
+ /* Write registers */
+ iowrite32(ioread32(&vmeLL->dva), ca91cx42_bridge->base + DVA);
+ iowrite32(ioread32(&vmeLL->dlv), ca91cx42_bridge->base + DLA);
+ iowrite32(ioread32(&vmeLL->dtbc), ca91cx42_bridge->base + DTBC);
+ iowrite32(ioread32(&vmeLL->dctl), ca91cx42_bridge->base + DCTL);
+ iowrite32(0, ca91cx42_bridge->base + DCPP);
+ }
+
+ /* Start the operation */
+ iowrite32(dgcsreg, ca91cx42_bridge->base + DGCS);
+ val = get_tbl();
+ iowrite32(dgcsreg | 0x8000000F, ca91cx42_bridge->base + DGCS);
+ return val;
+}
+
+TDMA_Cmd_Packet *ca91cx42_setup_dma(vmeDmaPacket_t * vmeDma)
+{
+ vmeDmaPacket_t *vmeCur;
+ int maxPerPage;
+ int currentLLcount;
+ TDMA_Cmd_Packet *startLL;
+ TDMA_Cmd_Packet *currentLL;
+ TDMA_Cmd_Packet *nextLL;
+ unsigned int dctlreg = 0;
+
+ maxPerPage = PAGESIZE / sizeof(TDMA_Cmd_Packet) - 1;
+ startLL = (TDMA_Cmd_Packet *) __get_free_pages(GFP_KERNEL, 0);
+ if (startLL == 0) {
+ return startLL;
+ }
+ /* First allocate pages for descriptors and create linked list */
+ vmeCur = vmeDma;
+ currentLL = startLL;
+ currentLLcount = 0;
+ while (vmeCur != 0) {
+ if (vmeCur->pNextPacket != 0) {
+ currentLL->dcpp = (unsigned int)(currentLL + 1);
+ currentLLcount++;
+ if (currentLLcount >= maxPerPage) {
+ currentLL->dcpp =
+ __get_free_pages(GFP_KERNEL, 0);
+ currentLLcount = 0;
+ }
+ currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+ } else {
+ currentLL->dcpp = (unsigned int)0;
+ }
+ vmeCur = vmeCur->pNextPacket;
+ }
+
+ /* Next fill in information for each descriptor */
+ vmeCur = vmeDma;
+ currentLL = startLL;
+ while (vmeCur != 0) {
+ if (vmeCur->srcBus == VME_DMA_VME) {
+ iowrite32(vmeCur->srcAddr, &currentLL->dva);
+ iowrite32(vmeCur->dstAddr, &currentLL->dlv);
+ } else {
+ iowrite32(vmeCur->srcAddr, &currentLL->dlv);
+ iowrite32(vmeCur->dstAddr, &currentLL->dva);
+ }
+ uniSetupDctlReg(vmeCur, &dctlreg);
+ iowrite32(dctlreg, &currentLL->dctl);
+ iowrite32(vmeCur->byteCount, &currentLL->dtbc);
+
+ currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+ vmeCur = vmeCur->pNextPacket;
+ }
+
+ /* Convert Links to PCI addresses. */
+ currentLL = startLL;
+ while (currentLL != 0) {
+ nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+ if (nextLL == 0) {
+ iowrite32(1, &currentLL->dcpp);
+ } else {
+ iowrite32((unsigned int)virt_to_bus(nextLL),
+ &currentLL->dcpp);
+ }
+ currentLL = nextLL;
+ }
+
+ /* Return pointer to descriptors list */
+ return startLL;
+}
+
+int ca91cx42_free_dma(TDMA_Cmd_Packet *startLL)
+{
+ TDMA_Cmd_Packet *currentLL;
+ TDMA_Cmd_Packet *prevLL;
+ TDMA_Cmd_Packet *nextLL;
+ unsigned int dcppreg;
+
+ /* Convert Links to virtual addresses. */
+ currentLL = startLL;
+ while (currentLL != 0) {
+ dcppreg = ioread32(&currentLL->dcpp);
+ dcppreg &= ~6;
+ if (dcppreg & 1) {
+ currentLL->dcpp = 0;
+ } else {
+ currentLL->dcpp = (unsigned int)bus_to_virt(dcppreg);
+ }
+ currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+ }
+
+ /* Free all pages associated with the descriptors. */
+ currentLL = startLL;
+ prevLL = currentLL;
+ while (currentLL != 0) {
+ nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+ if (currentLL + 1 != nextLL) {
+ free_pages((int)prevLL, 0);
+ prevLL = nextLL;
+ }
+ currentLL = nextLL;
+ }
+
+ /* Return pointer to descriptors list */
+ return 0;
+}
+
+int ca91cx42_do_dma(vmeDmaPacket_t *vmeDma)
+{
+ unsigned int dgcsreg = 0;
+ unsigned int dctlreg = 0;
+ int val;
+ int channel, x;
+ vmeDmaPacket_t *curDma;
+ TDMA_Cmd_Packet *dmaLL;
+
+ /* Sanity check the VME chain. */
+ channel = vmeDma->channel_number;
+ if (channel > 0) {
+ return -EINVAL;
+ }
+ curDma = vmeDma;
+ while (curDma != 0) {
+ if (curDma->byteCount == 0) {
+ return -EINVAL;
+ }
+ if (curDma->byteCount >= 0x1000000) {
+ return -EINVAL;
+ }
+ if ((curDma->srcAddr & 7) != (curDma->dstAddr & 7)) {
+ return -EINVAL;
+ }
+ switch (curDma->srcBus) {
+ case VME_DMA_PCI:
+ if (curDma->dstBus != VME_DMA_VME) {
+ return -EINVAL;
+ }
+ break;
+ case VME_DMA_VME:
+ if (curDma->dstBus != VME_DMA_PCI) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ if (uniSetupDctlReg(curDma, &dctlreg) < 0) {
+ return -EINVAL;
+ }
+
+ curDma = curDma->pNextPacket;
+ if (curDma == vmeDma) { /* Endless Loop! */
+ return -EINVAL;
+ }
+ }
+
+ /* calculate control register */
+ if (vmeDma->pNextPacket != 0) {
+ dgcsreg = 0x8000000;
+ } else {
+ dgcsreg = 0;
+ }
+
+ for (x = 0; x < 8; x++) { /* vme block size */
+ if ((256 << x) >= vmeDma->maxVmeBlockSize) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dgcsreg |= (x << 20);
+
+ if (vmeDma->vmeBackOffTimer) {
+ for (x = 1; x < 8; x++) { /* vme timer */
+ if ((16 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dgcsreg |= (x << 16);
+ }
+ /*` Setup the dma chain */
+ dmaLL = ca91cx42_setup_dma(vmeDma);
+
+ /* Start the DMA */
+ if (dgcsreg & 0x8000000) {
+ vmeDma->vmeDmaStartTick =
+ ca91cx42_start_dma(channel, dgcsreg,
+ (TDMA_Cmd_Packet *) virt_to_phys(dmaLL));
+ } else {
+ vmeDma->vmeDmaStartTick =
+ ca91cx42_start_dma(channel, dgcsreg, dmaLL);
+ }
+
+ wait_event_interruptible(dma_queue,
+ ioread32(ca91cx42_bridge->base + DGCS) & 0x800);
+
+ val = ioread32(ca91cx42_bridge->base + DGCS);
+ iowrite32(val | 0xF00, ca91cx42_bridge->base + DGCS);
+
+ vmeDma->vmeDmaStatus = 0;
+
+ if (!(val & 0x00000800)) {
+ vmeDma->vmeDmaStatus = val & 0x700;
+ printk(KERN_ERR "ca91c042: DMA Error in ca91cx42_DMA_irqhandler"
+ " DGCS=%08X\n", val);
+ val = ioread32(ca91cx42_bridge->base + DCPP);
+ printk(KERN_ERR "ca91c042: DCPP=%08X\n", val);
+ val = ioread32(ca91cx42_bridge->base + DCTL);
+ printk(KERN_ERR "ca91c042: DCTL=%08X\n", val);
+ val = ioread32(ca91cx42_bridge->base + DTBC);
+ printk(KERN_ERR "ca91c042: DTBC=%08X\n", val);
+ val = ioread32(ca91cx42_bridge->base + DLA);
+ printk(KERN_ERR "ca91c042: DLA=%08X\n", val);
+ val = ioread32(ca91cx42_bridge->base + DVA);
+ printk(KERN_ERR "ca91c042: DVA=%08X\n", val);
+
+ }
+ /* Free the dma chain */
+ ca91cx42_free_dma(dmaLL);
+
+ return 0;
+}
+
+int ca91cx42_lm_set(vmeLmCfg_t *vmeLm)
+{
+ int temp_ctl = 0;
+
+ if (vmeLm->addrU)
+ return -EINVAL;
+
+ switch (vmeLm->addrSpace) {
+ case VME_A64:
+ case VME_USER3:
+ case VME_USER4:
+ return -EINVAL;
+ case VME_A16:
+ temp_ctl |= 0x00000;
+ break;
+ case VME_A24:
+ temp_ctl |= 0x10000;
+ break;
+ case VME_A32:
+ temp_ctl |= 0x20000;
+ break;
+ case VME_CRCSR:
+ temp_ctl |= 0x50000;
+ break;
+ case VME_USER1:
+ temp_ctl |= 0x60000;
+ break;
+ case VME_USER2:
+ temp_ctl |= 0x70000;
+ break;
+ }
+
+ /* Disable while we are mucking around */
+ iowrite32(0x00000000, ca91cx42_bridge->base + LM_CTL);
+
+ iowrite32(vmeLm->addr, ca91cx42_bridge->base + LM_BS);
+
+ /* Setup CTL register. */
+ if (vmeLm->userAccessType & VME_SUPER)
+ temp_ctl |= 0x00200000;
+ if (vmeLm->userAccessType & VME_USER)
+ temp_ctl |= 0x00100000;
+ if (vmeLm->dataAccessType & VME_PROG)
+ temp_ctl |= 0x00800000;
+ if (vmeLm->dataAccessType & VME_DATA)
+ temp_ctl |= 0x00400000;
+
+
+ /* Write ctl reg and enable */
+ iowrite32(0x80000000 | temp_ctl, ca91cx42_bridge->base + LM_CTL);
+ temp_ctl = ioread32(ca91cx42_bridge->base + LM_CTL);
+
+ return 0;
+}
+
+int ca91cx42_wait_lm(vmeLmCfg_t *vmeLm)
+{
+ unsigned long flags;
+ unsigned int tmp;
+
+ spin_lock_irqsave(&lm_lock, flags);
+ spin_unlock_irqrestore(&lm_lock, flags);
+ if (tmp == 0) {
+ if (vmeLm->lmWait < 10)
+ vmeLm->lmWait = 10;
+ interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait);
+ }
+ iowrite32(0x00000000, ca91cx42_bridge->base + LM_CTL);
+
+ return 0;
+}
+
+
+
+int ca91cx42_set_arbiter(vmeArbiterCfg_t *vmeArb)
+{
+ int temp_ctl = 0;
+ int vbto = 0;
+
+ temp_ctl = ioread32(ca91cx42_bridge->base + MISC_CTL);
+ temp_ctl &= 0x00FFFFFF;
+
+ if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
+ vbto = 7;
+ } else if (vmeArb->globalTimeoutTimer > 1024) {
+ return -EINVAL;
+ } else if (vmeArb->globalTimeoutTimer == 0) {
+ vbto = 0;
+ } else {
+ vbto = 1;
+ while ((16 * (1 << (vbto - 1))) < vmeArb->globalTimeoutTimer)
+ vbto += 1;
+ }
+ temp_ctl |= (vbto << 28);
+
+ if (vmeArb->arbiterMode == VME_PRIORITY_MODE)
+ temp_ctl |= 1 << 26;
+
+ if (vmeArb->arbiterTimeoutFlag)
+ temp_ctl |= 2 << 24;
+
+ iowrite32(temp_ctl, ca91cx42_bridge->base + MISC_CTL);
+ return 0;
+}
+
+int ca91cx42_get_arbiter(vmeArbiterCfg_t *vmeArb)
+{
+ int temp_ctl = 0;
+ int vbto = 0;
+
+ temp_ctl = ioread32(ca91cx42_bridge->base + MISC_CTL);
+
+ vbto = (temp_ctl >> 28) & 0xF;
+ if (vbto != 0)
+ vmeArb->globalTimeoutTimer = (16 * (1 << (vbto - 1)));
+
+ if (temp_ctl & (1 << 26))
+ vmeArb->arbiterMode = VME_PRIORITY_MODE;
+ else
+ vmeArb->arbiterMode = VME_R_ROBIN_MODE;
+
+ if (temp_ctl & (3 << 24))
+ vmeArb->arbiterTimeoutFlag = 1;
+
+ return 0;
+}
+
+int ca91cx42_set_requestor(vmeRequesterCfg_t *vmeReq)
+{
+ int temp_ctl = 0;
+
+ temp_ctl = ioread32(ca91cx42_bridge->base + MAST_CTL);
+ temp_ctl &= 0xFF0FFFFF;
+
+ if (vmeReq->releaseMode == 1)
+ temp_ctl |= (1 << 20);
+
+ if (vmeReq->fairMode == 1)
+ temp_ctl |= (1 << 21);
+
+ temp_ctl |= (vmeReq->requestLevel << 22);
+
+ iowrite32(temp_ctl, ca91cx42_bridge->base + MAST_CTL);
+ return 0;
+}
+
+int ca91cx42_get_requestor(vmeRequesterCfg_t *vmeReq)
+{
+ int temp_ctl = 0;
+
+ temp_ctl = ioread32(ca91cx42_bridge->base + MAST_CTL);
+
+ if (temp_ctl & (1 << 20))
+ vmeReq->releaseMode = 1;
+
+ if (temp_ctl & (1 << 21))
+ vmeReq->fairMode = 1;
+
+ vmeReq->requestLevel = (temp_ctl & 0xC00000) >> 22;
+
+ return 0;
+}
+
+
+#endif
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/staging/vme/bridges/vme_ca91cx42.h
new file mode 100644
index 000000000000..95a42c240a20
--- /dev/null
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.h
@@ -0,0 +1,505 @@
+/*
+ * ca91c042.h
+ *
+ * Support for the Tundra Universe 1 and Universe II VME bridge chips
+ *
+ * Author: Tom Armistead
+ * Updated by Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * Further updated by Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2009 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Derived from ca91c042.h by Michael Wyrick
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _CA91CX42_H
+#define _CA91CX42_H
+
+#ifndef PCI_VENDOR_ID_TUNDRA
+#define PCI_VENDOR_ID_TUNDRA 0x10e3
+#endif
+
+#ifndef PCI_DEVICE_ID_TUNDRA_CA91C142
+#define PCI_DEVICE_ID_TUNDRA_CA91C142 0x0000
+#endif
+
+/*
+ * Define the number of each that the CA91C142 supports.
+ */
+#define CA91C142_MAX_MASTER 8 /* Max Master Windows */
+#define CA91C142_MAX_SLAVE 8 /* Max Slave Windows */
+#define CA91C142_MAX_DMA 1 /* Max DMA Controllers */
+#define CA91C142_MAX_MAILBOX 4 /* Max Mail Box registers */
+
+/* See Page 2-77 in the Universe User Manual */
+struct ca91cx42_dma_descriptor {
+ unsigned int dctl; /* DMA Control */
+ unsigned int dtbc; /* Transfer Byte Count */
+ unsigned int dlv; /* PCI Address */
+ unsigned int res1; /* Reserved */
+ unsigned int dva; /* Vme Address */
+ unsigned int res2; /* Reserved */
+ unsigned int dcpp; /* Pointer to Numed Cmd Packet with rPN */
+ unsigned int res3; /* Reserved */
+};
+
+struct ca91cx42_dma_entry {
+ struct ca91cx42_dma_descriptor descriptor;
+ struct list_head list;
+};
+
+/* Universe Register Offsets */
+/* general PCI configuration registers */
+#define CA91CX42_PCI_ID 0x000
+#define CA91CX42_PCI_CSR 0x004
+#define CA91CX42_PCI_CLASS 0x008
+#define CA91CX42_PCI_MISC0 0x00C
+#define CA91CX42_PCI_BS 0x010
+#define CA91CX42_PCI_MISC1 0x03C
+
+#define LSI0_CTL 0x0100
+#define LSI0_BS 0x0104
+#define LSI0_BD 0x0108
+#define LSI0_TO 0x010C
+
+#define LSI1_CTL 0x0114
+#define LSI1_BS 0x0118
+#define LSI1_BD 0x011C
+#define LSI1_TO 0x0120
+
+#define LSI2_CTL 0x0128
+#define LSI2_BS 0x012C
+#define LSI2_BD 0x0130
+#define LSI2_TO 0x0134
+
+#define LSI3_CTL 0x013C
+#define LSI3_BS 0x0140
+#define LSI3_BD 0x0144
+#define LSI3_TO 0x0148
+
+#define LSI4_CTL 0x01A0
+#define LSI4_BS 0x01A4
+#define LSI4_BD 0x01A8
+#define LSI4_TO 0x01AC
+
+#define LSI5_CTL 0x01B4
+#define LSI5_BS 0x01B8
+#define LSI5_BD 0x01BC
+#define LSI5_TO 0x01C0
+
+#define LSI6_CTL 0x01C8
+#define LSI6_BS 0x01CC
+#define LSI6_BD 0x01D0
+#define LSI6_TO 0x01D4
+
+#define LSI7_CTL 0x01DC
+#define LSI7_BS 0x01E0
+#define LSI7_BD 0x01E4
+#define LSI7_TO 0x01E8
+
+static const int CA91CX42_LSI_CTL[] = { LSI0_CTL, LSI1_CTL, LSI2_CTL, LSI3_CTL,
+ LSI4_CTL, LSI5_CTL, LSI6_CTL, LSI7_CTL };
+
+static const int CA91CX42_LSI_BS[] = { LSI0_BS, LSI1_BS, LSI2_BS, LSI3_BS,
+ LSI4_BS, LSI5_BS, LSI6_BS, LSI7_BS };
+
+static const int CA91CX42_LSI_BD[] = { LSI0_BD, LSI1_BD, LSI2_BD, LSI3_BD,
+ LSI4_BD, LSI5_BD, LSI6_BD, LSI7_BD };
+
+static const int CA91CX42_LSI_TO[] = { LSI0_TO, LSI1_TO, LSI2_TO, LSI3_TO,
+ LSI4_TO, LSI5_TO, LSI6_TO, LSI7_TO };
+
+#define SCYC_CTL 0x0170
+#define SCYC_ADDR 0x0174
+#define SCYC_EN 0x0178
+#define SCYC_CMP 0x017C
+#define SCYC_SWP 0x0180
+#define LMISC 0x0184
+#define SLSI 0x0188
+#define L_CMDERR 0x018C
+#define LAERR 0x0190
+
+#define DCTL 0x0200
+#define DTBC 0x0204
+#define DLA 0x0208
+#define DVA 0x0210
+#define DCPP 0x0218
+#define DGCS 0x0220
+#define D_LLUE 0x0224
+
+#define LINT_EN 0x0300
+#define LINT_STAT 0x0304
+#define LINT_MAP0 0x0308
+#define LINT_MAP1 0x030C
+#define VINT_EN 0x0310
+#define VINT_STAT 0x0314
+#define VINT_MAP0 0x0318
+#define VINT_MAP1 0x031C
+#define STATID 0x0320
+
+#define V1_STATID 0x0324
+#define V2_STATID 0x0328
+#define V3_STATID 0x032C
+#define V4_STATID 0x0330
+#define V5_STATID 0x0334
+#define V6_STATID 0x0338
+#define V7_STATID 0x033C
+
+static const int CA91CX42_V_STATID[8] = { 0, V1_STATID, V2_STATID, V3_STATID,
+ V4_STATID, V5_STATID, V6_STATID,
+ V7_STATID };
+
+#define LINT_MAP2 0x0340
+#define VINT_MAP2 0x0344
+
+#define MBOX0 0x0348
+#define MBOX1 0x034C
+#define MBOX2 0x0350
+#define MBOX3 0x0354
+#define SEMA0 0x0358
+#define SEMA1 0x035C
+
+#define MAST_CTL 0x0400
+#define MISC_CTL 0x0404
+#define MISC_STAT 0x0408
+#define USER_AM 0x040C
+
+#define VSI0_CTL 0x0F00
+#define VSI0_BS 0x0F04
+#define VSI0_BD 0x0F08
+#define VSI0_TO 0x0F0C
+
+#define VSI1_CTL 0x0F14
+#define VSI1_BS 0x0F18
+#define VSI1_BD 0x0F1C
+#define VSI1_TO 0x0F20
+
+#define VSI2_CTL 0x0F28
+#define VSI2_BS 0x0F2C
+#define VSI2_BD 0x0F30
+#define VSI2_TO 0x0F34
+
+#define VSI3_CTL 0x0F3C
+#define VSI3_BS 0x0F40
+#define VSI3_BD 0x0F44
+#define VSI3_TO 0x0F48
+
+#define LM_CTL 0x0F64
+#define LM_BS 0x0F68
+
+#define VRAI_CTL 0x0F70
+
+#define VRAI_BS 0x0F74
+#define VCSR_CTL 0x0F80
+#define VCSR_TO 0x0F84
+#define V_AMERR 0x0F88
+#define VAERR 0x0F8C
+
+#define VSI4_CTL 0x0F90
+#define VSI4_BS 0x0F94
+#define VSI4_BD 0x0F98
+#define VSI4_TO 0x0F9C
+
+#define VSI5_CTL 0x0FA4
+#define VSI5_BS 0x0FA8
+#define VSI5_BD 0x0FAC
+#define VSI5_TO 0x0FB0
+
+#define VSI6_CTL 0x0FB8
+#define VSI6_BS 0x0FBC
+#define VSI6_BD 0x0FC0
+#define VSI6_TO 0x0FC4
+
+#define VSI7_CTL 0x0FCC
+#define VSI7_BS 0x0FD0
+#define VSI7_BD 0x0FD4
+#define VSI7_TO 0x0FD8
+
+static const int CA91CX42_VSI_CTL[] = { VSI0_CTL, VSI1_CTL, VSI2_CTL, VSI3_CTL,
+ VSI4_CTL, VSI5_CTL, VSI6_CTL, VSI7_CTL };
+
+static const int CA91CX42_VSI_BS[] = { VSI0_BS, VSI1_BS, VSI2_BS, VSI3_BS,
+ VSI4_BS, VSI5_BS, VSI6_BS, VSI7_BS };
+
+static const int CA91CX42_VSI_BD[] = { VSI0_BD, VSI1_BD, VSI2_BD, VSI3_BD,
+ VSI4_BD, VSI5_BD, VSI6_BD, VSI7_BD };
+
+static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
+ VSI4_TO, VSI5_TO, VSI6_TO, VSI7_TO };
+
+#define VCSR_CLR 0x0FF4
+#define VCSR_SET 0x0FF8
+#define VCSR_BS 0x0FFC
+
+// DMA General Control/Status Register DGCS (0x220)
+// 32-24 || GO | STOPR | HALTR | 0 || CHAIN | 0 | 0 | 0 ||
+// 23-16 || VON || VOFF ||
+// 15-08 || ACT | STOP | HALT | 0 || DONE | LERR | VERR | P_ERR ||
+// 07-00 || 0 | INT_S | INT_H | 0 || I_DNE | I_LER | I_VER | I_PER ||
+
+// VON - Length Per DMA VMEBus Transfer
+// 0000 = None
+// 0001 = 256 Bytes
+// 0010 = 512
+// 0011 = 1024
+// 0100 = 2048
+// 0101 = 4096
+// 0110 = 8192
+// 0111 = 16384
+
+// VOFF - wait between DMA tenures
+// 0000 = 0 us
+// 0001 = 16
+// 0010 = 32
+// 0011 = 64
+// 0100 = 128
+// 0101 = 256
+// 0110 = 512
+// 0111 = 1024
+
+/*
+ * PCI Class Register
+ * offset 008
+ */
+#define CA91CX42_BM_PCI_CLASS_BASE 0xFF000000
+#define CA91CX42_OF_PCI_CLASS_BASE 24
+#define CA91CX42_BM_PCI_CLASS_SUB 0x00FF0000
+#define CA91CX42_OF_PCI_CLASS_SUB 16
+#define CA91CX42_BM_PCI_CLASS_PROG 0x0000FF00
+#define CA91CX42_OF_PCI_CLASS_PROG 8
+#define CA91CX42_BM_PCI_CLASS_RID 0x000000FF
+#define CA91CX42_OF_PCI_CLASS_RID 0
+
+#define CA91CX42_OF_PCI_CLASS_RID_UNIVERSE_I 0
+#define CA91CX42_OF_PCI_CLASS_RID_UNIVERSE_II 1
+
+/*
+ * PCI Misc Register
+ * offset 00C
+ */
+#define CA91CX42_BM_PCI_MISC0_BISTC 0x80000000
+#define CA91CX42_BM_PCI_MISC0_SBIST 0x60000000
+#define CA91CX42_BM_PCI_MISC0_CCODE 0x0F000000
+#define CA91CX42_BM_PCI_MISC0_MFUNCT 0x00800000
+#define CA91CX42_BM_PCI_MISC0_LAYOUT 0x007F0000
+#define CA91CX42_BM_PCI_MISC0_LTIMER 0x0000FF00
+#define CA91CX42_OF_PCI_MISC0_LTIMER 8
+
+
+/*
+ * LSI Control Register
+ * offset 100
+ */
+#define CA91CX42_LSI_CTL_EN (1<<31)
+#define CA91CX42_LSI_CTL_PWEN (1<<30)
+
+#define CA91CX42_LSI_CTL_VDW_M (3<<22)
+#define CA91CX42_LSI_CTL_VDW_D8 0
+#define CA91CX42_LSI_CTL_VDW_D16 (1<<22)
+#define CA91CX42_LSI_CTL_VDW_D32 (1<<23)
+#define CA91CX42_LSI_CTL_VDW_D64 (3<<22)
+
+#define CA91CX42_LSI_CTL_VAS_M (7<<16)
+#define CA91CX42_LSI_CTL_VAS_A16 0
+#define CA91CX42_LSI_CTL_VAS_A24 (1<<16)
+#define CA91CX42_LSI_CTL_VAS_A32 (1<<17)
+#define CA91CX42_LSI_CTL_VAS_CRCSR (5<<16)
+#define CA91CX42_LSI_CTL_VAS_USER1 (3<<17)
+#define CA91CX42_LSI_CTL_VAS_USER2 (7<<16)
+
+#define CA91CX42_LSI_CTL_PGM_M (1<<14)
+#define CA91CX42_LSI_CTL_PGM_DATA 0
+#define CA91CX42_LSI_CTL_PGM_PGM (1<<14)
+
+#define CA91CX42_LSI_CTL_SUPER_M (1<<12)
+#define CA91CX42_LSI_CTL_SUPER_NPRIV 0
+#define CA91CX42_LSI_CTL_SUPER_SUPR (1<<12)
+
+#define CA91CX42_LSI_CTL_VCT_M (1<<8)
+#define CA91CX42_LSI_CTL_VCT_BLT (1<<8)
+#define CA91CX42_LSI_CTL_VCT_MBLT (1<<8)
+#define CA91CX42_LSI_CTL_LAS (1<<0)
+
+
+/*
+ * LMISC Register
+ * offset 184
+ */
+#define CA91CX42_BM_LMISC_CRT 0xF0000000
+#define CA91CX42_OF_LMISC_CRT 28
+#define CA91CX42_BM_LMISC_CWT 0x0F000000
+#define CA91CX42_OF_LMISC_CWT 24
+
+/*
+ * SLSI Register
+ * offset 188
+ */
+#define CA91CX42_BM_SLSI_EN 0x80000000
+#define CA91CX42_BM_SLSI_PWEN 0x40000000
+#define CA91CX42_BM_SLSI_VDW 0x00F00000
+#define CA91CX42_OF_SLSI_VDW 20
+#define CA91CX42_BM_SLSI_PGM 0x0000F000
+#define CA91CX42_OF_SLSI_PGM 12
+#define CA91CX42_BM_SLSI_SUPER 0x00000F00
+#define CA91CX42_OF_SLSI_SUPER 8
+#define CA91CX42_BM_SLSI_BS 0x000000F6
+#define CA91CX42_OF_SLSI_BS 2
+#define CA91CX42_BM_SLSI_LAS 0x00000003
+#define CA91CX42_OF_SLSI_LAS 0
+#define CA91CX42_BM_SLSI_RESERVED 0x3F0F0000
+
+/*
+ * PCI Interrupt Enable Register
+ * offset 300
+ */
+#define CA91CX42_LINT_LM3 0x00800000
+#define CA91CX42_LINT_LM2 0x00400000
+#define CA91CX42_LINT_LM1 0x00200000
+#define CA91CX42_LINT_LM0 0x00100000
+#define CA91CX42_LINT_MBOX3 0x00080000
+#define CA91CX42_LINT_MBOX2 0x00040000
+#define CA91CX42_LINT_MBOX1 0x00020000
+#define CA91CX42_LINT_MBOX0 0x00010000
+#define CA91CX42_LINT_ACFAIL 0x00008000
+#define CA91CX42_LINT_SYSFAIL 0x00004000
+#define CA91CX42_LINT_SW_INT 0x00002000
+#define CA91CX42_LINT_SW_IACK 0x00001000
+
+#define CA91CX42_LINT_VERR 0x00000400
+#define CA91CX42_LINT_LERR 0x00000200
+#define CA91CX42_LINT_DMA 0x00000100
+#define CA91CX42_LINT_VIRQ7 0x00000080
+#define CA91CX42_LINT_VIRQ6 0x00000040
+#define CA91CX42_LINT_VIRQ5 0x00000020
+#define CA91CX42_LINT_VIRQ4 0x00000010
+#define CA91CX42_LINT_VIRQ3 0x00000008
+#define CA91CX42_LINT_VIRQ2 0x00000004
+#define CA91CX42_LINT_VIRQ1 0x00000002
+#define CA91CX42_LINT_VOWN 0x00000001
+
+static const int CA91CX42_LINT_VIRQ[] = { 0, CA91CX42_LINT_VIRQ1,
+ CA91CX42_LINT_VIRQ2, CA91CX42_LINT_VIRQ3,
+ CA91CX42_LINT_VIRQ4, CA91CX42_LINT_VIRQ5,
+ CA91CX42_LINT_VIRQ6, CA91CX42_LINT_VIRQ7 };
+
+#define CA91CX42_LINT_MBOX 0x000F0000
+
+static const int CA91CX42_LINT_LM[] = { CA91CX42_LINT_LM0, CA91CX42_LINT_LM1,
+ CA91CX42_LINT_LM2, CA91CX42_LINT_LM3 };
+
+/*
+ * MAST_CTL Register
+ * offset 400
+ */
+#define CA91CX42_BM_MAST_CTL_MAXRTRY 0xF0000000
+#define CA91CX42_OF_MAST_CTL_MAXRTRY 28
+#define CA91CX42_BM_MAST_CTL_PWON 0x0F000000
+#define CA91CX42_OF_MAST_CTL_PWON 24
+#define CA91CX42_BM_MAST_CTL_VRL 0x00C00000
+#define CA91CX42_OF_MAST_CTL_VRL 22
+#define CA91CX42_BM_MAST_CTL_VRM 0x00200000
+#define CA91CX42_BM_MAST_CTL_VREL 0x00100000
+#define CA91CX42_BM_MAST_CTL_VOWN 0x00080000
+#define CA91CX42_BM_MAST_CTL_VOWN_ACK 0x00040000
+#define CA91CX42_BM_MAST_CTL_PABS 0x00001000
+#define CA91CX42_BM_MAST_CTL_BUS_NO 0x0000000F
+#define CA91CX42_OF_MAST_CTL_BUS_NO 0
+
+/*
+ * MISC_CTL Register
+ * offset 404
+ */
+#define CA91CX42_MISC_CTL_VBTO 0xF0000000
+#define CA91CX42_MISC_CTL_VARB 0x04000000
+#define CA91CX42_MISC_CTL_VARBTO 0x03000000
+#define CA91CX42_MISC_CTL_SW_LRST 0x00800000
+#define CA91CX42_MISC_CTL_SW_SRST 0x00400000
+#define CA91CX42_MISC_CTL_BI 0x00100000
+#define CA91CX42_MISC_CTL_ENGBI 0x00080000
+#define CA91CX42_MISC_CTL_RESCIND 0x00040000
+#define CA91CX42_MISC_CTL_SYSCON 0x00020000
+#define CA91CX42_MISC_CTL_V64AUTO 0x00010000
+#define CA91CX42_MISC_CTL_RESERVED 0x0820FFFF
+
+#define CA91CX42_OF_MISC_CTL_VARBTO 24
+#define CA91CX42_OF_MISC_CTL_VBTO 28
+
+/*
+ * MISC_STAT Register
+ * offset 408
+ */
+#define CA91CX42_BM_MISC_STAT_ENDIAN 0x80000000
+#define CA91CX42_BM_MISC_STAT_LCLSIZE 0x40000000
+#define CA91CX42_BM_MISC_STAT_DY4AUTO 0x08000000
+#define CA91CX42_BM_MISC_STAT_MYBBSY 0x00200000
+#define CA91CX42_BM_MISC_STAT_DY4DONE 0x00080000
+#define CA91CX42_BM_MISC_STAT_TXFE 0x00040000
+#define CA91CX42_BM_MISC_STAT_RXFE 0x00020000
+#define CA91CX42_BM_MISC_STAT_DY4AUTOID 0x0000FF00
+#define CA91CX42_OF_MISC_STAT_DY4AUTOID 8
+
+/*
+ * VSI Control Register
+ * offset F00
+ */
+#define CA91CX42_VSI_CTL_EN (1<<31)
+#define CA91CX42_VSI_CTL_PWEN (1<<30)
+#define CA91CX42_VSI_CTL_PREN (1<<29)
+
+#define CA91CX42_VSI_CTL_PGM_M (3<<22)
+#define CA91CX42_VSI_CTL_PGM_DATA (1<<22)
+#define CA91CX42_VSI_CTL_PGM_PGM (1<<23)
+
+#define CA91CX42_VSI_CTL_SUPER_M (3<<20)
+#define CA91CX42_VSI_CTL_SUPER_NPRIV (1<<20)
+#define CA91CX42_VSI_CTL_SUPER_SUPR (1<<21)
+
+#define CA91CX42_VSI_CTL_VAS_M (7<<16)
+#define CA91CX42_VSI_CTL_VAS_A16 0
+#define CA91CX42_VSI_CTL_VAS_A24 (1<<16)
+#define CA91CX42_VSI_CTL_VAS_A32 (1<<17)
+#define CA91CX42_VSI_CTL_VAS_USER1 (3<<17)
+#define CA91CX42_VSI_CTL_VAS_USER2 (7<<16)
+
+#define CA91CX42_VSI_CTL_LD64EN (1<<7)
+#define CA91CX42_VSI_CTL_LLRMW (1<<6)
+
+#define CA91CX42_VSI_CTL_LAS_M (3<<0)
+#define CA91CX42_VSI_CTL_LAS_PCI_MS 0
+#define CA91CX42_VSI_CTL_LAS_PCI_IO (1<<0)
+#define CA91CX42_VSI_CTL_LAS_PCI_CONF (1<<1)
+
+/*
+ * VRAI_CTL Register
+ * offset F70
+ */
+#define CA91CX42_BM_VRAI_CTL_EN 0x80000000
+#define CA91CX42_BM_VRAI_CTL_PGM 0x00C00000
+#define CA91CX42_OF_VRAI_CTL_PGM 22
+#define CA91CX42_BM_VRAI_CTL_SUPER 0x00300000
+#define CA91CX42_OF_VRAI_CTL_SUPER 20
+#define CA91CX42_BM_VRAI_CTL_VAS 0x00030000
+#define CA91CX42_OF_VRAI_CTL_VAS 16
+
+/* VCSR_CTL Register
+ * offset F80
+ */
+#define CA91CX42_VCSR_CTL_EN (1<<31)
+
+#define CA91CX42_VCSR_CTL_LAS_M (3<<0)
+#define CA91CX42_VCSR_CTL_LAS_PCI_MS 0
+#define CA91CX42_VCSR_CTL_LAS_PCI_IO (1<<0)
+#define CA91CX42_VCSR_CTL_LAS_PCI_CONF (1<<1)
+
+/* VCSR_BS Register
+ * offset FFC
+ */
+#define CA91CX42_VCSR_BS_SLOT_M (0x1F<<27)
+
+#endif /* _CA91CX42_H */
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
new file mode 100644
index 000000000000..8960fa9ee7aa
--- /dev/null
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -0,0 +1,2925 @@
+/*
+ * Support for the Tundra TSI148 VME-PCI Bridge Chip
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "../vme.h"
+#include "../vme_bridge.h"
+#include "vme_tsi148.h"
+
+static int __init tsi148_init(void);
+static int tsi148_probe(struct pci_dev *, const struct pci_device_id *);
+static void tsi148_remove(struct pci_dev *);
+static void __exit tsi148_exit(void);
+
+
+int tsi148_slave_set(struct vme_slave_resource *, int, unsigned long long,
+ unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t);
+int tsi148_slave_get(struct vme_slave_resource *, int *, unsigned long long *,
+ unsigned long long *, dma_addr_t *, vme_address_t *, vme_cycle_t *);
+
+int tsi148_master_get(struct vme_master_resource *, int *, unsigned long long *,
+ unsigned long long *, vme_address_t *, vme_cycle_t *, vme_width_t *);
+int tsi148_master_set(struct vme_master_resource *, int, unsigned long long,
+ unsigned long long, vme_address_t, vme_cycle_t, vme_width_t);
+ssize_t tsi148_master_read(struct vme_master_resource *, void *, size_t,
+ loff_t);
+ssize_t tsi148_master_write(struct vme_master_resource *, void *, size_t,
+ loff_t);
+unsigned int tsi148_master_rmw(struct vme_master_resource *, unsigned int,
+ unsigned int, unsigned int, loff_t);
+int tsi148_dma_list_add (struct vme_dma_list *, struct vme_dma_attr *,
+ struct vme_dma_attr *, size_t);
+int tsi148_dma_list_exec(struct vme_dma_list *);
+int tsi148_dma_list_empty(struct vme_dma_list *);
+int tsi148_generate_irq(int, int);
+int tsi148_slot_get(void);
+
+/* Modue parameter */
+int err_chk = 0;
+
+/* XXX These should all be in a per device structure */
+struct vme_bridge *tsi148_bridge;
+wait_queue_head_t dma_queue[2];
+wait_queue_head_t iack_queue;
+void (*lm_callback[4])(int); /* Called in interrupt handler, be careful! */
+void *crcsr_kernel;
+dma_addr_t crcsr_bus;
+struct vme_master_resource *flush_image;
+struct mutex vme_rmw; /* Only one RMW cycle at a time */
+struct mutex vme_int; /*
+ * Only one VME interrupt can be
+ * generated at a time, provide locking
+ */
+struct mutex vme_irq; /* Locking for VME irq callback configuration */
+
+
+static char driver_name[] = "vme_tsi148";
+
+static struct pci_device_id tsi148_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
+ { },
+};
+
+static struct pci_driver tsi148_driver = {
+ .name = driver_name,
+ .id_table = tsi148_ids,
+ .probe = tsi148_probe,
+ .remove = tsi148_remove,
+};
+
+static void reg_join(unsigned int high, unsigned int low,
+ unsigned long long *variable)
+{
+ *variable = (unsigned long long)high << 32;
+ *variable |= (unsigned long long)low;
+}
+
+static void reg_split(unsigned long long variable, unsigned int *high,
+ unsigned int *low)
+{
+ *low = (unsigned int)variable & 0xFFFFFFFF;
+ *high = (unsigned int)(variable >> 32);
+}
+
+/*
+ * Wakes up DMA queue.
+ */
+static u32 tsi148_DMA_irqhandler(int channel_mask)
+{
+ u32 serviced = 0;
+
+ if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
+ wake_up(&dma_queue[0]);
+ serviced |= TSI148_LCSR_INTC_DMA0C;
+ }
+ if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
+ wake_up(&dma_queue[1]);
+ serviced |= TSI148_LCSR_INTC_DMA1C;
+ }
+
+ return serviced;
+}
+
+/*
+ * Wake up location monitor queue
+ */
+static u32 tsi148_LM_irqhandler(u32 stat)
+{
+ int i;
+ u32 serviced = 0;
+
+ for (i = 0; i < 4; i++) {
+ if(stat & TSI148_LCSR_INTS_LMS[i]) {
+ /* We only enable interrupts if the callback is set */
+ lm_callback[i](i);
+ serviced |= TSI148_LCSR_INTC_LMC[i];
+ }
+ }
+
+ return serviced;
+}
+
+/*
+ * Wake up mail box queue.
+ *
+ * XXX This functionality is not exposed up though API.
+ */
+static u32 tsi148_MB_irqhandler(u32 stat)
+{
+ int i;
+ u32 val;
+ u32 serviced = 0;
+
+ for (i = 0; i < 4; i++) {
+ if(stat & TSI148_LCSR_INTS_MBS[i]) {
+ val = ioread32be(tsi148_bridge->base +
+ TSI148_GCSR_MBOX[i]);
+ printk("VME Mailbox %d received: 0x%x\n", i, val);
+ serviced |= TSI148_LCSR_INTC_MBC[i];
+ }
+ }
+
+ return serviced;
+}
+
+/*
+ * Display error & status message when PERR (PCI) exception interrupt occurs.
+ */
+static u32 tsi148_PERR_irqhandler(void)
+{
+ printk(KERN_ERR
+ "PCI Exception at address: 0x%08x:%08x, attributes: %08x\n",
+ ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAU),
+ ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAL),
+ ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPAT)
+ );
+ printk(KERN_ERR
+ "PCI-X attribute reg: %08x, PCI-X split completion reg: %08x\n",
+ ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPXA),
+ ioread32be(tsi148_bridge->base + TSI148_LCSR_EDPXS)
+ );
+
+ iowrite32be(TSI148_LCSR_EDPAT_EDPCL,
+ tsi148_bridge->base + TSI148_LCSR_EDPAT);
+
+ return TSI148_LCSR_INTC_PERRC;
+}
+
+/*
+ * Save address and status when VME error interrupt occurs.
+ */
+static u32 tsi148_VERR_irqhandler(void)
+{
+ unsigned int error_addr_high, error_addr_low;
+ unsigned long long error_addr;
+ u32 error_attrib;
+ struct vme_bus_error *error;
+
+ error_addr_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAU);
+ error_addr_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAL);
+ error_attrib = ioread32be(tsi148_bridge->base + TSI148_LCSR_VEAT);
+
+ reg_join(error_addr_high, error_addr_low, &error_addr);
+
+ /* Check for exception register overflow (we have lost error data) */
+ if(error_attrib & TSI148_LCSR_VEAT_VEOF) {
+ printk(KERN_ERR "VME Bus Exception Overflow Occurred\n");
+ }
+
+ error = (struct vme_bus_error *)kmalloc(sizeof (struct vme_bus_error),
+ GFP_ATOMIC);
+ if (error) {
+ error->address = error_addr;
+ error->attributes = error_attrib;
+ list_add_tail(&(error->list), &(tsi148_bridge->vme_errors));
+ } else {
+ printk(KERN_ERR
+ "Unable to alloc memory for VMEbus Error reporting\n");
+ printk(KERN_ERR
+ "VME Bus Error at address: 0x%llx, attributes: %08x\n",
+ error_addr, error_attrib);
+ }
+
+ /* Clear Status */
+ iowrite32be(TSI148_LCSR_VEAT_VESCL,
+ tsi148_bridge->base + TSI148_LCSR_VEAT);
+
+ return TSI148_LCSR_INTC_VERRC;
+}
+
+/*
+ * Wake up IACK queue.
+ */
+static u32 tsi148_IACK_irqhandler(void)
+{
+ printk("tsi148_IACK_irqhandler\n");
+ wake_up(&iack_queue);
+
+ return TSI148_LCSR_INTC_IACKC;
+}
+
+/*
+ * Calling VME bus interrupt callback if provided.
+ */
+static u32 tsi148_VIRQ_irqhandler(u32 stat)
+{
+ int vec, i, serviced = 0;
+ void (*call)(int, int, void *);
+ void *priv_data;
+
+ for (i = 7; i > 0; i--) {
+ if (stat & (1 << i)) {
+ /*
+ * Note: Even though the registers are defined
+ * as 32-bits in the spec, we only want to issue
+ * 8-bit IACK cycles on the bus, read from offset
+ * 3.
+ */
+ vec = ioread8(tsi148_bridge->base +
+ TSI148_LCSR_VIACK[i] + 3);
+
+ call = tsi148_bridge->irq[i - 1].callback[vec].func;
+ priv_data =
+ tsi148_bridge->irq[i-1].callback[vec].priv_data;
+
+ if (call != NULL)
+ call(i, vec, priv_data);
+ else
+ printk("Spurilous VME interrupt, level:%x, "
+ "vector:%x\n", i, vec);
+
+ serviced |= (1 << i);
+ }
+ }
+
+ return serviced;
+}
+
+/*
+ * Top level interrupt handler. Clears appropriate interrupt status bits and
+ * then calls appropriate sub handler(s).
+ */
+static irqreturn_t tsi148_irqhandler(int irq, void *dev_id)
+{
+ u32 stat, enable, serviced = 0;
+
+ /* Determine which interrupts are unmasked and set */
+ enable = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ stat = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTS);
+
+ /* Only look at unmasked interrupts */
+ stat &= enable;
+
+ if (unlikely(!stat)) {
+ return IRQ_NONE;
+ }
+
+ /* Call subhandlers as appropriate */
+ /* DMA irqs */
+ if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
+ serviced |= tsi148_DMA_irqhandler(stat);
+
+ /* Location monitor irqs */
+ if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
+ TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
+ serviced |= tsi148_LM_irqhandler(stat);
+
+ /* Mail box irqs */
+ if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
+ TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
+ serviced |= tsi148_MB_irqhandler(stat);
+
+ /* PCI bus error */
+ if (stat & TSI148_LCSR_INTS_PERRS)
+ serviced |= tsi148_PERR_irqhandler();
+
+ /* VME bus error */
+ if (stat & TSI148_LCSR_INTS_VERRS)
+ serviced |= tsi148_VERR_irqhandler();
+
+ /* IACK irq */
+ if (stat & TSI148_LCSR_INTS_IACKS)
+ serviced |= tsi148_IACK_irqhandler();
+
+ /* VME bus irqs */
+ if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
+ TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
+ TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
+ TSI148_LCSR_INTS_IRQ1S))
+ serviced |= tsi148_VIRQ_irqhandler(stat);
+
+ /* Clear serviced interrupts */
+ iowrite32be(serviced, tsi148_bridge->base + TSI148_LCSR_INTC);
+
+ return IRQ_HANDLED;
+}
+
+static int tsi148_irq_init(struct vme_bridge *bridge)
+{
+ int result;
+ unsigned int tmp;
+ struct pci_dev *pdev;
+
+ /* Need pdev */
+ pdev = container_of(bridge->parent, struct pci_dev, dev);
+
+ /* Initialise list for VME bus errors */
+ INIT_LIST_HEAD(&(bridge->vme_errors));
+
+ result = request_irq(pdev->irq,
+ tsi148_irqhandler,
+ IRQF_SHARED,
+ driver_name, pdev);
+ if (result) {
+ dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n",
+ pdev->irq);
+ return result;
+ }
+
+ /* Enable and unmask interrupts */
+ tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO |
+ TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO |
+ TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO |
+ TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
+ TSI148_LCSR_INTEO_IACKEO;
+
+ /* XXX This leaves the following interrupts masked.
+ * TSI148_LCSR_INTEO_VIEEO
+ * TSI148_LCSR_INTEO_SYSFLEO
+ * TSI148_LCSR_INTEO_ACFLEO
+ */
+
+ /* Don't enable Location Monitor interrupts here - they will be
+ * enabled when the location monitors are properly configured and
+ * a callback has been attached.
+ * TSI148_LCSR_INTEO_LM0EO
+ * TSI148_LCSR_INTEO_LM1EO
+ * TSI148_LCSR_INTEO_LM2EO
+ * TSI148_LCSR_INTEO_LM3EO
+ */
+
+ /* Don't enable VME interrupts until we add a handler, else the board
+ * will respond to it and we don't want that unless it knows how to
+ * properly deal with it.
+ * TSI148_LCSR_INTEO_IRQ7EO
+ * TSI148_LCSR_INTEO_IRQ6EO
+ * TSI148_LCSR_INTEO_IRQ5EO
+ * TSI148_LCSR_INTEO_IRQ4EO
+ * TSI148_LCSR_INTEO_IRQ3EO
+ * TSI148_LCSR_INTEO_IRQ2EO
+ * TSI148_LCSR_INTEO_IRQ1EO
+ */
+
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
+
+ return 0;
+}
+
+static void tsi148_irq_exit(struct pci_dev *pdev)
+{
+ /* Turn off interrupts */
+ iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ /* Clear all interrupts */
+ iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTC);
+
+ /* Detach interrupt handler */
+ free_irq(pdev->irq, pdev);
+}
+
+/*
+ * Check to see if an IACk has been received, return true (1) or false (0).
+ */
+int tsi148_iack_received(void)
+{
+ u32 tmp;
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR);
+
+ if (tmp & TSI148_LCSR_VICR_IRQS)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Set up an VME interrupt
+ */
+int tsi148_request_irq(int level, int statid,
+ void (*callback)(int level, int vector, void *priv_data),
+ void *priv_data)
+{
+ u32 tmp;
+
+ mutex_lock(&(vme_irq));
+
+ if(tsi148_bridge->irq[level - 1].callback[statid].func) {
+ mutex_unlock(&(vme_irq));
+ printk("VME Interrupt already taken\n");
+ return -EBUSY;
+ }
+
+
+ tsi148_bridge->irq[level - 1].count++;
+ tsi148_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
+ tsi148_bridge->irq[level - 1].callback[statid].func = callback;
+
+ /* Enable IRQ level */
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ mutex_unlock(&(vme_irq));
+
+ return 0;
+}
+
+/*
+ * Free VME interrupt
+ */
+void tsi148_free_irq(int level, int statid)
+{
+ u32 tmp;
+ struct pci_dev *pdev;
+
+ mutex_lock(&(vme_irq));
+
+ tsi148_bridge->irq[level - 1].count--;
+
+ /* Disable IRQ level if no more interrupts attached at this level*/
+ if (tsi148_bridge->irq[level - 1].count == 0) {
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+
+ pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
+
+ synchronize_irq(pdev->irq);
+ }
+
+ tsi148_bridge->irq[level - 1].callback[statid].func = NULL;
+ tsi148_bridge->irq[level - 1].callback[statid].priv_data = NULL;
+
+ mutex_unlock(&(vme_irq));
+}
+
+/*
+ * Generate a VME bus interrupt at the requested level & vector. Wait for
+ * interrupt to be acked.
+ */
+int tsi148_generate_irq(int level, int statid)
+{
+ u32 tmp;
+
+ mutex_lock(&(vme_int));
+
+ /* Read VICR register */
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR);
+
+ /* Set Status/ID */
+ tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
+ (statid & TSI148_LCSR_VICR_STID_M);
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VICR);
+
+ /* Assert VMEbus IRQ */
+ tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VICR);
+
+ /* XXX Consider implementing a timeout? */
+ wait_event_interruptible(iack_queue, tsi148_iack_received());
+
+ mutex_unlock(&(vme_int));
+
+ return 0;
+}
+
+/*
+ * Find the first error in this address range
+ */
+static struct vme_bus_error *tsi148_find_error(vme_address_t aspace,
+ unsigned long long address, size_t count)
+{
+ struct list_head *err_pos;
+ struct vme_bus_error *vme_err, *valid = NULL;
+ unsigned long long bound;
+
+ bound = address + count;
+
+ /*
+ * XXX We are currently not looking at the address space when parsing
+ * for errors. This is because parsing the Address Modifier Codes
+ * is going to be quite resource intensive to do properly. We
+ * should be OK just looking at the addresses and this is certainly
+ * much better than what we had before.
+ */
+ err_pos = NULL;
+ /* Iterate through errors */
+ list_for_each(err_pos, &(tsi148_bridge->vme_errors)) {
+ vme_err = list_entry(err_pos, struct vme_bus_error, list);
+ if((vme_err->address >= address) && (vme_err->address < bound)){
+ valid = vme_err;
+ break;
+ }
+ }
+
+ return valid;
+}
+
+/*
+ * Clear errors in the provided address range.
+ */
+static void tsi148_clear_errors(vme_address_t aspace,
+ unsigned long long address, size_t count)
+{
+ struct list_head *err_pos, *temp;
+ struct vme_bus_error *vme_err;
+ unsigned long long bound;
+
+ bound = address + count;
+
+ /*
+ * XXX We are currently not looking at the address space when parsing
+ * for errors. This is because parsing the Address Modifier Codes
+ * is going to be quite resource intensive to do properly. We
+ * should be OK just looking at the addresses and this is certainly
+ * much better than what we had before.
+ */
+ err_pos = NULL;
+ /* Iterate through errors */
+ list_for_each_safe(err_pos, temp, &(tsi148_bridge->vme_errors)) {
+ vme_err = list_entry(err_pos, struct vme_bus_error, list);
+
+ if((vme_err->address >= address) && (vme_err->address < bound)){
+ list_del(err_pos);
+ kfree(vme_err);
+ }
+ }
+}
+
+/*
+ * Initialize a slave window with the requested attributes.
+ */
+int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle)
+{
+ unsigned int i, addr = 0, granularity = 0;
+ unsigned int temp_ctl = 0;
+ unsigned int vme_base_low, vme_base_high;
+ unsigned int vme_bound_low, vme_bound_high;
+ unsigned int pci_offset_low, pci_offset_high;
+ unsigned long long vme_bound, pci_offset;
+
+#if 0
+ printk("Set slave image %d to:\n", image->number);
+ printk("\tEnabled: %s\n", (enabled == 1)? "yes" : "no");
+ printk("\tVME Base:0x%llx\n", vme_base);
+ printk("\tWindow Size:0x%llx\n", size);
+ printk("\tPCI Base:0x%lx\n", (unsigned long)pci_base);
+ printk("\tAddress Space:0x%x\n", aspace);
+ printk("\tTransfer Cycle Properties:0x%x\n", cycle);
+#endif
+
+ i = image->number;
+
+ switch (aspace) {
+ case VME_A16:
+ granularity = 0x10;
+ addr |= TSI148_LCSR_ITAT_AS_A16;
+ break;
+ case VME_A24:
+ granularity = 0x1000;
+ addr |= TSI148_LCSR_ITAT_AS_A24;
+ break;
+ case VME_A32:
+ granularity = 0x10000;
+ addr |= TSI148_LCSR_ITAT_AS_A32;
+ break;
+ case VME_A64:
+ granularity = 0x10000;
+ addr |= TSI148_LCSR_ITAT_AS_A64;
+ break;
+ case VME_CRCSR:
+ case VME_USER1:
+ case VME_USER2:
+ case VME_USER3:
+ case VME_USER4:
+ default:
+ printk("Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ /* Convert 64-bit variables to 2x 32-bit variables */
+ reg_split(vme_base, &vme_base_high, &vme_base_low);
+
+ /*
+ * Bound address is a valid address for the window, adjust
+ * accordingly
+ */
+ vme_bound = vme_base + size - granularity;
+ reg_split(vme_bound, &vme_bound_high, &vme_bound_low);
+ pci_offset = (unsigned long long)pci_base - vme_base;
+ reg_split(pci_offset, &pci_offset_high, &pci_offset_low);
+
+ if (vme_base_low & (granularity - 1)) {
+ printk("Invalid VME base alignment\n");
+ return -EINVAL;
+ }
+ if (vme_bound_low & (granularity - 1)) {
+ printk("Invalid VME bound alignment\n");
+ return -EINVAL;
+ }
+ if (pci_offset_low & (granularity - 1)) {
+ printk("Invalid PCI Offset alignment\n");
+ return -EINVAL;
+ }
+
+#if 0
+ printk("\tVME Bound:0x%llx\n", vme_bound);
+ printk("\tPCI Offset:0x%llx\n", pci_offset);
+#endif
+
+ /* Disable while we are mucking around */
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+ temp_ctl &= ~TSI148_LCSR_ITAT_EN;
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+
+ /* Setup mapping */
+ iowrite32be(vme_base_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITSAU);
+ iowrite32be(vme_base_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITSAL);
+ iowrite32be(vme_bound_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITEAU);
+ iowrite32be(vme_bound_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITEAL);
+ iowrite32be(pci_offset_high, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITOFU);
+ iowrite32be(pci_offset_low, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITOFL);
+
+/* XXX Prefetch stuff currently unsupported */
+#if 0
+
+ for (x = 0; x < 4; x++) {
+ if ((64 << x) >= vmeIn->prefetchSize) {
+ break;
+ }
+ }
+ if (x == 4)
+ x--;
+ temp_ctl |= (x << 16);
+
+ if (vmeIn->prefetchThreshold)
+ if (vmeIn->prefetchThreshold)
+ temp_ctl |= 0x40000;
+#endif
+
+ /* Setup 2eSST speeds */
+ temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
+ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+ case VME_2eSST160:
+ temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160;
+ break;
+ case VME_2eSST267:
+ temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267;
+ break;
+ case VME_2eSST320:
+ temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320;
+ break;
+ }
+
+ /* Setup cycle types */
+ temp_ctl &= ~(0x1F << 7);
+ if (cycle & VME_BLT)
+ temp_ctl |= TSI148_LCSR_ITAT_BLT;
+ if (cycle & VME_MBLT)
+ temp_ctl |= TSI148_LCSR_ITAT_MBLT;
+ if (cycle & VME_2eVME)
+ temp_ctl |= TSI148_LCSR_ITAT_2eVME;
+ if (cycle & VME_2eSST)
+ temp_ctl |= TSI148_LCSR_ITAT_2eSST;
+ if (cycle & VME_2eSSTB)
+ temp_ctl |= TSI148_LCSR_ITAT_2eSSTB;
+
+ /* Setup address space */
+ temp_ctl &= ~TSI148_LCSR_ITAT_AS_M;
+ temp_ctl |= addr;
+
+ temp_ctl &= ~0xF;
+ if (cycle & VME_SUPER)
+ temp_ctl |= TSI148_LCSR_ITAT_SUPR ;
+ if (cycle & VME_USER)
+ temp_ctl |= TSI148_LCSR_ITAT_NPRIV;
+ if (cycle & VME_PROG)
+ temp_ctl |= TSI148_LCSR_ITAT_PGM;
+ if (cycle & VME_DATA)
+ temp_ctl |= TSI148_LCSR_ITAT_DATA;
+
+ /* Write ctl reg without enable */
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+
+ if (enabled)
+ temp_ctl |= TSI148_LCSR_ITAT_EN;
+
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+
+ return 0;
+}
+
+/*
+ * Get slave window configuration.
+ *
+ * XXX Prefetch currently unsupported.
+ */
+int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ unsigned int i, granularity = 0, ctl = 0;
+ unsigned int vme_base_low, vme_base_high;
+ unsigned int vme_bound_low, vme_bound_high;
+ unsigned int pci_offset_low, pci_offset_high;
+ unsigned long long vme_bound, pci_offset;
+
+
+ i = image->number;
+
+ /* Read registers */
+ ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+
+ vme_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITSAU);
+ vme_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITSAL);
+ vme_bound_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITEAU);
+ vme_bound_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITEAL);
+ pci_offset_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITOFU);
+ pci_offset_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITOFL);
+
+ /* Convert 64-bit variables to 2x 32-bit variables */
+ reg_join(vme_base_high, vme_base_low, vme_base);
+ reg_join(vme_bound_high, vme_bound_low, &vme_bound);
+ reg_join(pci_offset_high, pci_offset_low, &pci_offset);
+
+ *pci_base = (dma_addr_t)vme_base + pci_offset;
+
+ *enabled = 0;
+ *aspace = 0;
+ *cycle = 0;
+
+ if (ctl & TSI148_LCSR_ITAT_EN)
+ *enabled = 1;
+
+ if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) {
+ granularity = 0x10;
+ *aspace |= VME_A16;
+ }
+ if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) {
+ granularity = 0x1000;
+ *aspace |= VME_A24;
+ }
+ if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) {
+ granularity = 0x10000;
+ *aspace |= VME_A32;
+ }
+ if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) {
+ granularity = 0x10000;
+ *aspace |= VME_A64;
+ }
+
+ /* Need granularity before we set the size */
+ *size = (unsigned long long)((vme_bound - *vme_base) + granularity);
+
+
+ if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160)
+ *cycle |= VME_2eSST160;
+ if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267)
+ *cycle |= VME_2eSST267;
+ if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320)
+ *cycle |= VME_2eSST320;
+
+ if (ctl & TSI148_LCSR_ITAT_BLT)
+ *cycle |= VME_BLT;
+ if (ctl & TSI148_LCSR_ITAT_MBLT)
+ *cycle |= VME_MBLT;
+ if (ctl & TSI148_LCSR_ITAT_2eVME)
+ *cycle |= VME_2eVME;
+ if (ctl & TSI148_LCSR_ITAT_2eSST)
+ *cycle |= VME_2eSST;
+ if (ctl & TSI148_LCSR_ITAT_2eSSTB)
+ *cycle |= VME_2eSSTB;
+
+ if (ctl & TSI148_LCSR_ITAT_SUPR)
+ *cycle |= VME_SUPER;
+ if (ctl & TSI148_LCSR_ITAT_NPRIV)
+ *cycle |= VME_USER;
+ if (ctl & TSI148_LCSR_ITAT_PGM)
+ *cycle |= VME_PROG;
+ if (ctl & TSI148_LCSR_ITAT_DATA)
+ *cycle |= VME_DATA;
+
+ return 0;
+}
+
+/*
+ * Allocate and map PCI Resource
+ */
+static int tsi148_alloc_resource(struct vme_master_resource *image,
+ unsigned long long size)
+{
+ unsigned long long existing_size;
+ int retval = 0;
+ struct pci_dev *pdev;
+
+ /* Find pci_dev container of dev */
+ if (tsi148_bridge->parent == NULL) {
+ printk("Dev entry NULL\n");
+ return -EINVAL;
+ }
+ pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
+
+ existing_size = (unsigned long long)(image->pci_resource.end -
+ image->pci_resource.start);
+
+ /* If the existing size is OK, return */
+ if (existing_size == (size - 1))
+ return 0;
+
+ if (existing_size != 0) {
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+ if (image->pci_resource.name != NULL)
+ kfree(image->pci_resource.name);
+ release_resource(&(image->pci_resource));
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+ }
+
+ if (image->pci_resource.name == NULL) {
+ image->pci_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ if (image->pci_resource.name == NULL) {
+ printk(KERN_ERR "Unable to allocate memory for resource"
+ " name\n");
+ retval = -ENOMEM;
+ goto err_name;
+ }
+ }
+
+ sprintf((char *)image->pci_resource.name, "%s.%d", tsi148_bridge->name,
+ image->number);
+
+ image->pci_resource.start = 0;
+ image->pci_resource.end = (unsigned long)size;
+ image->pci_resource.flags = IORESOURCE_MEM;
+
+ retval = pci_bus_alloc_resource(pdev->bus,
+ &(image->pci_resource), size, size, PCIBIOS_MIN_MEM,
+ 0, NULL, NULL);
+ if (retval) {
+ printk(KERN_ERR "Failed to allocate mem resource for "
+ "window %d size 0x%lx start 0x%lx\n",
+ image->number, (unsigned long)size,
+ (unsigned long)image->pci_resource.start);
+ goto err_resource;
+ }
+
+ image->kern_base = ioremap_nocache(
+ image->pci_resource.start, size);
+ if (image->kern_base == NULL) {
+ printk(KERN_ERR "Failed to remap resource\n");
+ retval = -ENOMEM;
+ goto err_remap;
+ }
+
+ return 0;
+
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+err_remap:
+ release_resource(&(image->pci_resource));
+err_resource:
+ kfree(image->pci_resource.name);
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+err_name:
+ return retval;
+}
+
+/*
+ * Free and unmap PCI Resource
+ */
+static void tsi148_free_resource(struct vme_master_resource *image)
+{
+ iounmap(image->kern_base);
+ image->kern_base = NULL;
+ release_resource(&(image->pci_resource));
+ kfree(image->pci_resource.name);
+ memset(&(image->pci_resource), 0, sizeof(struct resource));
+}
+
+/*
+ * Set the attributes of an outbound window.
+ */
+int tsi148_master_set( struct vme_master_resource *image, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
+{
+ int retval = 0;
+ unsigned int i;
+ unsigned int temp_ctl = 0;
+ unsigned int pci_base_low, pci_base_high;
+ unsigned int pci_bound_low, pci_bound_high;
+ unsigned int vme_offset_low, vme_offset_high;
+ unsigned long long pci_bound, vme_offset, pci_base;
+
+ /* Verify input data */
+ if (vme_base & 0xFFFF) {
+ printk("Invalid VME Window alignment\n");
+ retval = -EINVAL;
+ goto err_window;
+ }
+ if (size < 0x10000) {
+ printk("Invalid VME Window size\n");
+ retval = -EINVAL;
+ goto err_window;
+ }
+
+ spin_lock(&(image->lock));
+
+ /* Let's allocate the resource here rather than further up the stack as
+ * it avoids pushing loads of bus dependant stuff up the stack
+ */
+ retval = tsi148_alloc_resource(image, size);
+ if (retval) {
+ spin_unlock(&(image->lock));
+ printk(KERN_ERR "Unable to allocate memory for resource "
+ "name\n");
+ retval = -ENOMEM;
+ goto err_res;
+ }
+
+ pci_base = (unsigned long long)image->pci_resource.start;
+
+
+ /*
+ * Bound address is a valid address for the window, adjust
+ * according to window granularity.
+ */
+ pci_bound = pci_base + (size - 0x10000);
+ vme_offset = vme_base - pci_base;
+
+ /* Convert 64-bit variables to 2x 32-bit variables */
+ reg_split(pci_base, &pci_base_high, &pci_base_low);
+ reg_split(pci_bound, &pci_bound_high, &pci_bound_low);
+ reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
+
+ if (pci_base_low & 0xFFFF) {
+ spin_unlock(&(image->lock));
+ printk("Invalid PCI base alignment\n");
+ retval = -EINVAL;
+ goto err_gran;
+ }
+ if (pci_bound_low & 0xFFFF) {
+ spin_unlock(&(image->lock));
+ printk("Invalid PCI bound alignment\n");
+ retval = -EINVAL;
+ goto err_gran;
+ }
+ if (vme_offset_low & 0xFFFF) {
+ spin_unlock(&(image->lock));
+ printk("Invalid VME Offset alignment\n");
+ retval = -EINVAL;
+ goto err_gran;
+ }
+
+ i = image->number;
+
+ /* Disable while we are mucking around */
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+ temp_ctl &= ~TSI148_LCSR_OTAT_EN;
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+
+/* XXX Prefetch stuff currently unsupported */
+#if 0
+ if (vmeOut->prefetchEnable) {
+ temp_ctl |= 0x40000;
+ for (x = 0; x < 4; x++) {
+ if ((2 << x) >= vmeOut->prefetchSize)
+ break;
+ }
+ if (x == 4)
+ x = 3;
+ temp_ctl |= (x << 16);
+ }
+#endif
+
+ /* Setup 2eSST speeds */
+ temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
+ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+ case VME_2eSST160:
+ temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160;
+ break;
+ case VME_2eSST267:
+ temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267;
+ break;
+ case VME_2eSST320:
+ temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320;
+ break;
+ }
+
+ /* Setup cycle types */
+ if (cycle & VME_BLT) {
+ temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+ temp_ctl |= TSI148_LCSR_OTAT_TM_BLT;
+ }
+ if (cycle & VME_MBLT) {
+ temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+ temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT;
+ }
+ if (cycle & VME_2eVME) {
+ temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+ temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME;
+ }
+ if (cycle & VME_2eSST) {
+ temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+ temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
+ }
+ if (cycle & VME_2eSSTB) {
+ printk("Currently not setting Broadcast Select Registers\n");
+ temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
+ temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
+ }
+
+ /* Setup data width */
+ temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M;
+ switch (dwidth) {
+ case VME_D16:
+ temp_ctl |= TSI148_LCSR_OTAT_DBW_16;
+ break;
+ case VME_D32:
+ temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
+ break;
+ default:
+ spin_unlock(&(image->lock));
+ printk("Invalid data width\n");
+ retval = -EINVAL;
+ goto err_dwidth;
+ }
+
+ /* Setup address space */
+ temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M;
+ switch (aspace) {
+ case VME_A16:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16;
+ break;
+ case VME_A24:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24;
+ break;
+ case VME_A32:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32;
+ break;
+ case VME_A64:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64;
+ break;
+ case VME_CRCSR:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR;
+ break;
+ case VME_USER1:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1;
+ break;
+ case VME_USER2:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2;
+ break;
+ case VME_USER3:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3;
+ break;
+ case VME_USER4:
+ temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
+ break;
+ default:
+ spin_unlock(&(image->lock));
+ printk("Invalid address space\n");
+ retval = -EINVAL;
+ goto err_aspace;
+ break;
+ }
+
+ temp_ctl &= ~(3<<4);
+ if (cycle & VME_SUPER)
+ temp_ctl |= TSI148_LCSR_OTAT_SUP;
+ if (cycle & VME_PROG)
+ temp_ctl |= TSI148_LCSR_OTAT_PGM;
+
+ /* Setup mapping */
+ iowrite32be(pci_base_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAU);
+ iowrite32be(pci_base_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAL);
+ iowrite32be(pci_bound_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTEAU);
+ iowrite32be(pci_bound_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTEAL);
+ iowrite32be(vme_offset_high, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTOFU);
+ iowrite32be(vme_offset_low, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTOFL);
+
+/* XXX We need to deal with OTBS */
+#if 0
+ iowrite32be(vmeOut->bcastSelect2esst, tsi148_bridge->base +
+ TSI148_LCSR_OT[i] + TSI148_LCSR_OFFSET_OTBS);
+#endif
+
+ /* Write ctl reg without enable */
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+
+ if (enabled)
+ temp_ctl |= TSI148_LCSR_OTAT_EN;
+
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+
+ spin_unlock(&(image->lock));
+ return 0;
+
+err_aspace:
+err_dwidth:
+err_gran:
+ tsi148_free_resource(image);
+err_res:
+err_window:
+ return retval;
+
+}
+
+/*
+ * Set the attributes of an outbound window.
+ *
+ * XXX Not parsing prefetch information.
+ */
+int __tsi148_master_get( struct vme_master_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
+{
+ unsigned int i, ctl;
+ unsigned int pci_base_low, pci_base_high;
+ unsigned int pci_bound_low, pci_bound_high;
+ unsigned int vme_offset_low, vme_offset_high;
+
+ unsigned long long pci_base, pci_bound, vme_offset;
+
+ i = image->number;
+
+ ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+
+ pci_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAU);
+ pci_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAL);
+ pci_bound_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTEAU);
+ pci_bound_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTEAL);
+ vme_offset_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTOFU);
+ vme_offset_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTOFL);
+
+ /* Convert 64-bit variables to 2x 32-bit variables */
+ reg_join(pci_base_high, pci_base_low, &pci_base);
+ reg_join(pci_bound_high, pci_bound_low, &pci_bound);
+ reg_join(vme_offset_high, vme_offset_low, &vme_offset);
+
+ *vme_base = pci_base + vme_offset;
+ *size = (unsigned long long)(pci_bound - pci_base) + 0x10000;
+
+ *enabled = 0;
+ *aspace = 0;
+ *cycle = 0;
+ *dwidth = 0;
+
+ if (ctl & TSI148_LCSR_OTAT_EN)
+ *enabled = 1;
+
+ /* Setup address space */
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16)
+ *aspace |= VME_A16;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24)
+ *aspace |= VME_A24;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32)
+ *aspace |= VME_A32;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64)
+ *aspace |= VME_A64;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR)
+ *aspace |= VME_CRCSR;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1)
+ *aspace |= VME_USER1;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2)
+ *aspace |= VME_USER2;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3)
+ *aspace |= VME_USER3;
+ if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4)
+ *aspace |= VME_USER4;
+
+ /* Setup 2eSST speeds */
+ if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160)
+ *cycle |= VME_2eSST160;
+ if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267)
+ *cycle |= VME_2eSST267;
+ if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320)
+ *cycle |= VME_2eSST320;
+
+ /* Setup cycle types */
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_SCT)
+ *cycle |= VME_SCT;
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_BLT)
+ *cycle |= VME_BLT;
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_MBLT)
+ *cycle |= VME_MBLT;
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_2eVME)
+ *cycle |= VME_2eVME;
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_2eSST)
+ *cycle |= VME_2eSST;
+ if ((ctl & TSI148_LCSR_OTAT_TM_M ) == TSI148_LCSR_OTAT_TM_2eSSTB)
+ *cycle |= VME_2eSSTB;
+
+ if (ctl & TSI148_LCSR_OTAT_SUP)
+ *cycle |= VME_SUPER;
+ else
+ *cycle |= VME_USER;
+
+ if (ctl & TSI148_LCSR_OTAT_PGM)
+ *cycle |= VME_PROG;
+ else
+ *cycle |= VME_DATA;
+
+ /* Setup data width */
+ if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16)
+ *dwidth = VME_D16;
+ if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32)
+ *dwidth = VME_D32;
+
+ return 0;
+}
+
+
+int tsi148_master_get( struct vme_master_resource *image, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
+{
+ int retval;
+
+ spin_lock(&(image->lock));
+
+ retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
+ cycle, dwidth);
+
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
+ size_t count, loff_t offset)
+{
+ int retval, enabled;
+ unsigned long long vme_base, size;
+ vme_address_t aspace;
+ vme_cycle_t cycle;
+ vme_width_t dwidth;
+ struct vme_bus_error *vme_err = NULL;
+
+ spin_lock(&(image->lock));
+
+ memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
+ retval = count;
+
+ if (!err_chk)
+ goto skip_chk;
+
+ __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
+ &dwidth);
+
+ vme_err = tsi148_find_error(aspace, vme_base + offset, count);
+ if(vme_err != NULL) {
+ dev_err(image->parent->parent, "First VME read error detected "
+ "an at address 0x%llx\n", vme_err->address);
+ retval = vme_err->address - (vme_base + offset);
+ /* Clear down save errors in this address range */
+ tsi148_clear_errors(aspace, vme_base + offset, count);
+ }
+
+skip_chk:
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+
+/* XXX We need to change vme_master_resource->mtx to a spinlock so that read
+ * and write functions can be used in an interrupt context
+ */
+ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
+ size_t count, loff_t offset)
+{
+ int retval = 0, enabled;
+ unsigned long long vme_base, size;
+ vme_address_t aspace;
+ vme_cycle_t cycle;
+ vme_width_t dwidth;
+
+ struct vme_bus_error *vme_err = NULL;
+
+ spin_lock(&(image->lock));
+
+ memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
+ retval = count;
+
+ /*
+ * Writes are posted. We need to do a read on the VME bus to flush out
+ * all of the writes before we check for errors. We can't guarentee
+ * that reading the data we have just written is safe. It is believed
+ * that there isn't any read, write re-ordering, so we can read any
+ * location in VME space, so lets read the Device ID from the tsi148's
+ * own registers as mapped into CR/CSR space.
+ *
+ * We check for saved errors in the written address range/space.
+ */
+
+ if (!err_chk)
+ goto skip_chk;
+
+ /*
+ * Get window info first, to maximise the time that the buffers may
+ * fluch on their own
+ */
+ __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
+ &dwidth);
+
+ ioread16(flush_image->kern_base + 0x7F000);
+
+ vme_err = tsi148_find_error(aspace, vme_base + offset, count);
+ if(vme_err != NULL) {
+ printk("First VME write error detected an at address 0x%llx\n",
+ vme_err->address);
+ retval = vme_err->address - (vme_base + offset);
+ /* Clear down save errors in this address range */
+ tsi148_clear_errors(aspace, vme_base + offset, count);
+ }
+
+skip_chk:
+ spin_unlock(&(image->lock));
+
+ return retval;
+}
+
+/*
+ * Perform an RMW cycle on the VME bus.
+ *
+ * Requires a previously configured master window, returns final value.
+ */
+unsigned int tsi148_master_rmw(struct vme_master_resource *image,
+ unsigned int mask, unsigned int compare, unsigned int swap,
+ loff_t offset)
+{
+ unsigned long long pci_addr;
+ unsigned int pci_addr_high, pci_addr_low;
+ u32 tmp, result;
+ int i;
+
+
+ /* Find the PCI address that maps to the desired VME address */
+ i = image->number;
+
+ /* Locking as we can only do one of these at a time */
+ mutex_lock(&(vme_rmw));
+
+ /* Lock image */
+ spin_lock(&(image->lock));
+
+ pci_addr_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAU);
+ pci_addr_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTSAL);
+
+ reg_join(pci_addr_high, pci_addr_low, &pci_addr);
+ reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
+
+ /* Configure registers */
+ iowrite32be(mask, tsi148_bridge->base + TSI148_LCSR_RMWEN);
+ iowrite32be(compare, tsi148_bridge->base + TSI148_LCSR_RMWC);
+ iowrite32be(swap, tsi148_bridge->base + TSI148_LCSR_RMWS);
+ iowrite32be(pci_addr_high, tsi148_bridge->base + TSI148_LCSR_RMWAU);
+ iowrite32be(pci_addr_low, tsi148_bridge->base + TSI148_LCSR_RMWAL);
+
+ /* Enable RMW */
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ tmp |= TSI148_LCSR_VMCTRL_RMWEN;
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+
+ /* Kick process off with a read to the required address. */
+ result = ioread32be(image->kern_base + offset);
+
+ /* Disable RMW */
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+
+ spin_unlock(&(image->lock));
+
+ mutex_unlock(&(vme_rmw));
+
+ return result;
+}
+
+static int tsi148_dma_set_vme_src_attributes (u32 *attr, vme_address_t aspace,
+ vme_cycle_t cycle, vme_width_t dwidth)
+{
+ /* Setup 2eSST speeds */
+ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+ case VME_2eSST160:
+ *attr |= TSI148_LCSR_DSAT_2eSSTM_160;
+ break;
+ case VME_2eSST267:
+ *attr |= TSI148_LCSR_DSAT_2eSSTM_267;
+ break;
+ case VME_2eSST320:
+ *attr |= TSI148_LCSR_DSAT_2eSSTM_320;
+ break;
+ }
+
+ /* Setup cycle types */
+ if (cycle & VME_SCT) {
+ *attr |= TSI148_LCSR_DSAT_TM_SCT;
+ }
+ if (cycle & VME_BLT) {
+ *attr |= TSI148_LCSR_DSAT_TM_BLT;
+ }
+ if (cycle & VME_MBLT) {
+ *attr |= TSI148_LCSR_DSAT_TM_MBLT;
+ }
+ if (cycle & VME_2eVME) {
+ *attr |= TSI148_LCSR_DSAT_TM_2eVME;
+ }
+ if (cycle & VME_2eSST) {
+ *attr |= TSI148_LCSR_DSAT_TM_2eSST;
+ }
+ if (cycle & VME_2eSSTB) {
+ printk("Currently not setting Broadcast Select Registers\n");
+ *attr |= TSI148_LCSR_DSAT_TM_2eSSTB;
+ }
+
+ /* Setup data width */
+ switch (dwidth) {
+ case VME_D16:
+ *attr |= TSI148_LCSR_DSAT_DBW_16;
+ break;
+ case VME_D32:
+ *attr |= TSI148_LCSR_DSAT_DBW_32;
+ break;
+ default:
+ printk("Invalid data width\n");
+ return -EINVAL;
+ }
+
+ /* Setup address space */
+ switch (aspace) {
+ case VME_A16:
+ *attr |= TSI148_LCSR_DSAT_AMODE_A16;
+ break;
+ case VME_A24:
+ *attr |= TSI148_LCSR_DSAT_AMODE_A24;
+ break;
+ case VME_A32:
+ *attr |= TSI148_LCSR_DSAT_AMODE_A32;
+ break;
+ case VME_A64:
+ *attr |= TSI148_LCSR_DSAT_AMODE_A64;
+ break;
+ case VME_CRCSR:
+ *attr |= TSI148_LCSR_DSAT_AMODE_CRCSR;
+ break;
+ case VME_USER1:
+ *attr |= TSI148_LCSR_DSAT_AMODE_USER1;
+ break;
+ case VME_USER2:
+ *attr |= TSI148_LCSR_DSAT_AMODE_USER2;
+ break;
+ case VME_USER3:
+ *attr |= TSI148_LCSR_DSAT_AMODE_USER3;
+ break;
+ case VME_USER4:
+ *attr |= TSI148_LCSR_DSAT_AMODE_USER4;
+ break;
+ default:
+ printk("Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (cycle & VME_SUPER)
+ *attr |= TSI148_LCSR_DSAT_SUP;
+ if (cycle & VME_PROG)
+ *attr |= TSI148_LCSR_DSAT_PGM;
+
+ return 0;
+}
+
+static int tsi148_dma_set_vme_dest_attributes(u32 *attr, vme_address_t aspace,
+ vme_cycle_t cycle, vme_width_t dwidth)
+{
+ /* Setup 2eSST speeds */
+ switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
+ case VME_2eSST160:
+ *attr |= TSI148_LCSR_DDAT_2eSSTM_160;
+ break;
+ case VME_2eSST267:
+ *attr |= TSI148_LCSR_DDAT_2eSSTM_267;
+ break;
+ case VME_2eSST320:
+ *attr |= TSI148_LCSR_DDAT_2eSSTM_320;
+ break;
+ }
+
+ /* Setup cycle types */
+ if (cycle & VME_SCT) {
+ *attr |= TSI148_LCSR_DDAT_TM_SCT;
+ }
+ if (cycle & VME_BLT) {
+ *attr |= TSI148_LCSR_DDAT_TM_BLT;
+ }
+ if (cycle & VME_MBLT) {
+ *attr |= TSI148_LCSR_DDAT_TM_MBLT;
+ }
+ if (cycle & VME_2eVME) {
+ *attr |= TSI148_LCSR_DDAT_TM_2eVME;
+ }
+ if (cycle & VME_2eSST) {
+ *attr |= TSI148_LCSR_DDAT_TM_2eSST;
+ }
+ if (cycle & VME_2eSSTB) {
+ printk("Currently not setting Broadcast Select Registers\n");
+ *attr |= TSI148_LCSR_DDAT_TM_2eSSTB;
+ }
+
+ /* Setup data width */
+ switch (dwidth) {
+ case VME_D16:
+ *attr |= TSI148_LCSR_DDAT_DBW_16;
+ break;
+ case VME_D32:
+ *attr |= TSI148_LCSR_DDAT_DBW_32;
+ break;
+ default:
+ printk("Invalid data width\n");
+ return -EINVAL;
+ }
+
+ /* Setup address space */
+ switch (aspace) {
+ case VME_A16:
+ *attr |= TSI148_LCSR_DDAT_AMODE_A16;
+ break;
+ case VME_A24:
+ *attr |= TSI148_LCSR_DDAT_AMODE_A24;
+ break;
+ case VME_A32:
+ *attr |= TSI148_LCSR_DDAT_AMODE_A32;
+ break;
+ case VME_A64:
+ *attr |= TSI148_LCSR_DDAT_AMODE_A64;
+ break;
+ case VME_CRCSR:
+ *attr |= TSI148_LCSR_DDAT_AMODE_CRCSR;
+ break;
+ case VME_USER1:
+ *attr |= TSI148_LCSR_DDAT_AMODE_USER1;
+ break;
+ case VME_USER2:
+ *attr |= TSI148_LCSR_DDAT_AMODE_USER2;
+ break;
+ case VME_USER3:
+ *attr |= TSI148_LCSR_DDAT_AMODE_USER3;
+ break;
+ case VME_USER4:
+ *attr |= TSI148_LCSR_DDAT_AMODE_USER4;
+ break;
+ default:
+ printk("Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (cycle & VME_SUPER)
+ *attr |= TSI148_LCSR_DDAT_SUP;
+ if (cycle & VME_PROG)
+ *attr |= TSI148_LCSR_DDAT_PGM;
+
+ return 0;
+}
+
+/*
+ * Add a link list descriptor to the list
+ *
+ * XXX Need to handle 2eSST Broadcast select bits
+ */
+int tsi148_dma_list_add (struct vme_dma_list *list, struct vme_dma_attr *src,
+ struct vme_dma_attr *dest, size_t count)
+{
+ struct tsi148_dma_entry *entry, *prev;
+ u32 address_high, address_low;
+ struct vme_dma_pattern *pattern_attr;
+ struct vme_dma_pci *pci_attr;
+ struct vme_dma_vme *vme_attr;
+ dma_addr_t desc_ptr;
+ int retval = 0;
+
+ /* XXX descriptor must be aligned on 64-bit boundaries */
+ entry = (struct tsi148_dma_entry *)kmalloc(
+ sizeof(struct tsi148_dma_entry), GFP_KERNEL);
+ if (entry == NULL) {
+ printk("Failed to allocate memory for dma resource "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_mem;
+ }
+
+ /* Test descriptor alignment */
+ if ((unsigned long)&(entry->descriptor) & 0x7) {
+ printk("Descriptor not aligned to 8 byte boundary as "
+ "required: %p\n", &(entry->descriptor));
+ retval = -EINVAL;
+ goto err_align;
+ }
+
+ /* Given we are going to fill out the structure, we probably don't
+ * need to zero it, but better safe than sorry for now.
+ */
+ memset(&(entry->descriptor), 0, sizeof(struct tsi148_dma_descriptor));
+
+ /* Fill out source part */
+ switch (src->type) {
+ case VME_DMA_PATTERN:
+ pattern_attr = (struct vme_dma_pattern *)src->private;
+
+ entry->descriptor.dsal = pattern_attr->pattern;
+ entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
+ /* Default behaviour is 32 bit pattern */
+ if (pattern_attr->type & VME_DMA_PATTERN_BYTE) {
+ entry->descriptor.dsat |= TSI148_LCSR_DSAT_PSZ;
+ }
+ /* It seems that the default behaviour is to increment */
+ if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0) {
+ entry->descriptor.dsat |= TSI148_LCSR_DSAT_NIN;
+ }
+ break;
+ case VME_DMA_PCI:
+ pci_attr = (struct vme_dma_pci *)src->private;
+
+ reg_split((unsigned long long)pci_attr->address, &address_high,
+ &address_low);
+ entry->descriptor.dsau = address_high;
+ entry->descriptor.dsal = address_low;
+ entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
+ break;
+ case VME_DMA_VME:
+ vme_attr = (struct vme_dma_vme *)src->private;
+
+ reg_split((unsigned long long)vme_attr->address, &address_high,
+ &address_low);
+ entry->descriptor.dsau = address_high;
+ entry->descriptor.dsal = address_low;
+ entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
+
+ retval = tsi148_dma_set_vme_src_attributes(
+ &(entry->descriptor.dsat), vme_attr->aspace,
+ vme_attr->cycle, vme_attr->dwidth);
+ if(retval < 0 )
+ goto err_source;
+ break;
+ default:
+ printk("Invalid source type\n");
+ retval = -EINVAL;
+ goto err_source;
+ break;
+ }
+
+ /* Assume last link - this will be over-written by adding another */
+ entry->descriptor.dnlau = 0;
+ entry->descriptor.dnlal = TSI148_LCSR_DNLAL_LLA;
+
+
+ /* Fill out destination part */
+ switch (dest->type) {
+ case VME_DMA_PCI:
+ pci_attr = (struct vme_dma_pci *)dest->private;
+
+ reg_split((unsigned long long)pci_attr->address, &address_high,
+ &address_low);
+ entry->descriptor.ddau = address_high;
+ entry->descriptor.ddal = address_low;
+ entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
+ break;
+ case VME_DMA_VME:
+ vme_attr = (struct vme_dma_vme *)dest->private;
+
+ reg_split((unsigned long long)vme_attr->address, &address_high,
+ &address_low);
+ entry->descriptor.ddau = address_high;
+ entry->descriptor.ddal = address_low;
+ entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
+
+ retval = tsi148_dma_set_vme_dest_attributes(
+ &(entry->descriptor.ddat), vme_attr->aspace,
+ vme_attr->cycle, vme_attr->dwidth);
+ if(retval < 0 )
+ goto err_dest;
+ break;
+ default:
+ printk("Invalid destination type\n");
+ retval = -EINVAL;
+ goto err_dest;
+ break;
+ }
+
+ /* Fill out count */
+ entry->descriptor.dcnt = (u32)count;
+
+ /* Add to list */
+ list_add_tail(&(entry->list), &(list->entries));
+
+ /* Fill out previous descriptors "Next Address" */
+ if(entry->list.prev != &(list->entries)){
+ prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
+ list);
+ /* We need the bus address for the pointer */
+ desc_ptr = virt_to_bus(&(entry->descriptor));
+ reg_split(desc_ptr, &(prev->descriptor.dnlau),
+ &(prev->descriptor.dnlal));
+ }
+
+ return 0;
+
+err_dest:
+err_source:
+err_align:
+ kfree(entry);
+err_mem:
+ return retval;
+}
+
+/*
+ * Check to see if the provided DMA channel is busy.
+ */
+static int tsi148_dma_busy(int channel)
+{
+ u32 tmp;
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DSTA);
+
+ if (tmp & TSI148_LCSR_DSTA_BSY)
+ return 0;
+ else
+ return 1;
+
+}
+
+/*
+ * Execute a previously generated link list
+ *
+ * XXX Need to provide control register configuration.
+ */
+int tsi148_dma_list_exec(struct vme_dma_list *list)
+{
+ struct vme_dma_resource *ctrlr;
+ int channel, retval = 0;
+ struct tsi148_dma_entry *entry;
+ dma_addr_t bus_addr;
+ u32 bus_addr_high, bus_addr_low;
+ u32 val, dctlreg = 0;
+#if 0
+ int x;
+#endif
+
+ ctrlr = list->parent;
+
+ mutex_lock(&(ctrlr->mtx));
+
+ channel = ctrlr->number;
+
+ if (! list_empty(&(ctrlr->running))) {
+ /*
+ * XXX We have an active DMA transfer and currently haven't
+ * sorted out the mechanism for "pending" DMA transfers.
+ * Return busy.
+ */
+ /* Need to add to pending here */
+ mutex_unlock(&(ctrlr->mtx));
+ return -EBUSY;
+ } else {
+ list_add(&(list->list), &(ctrlr->running));
+ }
+#if 0
+ /* XXX Still todo */
+ for (x = 0; x < 8; x++) { /* vme block size */
+ if ((32 << x) >= vmeDma->maxVmeBlockSize) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 12);
+
+ for (x = 0; x < 8; x++) { /* pci block size */
+ if ((32 << x) >= vmeDma->maxPciBlockSize) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 4);
+
+ if (vmeDma->vmeBackOffTimer) {
+ for (x = 1; x < 8; x++) { /* vme timer */
+ if ((1 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 8);
+ }
+
+ if (vmeDma->pciBackOffTimer) {
+ for (x = 1; x < 8; x++) { /* pci timer */
+ if ((1 << (x - 1)) >= vmeDma->pciBackOffTimer) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 0);
+ }
+#endif
+
+ /* Get first bus address and write into registers */
+ entry = list_first_entry(&(list->entries), struct tsi148_dma_entry,
+ list);
+
+ bus_addr = virt_to_bus(&(entry->descriptor));
+
+ mutex_unlock(&(ctrlr->mtx));
+
+ reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
+
+ iowrite32be(bus_addr_high, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
+ iowrite32be(bus_addr_low, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
+
+ /* Start the operation */
+ iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
+
+ wait_event_interruptible(dma_queue[channel], tsi148_dma_busy(channel));
+ /*
+ * Read status register, this register is valid until we kick off a
+ * new transfer.
+ */
+ val = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DSTA);
+
+ if (val & TSI148_LCSR_DSTA_VBE) {
+ printk(KERN_ERR "tsi148: DMA Error. DSTA=%08X\n", val);
+ retval = -EIO;
+ }
+
+ /* Remove list from running list */
+ mutex_lock(&(ctrlr->mtx));
+ list_del(&(list->list));
+ mutex_unlock(&(ctrlr->mtx));
+
+ return retval;
+}
+
+/*
+ * Clean up a previously generated link list
+ *
+ * We have a separate function, don't assume that the chain can't be reused.
+ */
+int tsi148_dma_list_empty(struct vme_dma_list *list)
+{
+ struct list_head *pos, *temp;
+ struct tsi148_dma_entry *entry;
+
+ /* detach and free each entry */
+ list_for_each_safe(pos, temp, &(list->entries)) {
+ list_del(pos);
+ entry = list_entry(pos, struct tsi148_dma_entry, list);
+ kfree(entry);
+ }
+
+ return (0);
+}
+
+/*
+ * All 4 location monitors reside at the same base - this is therefore a
+ * system wide configuration.
+ *
+ * This does not enable the LM monitor - that should be done when the first
+ * callback is attached and disabled when the last callback is removed.
+ */
+int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
+ vme_address_t aspace, vme_cycle_t cycle)
+{
+ u32 lm_base_high, lm_base_low, lm_ctl = 0;
+ int i;
+
+ mutex_lock(&(lm->mtx));
+
+ /* If we already have a callback attached, we can't move it! */
+ for (i = 0; i < lm->monitors; i++) {
+ if(lm_callback[i] != NULL) {
+ mutex_unlock(&(lm->mtx));
+ printk("Location monitor callback attached, can't "
+ "reset\n");
+ return -EBUSY;
+ }
+ }
+
+ switch (aspace) {
+ case VME_A16:
+ lm_ctl |= TSI148_LCSR_LMAT_AS_A16;
+ break;
+ case VME_A24:
+ lm_ctl |= TSI148_LCSR_LMAT_AS_A24;
+ break;
+ case VME_A32:
+ lm_ctl |= TSI148_LCSR_LMAT_AS_A32;
+ break;
+ case VME_A64:
+ lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
+ break;
+ default:
+ mutex_unlock(&(lm->mtx));
+ printk("Invalid address space\n");
+ return -EINVAL;
+ break;
+ }
+
+ if (cycle & VME_SUPER)
+ lm_ctl |= TSI148_LCSR_LMAT_SUPR ;
+ if (cycle & VME_USER)
+ lm_ctl |= TSI148_LCSR_LMAT_NPRIV;
+ if (cycle & VME_PROG)
+ lm_ctl |= TSI148_LCSR_LMAT_PGM;
+ if (cycle & VME_DATA)
+ lm_ctl |= TSI148_LCSR_LMAT_DATA;
+
+ reg_split(lm_base, &lm_base_high, &lm_base_low);
+
+ iowrite32be(lm_base_high, tsi148_bridge->base + TSI148_LCSR_LMBAU);
+ iowrite32be(lm_base_low, tsi148_bridge->base + TSI148_LCSR_LMBAL);
+ iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+/* Get configuration of the callback monitor and return whether it is enabled
+ * or disabled.
+ */
+int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base,
+ vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
+
+ mutex_lock(&(lm->mtx));
+
+ lm_base_high = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAU);
+ lm_base_low = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMBAL);
+ lm_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+
+ reg_join(lm_base_high, lm_base_low, lm_base);
+
+ if (lm_ctl & TSI148_LCSR_LMAT_EN)
+ enabled = 1;
+
+ if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16) {
+ *aspace |= VME_A16;
+ }
+ if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24) {
+ *aspace |= VME_A24;
+ }
+ if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32) {
+ *aspace |= VME_A32;
+ }
+ if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64) {
+ *aspace |= VME_A64;
+ }
+
+ if (lm_ctl & TSI148_LCSR_LMAT_SUPR)
+ *cycle |= VME_SUPER;
+ if (lm_ctl & TSI148_LCSR_LMAT_NPRIV)
+ *cycle |= VME_USER;
+ if (lm_ctl & TSI148_LCSR_LMAT_PGM)
+ *cycle |= VME_PROG;
+ if (lm_ctl & TSI148_LCSR_LMAT_DATA)
+ *cycle |= VME_DATA;
+
+ mutex_unlock(&(lm->mtx));
+
+ return enabled;
+}
+
+/*
+ * Attach a callback to a specific location monitor.
+ *
+ * Callback will be passed the monitor triggered.
+ */
+int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
+ void (*callback)(int))
+{
+ u32 lm_ctl, tmp;
+
+ mutex_lock(&(lm->mtx));
+
+ /* Ensure that the location monitor is configured - need PGM or DATA */
+ lm_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+ if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
+ mutex_unlock(&(lm->mtx));
+ printk("Location monitor not properly configured\n");
+ return -EINVAL;
+ }
+
+ /* Check that a callback isn't already attached */
+ if (lm_callback[monitor] != NULL) {
+ mutex_unlock(&(lm->mtx));
+ printk("Existing callback attached\n");
+ return -EBUSY;
+ }
+
+ /* Attach callback */
+ lm_callback[monitor] = callback;
+
+ /* Enable Location Monitor interrupt */
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+
+ /* Ensure that global Location Monitor Enable set */
+ if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
+ lm_ctl |= TSI148_LCSR_LMAT_EN;
+ iowrite32be(lm_ctl, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ }
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+/*
+ * Detach a callback function forn a specific location monitor.
+ */
+int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
+{
+ u32 lm_en, tmp;
+
+ mutex_lock(&(lm->mtx));
+
+ /* Disable Location Monitor and ensure previous interrupts are clear */
+ lm_en = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
+ iowrite32be(lm_en, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
+
+ iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
+ tsi148_bridge->base + TSI148_LCSR_INTEO);
+
+ /* Detach callback */
+ lm_callback[monitor] = NULL;
+
+ /* If all location monitors disabled, disable global Location Monitor */
+ if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
+ TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_LMAT);
+ tmp &= ~TSI148_LCSR_LMAT_EN;
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_LMAT);
+ }
+
+ mutex_unlock(&(lm->mtx));
+
+ return 0;
+}
+
+/*
+ * Determine Geographical Addressing
+ */
+int tsi148_slot_get(void)
+{
+ u32 slot = 0;
+
+ slot = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ slot = slot & TSI148_LCSR_VSTAT_GA_M;
+ return (int)slot;
+}
+
+static int __init tsi148_init(void)
+{
+ return pci_register_driver(&tsi148_driver);
+}
+
+/*
+ * Configure CR/CSR space
+ *
+ * Access to the CR/CSR can be configured at power-up. The location of the
+ * CR/CSR registers in the CR/CSR address space is determined by the boards
+ * Auto-ID or Geographic address. This function ensures that the window is
+ * enabled at an offset consistent with the boards geopgraphic address.
+ *
+ * Each board has a 512kB window, with the highest 4kB being used for the
+ * boards registers, this means there is a fix length 508kB window which must
+ * be mapped onto PCI memory.
+ */
+static int tsi148_crcsr_init(struct pci_dev *pdev)
+{
+ u32 cbar, crat, vstat;
+ u32 crcsr_bus_high, crcsr_bus_low;
+ int retval;
+
+ /* Allocate mem for CR/CSR image */
+ crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
+ &crcsr_bus);
+ if (crcsr_kernel == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR "
+ "image\n");
+ return -ENOMEM;
+ }
+
+ memset(crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
+
+ reg_split(crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
+
+ iowrite32be(crcsr_bus_high, tsi148_bridge->base + TSI148_LCSR_CROU);
+ iowrite32be(crcsr_bus_low, tsi148_bridge->base + TSI148_LCSR_CROL);
+
+ /* Ensure that the CR/CSR is configured at the correct offset */
+ cbar = ioread32be(tsi148_bridge->base + TSI148_CBAR);
+ cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
+
+ vstat = tsi148_slot_get();
+
+ if (cbar != vstat) {
+ dev_info(&pdev->dev, "Setting CR/CSR offset\n");
+ iowrite32be(cbar<<3, tsi148_bridge->base + TSI148_CBAR);
+ }
+ dev_info(&pdev->dev, "CR/CSR Offset: %d\n", cbar);
+
+ crat = ioread32be(tsi148_bridge->base + TSI148_LCSR_CRAT);
+ if (crat & TSI148_LCSR_CRAT_EN) {
+ dev_info(&pdev->dev, "Enabling CR/CSR space\n");
+ iowrite32be(crat | TSI148_LCSR_CRAT_EN,
+ tsi148_bridge->base + TSI148_LCSR_CRAT);
+ } else
+ dev_info(&pdev->dev, "CR/CSR already enabled\n");
+
+ /* If we want flushed, error-checked writes, set up a window
+ * over the CR/CSR registers. We read from here to safely flush
+ * through VME writes.
+ */
+ if(err_chk) {
+ retval = tsi148_master_set(flush_image, 1, (vstat * 0x80000),
+ 0x80000, VME_CRCSR, VME_SCT, VME_D16);
+ if (retval)
+ dev_err(&pdev->dev, "Configuring flush image failed\n");
+ }
+
+ return 0;
+
+}
+
+static void tsi148_crcsr_exit(struct pci_dev *pdev)
+{
+ u32 crat;
+
+ /* Turn off CR/CSR space */
+ crat = ioread32be(tsi148_bridge->base + TSI148_LCSR_CRAT);
+ iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
+ tsi148_bridge->base + TSI148_LCSR_CRAT);
+
+ /* Free image */
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CROU);
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CROL);
+
+ pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, crcsr_kernel, crcsr_bus);
+}
+
+static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int retval, i, master_num;
+ u32 data;
+ struct list_head *pos = NULL;
+ struct vme_master_resource *master_image;
+ struct vme_slave_resource *slave_image;
+ struct vme_dma_resource *dma_ctrlr;
+ struct vme_lm_resource *lm;
+
+ /* If we want to support more than one of each bridge, we need to
+ * dynamically generate this so we get one per device
+ */
+ tsi148_bridge = (struct vme_bridge *)kmalloc(sizeof(struct vme_bridge),
+ GFP_KERNEL);
+ if (tsi148_bridge == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for device "
+ "structure\n");
+ retval = -ENOMEM;
+ goto err_struct;
+ }
+
+ memset(tsi148_bridge, 0, sizeof(struct vme_bridge));
+
+ /* Enable the device */
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to enable device\n");
+ goto err_enable;
+ }
+
+ /* Map Registers */
+ retval = pci_request_regions(pdev, driver_name);
+ if (retval) {
+ dev_err(&pdev->dev, "Unable to reserve resources\n");
+ goto err_resource;
+ }
+
+ /* map registers in BAR 0 */
+ tsi148_bridge->base = ioremap_nocache(pci_resource_start(pdev, 0), 4096);
+ if (!tsi148_bridge->base) {
+ dev_err(&pdev->dev, "Unable to remap CRG region\n");
+ retval = -EIO;
+ goto err_remap;
+ }
+
+ /* Check to see if the mapping worked out */
+ data = ioread32(tsi148_bridge->base + TSI148_PCFS_ID) & 0x0000FFFF;
+ if (data != PCI_VENDOR_ID_TUNDRA) {
+ dev_err(&pdev->dev, "CRG region check failed\n");
+ retval = -EIO;
+ goto err_test;
+ }
+
+ /* Initialize wait queues & mutual exclusion flags */
+ /* XXX These need to be moved to the vme_bridge structure */
+ init_waitqueue_head(&dma_queue[0]);
+ init_waitqueue_head(&dma_queue[1]);
+ init_waitqueue_head(&iack_queue);
+ mutex_init(&(vme_int));
+ mutex_init(&(vme_irq));
+ mutex_init(&(vme_rmw));
+
+ tsi148_bridge->parent = &(pdev->dev);
+ strcpy(tsi148_bridge->name, driver_name);
+
+ /* Setup IRQ */
+ retval = tsi148_irq_init(tsi148_bridge);
+ if (retval != 0) {
+ dev_err(&pdev->dev, "Chip Initialization failed.\n");
+ goto err_irq;
+ }
+
+ /* If we are going to flush writes, we need to read from the VME bus.
+ * We need to do this safely, thus we read the devices own CR/CSR
+ * register. To do this we must set up a window in CR/CSR space and
+ * hence have one less master window resource available.
+ */
+ master_num = TSI148_MAX_MASTER;
+ if(err_chk){
+ master_num--;
+ /* XXX */
+ flush_image = (struct vme_master_resource *)kmalloc(
+ sizeof(struct vme_master_resource), GFP_KERNEL);
+ if (flush_image == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "flush resource structure\n");
+ retval = -ENOMEM;
+ goto err_master;
+ }
+ flush_image->parent = tsi148_bridge;
+ spin_lock_init(&(flush_image->lock));
+ flush_image->locked = 1;
+ flush_image->number = master_num;
+ flush_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+ VME_A64;
+ flush_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+ VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+ VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+ VME_PROG | VME_DATA;
+ flush_image->width_attr = VME_D16 | VME_D32;
+ memset(&(flush_image->pci_resource), 0,
+ sizeof(struct resource));
+ flush_image->kern_base = NULL;
+ }
+
+ /* Add master windows to list */
+ INIT_LIST_HEAD(&(tsi148_bridge->master_resources));
+ for (i = 0; i < master_num; i++) {
+ master_image = (struct vme_master_resource *)kmalloc(
+ sizeof(struct vme_master_resource), GFP_KERNEL);
+ if (master_image == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "master resource structure\n");
+ retval = -ENOMEM;
+ goto err_master;
+ }
+ master_image->parent = tsi148_bridge;
+ spin_lock_init(&(master_image->lock));
+ master_image->locked = 0;
+ master_image->number = i;
+ master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+ VME_A64;
+ master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+ VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+ VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+ VME_PROG | VME_DATA;
+ master_image->width_attr = VME_D16 | VME_D32;
+ memset(&(master_image->pci_resource), 0,
+ sizeof(struct resource));
+ master_image->kern_base = NULL;
+ list_add_tail(&(master_image->list),
+ &(tsi148_bridge->master_resources));
+ }
+
+ /* Add slave windows to list */
+ INIT_LIST_HEAD(&(tsi148_bridge->slave_resources));
+ for (i = 0; i < TSI148_MAX_SLAVE; i++) {
+ slave_image = (struct vme_slave_resource *)kmalloc(
+ sizeof(struct vme_slave_resource), GFP_KERNEL);
+ if (slave_image == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "slave resource structure\n");
+ retval = -ENOMEM;
+ goto err_slave;
+ }
+ slave_image->parent = tsi148_bridge;
+ mutex_init(&(slave_image->mtx));
+ slave_image->locked = 0;
+ slave_image->number = i;
+ slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+ VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
+ VME_USER3 | VME_USER4;
+ slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+ VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+ VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+ VME_PROG | VME_DATA;
+ list_add_tail(&(slave_image->list),
+ &(tsi148_bridge->slave_resources));
+ }
+
+ /* Add dma engines to list */
+ INIT_LIST_HEAD(&(tsi148_bridge->dma_resources));
+ for (i = 0; i < TSI148_MAX_DMA; i++) {
+ dma_ctrlr = (struct vme_dma_resource *)kmalloc(
+ sizeof(struct vme_dma_resource), GFP_KERNEL);
+ if (dma_ctrlr == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "dma resource structure\n");
+ retval = -ENOMEM;
+ goto err_dma;
+ }
+ dma_ctrlr->parent = tsi148_bridge;
+ mutex_init(&(dma_ctrlr->mtx));
+ dma_ctrlr->locked = 0;
+ dma_ctrlr->number = i;
+ INIT_LIST_HEAD(&(dma_ctrlr->pending));
+ INIT_LIST_HEAD(&(dma_ctrlr->running));
+ list_add_tail(&(dma_ctrlr->list),
+ &(tsi148_bridge->dma_resources));
+ }
+
+ /* Add location monitor to list */
+ INIT_LIST_HEAD(&(tsi148_bridge->lm_resources));
+ lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
+ if (lm == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate memory for "
+ "location monitor resource structure\n");
+ retval = -ENOMEM;
+ goto err_lm;
+ }
+ lm->parent = tsi148_bridge;
+ mutex_init(&(lm->mtx));
+ lm->locked = 0;
+ lm->number = 1;
+ lm->monitors = 4;
+ list_add_tail(&(lm->list), &(tsi148_bridge->lm_resources));
+
+ tsi148_bridge->slave_get = tsi148_slave_get;
+ tsi148_bridge->slave_set = tsi148_slave_set;
+ tsi148_bridge->master_get = tsi148_master_get;
+ tsi148_bridge->master_set = tsi148_master_set;
+ tsi148_bridge->master_read = tsi148_master_read;
+ tsi148_bridge->master_write = tsi148_master_write;
+ tsi148_bridge->master_rmw = tsi148_master_rmw;
+ tsi148_bridge->dma_list_add = tsi148_dma_list_add;
+ tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
+ tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
+ tsi148_bridge->request_irq = tsi148_request_irq;
+ tsi148_bridge->free_irq = tsi148_free_irq;
+ tsi148_bridge->generate_irq = tsi148_generate_irq;
+ tsi148_bridge->lm_set = tsi148_lm_set;
+ tsi148_bridge->lm_get = tsi148_lm_get;
+ tsi148_bridge->lm_attach = tsi148_lm_attach;
+ tsi148_bridge->lm_detach = tsi148_lm_detach;
+ tsi148_bridge->slot_get = tsi148_slot_get;
+
+ data = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ dev_info(&pdev->dev, "Board is%s the VME system controller\n",
+ (data & TSI148_LCSR_VSTAT_SCONS)? "" : " not");
+ dev_info(&pdev->dev, "VME geographical address is %d\n",
+ data & TSI148_LCSR_VSTAT_GA_M);
+ dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
+ err_chk ? "enabled" : "disabled");
+
+ if(tsi148_crcsr_init(pdev)) {
+ dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
+ goto err_crcsr;
+
+ }
+
+ /* Need to save tsi148_bridge pointer locally in link list for use in
+ * tsi148_remove()
+ */
+ retval = vme_register_bridge(tsi148_bridge);
+ if (retval != 0) {
+ dev_err(&pdev->dev, "Chip Registration failed.\n");
+ goto err_reg;
+ }
+
+ /* Clear VME bus "board fail", and "power-up reset" lines */
+ data = ioread32be(tsi148_bridge->base + TSI148_LCSR_VSTAT);
+ data &= ~TSI148_LCSR_VSTAT_BRDFL;
+ data |= TSI148_LCSR_VSTAT_CPURST;
+ iowrite32be(data, tsi148_bridge->base + TSI148_LCSR_VSTAT);
+
+ return 0;
+
+ vme_unregister_bridge(tsi148_bridge);
+err_reg:
+ tsi148_crcsr_exit(pdev);
+err_crcsr:
+err_lm:
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->lm_resources)) {
+ lm = list_entry(pos, struct vme_lm_resource, list);
+ list_del(pos);
+ kfree(lm);
+ }
+err_dma:
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->dma_resources)) {
+ dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+ list_del(pos);
+ kfree(dma_ctrlr);
+ }
+err_slave:
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->slave_resources)) {
+ slave_image = list_entry(pos, struct vme_slave_resource, list);
+ list_del(pos);
+ kfree(slave_image);
+ }
+err_master:
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->master_resources)) {
+ master_image = list_entry(pos, struct vme_master_resource, list);
+ list_del(pos);
+ kfree(master_image);
+ }
+
+ tsi148_irq_exit(pdev);
+err_irq:
+err_test:
+ iounmap(tsi148_bridge->base);
+err_remap:
+ pci_release_regions(pdev);
+err_resource:
+ pci_disable_device(pdev);
+err_enable:
+ kfree(tsi148_bridge);
+err_struct:
+ return retval;
+
+}
+
+static void tsi148_remove(struct pci_dev *pdev)
+{
+ struct list_head *pos = NULL;
+ struct vme_master_resource *master_image;
+ struct vme_slave_resource *slave_image;
+ struct vme_dma_resource *dma_ctrlr;
+ int i;
+
+ dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
+
+ /* XXX We need to find the pdev->dev in the list of vme_bridge->dev's */
+
+ /*
+ * Shutdown all inbound and outbound windows.
+ */
+ for (i = 0; i < 8; i++) {
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_IT[i] +
+ TSI148_LCSR_OFFSET_ITAT);
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_OT[i] +
+ TSI148_LCSR_OFFSET_OTAT);
+ }
+
+ /*
+ * Shutdown Location monitor.
+ */
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_LMAT);
+
+ /*
+ * Shutdown CRG map.
+ */
+ iowrite32be(0, tsi148_bridge->base + TSI148_LCSR_CSRAT);
+
+ /*
+ * Clear error status.
+ */
+ iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_EDPAT);
+ iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_VEAT);
+ iowrite32be(0x07000700, tsi148_bridge->base + TSI148_LCSR_PSTAT);
+
+ /*
+ * Remove VIRQ interrupt (if any)
+ */
+ if (ioread32be(tsi148_bridge->base + TSI148_LCSR_VICR) & 0x800) {
+ iowrite32be(0x8000, tsi148_bridge->base + TSI148_LCSR_VICR);
+ }
+
+ /*
+ * Disable and clear all interrupts.
+ */
+ iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEO);
+ iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTC);
+ iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTEN);
+
+ /*
+ * Map all Interrupts to PCI INTA
+ */
+ iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTM1);
+ iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTM2);
+
+ tsi148_irq_exit(pdev);
+
+ vme_unregister_bridge(tsi148_bridge);
+
+ tsi148_crcsr_exit(pdev);
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->dma_resources)) {
+ dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
+ list_del(pos);
+ kfree(dma_ctrlr);
+ }
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->slave_resources)) {
+ slave_image = list_entry(pos, struct vme_slave_resource, list);
+ list_del(pos);
+ kfree(slave_image);
+ }
+
+ /* resources are stored in link list */
+ list_for_each(pos, &(tsi148_bridge->master_resources)) {
+ master_image = list_entry(pos, struct vme_master_resource, list);
+ list_del(pos);
+ kfree(master_image);
+ }
+
+ tsi148_irq_exit(pdev);
+
+ iounmap(tsi148_bridge->base);
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+
+ kfree(tsi148_bridge);
+}
+
+static void __exit tsi148_exit(void)
+{
+ pci_unregister_driver(&tsi148_driver);
+
+ printk(KERN_DEBUG "Driver removed.\n");
+}
+
+MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
+module_param(err_chk, bool, 0);
+
+MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
+MODULE_LICENSE("GPL");
+
+module_init(tsi148_init);
+module_exit(tsi148_exit);
+
+/*----------------------------------------------------------------------------
+ * STAGING
+ *--------------------------------------------------------------------------*/
+
+#if 0
+/*
+ * Direct Mode DMA transfer
+ *
+ * XXX Not looking at direct mode for now, we can always use link list mode
+ * with a single entry.
+ */
+int tsi148_dma_run(struct vme_dma_resource *resource, struct vme_dma_attr src,
+ struct vme_dma_attr dest, size_t count)
+{
+ u32 dctlreg = 0;
+ unsigned int tmp;
+ int val;
+ int channel, x;
+ struct vmeDmaPacket *cur_dma;
+ struct tsi148_dma_descriptor *dmaLL;
+
+ /* direct mode */
+ dctlreg = 0x800000;
+
+ for (x = 0; x < 8; x++) { /* vme block size */
+ if ((32 << x) >= vmeDma->maxVmeBlockSize) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 12);
+
+ for (x = 0; x < 8; x++) { /* pci block size */
+ if ((32 << x) >= vmeDma->maxPciBlockSize) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 4);
+
+ if (vmeDma->vmeBackOffTimer) {
+ for (x = 1; x < 8; x++) { /* vme timer */
+ if ((1 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 8);
+ }
+
+ if (vmeDma->pciBackOffTimer) {
+ for (x = 1; x < 8; x++) { /* pci timer */
+ if ((1 << (x - 1)) >= vmeDma->pciBackOffTimer) {
+ break;
+ }
+ }
+ if (x == 8)
+ x = 7;
+ dctlreg |= (x << 0);
+ }
+
+ /* Program registers for DMA transfer */
+ iowrite32be(dmaLL->dsau, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAU);
+ iowrite32be(dmaLL->dsal, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAL);
+ iowrite32be(dmaLL->ddau, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAU);
+ iowrite32be(dmaLL->ddal, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAL);
+ iowrite32be(dmaLL->dsat, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DSAT);
+ iowrite32be(dmaLL->ddat, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDAT);
+ iowrite32be(dmaLL->dcnt, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCNT);
+ iowrite32be(dmaLL->ddbs, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DDBS);
+
+ /* Start the operation */
+ iowrite32be(dctlreg | 0x2000000, tsi148_bridge->base +
+ TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
+
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DSTA);
+ wait_event_interruptible(dma_queue[channel], (tmp & 0x1000000) == 0);
+
+ /*
+ * Read status register, we should probably do this in some error
+ * handler rather than here so that we can be sure we haven't kicked off
+ * another DMA transfer.
+ */
+ val = ioread32be(tsi148_bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DSTA);
+
+ vmeDma->vmeDmaStatus = 0;
+ if (val & 0x10000000) {
+ printk(KERN_ERR
+ "DMA Error in DMA_tempe_irqhandler DSTA=%08X\n",
+ val);
+ vmeDma->vmeDmaStatus = val;
+
+ }
+ return (0);
+}
+#endif
+
+#if 0
+
+/* Global VME controller information */
+struct pci_dev *vme_pci_dev;
+
+/*
+ * Set the VME bus arbiter with the requested attributes
+ */
+int tempe_set_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+ int temp_ctl = 0;
+ int gto = 0;
+
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VCTRL);
+ temp_ctl &= 0xFFEFFF00;
+
+ if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
+ gto = 8;
+ } else if (vmeArb->globalTimeoutTimer > 2048) {
+ return (-EINVAL);
+ } else if (vmeArb->globalTimeoutTimer == 0) {
+ gto = 0;
+ } else {
+ gto = 1;
+ while ((16 * (1 << (gto - 1))) < vmeArb->globalTimeoutTimer) {
+ gto += 1;
+ }
+ }
+ temp_ctl |= gto;
+
+ if (vmeArb->arbiterMode != VME_PRIORITY_MODE) {
+ temp_ctl |= 1 << 6;
+ }
+
+ if (vmeArb->arbiterTimeoutFlag) {
+ temp_ctl |= 1 << 7;
+ }
+
+ if (vmeArb->noEarlyReleaseFlag) {
+ temp_ctl |= 1 << 20;
+ }
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_VCTRL);
+
+ return (0);
+}
+
+/*
+ * Return the attributes of the VME bus arbiter.
+ */
+int tempe_get_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+ int temp_ctl = 0;
+ int gto = 0;
+
+
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VCTRL);
+
+ gto = temp_ctl & 0xF;
+ if (gto != 0) {
+ vmeArb->globalTimeoutTimer = (16 * (1 << (gto - 1)));
+ }
+
+ if (temp_ctl & (1 << 6)) {
+ vmeArb->arbiterMode = VME_R_ROBIN_MODE;
+ } else {
+ vmeArb->arbiterMode = VME_PRIORITY_MODE;
+ }
+
+ if (temp_ctl & (1 << 7)) {
+ vmeArb->arbiterTimeoutFlag = 1;
+ }
+
+ if (temp_ctl & (1 << 20)) {
+ vmeArb->noEarlyReleaseFlag = 1;
+ }
+
+ return (0);
+}
+
+/*
+ * Set the VME bus requestor with the requested attributes
+ */
+int tempe_set_requestor(vmeRequesterCfg_t * vmeReq)
+{
+ int temp_ctl = 0;
+
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ temp_ctl &= 0xFFFF0000;
+
+ if (vmeReq->releaseMode == 1) {
+ temp_ctl |= (1 << 3);
+ }
+
+ if (vmeReq->fairMode == 1) {
+ temp_ctl |= (1 << 2);
+ }
+
+ temp_ctl |= (vmeReq->timeonTimeoutTimer & 7) << 8;
+ temp_ctl |= (vmeReq->timeoffTimeoutTimer & 7) << 12;
+ temp_ctl |= vmeReq->requestLevel;
+
+ iowrite32be(temp_ctl, tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+ return (0);
+}
+
+/*
+ * Return the attributes of the VME bus requestor
+ */
+int tempe_get_requestor(vmeRequesterCfg_t * vmeReq)
+{
+ int temp_ctl = 0;
+
+ temp_ctl = ioread32be(tsi148_bridge->base + TSI148_LCSR_VMCTRL);
+
+ if (temp_ctl & 0x18) {
+ vmeReq->releaseMode = 1;
+ }
+
+ if (temp_ctl & (1 << 2)) {
+ vmeReq->fairMode = 1;
+ }
+
+ vmeReq->requestLevel = temp_ctl & 3;
+ vmeReq->timeonTimeoutTimer = (temp_ctl >> 8) & 7;
+ vmeReq->timeoffTimeoutTimer = (temp_ctl >> 12) & 7;
+
+ return (0);
+}
+
+
+#endif
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h
new file mode 100644
index 000000000000..6f0f705ce6be
--- /dev/null
+++ b/drivers/staging/vme/bridges/vme_tsi148.h
@@ -0,0 +1,1387 @@
+/*
+ * tsi148.h
+ *
+ * Support for the Tundra TSI148 VME Bridge chip
+ *
+ * Author: Tom Armistead
+ * Updated and maintained by Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef TSI148_H
+#define TSI148_H
+
+#ifndef PCI_VENDOR_ID_TUNDRA
+#define PCI_VENDOR_ID_TUNDRA 0x10e3
+#endif
+
+#ifndef PCI_DEVICE_ID_TUNDRA_TSI148
+#define PCI_DEVICE_ID_TUNDRA_TSI148 0x148
+#endif
+
+/*
+ * Define the number of each that the Tsi148 supports.
+ */
+#define TSI148_MAX_MASTER 8 /* Max Master Windows */
+#define TSI148_MAX_SLAVE 8 /* Max Slave Windows */
+#define TSI148_MAX_DMA 2 /* Max DMA Controllers */
+#define TSI148_MAX_MAILBOX 4 /* Max Mail Box registers */
+#define TSI148_MAX_SEMAPHORE 8 /* Max Semaphores */
+
+/*
+ * Layout of a DMAC Linked-List Descriptor
+ *
+ * Note: This structure is accessed via the chip and therefore must be
+ * correctly laid out - It must also be aligned on 64-bit boundaries.
+ */
+struct tsi148_dma_descriptor {
+ u32 dsau; /* Source Address */
+ u32 dsal;
+ u32 ddau; /* Destination Address */
+ u32 ddal;
+ u32 dsat; /* Source attributes */
+ u32 ddat; /* Destination attributes */
+ u32 dnlau; /* Next link address */
+ u32 dnlal;
+ u32 dcnt; /* Byte count */
+ u32 ddbs; /* 2eSST Broadcast select */
+};
+
+struct tsi148_dma_entry {
+ /*
+ * The descriptor needs to be aligned on a 64-bit boundary, we increase
+ * the chance of this by putting it first in the structure.
+ */
+ struct tsi148_dma_descriptor descriptor;
+ struct list_head list;
+};
+
+/*
+ * TSI148 ASIC register structure overlays and bit field definitions.
+ *
+ * Note: Tsi148 Register Group (CRG) consists of the following
+ * combination of registers:
+ * PCFS - PCI Configuration Space Registers
+ * LCSR - Local Control and Status Registers
+ * GCSR - Global Control and Status Registers
+ * CR/CSR - Subset of Configuration ROM /
+ * Control and Status Registers
+ */
+
+
+/*
+ * Command/Status Registers (CRG + $004)
+ */
+#define TSI148_PCFS_ID 0x0
+#define TSI148_PCFS_CSR 0x4
+#define TSI148_PCFS_CLASS 0x8
+#define TSI148_PCFS_MISC0 0xC
+#define TSI148_PCFS_MBARL 0x10
+#define TSI148_PCFS_MBARU 0x14
+
+#define TSI148_PCFS_SUBID 0x28
+
+#define TSI148_PCFS_CAPP 0x34
+
+#define TSI148_PCFS_MISC1 0x3C
+
+#define TSI148_PCFS_XCAPP 0x40
+#define TSI148_PCFS_XSTAT 0x44
+
+/*
+ * LCSR definitions
+ */
+
+/*
+ * Outbound Translations
+ */
+#define TSI148_LCSR_OT0_OTSAU 0x100
+#define TSI148_LCSR_OT0_OTSAL 0x104
+#define TSI148_LCSR_OT0_OTEAU 0x108
+#define TSI148_LCSR_OT0_OTEAL 0x10C
+#define TSI148_LCSR_OT0_OTOFU 0x110
+#define TSI148_LCSR_OT0_OTOFL 0x114
+#define TSI148_LCSR_OT0_OTBS 0x118
+#define TSI148_LCSR_OT0_OTAT 0x11C
+
+#define TSI148_LCSR_OT1_OTSAU 0x120
+#define TSI148_LCSR_OT1_OTSAL 0x124
+#define TSI148_LCSR_OT1_OTEAU 0x128
+#define TSI148_LCSR_OT1_OTEAL 0x12C
+#define TSI148_LCSR_OT1_OTOFU 0x130
+#define TSI148_LCSR_OT1_OTOFL 0x134
+#define TSI148_LCSR_OT1_OTBS 0x138
+#define TSI148_LCSR_OT1_OTAT 0x13C
+
+#define TSI148_LCSR_OT2_OTSAU 0x140
+#define TSI148_LCSR_OT2_OTSAL 0x144
+#define TSI148_LCSR_OT2_OTEAU 0x148
+#define TSI148_LCSR_OT2_OTEAL 0x14C
+#define TSI148_LCSR_OT2_OTOFU 0x150
+#define TSI148_LCSR_OT2_OTOFL 0x154
+#define TSI148_LCSR_OT2_OTBS 0x158
+#define TSI148_LCSR_OT2_OTAT 0x15C
+
+#define TSI148_LCSR_OT3_OTSAU 0x160
+#define TSI148_LCSR_OT3_OTSAL 0x164
+#define TSI148_LCSR_OT3_OTEAU 0x168
+#define TSI148_LCSR_OT3_OTEAL 0x16C
+#define TSI148_LCSR_OT3_OTOFU 0x170
+#define TSI148_LCSR_OT3_OTOFL 0x174
+#define TSI148_LCSR_OT3_OTBS 0x178
+#define TSI148_LCSR_OT3_OTAT 0x17C
+
+#define TSI148_LCSR_OT4_OTSAU 0x180
+#define TSI148_LCSR_OT4_OTSAL 0x184
+#define TSI148_LCSR_OT4_OTEAU 0x188
+#define TSI148_LCSR_OT4_OTEAL 0x18C
+#define TSI148_LCSR_OT4_OTOFU 0x190
+#define TSI148_LCSR_OT4_OTOFL 0x194
+#define TSI148_LCSR_OT4_OTBS 0x198
+#define TSI148_LCSR_OT4_OTAT 0x19C
+
+#define TSI148_LCSR_OT5_OTSAU 0x1A0
+#define TSI148_LCSR_OT5_OTSAL 0x1A4
+#define TSI148_LCSR_OT5_OTEAU 0x1A8
+#define TSI148_LCSR_OT5_OTEAL 0x1AC
+#define TSI148_LCSR_OT5_OTOFU 0x1B0
+#define TSI148_LCSR_OT5_OTOFL 0x1B4
+#define TSI148_LCSR_OT5_OTBS 0x1B8
+#define TSI148_LCSR_OT5_OTAT 0x1BC
+
+#define TSI148_LCSR_OT6_OTSAU 0x1C0
+#define TSI148_LCSR_OT6_OTSAL 0x1C4
+#define TSI148_LCSR_OT6_OTEAU 0x1C8
+#define TSI148_LCSR_OT6_OTEAL 0x1CC
+#define TSI148_LCSR_OT6_OTOFU 0x1D0
+#define TSI148_LCSR_OT6_OTOFL 0x1D4
+#define TSI148_LCSR_OT6_OTBS 0x1D8
+#define TSI148_LCSR_OT6_OTAT 0x1DC
+
+#define TSI148_LCSR_OT7_OTSAU 0x1E0
+#define TSI148_LCSR_OT7_OTSAL 0x1E4
+#define TSI148_LCSR_OT7_OTEAU 0x1E8
+#define TSI148_LCSR_OT7_OTEAL 0x1EC
+#define TSI148_LCSR_OT7_OTOFU 0x1F0
+#define TSI148_LCSR_OT7_OTOFL 0x1F4
+#define TSI148_LCSR_OT7_OTBS 0x1F8
+#define TSI148_LCSR_OT7_OTAT 0x1FC
+
+#define TSI148_LCSR_OT0 0x100
+#define TSI148_LCSR_OT1 0x120
+#define TSI148_LCSR_OT2 0x140
+#define TSI148_LCSR_OT3 0x160
+#define TSI148_LCSR_OT4 0x180
+#define TSI148_LCSR_OT5 0x1A0
+#define TSI148_LCSR_OT6 0x1C0
+#define TSI148_LCSR_OT7 0x1E0
+
+static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1,
+ TSI148_LCSR_OT2, TSI148_LCSR_OT3,
+ TSI148_LCSR_OT4, TSI148_LCSR_OT5,
+ TSI148_LCSR_OT6, TSI148_LCSR_OT7 };
+
+#define TSI148_LCSR_OFFSET_OTSAU 0x0
+#define TSI148_LCSR_OFFSET_OTSAL 0x4
+#define TSI148_LCSR_OFFSET_OTEAU 0x8
+#define TSI148_LCSR_OFFSET_OTEAL 0xC
+#define TSI148_LCSR_OFFSET_OTOFU 0x10
+#define TSI148_LCSR_OFFSET_OTOFL 0x14
+#define TSI148_LCSR_OFFSET_OTBS 0x18
+#define TSI148_LCSR_OFFSET_OTAT 0x1C
+
+/*
+ * VMEbus interupt ack
+ * offset 200
+ */
+#define TSI148_LCSR_VIACK1 0x204
+#define TSI148_LCSR_VIACK2 0x208
+#define TSI148_LCSR_VIACK3 0x20C
+#define TSI148_LCSR_VIACK4 0x210
+#define TSI148_LCSR_VIACK5 0x214
+#define TSI148_LCSR_VIACK6 0x218
+#define TSI148_LCSR_VIACK7 0x21C
+
+static const int TSI148_LCSR_VIACK[8] = { 0, TSI148_LCSR_VIACK1,
+ TSI148_LCSR_VIACK2, TSI148_LCSR_VIACK3,
+ TSI148_LCSR_VIACK4, TSI148_LCSR_VIACK5,
+ TSI148_LCSR_VIACK6, TSI148_LCSR_VIACK7 };
+
+/*
+ * RMW
+ * offset 220
+ */
+#define TSI148_LCSR_RMWAU 0x220
+#define TSI148_LCSR_RMWAL 0x224
+#define TSI148_LCSR_RMWEN 0x228
+#define TSI148_LCSR_RMWC 0x22C
+#define TSI148_LCSR_RMWS 0x230
+
+/*
+ * VMEbus control
+ * offset 234
+ */
+#define TSI148_LCSR_VMCTRL 0x234
+#define TSI148_LCSR_VCTRL 0x238
+#define TSI148_LCSR_VSTAT 0x23C
+
+/*
+ * PCI status
+ * offset 240
+ */
+#define TSI148_LCSR_PSTAT 0x240
+
+/*
+ * VME filter.
+ * offset 250
+ */
+#define TSI148_LCSR_VMEFL 0x250
+
+ /*
+ * VME exception.
+ * offset 260
+ */
+#define TSI148_LCSR_VEAU 0x260
+#define TSI148_LCSR_VEAL 0x264
+#define TSI148_LCSR_VEAT 0x268
+
+ /*
+ * PCI error
+ * offset 270
+ */
+#define TSI148_LCSR_EDPAU 0x270
+#define TSI148_LCSR_EDPAL 0x274
+#define TSI148_LCSR_EDPXA 0x278
+#define TSI148_LCSR_EDPXS 0x27C
+#define TSI148_LCSR_EDPAT 0x280
+
+ /*
+ * Inbound Translations
+ * offset 300
+ */
+#define TSI148_LCSR_IT0_ITSAU 0x300
+#define TSI148_LCSR_IT0_ITSAL 0x304
+#define TSI148_LCSR_IT0_ITEAU 0x308
+#define TSI148_LCSR_IT0_ITEAL 0x30C
+#define TSI148_LCSR_IT0_ITOFU 0x310
+#define TSI148_LCSR_IT0_ITOFL 0x314
+#define TSI148_LCSR_IT0_ITAT 0x318
+
+#define TSI148_LCSR_IT1_ITSAU 0x320
+#define TSI148_LCSR_IT1_ITSAL 0x324
+#define TSI148_LCSR_IT1_ITEAU 0x328
+#define TSI148_LCSR_IT1_ITEAL 0x32C
+#define TSI148_LCSR_IT1_ITOFU 0x330
+#define TSI148_LCSR_IT1_ITOFL 0x334
+#define TSI148_LCSR_IT1_ITAT 0x338
+
+#define TSI148_LCSR_IT2_ITSAU 0x340
+#define TSI148_LCSR_IT2_ITSAL 0x344
+#define TSI148_LCSR_IT2_ITEAU 0x348
+#define TSI148_LCSR_IT2_ITEAL 0x34C
+#define TSI148_LCSR_IT2_ITOFU 0x350
+#define TSI148_LCSR_IT2_ITOFL 0x354
+#define TSI148_LCSR_IT2_ITAT 0x358
+
+#define TSI148_LCSR_IT3_ITSAU 0x360
+#define TSI148_LCSR_IT3_ITSAL 0x364
+#define TSI148_LCSR_IT3_ITEAU 0x368
+#define TSI148_LCSR_IT3_ITEAL 0x36C
+#define TSI148_LCSR_IT3_ITOFU 0x370
+#define TSI148_LCSR_IT3_ITOFL 0x374
+#define TSI148_LCSR_IT3_ITAT 0x378
+
+#define TSI148_LCSR_IT4_ITSAU 0x380
+#define TSI148_LCSR_IT4_ITSAL 0x384
+#define TSI148_LCSR_IT4_ITEAU 0x388
+#define TSI148_LCSR_IT4_ITEAL 0x38C
+#define TSI148_LCSR_IT4_ITOFU 0x390
+#define TSI148_LCSR_IT4_ITOFL 0x394
+#define TSI148_LCSR_IT4_ITAT 0x398
+
+#define TSI148_LCSR_IT5_ITSAU 0x3A0
+#define TSI148_LCSR_IT5_ITSAL 0x3A4
+#define TSI148_LCSR_IT5_ITEAU 0x3A8
+#define TSI148_LCSR_IT5_ITEAL 0x3AC
+#define TSI148_LCSR_IT5_ITOFU 0x3B0
+#define TSI148_LCSR_IT5_ITOFL 0x3B4
+#define TSI148_LCSR_IT5_ITAT 0x3B8
+
+#define TSI148_LCSR_IT6_ITSAU 0x3C0
+#define TSI148_LCSR_IT6_ITSAL 0x3C4
+#define TSI148_LCSR_IT6_ITEAU 0x3C8
+#define TSI148_LCSR_IT6_ITEAL 0x3CC
+#define TSI148_LCSR_IT6_ITOFU 0x3D0
+#define TSI148_LCSR_IT6_ITOFL 0x3D4
+#define TSI148_LCSR_IT6_ITAT 0x3D8
+
+#define TSI148_LCSR_IT7_ITSAU 0x3E0
+#define TSI148_LCSR_IT7_ITSAL 0x3E4
+#define TSI148_LCSR_IT7_ITEAU 0x3E8
+#define TSI148_LCSR_IT7_ITEAL 0x3EC
+#define TSI148_LCSR_IT7_ITOFU 0x3F0
+#define TSI148_LCSR_IT7_ITOFL 0x3F4
+#define TSI148_LCSR_IT7_ITAT 0x3F8
+
+
+#define TSI148_LCSR_IT0 0x300
+#define TSI148_LCSR_IT1 0x320
+#define TSI148_LCSR_IT2 0x340
+#define TSI148_LCSR_IT3 0x360
+#define TSI148_LCSR_IT4 0x380
+#define TSI148_LCSR_IT5 0x3A0
+#define TSI148_LCSR_IT6 0x3C0
+#define TSI148_LCSR_IT7 0x3E0
+
+static const int TSI148_LCSR_IT[8] = { TSI148_LCSR_IT0, TSI148_LCSR_IT1,
+ TSI148_LCSR_IT2, TSI148_LCSR_IT3,
+ TSI148_LCSR_IT4, TSI148_LCSR_IT5,
+ TSI148_LCSR_IT6, TSI148_LCSR_IT7 };
+
+#define TSI148_LCSR_OFFSET_ITSAU 0x0
+#define TSI148_LCSR_OFFSET_ITSAL 0x4
+#define TSI148_LCSR_OFFSET_ITEAU 0x8
+#define TSI148_LCSR_OFFSET_ITEAL 0xC
+#define TSI148_LCSR_OFFSET_ITOFU 0x10
+#define TSI148_LCSR_OFFSET_ITOFL 0x14
+#define TSI148_LCSR_OFFSET_ITAT 0x18
+
+ /*
+ * Inbound Translation GCSR
+ * offset 400
+ */
+#define TSI148_LCSR_GBAU 0x400
+#define TSI148_LCSR_GBAL 0x404
+#define TSI148_LCSR_GCSRAT 0x408
+
+ /*
+ * Inbound Translation CRG
+ * offset 40C
+ */
+#define TSI148_LCSR_CBAU 0x40C
+#define TSI148_LCSR_CBAL 0x410
+#define TSI148_LCSR_CSRAT 0x414
+
+ /*
+ * Inbound Translation CR/CSR
+ * CRG
+ * offset 418
+ */
+#define TSI148_LCSR_CROU 0x418
+#define TSI148_LCSR_CROL 0x41C
+#define TSI148_LCSR_CRAT 0x420
+
+ /*
+ * Inbound Translation Location Monitor
+ * offset 424
+ */
+#define TSI148_LCSR_LMBAU 0x424
+#define TSI148_LCSR_LMBAL 0x428
+#define TSI148_LCSR_LMAT 0x42C
+
+ /*
+ * VMEbus Interrupt Control.
+ * offset 430
+ */
+#define TSI148_LCSR_BCU 0x430
+#define TSI148_LCSR_BCL 0x434
+#define TSI148_LCSR_BPGTR 0x438
+#define TSI148_LCSR_BPCTR 0x43C
+#define TSI148_LCSR_VICR 0x440
+
+ /*
+ * Local Bus Interrupt Control.
+ * offset 448
+ */
+#define TSI148_LCSR_INTEN 0x448
+#define TSI148_LCSR_INTEO 0x44C
+#define TSI148_LCSR_INTS 0x450
+#define TSI148_LCSR_INTC 0x454
+#define TSI148_LCSR_INTM1 0x458
+#define TSI148_LCSR_INTM2 0x45C
+
+ /*
+ * DMA Controllers
+ * offset 500
+ */
+#define TSI148_LCSR_DCTL0 0x500
+#define TSI148_LCSR_DSTA0 0x504
+#define TSI148_LCSR_DCSAU0 0x508
+#define TSI148_LCSR_DCSAL0 0x50C
+#define TSI148_LCSR_DCDAU0 0x510
+#define TSI148_LCSR_DCDAL0 0x514
+#define TSI148_LCSR_DCLAU0 0x518
+#define TSI148_LCSR_DCLAL0 0x51C
+#define TSI148_LCSR_DSAU0 0x520
+#define TSI148_LCSR_DSAL0 0x524
+#define TSI148_LCSR_DDAU0 0x528
+#define TSI148_LCSR_DDAL0 0x52C
+#define TSI148_LCSR_DSAT0 0x530
+#define TSI148_LCSR_DDAT0 0x534
+#define TSI148_LCSR_DNLAU0 0x538
+#define TSI148_LCSR_DNLAL0 0x53C
+#define TSI148_LCSR_DCNT0 0x540
+#define TSI148_LCSR_DDBS0 0x544
+
+#define TSI148_LCSR_DCTL1 0x580
+#define TSI148_LCSR_DSTA1 0x584
+#define TSI148_LCSR_DCSAU1 0x588
+#define TSI148_LCSR_DCSAL1 0x58C
+#define TSI148_LCSR_DCDAU1 0x590
+#define TSI148_LCSR_DCDAL1 0x594
+#define TSI148_LCSR_DCLAU1 0x598
+#define TSI148_LCSR_DCLAL1 0x59C
+#define TSI148_LCSR_DSAU1 0x5A0
+#define TSI148_LCSR_DSAL1 0x5A4
+#define TSI148_LCSR_DDAU1 0x5A8
+#define TSI148_LCSR_DDAL1 0x5AC
+#define TSI148_LCSR_DSAT1 0x5B0
+#define TSI148_LCSR_DDAT1 0x5B4
+#define TSI148_LCSR_DNLAU1 0x5B8
+#define TSI148_LCSR_DNLAL1 0x5BC
+#define TSI148_LCSR_DCNT1 0x5C0
+#define TSI148_LCSR_DDBS1 0x5C4
+
+#define TSI148_LCSR_DMA0 0x500
+#define TSI148_LCSR_DMA1 0x580
+
+
+static const int TSI148_LCSR_DMA[TSI148_MAX_DMA] = { TSI148_LCSR_DMA0,
+ TSI148_LCSR_DMA1 };
+
+#define TSI148_LCSR_OFFSET_DCTL 0x0
+#define TSI148_LCSR_OFFSET_DSTA 0x4
+#define TSI148_LCSR_OFFSET_DCSAU 0x8
+#define TSI148_LCSR_OFFSET_DCSAL 0xC
+#define TSI148_LCSR_OFFSET_DCDAU 0x10
+#define TSI148_LCSR_OFFSET_DCDAL 0x14
+#define TSI148_LCSR_OFFSET_DCLAU 0x18
+#define TSI148_LCSR_OFFSET_DCLAL 0x1C
+#define TSI148_LCSR_OFFSET_DSAU 0x20
+#define TSI148_LCSR_OFFSET_DSAL 0x24
+#define TSI148_LCSR_OFFSET_DDAU 0x28
+#define TSI148_LCSR_OFFSET_DDAL 0x2C
+#define TSI148_LCSR_OFFSET_DSAT 0x30
+#define TSI148_LCSR_OFFSET_DDAT 0x34
+#define TSI148_LCSR_OFFSET_DNLAU 0x38
+#define TSI148_LCSR_OFFSET_DNLAL 0x3C
+#define TSI148_LCSR_OFFSET_DCNT 0x40
+#define TSI148_LCSR_OFFSET_DDBS 0x44
+
+ /*
+ * GCSR Register Group
+ */
+
+ /*
+ * GCSR CRG
+ * offset 00 600 - DEVI/VENI
+ * offset 04 604 - CTRL/GA/REVID
+ * offset 08 608 - Semaphore3/2/1/0
+ * offset 0C 60C - Seamphore7/6/5/4
+ */
+#define TSI148_GCSR_ID 0x600
+#define TSI148_GCSR_CSR 0x604
+#define TSI148_GCSR_SEMA0 0x608
+#define TSI148_GCSR_SEMA1 0x60C
+
+ /*
+ * Mail Box
+ * GCSR CRG
+ * offset 10 610 - Mailbox0
+ */
+#define TSI148_GCSR_MBOX0 0x610
+#define TSI148_GCSR_MBOX1 0x614
+#define TSI148_GCSR_MBOX2 0x618
+#define TSI148_GCSR_MBOX3 0x61C
+
+static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0,
+ TSI148_GCSR_MBOX1,
+ TSI148_GCSR_MBOX2,
+ TSI148_GCSR_MBOX3 };
+
+ /*
+ * CR/CSR
+ */
+
+ /*
+ * CR/CSR CRG
+ * offset 7FFF4 FF4 - CSRBCR
+ * offset 7FFF8 FF8 - CSRBSR
+ * offset 7FFFC FFC - CBAR
+ */
+#define TSI148_CSRBCR 0xFF4
+#define TSI148_CSRBSR 0xFF8
+#define TSI148_CBAR 0xFFC
+
+
+
+
+ /*
+ * TSI148 Register Bit Definitions
+ */
+
+ /*
+ * PFCS Register Set
+ */
+#define TSI148_PCFS_CMMD_SERR (1<<8) /* SERR_L out pin ssys err */
+#define TSI148_PCFS_CMMD_PERR (1<<6) /* PERR_L out pin parity */
+#define TSI148_PCFS_CMMD_MSTR (1<<2) /* PCI bus master */
+#define TSI148_PCFS_CMMD_MEMSP (1<<1) /* PCI mem space access */
+#define TSI148_PCFS_CMMD_IOSP (1<<0) /* PCI I/O space enable */
+
+#define TSI148_PCFS_STAT_RCPVE (1<<15) /* Detected Parity Error */
+#define TSI148_PCFS_STAT_SIGSE (1<<14) /* Signalled System Error */
+#define TSI148_PCFS_STAT_RCVMA (1<<13) /* Received Master Abort */
+#define TSI148_PCFS_STAT_RCVTA (1<<12) /* Received Target Abort */
+#define TSI148_PCFS_STAT_SIGTA (1<<11) /* Signalled Target Abort */
+#define TSI148_PCFS_STAT_SELTIM (3<<9) /* DELSEL Timing */
+#define TSI148_PCFS_STAT_DPAR (1<<8) /* Data Parity Err Reported */
+#define TSI148_PCFS_STAT_FAST (1<<7) /* Fast back-to-back Cap */
+#define TSI148_PCFS_STAT_P66M (1<<5) /* 66 MHz Capable */
+#define TSI148_PCFS_STAT_CAPL (1<<4) /* Capab List - address $34 */
+
+/*
+ * Revision ID/Class Code Registers (CRG +$008)
+ */
+#define TSI148_PCFS_CLAS_M (0xFF<<24) /* Class ID */
+#define TSI148_PCFS_SUBCLAS_M (0xFF<<16) /* Sub-Class ID */
+#define TSI148_PCFS_PROGIF_M (0xFF<<8) /* Sub-Class ID */
+#define TSI148_PCFS_REVID_M (0xFF<<0) /* Rev ID */
+
+/*
+ * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C)
+ */
+#define TSI148_PCFS_HEAD_M (0xFF<<16) /* Master Lat Timer */
+#define TSI148_PCFS_MLAT_M (0xFF<<8) /* Master Lat Timer */
+#define TSI148_PCFS_CLSZ_M (0xFF<<0) /* Cache Line Size */
+
+/*
+ * Memory Base Address Lower Reg (CRG + $010)
+ */
+#define TSI148_PCFS_MBARL_BASEL_M (0xFFFFF<<12) /* Base Addr Lower Mask */
+#define TSI148_PCFS_MBARL_PRE (1<<3) /* Prefetch */
+#define TSI148_PCFS_MBARL_MTYPE_M (3<<1) /* Memory Type Mask */
+#define TSI148_PCFS_MBARL_IOMEM (1<<0) /* I/O Space Indicator */
+
+/*
+ * Message Signaled Interrupt Capabilities Register (CRG + $040)
+ */
+#define TSI148_PCFS_MSICAP_64BAC (1<<7) /* 64-bit Address Capable */
+#define TSI148_PCFS_MSICAP_MME_M (7<<4) /* Multiple Msg Enable Mask */
+#define TSI148_PCFS_MSICAP_MMC_M (7<<1) /* Multiple Msg Capable Mask */
+#define TSI148_PCFS_MSICAP_MSIEN (1<<0) /* Msg signaled INT Enable */
+
+/*
+ * Message Address Lower Register (CRG +$044)
+ */
+#define TSI148_PCFS_MSIAL_M (0x3FFFFFFF<<2) /* Mask */
+
+/*
+ * Message Data Register (CRG + 4C)
+ */
+#define TSI148_PCFS_MSIMD_M (0xFFFF<<0) /* Mask */
+
+/*
+ * PCI-X Capabilities Register (CRG + $050)
+ */
+#define TSI148_PCFS_PCIXCAP_MOST_M (7<<4) /* Max outstanding Split Tran */
+#define TSI148_PCFS_PCIXCAP_MMRBC_M (3<<2) /* Max Mem Read byte cnt */
+#define TSI148_PCFS_PCIXCAP_ERO (1<<1) /* Enable Relaxed Ordering */
+#define TSI148_PCFS_PCIXCAP_DPERE (1<<0) /* Data Parity Recover Enable */
+
+/*
+ * PCI-X Status Register (CRG +$054)
+ */
+#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Recieved Split Comp Error */
+#define TSI148_PCFS_PCIXSTAT_DMCRS_M (7<<26) /* max Cumulative Read Size */
+#define TSI148_PCFS_PCIXSTAT_DMOST_M (7<<23) /* max outstanding Split Trans */
+#define TSI148_PCFS_PCIXSTAT_DMMRC_M (3<<21) /* max mem read byte count */
+#define TSI148_PCFS_PCIXSTAT_DC (1<<20) /* Device Complexity */
+#define TSI148_PCFS_PCIXSTAT_USC (1<<19) /* Unexpected Split comp */
+#define TSI148_PCFS_PCIXSTAT_SCD (1<<18) /* Split completion discard */
+#define TSI148_PCFS_PCIXSTAT_133C (1<<17) /* 133MHz capable */
+#define TSI148_PCFS_PCIXSTAT_64D (1<<16) /* 64 bit device */
+#define TSI148_PCFS_PCIXSTAT_BN_M (0xFF<<8) /* Bus number */
+#define TSI148_PCFS_PCIXSTAT_DN_M (0x1F<<3) /* Device number */
+#define TSI148_PCFS_PCIXSTAT_FN_M (7<<0) /* Function Number */
+
+/*
+ * LCSR Registers
+ */
+
+/*
+ * Outbound Translation Starting Address Lower
+ */
+#define TSI148_LCSR_OTSAL_M (0xFFFF<<16) /* Mask */
+
+/*
+ * Outbound Translation Ending Address Lower
+ */
+#define TSI148_LCSR_OTEAL_M (0xFFFF<<16) /* Mask */
+
+/*
+ * Outbound Translation Offset Lower
+ */
+#define TSI148_LCSR_OTOFFL_M (0xFFFF<<16) /* Mask */
+
+/*
+ * Outbound Translation 2eSST Broadcast Select
+ */
+#define TSI148_LCSR_OTBS_M (0xFFFFF<<0) /* Mask */
+
+/*
+ * Outbound Translation Attribute
+ */
+#define TSI148_LCSR_OTAT_EN (1<<31) /* Window Enable */
+#define TSI148_LCSR_OTAT_MRPFD (1<<18) /* Prefetch Disable */
+
+#define TSI148_LCSR_OTAT_PFS_M (3<<16) /* Prefetch Size Mask */
+#define TSI148_LCSR_OTAT_PFS_2 (0<<16) /* 2 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_4 (1<<16) /* 4 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_8 (2<<16) /* 8 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_16 (3<<16) /* 16 Cache Lines P Size */
+
+#define TSI148_LCSR_OTAT_2eSSTM_M (7<<11) /* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_OTAT_2eSSTM_160 (0<<11) /* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_267 (1<<11) /* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_320 (2<<11) /* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_OTAT_TM_M (7<<8) /* Xfer Protocol Mask */
+#define TSI148_LCSR_OTAT_TM_SCT (0<<8) /* SCT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_BLT (1<<8) /* BLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_MBLT (2<<8) /* MBLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eVME (3<<8) /* 2eVME Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSST (4<<8) /* 2eSST Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSSTB (5<<8) /* 2eSST Bcast Xfer Protocol */
+
+#define TSI148_LCSR_OTAT_DBW_M (3<<6) /* Max Data Width */
+#define TSI148_LCSR_OTAT_DBW_16 (0<<6) /* 16-bit Data Width */
+#define TSI148_LCSR_OTAT_DBW_32 (1<<6) /* 32-bit Data Width */
+
+#define TSI148_LCSR_OTAT_SUP (1<<5) /* Supervisory Access */
+#define TSI148_LCSR_OTAT_PGM (1<<4) /* Program Access */
+
+#define TSI148_LCSR_OTAT_AMODE_M (0xf<<0) /* Address Mode Mask */
+#define TSI148_LCSR_OTAT_AMODE_A16 (0<<0) /* A16 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A24 (1<<0) /* A24 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A32 (2<<0) /* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A64 (4<<0) /* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_CRCSR (5<<0) /* CR/CSR Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER1 (8<<0) /* User1 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER2 (9<<0) /* User2 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER3 (10<<0) /* User3 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_USER4 (11<<0) /* User4 Address Space */
+
+/*
+ * VME Master Control Register CRG+$234
+ */
+#define TSI148_LCSR_VMCTRL_VSA (1<<27) /* VMEbus Stop Ack */
+#define TSI148_LCSR_VMCTRL_VS (1<<26) /* VMEbus Stop */
+#define TSI148_LCSR_VMCTRL_DHB (1<<25) /* Device Has Bus */
+#define TSI148_LCSR_VMCTRL_DWB (1<<24) /* Device Wants Bus */
+
+#define TSI148_LCSR_VMCTRL_RMWEN (1<<20) /* RMW Enable */
+
+#define TSI148_LCSR_VMCTRL_ATO_M (7<<16) /* Master Access Time-out Mask */
+#define TSI148_LCSR_VMCTRL_ATO_32 (0<<16) /* 32 us */
+#define TSI148_LCSR_VMCTRL_ATO_128 (1<<16) /* 128 us */
+#define TSI148_LCSR_VMCTRL_ATO_512 (2<<16) /* 512 us */
+#define TSI148_LCSR_VMCTRL_ATO_2M (3<<16) /* 2 ms */
+#define TSI148_LCSR_VMCTRL_ATO_8M (4<<16) /* 8 ms */
+#define TSI148_LCSR_VMCTRL_ATO_32M (5<<16) /* 32 ms */
+#define TSI148_LCSR_VMCTRL_ATO_128M (6<<16) /* 128 ms */
+#define TSI148_LCSR_VMCTRL_ATO_DIS (7<<16) /* Disabled */
+
+#define TSI148_LCSR_VMCTRL_VTOFF_M (7<<12) /* VMEbus Master Time off */
+#define TSI148_LCSR_VMCTRL_VTOFF_0 (0<<12) /* 0us */
+#define TSI148_LCSR_VMCTRL_VTOFF_1 (1<<12) /* 1us */
+#define TSI148_LCSR_VMCTRL_VTOFF_2 (2<<12) /* 2us */
+#define TSI148_LCSR_VMCTRL_VTOFF_4 (3<<12) /* 4us */
+#define TSI148_LCSR_VMCTRL_VTOFF_8 (4<<12) /* 8us */
+#define TSI148_LCSR_VMCTRL_VTOFF_16 (5<<12) /* 16us */
+#define TSI148_LCSR_VMCTRL_VTOFF_32 (6<<12) /* 32us */
+#define TSI148_LCSR_VMCTRL_VTOFF_64 (7<<12) /* 64us */
+
+#define TSI148_LCSR_VMCTRL_VTON_M (7<<8) /* VMEbus Master Time On */
+#define TSI148_LCSR_VMCTRL_VTON_4 (0<<8) /* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_8 (1<<8) /* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_16 (2<<8) /* 16us */
+#define TSI148_LCSR_VMCTRL_VTON_32 (3<<8) /* 32us */
+#define TSI148_LCSR_VMCTRL_VTON_64 (4<<8) /* 64us */
+#define TSI148_LCSR_VMCTRL_VTON_128 (5<<8) /* 128us */
+#define TSI148_LCSR_VMCTRL_VTON_256 (6<<8) /* 256us */
+#define TSI148_LCSR_VMCTRL_VTON_512 (7<<8) /* 512us */
+
+#define TSI148_LCSR_VMCTRL_VREL_M (3<<3) /* VMEbus Master Rel Mode Mask */
+#define TSI148_LCSR_VMCTRL_VREL_T_D (0<<3) /* Time on or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_R_D (1<<3) /* Time on and REQ or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_B_D (2<<3) /* Time on and BCLR or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_D_R (3<<3) /* Time on or Done and REQ */
+
+#define TSI148_LCSR_VMCTRL_VFAIR (1<<2) /* VMEbus Master Fair Mode */
+#define TSI148_LCSR_VMCTRL_VREQL_M (3<<0) /* VMEbus Master Req Level Mask */
+
+/*
+ * VMEbus Control Register CRG+$238
+ */
+#define TSI148_LCSR_VCTRL_LRE (1<<31) /* Late Retry Enable */
+
+#define TSI148_LCSR_VCTRL_DLT_M (0xF<<24) /* Deadlock Timer */
+#define TSI148_LCSR_VCTRL_DLT_OFF (0<<24) /* Deadlock Timer Off */
+#define TSI148_LCSR_VCTRL_DLT_16 (1<<24) /* 16 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32 (2<<24) /* 32 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_64 (3<<24) /* 64 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_128 (4<<24) /* 128 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_256 (5<<24) /* 256 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_512 (6<<24) /* 512 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_1024 (7<<24) /* 1024 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_2048 (8<<24) /* 2048 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_4096 (9<<24) /* 4096 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_8192 (0xA<<24) /* 8192 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_16384 (0xB<<24) /* 16384 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32768 (0xC<<24) /* 32768 VCLKS */
+
+#define TSI148_LCSR_VCTRL_NERBB (1<<20) /* No Early Release of Bus Busy */
+
+#define TSI148_LCSR_VCTRL_SRESET (1<<17) /* System Reset */
+#define TSI148_LCSR_VCTRL_LRESET (1<<16) /* Local Reset */
+
+#define TSI148_LCSR_VCTRL_SFAILAI (1<<15) /* SYSFAIL Auto Slot ID */
+#define TSI148_LCSR_VCTRL_BID_M (0x1F<<8) /* Broadcast ID Mask */
+
+#define TSI148_LCSR_VCTRL_ATOEN (1<<7) /* Arbiter Time-out Enable */
+#define TSI148_LCSR_VCTRL_ROBIN (1<<6) /* VMEbus Round Robin */
+
+#define TSI148_LCSR_VCTRL_GTO_M (7<<0) /* VMEbus Global Time-out Mask */
+#define TSI148_LCSR_VCTRL_GTO_8 (0<<0) /* 8 us */
+#define TSI148_LCSR_VCTRL_GTO_16 (1<<0) /* 16 us */
+#define TSI148_LCSR_VCTRL_GTO_32 (2<<0) /* 32 us */
+#define TSI148_LCSR_VCTRL_GTO_64 (3<<0) /* 64 us */
+#define TSI148_LCSR_VCTRL_GTO_128 (4<<0) /* 128 us */
+#define TSI148_LCSR_VCTRL_GTO_256 (5<<0) /* 256 us */
+#define TSI148_LCSR_VCTRL_GTO_512 (6<<0) /* 512 us */
+#define TSI148_LCSR_VCTRL_GTO_DIS (7<<0) /* Disabled */
+
+/*
+ * VMEbus Status Register CRG + $23C
+ */
+#define TSI148_LCSR_VSTAT_CPURST (1<<15) /* Clear power up reset */
+#define TSI148_LCSR_VSTAT_BRDFL (1<<14) /* Board fail */
+#define TSI148_LCSR_VSTAT_PURSTS (1<<12) /* Power up reset status */
+#define TSI148_LCSR_VSTAT_BDFAILS (1<<11) /* Board Fail Status */
+#define TSI148_LCSR_VSTAT_SYSFAILS (1<<10) /* System Fail Status */
+#define TSI148_LCSR_VSTAT_ACFAILS (1<<9) /* AC fail status */
+#define TSI148_LCSR_VSTAT_SCONS (1<<8) /* System Cont Status */
+#define TSI148_LCSR_VSTAT_GAP (1<<5) /* Geographic Addr Parity */
+#define TSI148_LCSR_VSTAT_GA_M (0x1F<<0) /* Geographic Addr Mask */
+
+/*
+ * PCI Configuration Status Register CRG+$240
+ */
+#define TSI148_LCSR_PSTAT_REQ64S (1<<6) /* Request 64 status set */
+#define TSI148_LCSR_PSTAT_M66ENS (1<<5) /* M66ENS 66Mhz enable */
+#define TSI148_LCSR_PSTAT_FRAMES (1<<4) /* Frame Status */
+#define TSI148_LCSR_PSTAT_IRDYS (1<<3) /* IRDY status */
+#define TSI148_LCSR_PSTAT_DEVSELS (1<<2) /* DEVL status */
+#define TSI148_LCSR_PSTAT_STOPS (1<<1) /* STOP status */
+#define TSI148_LCSR_PSTAT_TRDYS (1<<0) /* TRDY status */
+
+/*
+ * VMEbus Exception Attributes Register CRG + $268
+ */
+#define TSI148_LCSR_VEAT_VES (1<<31) /* Status */
+#define TSI148_LCSR_VEAT_VEOF (1<<30) /* Overflow */
+#define TSI148_LCSR_VEAT_VESCL (1<<29) /* Status Clear */
+#define TSI148_LCSR_VEAT_2EOT (1<<21) /* 2e Odd Termination */
+#define TSI148_LCSR_VEAT_2EST (1<<20) /* 2e Slave terminated */
+#define TSI148_LCSR_VEAT_BERR (1<<19) /* Bus Error */
+#define TSI148_LCSR_VEAT_LWORD (1<<18) /* LWORD_ signal state */
+#define TSI148_LCSR_VEAT_WRITE (1<<17) /* WRITE_ signal state */
+#define TSI148_LCSR_VEAT_IACK (1<<16) /* IACK_ signal state */
+#define TSI148_LCSR_VEAT_DS1 (1<<15) /* DS1_ signal state */
+#define TSI148_LCSR_VEAT_DS0 (1<<14) /* DS0_ signal state */
+#define TSI148_LCSR_VEAT_AM_M (0x3F<<8) /* Address Mode Mask */
+#define TSI148_LCSR_VEAT_XAM_M (0xFF<<0) /* Master AMode Mask */
+
+
+/*
+ * VMEbus PCI Error Diagnostics PCI/X Attributes Register CRG + $280
+ */
+#define TSI148_LCSR_EDPAT_EDPCL (1<<29)
+
+/*
+ * Inbound Translation Starting Address Lower
+ */
+#define TSI148_LCSR_ITSAL6432_M (0xFFFF<<16) /* Mask */
+#define TSI148_LCSR_ITSAL24_M (0x00FFF<<12) /* Mask */
+#define TSI148_LCSR_ITSAL16_M (0x0000FFF<<4) /* Mask */
+
+/*
+ * Inbound Translation Ending Address Lower
+ */
+#define TSI148_LCSR_ITEAL6432_M (0xFFFF<<16) /* Mask */
+#define TSI148_LCSR_ITEAL24_M (0x00FFF<<12) /* Mask */
+#define TSI148_LCSR_ITEAL16_M (0x0000FFF<<4) /* Mask */
+
+/*
+ * Inbound Translation Offset Lower
+ */
+#define TSI148_LCSR_ITOFFL6432_M (0xFFFF<<16) /* Mask */
+#define TSI148_LCSR_ITOFFL24_M (0xFFFFF<<12) /* Mask */
+#define TSI148_LCSR_ITOFFL16_M (0xFFFFFFF<<4) /* Mask */
+
+/*
+ * Inbound Translation Attribute
+ */
+#define TSI148_LCSR_ITAT_EN (1<<31) /* Window Enable */
+#define TSI148_LCSR_ITAT_TH (1<<18) /* Prefetch Threshold */
+
+#define TSI148_LCSR_ITAT_VFS_M (3<<16) /* Virtual FIFO Size Mask */
+#define TSI148_LCSR_ITAT_VFS_64 (0<<16) /* 64 bytes Virtual FIFO Size */
+#define TSI148_LCSR_ITAT_VFS_128 (1<<16) /* 128 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_256 (2<<16) /* 256 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_512 (3<<16) /* 512 bytes Virtual FIFO Sz */
+
+#define TSI148_LCSR_ITAT_2eSSTM_M (7<<12) /* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_ITAT_2eSSTM_160 (0<<12) /* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_267 (1<<12) /* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_320 (2<<12) /* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_ITAT_2eSSTB (1<<11) /* 2eSST Bcast Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eSST (1<<10) /* 2eSST Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eVME (1<<9) /* 2eVME Xfer Protocol */
+#define TSI148_LCSR_ITAT_MBLT (1<<8) /* MBLT Xfer Protocol */
+#define TSI148_LCSR_ITAT_BLT (1<<7) /* BLT Xfer Protocol */
+
+#define TSI148_LCSR_ITAT_AS_M (7<<4) /* Address Space Mask */
+#define TSI148_LCSR_ITAT_AS_A16 (0<<4) /* A16 Address Space */
+#define TSI148_LCSR_ITAT_AS_A24 (1<<4) /* A24 Address Space */
+#define TSI148_LCSR_ITAT_AS_A32 (2<<4) /* A32 Address Space */
+#define TSI148_LCSR_ITAT_AS_A64 (4<<4) /* A64 Address Space */
+
+#define TSI148_LCSR_ITAT_SUPR (1<<3) /* Supervisor Access */
+#define TSI148_LCSR_ITAT_NPRIV (1<<2) /* Non-Priv (User) Access */
+#define TSI148_LCSR_ITAT_PGM (1<<1) /* Program Access */
+#define TSI148_LCSR_ITAT_DATA (1<<0) /* Data Access */
+
+/*
+ * GCSR Base Address Lower Address CRG +$404
+ */
+#define TSI148_LCSR_GBAL_M (0x7FFFFFF<<5) /* Mask */
+
+/*
+ * GCSR Attribute Register CRG + $408
+ */
+#define TSI148_LCSR_GCSRAT_EN (1<<7) /* Enable access to GCSR */
+
+#define TSI148_LCSR_GCSRAT_AS_M (7<<4) /* Address Space Mask */
+#define TSI148_LCSR_GCSRAT_AS_A16 (0<<4) /* Address Space 16 */
+#define TSI148_LCSR_GCSRAT_AS_A24 (1<<4) /* Address Space 24 */
+#define TSI148_LCSR_GCSRAT_AS_A32 (2<<4) /* Address Space 32 */
+#define TSI148_LCSR_GCSRAT_AS_A64 (4<<4) /* Address Space 64 */
+
+#define TSI148_LCSR_GCSRAT_SUPR (1<<3) /* Sup set -GCSR decoder */
+#define TSI148_LCSR_GCSRAT_NPRIV (1<<2) /* Non-Privliged set - CGSR */
+#define TSI148_LCSR_GCSRAT_PGM (1<<1) /* Program set - GCSR decoder */
+#define TSI148_LCSR_GCSRAT_DATA (1<<0) /* DATA set GCSR decoder */
+
+/*
+ * CRG Base Address Lower Address CRG + $410
+ */
+#define TSI148_LCSR_CBAL_M (0xFFFFF<<12)
+
+/*
+ * CRG Attribute Register CRG + $414
+ */
+#define TSI148_LCSR_CRGAT_EN (1<<7) /* Enable PRG Access */
+
+#define TSI148_LCSR_CRGAT_AS_M (7<<4) /* Address Space */
+#define TSI148_LCSR_CRGAT_AS_A16 (0<<4) /* Address Space 16 */
+#define TSI148_LCSR_CRGAT_AS_A24 (1<<4) /* Address Space 24 */
+#define TSI148_LCSR_CRGAT_AS_A32 (2<<4) /* Address Space 32 */
+#define TSI148_LCSR_CRGAT_AS_A64 (4<<4) /* Address Space 64 */
+
+#define TSI148_LCSR_CRGAT_SUPR (1<<3) /* Supervisor Access */
+#define TSI148_LCSR_CRGAT_NPRIV (1<<2) /* Non-Privliged(User) Access */
+#define TSI148_LCSR_CRGAT_PGM (1<<1) /* Program Access */
+#define TSI148_LCSR_CRGAT_DATA (1<<0) /* Data Access */
+
+/*
+ * CR/CSR Offset Lower Register CRG + $41C
+ */
+#define TSI148_LCSR_CROL_M (0x1FFF<<19) /* Mask */
+
+/*
+ * CR/CSR Attribute register CRG + $420
+ */
+#define TSI148_LCSR_CRAT_EN (1<<7) /* Enable access to CR/CSR */
+
+/*
+ * Location Monitor base address lower register CRG + $428
+ */
+#define TSI148_LCSR_LMBAL_M (0x7FFFFFF<<5) /* Mask */
+
+/*
+ * Location Monitor Attribute Register CRG + $42C
+ */
+#define TSI148_LCSR_LMAT_EN (1<<7) /* Enable Location Monitor */
+
+#define TSI148_LCSR_LMAT_AS_M (7<<4) /* Address Space MASK */
+#define TSI148_LCSR_LMAT_AS_A16 (0<<4) /* A16 */
+#define TSI148_LCSR_LMAT_AS_A24 (1<<4) /* A24 */
+#define TSI148_LCSR_LMAT_AS_A32 (2<<4) /* A32 */
+#define TSI148_LCSR_LMAT_AS_A64 (4<<4) /* A64 */
+
+#define TSI148_LCSR_LMAT_SUPR (1<<3) /* Supervisor Access */
+#define TSI148_LCSR_LMAT_NPRIV (1<<2) /* Non-Priv (User) Access */
+#define TSI148_LCSR_LMAT_PGM (1<<1) /* Program Access */
+#define TSI148_LCSR_LMAT_DATA (1<<0) /* Data Access */
+
+/*
+ * Broadcast Pulse Generator Timer Register CRG + $438
+ */
+#define TSI148_LCSR_BPGTR_BPGT_M (0xFFFF<<0) /* Mask */
+
+/*
+ * Broadcast Programmable Clock Timer Register CRG + $43C
+ */
+#define TSI148_LCSR_BPCTR_BPCT_M (0xFFFFFF<<0) /* Mask */
+
+/*
+ * VMEbus Interrupt Control Register CRG + $43C
+ */
+#define TSI148_LCSR_VICR_CNTS_M (3<<22) /* Cntr Source MASK */
+#define TSI148_LCSR_VICR_CNTS_DIS (1<<22) /* Cntr Disable */
+#define TSI148_LCSR_VICR_CNTS_IRQ1 (2<<22) /* IRQ1 to Cntr */
+#define TSI148_LCSR_VICR_CNTS_IRQ2 (3<<22) /* IRQ2 to Cntr */
+
+#define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interupt MASK */
+#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interupt Disable */
+#define TSI148_LCSR_VICR_EDGIS_IRQ1 (2<<20) /* IRQ1 to Edge */
+#define TSI148_LCSR_VICR_EDGIS_IRQ2 (3<<20) /* IRQ2 to Edge */
+
+#define TSI148_LCSR_VICR_IRQIF_M (3<<18) /* IRQ1* Function MASK */
+#define TSI148_LCSR_VICR_IRQIF_NORM (1<<18) /* Normal */
+#define TSI148_LCSR_VICR_IRQIF_PULSE (2<<18) /* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQIF_PROG (3<<18) /* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQIF_1U (4<<18) /* 1us Clock */
+
+#define TSI148_LCSR_VICR_IRQ2F_M (3<<16) /* IRQ2* Function MASK */
+#define TSI148_LCSR_VICR_IRQ2F_NORM (1<<16) /* Normal */
+#define TSI148_LCSR_VICR_IRQ2F_PULSE (2<<16) /* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQ2F_PROG (3<<16) /* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQ2F_1U (4<<16) /* 1us Clock */
+
+#define TSI148_LCSR_VICR_BIP (1<<15) /* Broadcast Interrupt Pulse */
+
+#define TSI148_LCSR_VICR_IRQC (1<<12) /* VMEbus IRQ Clear */
+#define TSI148_LCSR_VICR_IRQS (1<<11) /* VMEbus IRQ Status */
+
+#define TSI148_LCSR_VICR_IRQL_M (7<<8) /* VMEbus SW IRQ Level Mask */
+#define TSI148_LCSR_VICR_IRQL_1 (1<<8) /* VMEbus SW IRQ Level 1 */
+#define TSI148_LCSR_VICR_IRQL_2 (2<<8) /* VMEbus SW IRQ Level 2 */
+#define TSI148_LCSR_VICR_IRQL_3 (3<<8) /* VMEbus SW IRQ Level 3 */
+#define TSI148_LCSR_VICR_IRQL_4 (4<<8) /* VMEbus SW IRQ Level 4 */
+#define TSI148_LCSR_VICR_IRQL_5 (5<<8) /* VMEbus SW IRQ Level 5 */
+#define TSI148_LCSR_VICR_IRQL_6 (6<<8) /* VMEbus SW IRQ Level 6 */
+#define TSI148_LCSR_VICR_IRQL_7 (7<<8) /* VMEbus SW IRQ Level 7 */
+
+static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1,
+ TSI148_LCSR_VICR_IRQL_2, TSI148_LCSR_VICR_IRQL_3,
+ TSI148_LCSR_VICR_IRQL_4, TSI148_LCSR_VICR_IRQL_5,
+ TSI148_LCSR_VICR_IRQL_6, TSI148_LCSR_VICR_IRQL_7 };
+
+#define TSI148_LCSR_VICR_STID_M (0xFF<<0) /* Status/ID Mask */
+
+/*
+ * Interrupt Enable Register CRG + $440
+ */
+#define TSI148_LCSR_INTEN_DMA1EN (1<<25) /* DMAC 1 */
+#define TSI148_LCSR_INTEN_DMA0EN (1<<24) /* DMAC 0 */
+#define TSI148_LCSR_INTEN_LM3EN (1<<23) /* Location Monitor 3 */
+#define TSI148_LCSR_INTEN_LM2EN (1<<22) /* Location Monitor 2 */
+#define TSI148_LCSR_INTEN_LM1EN (1<<21) /* Location Monitor 1 */
+#define TSI148_LCSR_INTEN_LM0EN (1<<20) /* Location Monitor 0 */
+#define TSI148_LCSR_INTEN_MB3EN (1<<19) /* Mail Box 3 */
+#define TSI148_LCSR_INTEN_MB2EN (1<<18) /* Mail Box 2 */
+#define TSI148_LCSR_INTEN_MB1EN (1<<17) /* Mail Box 1 */
+#define TSI148_LCSR_INTEN_MB0EN (1<<16) /* Mail Box 0 */
+#define TSI148_LCSR_INTEN_PERREN (1<<13) /* PCI/X Error */
+#define TSI148_LCSR_INTEN_VERREN (1<<12) /* VMEbus Error */
+#define TSI148_LCSR_INTEN_VIEEN (1<<11) /* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEN_IACKEN (1<<10) /* IACK */
+#define TSI148_LCSR_INTEN_SYSFLEN (1<<9) /* System Fail */
+#define TSI148_LCSR_INTEN_ACFLEN (1<<8) /* AC Fail */
+#define TSI148_LCSR_INTEN_IRQ7EN (1<<7) /* IRQ7 */
+#define TSI148_LCSR_INTEN_IRQ6EN (1<<6) /* IRQ6 */
+#define TSI148_LCSR_INTEN_IRQ5EN (1<<5) /* IRQ5 */
+#define TSI148_LCSR_INTEN_IRQ4EN (1<<4) /* IRQ4 */
+#define TSI148_LCSR_INTEN_IRQ3EN (1<<3) /* IRQ3 */
+#define TSI148_LCSR_INTEN_IRQ2EN (1<<2) /* IRQ2 */
+#define TSI148_LCSR_INTEN_IRQ1EN (1<<1) /* IRQ1 */
+
+static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN,
+ TSI148_LCSR_INTEN_LM1EN,
+ TSI148_LCSR_INTEN_LM2EN,
+ TSI148_LCSR_INTEN_LM3EN };
+
+static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN,
+ TSI148_LCSR_INTEN_IRQ2EN,
+ TSI148_LCSR_INTEN_IRQ3EN,
+ TSI148_LCSR_INTEN_IRQ4EN,
+ TSI148_LCSR_INTEN_IRQ5EN,
+ TSI148_LCSR_INTEN_IRQ6EN,
+ TSI148_LCSR_INTEN_IRQ7EN };
+
+/*
+ * Interrupt Enable Out Register CRG + $444
+ */
+#define TSI148_LCSR_INTEO_DMA1EO (1<<25) /* DMAC 1 */
+#define TSI148_LCSR_INTEO_DMA0EO (1<<24) /* DMAC 0 */
+#define TSI148_LCSR_INTEO_LM3EO (1<<23) /* Loc Monitor 3 */
+#define TSI148_LCSR_INTEO_LM2EO (1<<22) /* Loc Monitor 2 */
+#define TSI148_LCSR_INTEO_LM1EO (1<<21) /* Loc Monitor 1 */
+#define TSI148_LCSR_INTEO_LM0EO (1<<20) /* Location Monitor 0 */
+#define TSI148_LCSR_INTEO_MB3EO (1<<19) /* Mail Box 3 */
+#define TSI148_LCSR_INTEO_MB2EO (1<<18) /* Mail Box 2 */
+#define TSI148_LCSR_INTEO_MB1EO (1<<17) /* Mail Box 1 */
+#define TSI148_LCSR_INTEO_MB0EO (1<<16) /* Mail Box 0 */
+#define TSI148_LCSR_INTEO_PERREO (1<<13) /* PCI/X Error */
+#define TSI148_LCSR_INTEO_VERREO (1<<12) /* VMEbus Error */
+#define TSI148_LCSR_INTEO_VIEEO (1<<11) /* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEO_IACKEO (1<<10) /* IACK */
+#define TSI148_LCSR_INTEO_SYSFLEO (1<<9) /* System Fail */
+#define TSI148_LCSR_INTEO_ACFLEO (1<<8) /* AC Fail */
+#define TSI148_LCSR_INTEO_IRQ7EO (1<<7) /* IRQ7 */
+#define TSI148_LCSR_INTEO_IRQ6EO (1<<6) /* IRQ6 */
+#define TSI148_LCSR_INTEO_IRQ5EO (1<<5) /* IRQ5 */
+#define TSI148_LCSR_INTEO_IRQ4EO (1<<4) /* IRQ4 */
+#define TSI148_LCSR_INTEO_IRQ3EO (1<<3) /* IRQ3 */
+#define TSI148_LCSR_INTEO_IRQ2EO (1<<2) /* IRQ2 */
+#define TSI148_LCSR_INTEO_IRQ1EO (1<<1) /* IRQ1 */
+
+static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO,
+ TSI148_LCSR_INTEO_LM1EO,
+ TSI148_LCSR_INTEO_LM2EO,
+ TSI148_LCSR_INTEO_LM3EO };
+
+static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO,
+ TSI148_LCSR_INTEO_IRQ2EO,
+ TSI148_LCSR_INTEO_IRQ3EO,
+ TSI148_LCSR_INTEO_IRQ4EO,
+ TSI148_LCSR_INTEO_IRQ5EO,
+ TSI148_LCSR_INTEO_IRQ6EO,
+ TSI148_LCSR_INTEO_IRQ7EO };
+
+/*
+ * Interrupt Status Register CRG + $448
+ */
+#define TSI148_LCSR_INTS_DMA1S (1<<25) /* DMA 1 */
+#define TSI148_LCSR_INTS_DMA0S (1<<24) /* DMA 0 */
+#define TSI148_LCSR_INTS_LM3S (1<<23) /* Location Monitor 3 */
+#define TSI148_LCSR_INTS_LM2S (1<<22) /* Location Monitor 2 */
+#define TSI148_LCSR_INTS_LM1S (1<<21) /* Location Monitor 1 */
+#define TSI148_LCSR_INTS_LM0S (1<<20) /* Location Monitor 0 */
+#define TSI148_LCSR_INTS_MB3S (1<<19) /* Mail Box 3 */
+#define TSI148_LCSR_INTS_MB2S (1<<18) /* Mail Box 2 */
+#define TSI148_LCSR_INTS_MB1S (1<<17) /* Mail Box 1 */
+#define TSI148_LCSR_INTS_MB0S (1<<16) /* Mail Box 0 */
+#define TSI148_LCSR_INTS_PERRS (1<<13) /* PCI/X Error */
+#define TSI148_LCSR_INTS_VERRS (1<<12) /* VMEbus Error */
+#define TSI148_LCSR_INTS_VIES (1<<11) /* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTS_IACKS (1<<10) /* IACK */
+#define TSI148_LCSR_INTS_SYSFLS (1<<9) /* System Fail */
+#define TSI148_LCSR_INTS_ACFLS (1<<8) /* AC Fail */
+#define TSI148_LCSR_INTS_IRQ7S (1<<7) /* IRQ7 */
+#define TSI148_LCSR_INTS_IRQ6S (1<<6) /* IRQ6 */
+#define TSI148_LCSR_INTS_IRQ5S (1<<5) /* IRQ5 */
+#define TSI148_LCSR_INTS_IRQ4S (1<<4) /* IRQ4 */
+#define TSI148_LCSR_INTS_IRQ3S (1<<3) /* IRQ3 */
+#define TSI148_LCSR_INTS_IRQ2S (1<<2) /* IRQ2 */
+#define TSI148_LCSR_INTS_IRQ1S (1<<1) /* IRQ1 */
+
+static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S,
+ TSI148_LCSR_INTS_LM1S,
+ TSI148_LCSR_INTS_LM2S,
+ TSI148_LCSR_INTS_LM3S };
+
+static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S,
+ TSI148_LCSR_INTS_MB1S,
+ TSI148_LCSR_INTS_MB2S,
+ TSI148_LCSR_INTS_MB3S };
+
+/*
+ * Interrupt Clear Register CRG + $44C
+ */
+#define TSI148_LCSR_INTC_DMA1C (1<<25) /* DMA 1 */
+#define TSI148_LCSR_INTC_DMA0C (1<<24) /* DMA 0 */
+#define TSI148_LCSR_INTC_LM3C (1<<23) /* Location Monitor 3 */
+#define TSI148_LCSR_INTC_LM2C (1<<22) /* Location Monitor 2 */
+#define TSI148_LCSR_INTC_LM1C (1<<21) /* Location Monitor 1 */
+#define TSI148_LCSR_INTC_LM0C (1<<20) /* Location Monitor 0 */
+#define TSI148_LCSR_INTC_MB3C (1<<19) /* Mail Box 3 */
+#define TSI148_LCSR_INTC_MB2C (1<<18) /* Mail Box 2 */
+#define TSI148_LCSR_INTC_MB1C (1<<17) /* Mail Box 1 */
+#define TSI148_LCSR_INTC_MB0C (1<<16) /* Mail Box 0 */
+#define TSI148_LCSR_INTC_PERRC (1<<13) /* VMEbus Error */
+#define TSI148_LCSR_INTC_VERRC (1<<12) /* VMEbus Access Time-out */
+#define TSI148_LCSR_INTC_VIEC (1<<11) /* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTC_IACKC (1<<10) /* IACK */
+#define TSI148_LCSR_INTC_SYSFLC (1<<9) /* System Fail */
+#define TSI148_LCSR_INTC_ACFLC (1<<8) /* AC Fail */
+
+static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C,
+ TSI148_LCSR_INTC_LM1C,
+ TSI148_LCSR_INTC_LM2C,
+ TSI148_LCSR_INTC_LM3C };
+
+static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C,
+ TSI148_LCSR_INTC_MB1C,
+ TSI148_LCSR_INTC_MB2C,
+ TSI148_LCSR_INTC_MB3C };
+
+/*
+ * Interrupt Map Register 1 CRG + $458
+ */
+#define TSI148_LCSR_INTM1_DMA1M_M (3<<18) /* DMA 1 */
+#define TSI148_LCSR_INTM1_DMA0M_M (3<<16) /* DMA 0 */
+#define TSI148_LCSR_INTM1_LM3M_M (3<<14) /* Location Monitor 3 */
+#define TSI148_LCSR_INTM1_LM2M_M (3<<12) /* Location Monitor 2 */
+#define TSI148_LCSR_INTM1_LM1M_M (3<<10) /* Location Monitor 1 */
+#define TSI148_LCSR_INTM1_LM0M_M (3<<8) /* Location Monitor 0 */
+#define TSI148_LCSR_INTM1_MB3M_M (3<<6) /* Mail Box 3 */
+#define TSI148_LCSR_INTM1_MB2M_M (3<<4) /* Mail Box 2 */
+#define TSI148_LCSR_INTM1_MB1M_M (3<<2) /* Mail Box 1 */
+#define TSI148_LCSR_INTM1_MB0M_M (3<<0) /* Mail Box 0 */
+
+/*
+ * Interrupt Map Register 2 CRG + $45C
+ */
+#define TSI148_LCSR_INTM2_PERRM_M (3<<26) /* PCI Bus Error */
+#define TSI148_LCSR_INTM2_VERRM_M (3<<24) /* VMEbus Error */
+#define TSI148_LCSR_INTM2_VIEM_M (3<<22) /* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTM2_IACKM_M (3<<20) /* IACK */
+#define TSI148_LCSR_INTM2_SYSFLM_M (3<<18) /* System Fail */
+#define TSI148_LCSR_INTM2_ACFLM_M (3<<16) /* AC Fail */
+#define TSI148_LCSR_INTM2_IRQ7M_M (3<<14) /* IRQ7 */
+#define TSI148_LCSR_INTM2_IRQ6M_M (3<<12) /* IRQ6 */
+#define TSI148_LCSR_INTM2_IRQ5M_M (3<<10) /* IRQ5 */
+#define TSI148_LCSR_INTM2_IRQ4M_M (3<<8) /* IRQ4 */
+#define TSI148_LCSR_INTM2_IRQ3M_M (3<<6) /* IRQ3 */
+#define TSI148_LCSR_INTM2_IRQ2M_M (3<<4) /* IRQ2 */
+#define TSI148_LCSR_INTM2_IRQ1M_M (3<<2) /* IRQ1 */
+
+/*
+ * DMA Control (0-1) Registers CRG + $500
+ */
+#define TSI148_LCSR_DCTL_ABT (1<<27) /* Abort */
+#define TSI148_LCSR_DCTL_PAU (1<<26) /* Pause */
+#define TSI148_LCSR_DCTL_DGO (1<<25) /* DMA Go */
+
+#define TSI148_LCSR_DCTL_MOD (1<<23) /* Mode */
+
+#define TSI148_LCSR_DCTL_VBKS_M (7<<12) /* VMEbus block Size MASK */
+#define TSI148_LCSR_DCTL_VBKS_32 (0<<12) /* VMEbus block Size 32 */
+#define TSI148_LCSR_DCTL_VBKS_64 (1<<12) /* VMEbus block Size 64 */
+#define TSI148_LCSR_DCTL_VBKS_128 (2<<12) /* VMEbus block Size 128 */
+#define TSI148_LCSR_DCTL_VBKS_256 (3<<12) /* VMEbus block Size 256 */
+#define TSI148_LCSR_DCTL_VBKS_512 (4<<12) /* VMEbus block Size 512 */
+#define TSI148_LCSR_DCTL_VBKS_1024 (5<<12) /* VMEbus block Size 1024 */
+#define TSI148_LCSR_DCTL_VBKS_2048 (6<<12) /* VMEbus block Size 2048 */
+#define TSI148_LCSR_DCTL_VBKS_4096 (7<<12) /* VMEbus block Size 4096 */
+
+#define TSI148_LCSR_DCTL_VBOT_M (7<<8) /* VMEbus back-off MASK */
+#define TSI148_LCSR_DCTL_VBOT_0 (0<<8) /* VMEbus back-off 0us */
+#define TSI148_LCSR_DCTL_VBOT_1 (1<<8) /* VMEbus back-off 1us */
+#define TSI148_LCSR_DCTL_VBOT_2 (2<<8) /* VMEbus back-off 2us */
+#define TSI148_LCSR_DCTL_VBOT_4 (3<<8) /* VMEbus back-off 4us */
+#define TSI148_LCSR_DCTL_VBOT_8 (4<<8) /* VMEbus back-off 8us */
+#define TSI148_LCSR_DCTL_VBOT_16 (5<<8) /* VMEbus back-off 16us */
+#define TSI148_LCSR_DCTL_VBOT_32 (6<<8) /* VMEbus back-off 32us */
+#define TSI148_LCSR_DCTL_VBOT_64 (7<<8) /* VMEbus back-off 64us */
+
+#define TSI148_LCSR_DCTL_PBKS_M (7<<4) /* PCI block size MASK */
+#define TSI148_LCSR_DCTL_PBKS_32 (0<<4) /* PCI block size 32 bytes */
+#define TSI148_LCSR_DCTL_PBKS_64 (1<<4) /* PCI block size 64 bytes */
+#define TSI148_LCSR_DCTL_PBKS_128 (2<<4) /* PCI block size 128 bytes */
+#define TSI148_LCSR_DCTL_PBKS_256 (3<<4) /* PCI block size 256 bytes */
+#define TSI148_LCSR_DCTL_PBKS_512 (4<<4) /* PCI block size 512 bytes */
+#define TSI148_LCSR_DCTL_PBKS_1024 (5<<4) /* PCI block size 1024 bytes */
+#define TSI148_LCSR_DCTL_PBKS_2048 (6<<4) /* PCI block size 2048 bytes */
+#define TSI148_LCSR_DCTL_PBKS_4096 (7<<4) /* PCI block size 4096 bytes */
+
+#define TSI148_LCSR_DCTL_PBOT_M (7<<0) /* PCI back off MASK */
+#define TSI148_LCSR_DCTL_PBOT_0 (0<<0) /* PCI back off 0us */
+#define TSI148_LCSR_DCTL_PBOT_1 (1<<0) /* PCI back off 1us */
+#define TSI148_LCSR_DCTL_PBOT_2 (2<<0) /* PCI back off 2us */
+#define TSI148_LCSR_DCTL_PBOT_4 (3<<0) /* PCI back off 3us */
+#define TSI148_LCSR_DCTL_PBOT_8 (4<<0) /* PCI back off 4us */
+#define TSI148_LCSR_DCTL_PBOT_16 (5<<0) /* PCI back off 8us */
+#define TSI148_LCSR_DCTL_PBOT_32 (6<<0) /* PCI back off 16us */
+#define TSI148_LCSR_DCTL_PBOT_64 (7<<0) /* PCI back off 32us */
+
+/*
+ * DMA Status Registers (0-1) CRG + $504
+ */
+#define TSI148_LCSR_DSTA_SMA (1<<31) /* PCI Signalled Master Abt */
+#define TSI148_LCSR_DSTA_RTA (1<<30) /* PCI Received Target Abt */
+#define TSI148_LCSR_DSTA_MRC (1<<29) /* PCI Max Retry Count */
+#define TSI148_LCSR_DSTA_VBE (1<<28) /* VMEbus error */
+#define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */
+#define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */
+#define TSI148_LCSR_DSTA_DON (1<<25) /* Done */
+#define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */
+
+/*
+ * DMA Current Link Address Lower (0-1)
+ */
+#define TSI148_LCSR_DCLAL_M (0x3FFFFFF<<6) /* Mask */
+
+/*
+ * DMA Source Attribute (0-1) Reg
+ */
+#define TSI148_LCSR_DSAT_TYP_M (3<<28) /* Source Bus Type */
+#define TSI148_LCSR_DSAT_TYP_PCI (0<<28) /* PCI Bus */
+#define TSI148_LCSR_DSAT_TYP_VME (1<<28) /* VMEbus */
+#define TSI148_LCSR_DSAT_TYP_PAT (2<<28) /* Data Pattern */
+
+#define TSI148_LCSR_DSAT_PSZ (1<<25) /* Pattern Size */
+#define TSI148_LCSR_DSAT_NIN (1<<24) /* No Increment */
+
+#define TSI148_LCSR_DSAT_2eSSTM_M (3<<11) /* 2eSST Trans Rate Mask */
+#define TSI148_LCSR_DSAT_2eSSTM_160 (0<<11) /* 160 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_267 (1<<11) /* 267 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_320 (2<<11) /* 320 MB/s */
+
+#define TSI148_LCSR_DSAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DSAT_TM_SCT (0<<8) /* SCT */
+#define TSI148_LCSR_DSAT_TM_BLT (1<<8) /* BLT */
+#define TSI148_LCSR_DSAT_TM_MBLT (2<<8) /* MBLT */
+#define TSI148_LCSR_DSAT_TM_2eVME (3<<8) /* 2eVME */
+#define TSI148_LCSR_DSAT_TM_2eSST (4<<8) /* 2eSST */
+#define TSI148_LCSR_DSAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */
+
+#define TSI148_LCSR_DSAT_DBW_M (3<<6) /* Max Data Width MASK */
+#define TSI148_LCSR_DSAT_DBW_16 (0<<6) /* 16 Bits */
+#define TSI148_LCSR_DSAT_DBW_32 (1<<6) /* 32 Bits */
+
+#define TSI148_LCSR_DSAT_SUP (1<<5) /* Supervisory Mode */
+#define TSI148_LCSR_DSAT_PGM (1<<4) /* Program Mode */
+
+#define TSI148_LCSR_DSAT_AMODE_M (0xf<<0) /* Address Space Mask */
+#define TSI148_LCSR_DSAT_AMODE_A16 (0<<0) /* A16 */
+#define TSI148_LCSR_DSAT_AMODE_A24 (1<<0) /* A24 */
+#define TSI148_LCSR_DSAT_AMODE_A32 (2<<0) /* A32 */
+#define TSI148_LCSR_DSAT_AMODE_A64 (4<<0) /* A64 */
+#define TSI148_LCSR_DSAT_AMODE_CRCSR (5<<0) /* CR/CSR */
+#define TSI148_LCSR_DSAT_AMODE_USER1 (8<<0) /* User1 */
+#define TSI148_LCSR_DSAT_AMODE_USER2 (9<<0) /* User2 */
+#define TSI148_LCSR_DSAT_AMODE_USER3 (0xa<<0) /* User3 */
+#define TSI148_LCSR_DSAT_AMODE_USER4 (0xb<<0) /* User4 */
+
+/*
+ * DMA Destination Attribute Registers (0-1)
+ */
+#define TSI148_LCSR_DDAT_TYP_PCI (0<<28) /* Destination PCI Bus */
+#define TSI148_LCSR_DDAT_TYP_VME (1<<28) /* Destination VMEbus */
+
+#define TSI148_LCSR_DDAT_2eSSTM_M (3<<11) /* 2eSST Transfer Rate Mask */
+#define TSI148_LCSR_DDAT_2eSSTM_160 (0<<11) /* 160 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_267 (1<<11) /* 267 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_320 (2<<11) /* 320 MB/s */
+
+#define TSI148_LCSR_DDAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DDAT_TM_SCT (0<<8) /* SCT */
+#define TSI148_LCSR_DDAT_TM_BLT (1<<8) /* BLT */
+#define TSI148_LCSR_DDAT_TM_MBLT (2<<8) /* MBLT */
+#define TSI148_LCSR_DDAT_TM_2eVME (3<<8) /* 2eVME */
+#define TSI148_LCSR_DDAT_TM_2eSST (4<<8) /* 2eSST */
+#define TSI148_LCSR_DDAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */
+
+#define TSI148_LCSR_DDAT_DBW_M (3<<6) /* Max Data Width MASK */
+#define TSI148_LCSR_DDAT_DBW_16 (0<<6) /* 16 Bits */
+#define TSI148_LCSR_DDAT_DBW_32 (1<<6) /* 32 Bits */
+
+#define TSI148_LCSR_DDAT_SUP (1<<5) /* Supervisory/User Access */
+#define TSI148_LCSR_DDAT_PGM (1<<4) /* Program/Data Access */
+
+#define TSI148_LCSR_DDAT_AMODE_M (0xf<<0) /* Address Space Mask */
+#define TSI148_LCSR_DDAT_AMODE_A16 (0<<0) /* A16 */
+#define TSI148_LCSR_DDAT_AMODE_A24 (1<<0) /* A24 */
+#define TSI148_LCSR_DDAT_AMODE_A32 (2<<0) /* A32 */
+#define TSI148_LCSR_DDAT_AMODE_A64 (4<<0) /* A64 */
+#define TSI148_LCSR_DDAT_AMODE_CRCSR (5<<0) /* CRC/SR */
+#define TSI148_LCSR_DDAT_AMODE_USER1 (8<<0) /* User1 */
+#define TSI148_LCSR_DDAT_AMODE_USER2 (9<<0) /* User2 */
+#define TSI148_LCSR_DDAT_AMODE_USER3 (0xa<<0) /* User3 */
+#define TSI148_LCSR_DDAT_AMODE_USER4 (0xb<<0) /* User4 */
+
+/*
+ * DMA Next Link Address Lower
+ */
+#define TSI148_LCSR_DNLAL_DNLAL_M (0x3FFFFFF<<6) /* Address Mask */
+#define TSI148_LCSR_DNLAL_LLA (1<<0) /* Last Link Address Indicator */
+
+/*
+ * DMA 2eSST Broadcast Select
+ */
+#define TSI148_LCSR_DBS_M (0x1FFFFF<<0) /* Mask */
+
+/*
+ * GCSR Register Group
+ */
+
+/*
+ * GCSR Control and Status Register CRG + $604
+ */
+#define TSI148_GCSR_GCTRL_LRST (1<<15) /* Local Reset */
+#define TSI148_GCSR_GCTRL_SFAILEN (1<<14) /* System Fail enable */
+#define TSI148_GCSR_GCTRL_BDFAILS (1<<13) /* Board Fail Status */
+#define TSI148_GCSR_GCTRL_SCON (1<<12) /* System Copntroller */
+#define TSI148_GCSR_GCTRL_MEN (1<<11) /* Module Enable (READY) */
+
+#define TSI148_GCSR_GCTRL_LMI3S (1<<7) /* Loc Monitor 3 Int Status */
+#define TSI148_GCSR_GCTRL_LMI2S (1<<6) /* Loc Monitor 2 Int Status */
+#define TSI148_GCSR_GCTRL_LMI1S (1<<5) /* Loc Monitor 1 Int Status */
+#define TSI148_GCSR_GCTRL_LMI0S (1<<4) /* Loc Monitor 0 Int Status */
+#define TSI148_GCSR_GCTRL_MBI3S (1<<3) /* Mail box 3 Int Status */
+#define TSI148_GCSR_GCTRL_MBI2S (1<<2) /* Mail box 2 Int Status */
+#define TSI148_GCSR_GCTRL_MBI1S (1<<1) /* Mail box 1 Int Status */
+#define TSI148_GCSR_GCTRL_MBI0S (1<<0) /* Mail box 0 Int Status */
+
+#define TSI148_GCSR_GAP (1<<5) /* Geographic Addr Parity */
+#define TSI148_GCSR_GA_M (0x1F<<0) /* Geographic Address Mask */
+
+/*
+ * CR/CSR Register Group
+ */
+
+/*
+ * CR/CSR Bit Clear Register CRG + $FF4
+ */
+#define TSI148_CRCSR_CSRBCR_LRSTC (1<<7) /* Local Reset Clear */
+#define TSI148_CRCSR_CSRBCR_SFAILC (1<<6) /* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BDFAILS (1<<5) /* Board Fail Status */
+#define TSI148_CRCSR_CSRBCR_MENC (1<<4) /* Module Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BERRSC (1<<3) /* Bus Error Status Clear */
+
+/*
+ * CR/CSR Bit Set Register CRG+$FF8
+ */
+#define TSI148_CRCSR_CSRBSR_LISTS (1<<7) /* Local Reset Clear */
+#define TSI148_CRCSR_CSRBSR_SFAILS (1<<6) /* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BDFAILS (1<<5) /* Board Fail Status */
+#define TSI148_CRCSR_CSRBSR_MENS (1<<4) /* Module Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BERRS (1<<3) /* Bus Error Status Clear */
+
+/*
+ * CR/CSR Base Address Register CRG + FFC
+ */
+#define TSI148_CRCSR_CBAR_M (0x1F<<3) /* Mask */
+
+#endif /* TSI148_H */
diff --git a/drivers/staging/vme/devices/Kconfig b/drivers/staging/vme/devices/Kconfig
new file mode 100644
index 000000000000..ca5ba89e2d8c
--- /dev/null
+++ b/drivers/staging/vme/devices/Kconfig
@@ -0,0 +1,8 @@
+comment "VME Device Drivers"
+
+config VME_USER
+ tristate "VME user space access driver"
+ help
+ If you say Y here you want to be able to access a limited number of
+ VME windows in a manner at least semi-compatible with the interface
+ provided with the original driver at http://vmelinux.org/.
diff --git a/drivers/staging/vme/devices/Makefile b/drivers/staging/vme/devices/Makefile
new file mode 100644
index 000000000000..459742a75283
--- /dev/null
+++ b/drivers/staging/vme/devices/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the VME device drivers.
+#
+
+obj-$(CONFIG_VME_USER) += vme_user.o
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
new file mode 100644
index 000000000000..78912883d153
--- /dev/null
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -0,0 +1,826 @@
+/*
+ * VMEbus User access driver
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by:
+ * Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/syscalls.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "../vme.h"
+#include "vme_user.h"
+
+static char driver_name[] = "vme_user";
+
+static int bus[USER_BUS_MAX];
+static int bus_num;
+
+/* Currently Documentation/devices.txt defines the following for VME:
+ *
+ * 221 char VME bus
+ * 0 = /dev/bus/vme/m0 First master image
+ * 1 = /dev/bus/vme/m1 Second master image
+ * 2 = /dev/bus/vme/m2 Third master image
+ * 3 = /dev/bus/vme/m3 Fourth master image
+ * 4 = /dev/bus/vme/s0 First slave image
+ * 5 = /dev/bus/vme/s1 Second slave image
+ * 6 = /dev/bus/vme/s2 Third slave image
+ * 7 = /dev/bus/vme/s3 Fourth slave image
+ * 8 = /dev/bus/vme/ctl Control
+ *
+ * It is expected that all VME bus drivers will use the
+ * same interface. For interface documentation see
+ * http://www.vmelinux.org/.
+ *
+ * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't
+ * even support the tsi148 chipset (which has 8 master and 8 slave windows).
+ * We'll run with this or now as far as possible, however it probably makes
+ * sense to get rid of the old mappings and just do everything dynamically.
+ *
+ * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as
+ * defined above and try to support at least some of the interface from
+ * http://www.vmelinux.org/ as an alternative drive can be written providing a
+ * saner interface later.
+ *
+ * The vmelinux.org driver never supported slave images, the devices reserved
+ * for slaves were repurposed to support all 8 master images on the UniverseII!
+ * We shall support 4 masters and 4 slaves with this driver.
+ */
+#define VME_MAJOR 221 /* VME Major Device Number */
+#define VME_DEVS 9 /* Number of dev entries */
+
+#define MASTER_MINOR 0
+#define MASTER_MAX 3
+#define SLAVE_MINOR 4
+#define SLAVE_MAX 7
+#define CONTROL_MINOR 8
+
+#define PCI_BUF_SIZE 0x20000 /* Size of one slave image buffer */
+
+/*
+ * Structure to handle image related parameters.
+ */
+typedef struct {
+ void __iomem *kern_buf; /* Buffer address in kernel space */
+ dma_addr_t pci_buf; /* Buffer address in PCI address space */
+ unsigned long long size_buf; /* Buffer size */
+ struct semaphore sem; /* Semaphore for locking image */
+ struct device *device; /* Sysfs device */
+ struct vme_resource *resource; /* VME resource */
+ int users; /* Number of current users */
+} image_desc_t;
+static image_desc_t image[VME_DEVS];
+
+typedef struct {
+ unsigned long reads;
+ unsigned long writes;
+ unsigned long ioctls;
+ unsigned long irqs;
+ unsigned long berrs;
+ unsigned long dmaErrors;
+ unsigned long timeouts;
+ unsigned long external;
+} driver_stats_t;
+static driver_stats_t statistics;
+
+struct cdev *vme_user_cdev; /* Character device */
+struct class *vme_user_sysfs_class; /* Sysfs class */
+struct device *vme_user_bridge; /* Pointer to the bridge device */
+
+
+static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR,
+ MASTER_MINOR, MASTER_MINOR,
+ SLAVE_MINOR, SLAVE_MINOR,
+ SLAVE_MINOR, SLAVE_MINOR,
+ CONTROL_MINOR
+ };
+
+
+static int vme_user_open(struct inode *, struct file *);
+static int vme_user_release(struct inode *, struct file *);
+static ssize_t vme_user_read(struct file *, char *, size_t, loff_t *);
+static ssize_t vme_user_write(struct file *, const char *, size_t, loff_t *);
+static loff_t vme_user_llseek(struct file *, loff_t, int);
+static int vme_user_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+static int __init vme_user_probe(struct device *, int, int);
+static int __exit vme_user_remove(struct device *, int, int);
+
+static struct file_operations vme_user_fops = {
+ .open = vme_user_open,
+ .release = vme_user_release,
+ .read = vme_user_read,
+ .write = vme_user_write,
+ .llseek = vme_user_llseek,
+ .ioctl = vme_user_ioctl,
+};
+
+
+/*
+ * Reset all the statistic counters
+ */
+static void reset_counters(void)
+{
+ statistics.reads = 0;
+ statistics.writes = 0;
+ statistics.ioctls = 0;
+ statistics.irqs = 0;
+ statistics.berrs = 0;
+ statistics.dmaErrors = 0;
+ statistics.timeouts = 0;
+}
+
+static int vme_user_open(struct inode *inode, struct file *file)
+{
+ int err;
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ down(&image[minor].sem);
+ /* Only allow device to be opened if a resource is allocated */
+ if (image[minor].resource == NULL) {
+ printk(KERN_ERR "No resources allocated for device\n");
+ err = -EINVAL;
+ goto err_res;
+ }
+
+ /* Increment user count */
+ image[minor].users++;
+
+ up(&image[minor].sem);
+
+ return 0;
+
+err_res:
+ up(&image[minor].sem);
+
+ return err;
+}
+
+static int vme_user_release(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ down(&image[minor].sem);
+
+ /* Decrement user count */
+ image[minor].users--;
+
+ up(&image[minor].sem);
+
+ return 0;
+}
+
+/*
+ * We are going ot alloc a page during init per window for small transfers.
+ * Small transfers will go VME -> buffer -> user space. Larger (more than a
+ * page) transfers will lock the user space buffer into memory and then
+ * transfer the data directly into the user space buffers.
+ */
+static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ ssize_t retval;
+ ssize_t copied = 0;
+
+ if (count <= image[minor].size_buf) {
+ /* We copy to kernel buffer */
+ copied = vme_master_read(image[minor].resource,
+ image[minor].kern_buf, count, *ppos);
+ if (copied < 0) {
+ return (int)copied;
+ }
+
+ retval = __copy_to_user(buf, image[minor].kern_buf,
+ (unsigned long)copied);
+ if (retval != 0) {
+ copied = (copied - retval);
+ printk("User copy failed\n");
+ return -EINVAL;
+ }
+
+ } else {
+ /* XXX Need to write this */
+ printk("Currently don't support large transfers\n");
+ /* Map in pages from userspace */
+
+ /* Call vme_master_read to do the transfer */
+ return -EINVAL;
+ }
+
+ return copied;
+}
+
+/*
+ * We are going ot alloc a page during init per window for small transfers.
+ * Small transfers will go user space -> buffer -> VME. Larger (more than a
+ * page) transfers will lock the user space buffer into memory and then
+ * transfer the data directly from the user space buffers out to VME.
+ */
+static ssize_t resource_from_user(unsigned int minor, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+ ssize_t copied = 0;
+
+ if (count <= image[minor].size_buf) {
+ retval = __copy_from_user(image[minor].kern_buf, buf,
+ (unsigned long)count);
+ if (retval != 0)
+ copied = (copied - retval);
+ else
+ copied = count;
+
+ copied = vme_master_write(image[minor].resource,
+ image[minor].kern_buf, copied, *ppos);
+ } else {
+ /* XXX Need to write this */
+ printk("Currently don't support large transfers\n");
+ /* Map in pages from userspace */
+
+ /* Call vme_master_write to do the transfer */
+ return -EINVAL;
+ }
+
+ return copied;
+}
+
+static ssize_t buffer_to_user(unsigned int minor, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ void __iomem *image_ptr;
+ ssize_t retval;
+
+ image_ptr = image[minor].kern_buf + *ppos;
+
+ retval = __copy_to_user(buf, image_ptr, (unsigned long)count);
+ if (retval != 0) {
+ retval = (count - retval);
+ printk(KERN_WARNING "Partial copy to userspace\n");
+ } else
+ retval = count;
+
+ /* Return number of bytes successfully read */
+ return retval;
+}
+
+static ssize_t buffer_from_user(unsigned int minor, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ void __iomem *image_ptr;
+ size_t retval;
+
+ image_ptr = image[minor].kern_buf + *ppos;
+
+ retval = __copy_from_user(image_ptr, buf, (unsigned long)count);
+ if (retval != 0) {
+ retval = (count - retval);
+ printk(KERN_WARNING "Partial copy to userspace\n");
+ } else
+ retval = count;
+
+ /* Return number of bytes successfully read */
+ return retval;
+}
+
+static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
+ loff_t * ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ ssize_t retval;
+ size_t image_size;
+ size_t okcount;
+
+ down(&image[minor].sem);
+
+ /* XXX Do we *really* want this helper - we can use vme_*_get ? */
+ image_size = vme_get_size(image[minor].resource);
+
+ /* Ensure we are starting at a valid location */
+ if ((*ppos < 0) || (*ppos > (image_size - 1))) {
+ up(&image[minor].sem);
+ return 0;
+ }
+
+ /* Ensure not reading past end of the image */
+ if (*ppos + count > image_size)
+ okcount = image_size - *ppos;
+ else
+ okcount = count;
+
+ switch (type[minor]){
+ case MASTER_MINOR:
+ retval = resource_to_user(minor, buf, okcount, ppos);
+ break;
+ case SLAVE_MINOR:
+ retval = buffer_to_user(minor, buf, okcount, ppos);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ up(&image[minor].sem);
+
+ if (retval > 0)
+ *ppos += retval;
+
+ return retval;
+}
+
+static ssize_t vme_user_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ ssize_t retval;
+ size_t image_size;
+ size_t okcount;
+
+ down(&image[minor].sem);
+
+ image_size = vme_get_size(image[minor].resource);
+
+ /* Ensure we are starting at a valid location */
+ if ((*ppos < 0) || (*ppos > (image_size - 1))) {
+ up(&image[minor].sem);
+ return 0;
+ }
+
+ /* Ensure not reading past end of the image */
+ if (*ppos + count > image_size)
+ okcount = image_size - *ppos;
+ else
+ okcount = count;
+
+ switch (type[minor]){
+ case MASTER_MINOR:
+ retval = resource_from_user(minor, buf, okcount, ppos);
+ break;
+ case SLAVE_MINOR:
+ retval = buffer_from_user(minor, buf, okcount, ppos);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ up(&image[minor].sem);
+
+ if (retval > 0)
+ *ppos += retval;
+
+ return retval;
+}
+
+static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
+{
+ printk(KERN_ERR "Llseek currently incomplete\n");
+ return -EINVAL;
+}
+
+/*
+ * The ioctls provided by the old VME access method (the one at vmelinux.org)
+ * are most certainly wrong as the effectively push the registers layout
+ * through to user space. Given that the VME core can handle multiple bridges,
+ * with different register layouts this is most certainly not the way to go.
+ *
+ * We aren't using the structures defined in the Motorola driver either - these
+ * are also quite low level, however we should use the definitions that have
+ * already been defined.
+ */
+static int vme_user_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct vme_master master;
+ struct vme_slave slave;
+ unsigned long copied;
+ unsigned int minor = MINOR(inode->i_rdev);
+ int retval;
+ dma_addr_t pci_addr;
+
+ statistics.ioctls++;
+
+ switch (type[minor]) {
+ case CONTROL_MINOR:
+ break;
+ case MASTER_MINOR:
+ switch (cmd) {
+ case VME_GET_MASTER:
+ memset(&master, 0, sizeof(struct vme_master));
+
+ /* XXX We do not want to push aspace, cycle and width
+ * to userspace as they are
+ */
+ retval = vme_master_get(image[minor].resource,
+ &(master.enable), &(master.vme_addr),
+ &(master.size), &(master.aspace),
+ &(master.cycle), &(master.dwidth));
+
+ copied = copy_to_user((char *)arg, &master,
+ sizeof(struct vme_master));
+ if (copied != 0) {
+ printk(KERN_WARNING "Partial copy to "
+ "userspace\n");
+ return -EFAULT;
+ }
+
+ return retval;
+ break;
+
+ case VME_SET_MASTER:
+
+ copied = copy_from_user(&master, (char *)arg,
+ sizeof(master));
+ if (copied != 0) {
+ printk(KERN_WARNING "Partial copy from "
+ "userspace\n");
+ return -EFAULT;
+ }
+
+ /* XXX We do not want to push aspace, cycle and width
+ * to userspace as they are
+ */
+ return vme_master_set(image[minor].resource,
+ master.enable, master.vme_addr, master.size,
+ master.aspace, master.cycle, master.dwidth);
+
+ break;
+ }
+ break;
+ case SLAVE_MINOR:
+ switch (cmd) {
+ case VME_GET_SLAVE:
+ memset(&slave, 0, sizeof(struct vme_slave));
+
+ /* XXX We do not want to push aspace, cycle and width
+ * to userspace as they are
+ */
+ retval = vme_slave_get(image[minor].resource,
+ &(slave.enable), &(slave.vme_addr),
+ &(slave.size), &pci_addr, &(slave.aspace),
+ &(slave.cycle));
+
+ copied = copy_to_user((char *)arg, &slave,
+ sizeof(struct vme_slave));
+ if (copied != 0) {
+ printk(KERN_WARNING "Partial copy to "
+ "userspace\n");
+ return -EFAULT;
+ }
+
+ return retval;
+ break;
+
+ case VME_SET_SLAVE:
+
+ copied = copy_from_user(&slave, (char *)arg,
+ sizeof(slave));
+ if (copied != 0) {
+ printk(KERN_WARNING "Partial copy from "
+ "userspace\n");
+ return -EFAULT;
+ }
+
+ /* XXX We do not want to push aspace, cycle and width
+ * to userspace as they are
+ */
+ return vme_slave_set(image[minor].resource,
+ slave.enable, slave.vme_addr, slave.size,
+ image[minor].pci_buf, slave.aspace,
+ slave.cycle);
+
+ break;
+ }
+ break;
+ }
+
+ return -EINVAL;
+}
+
+
+/*
+ * Unallocate a previously allocated buffer
+ */
+static void buf_unalloc (int num)
+{
+ if (image[num].kern_buf) {
+#ifdef VME_DEBUG
+ printk(KERN_DEBUG "UniverseII:Releasing buffer at %p\n",
+ image[num].pci_buf);
+#endif
+
+ vme_free_consistent(image[num].resource, image[num].size_buf,
+ image[num].kern_buf, image[num].pci_buf);
+
+ image[num].kern_buf = NULL;
+ image[num].pci_buf = 0;
+ image[num].size_buf = 0;
+
+#ifdef VME_DEBUG
+ } else {
+ printk(KERN_DEBUG "UniverseII: Buffer not allocated\n");
+#endif
+ }
+}
+
+static struct vme_driver vme_user_driver = {
+ .name = driver_name,
+ .probe = vme_user_probe,
+ .remove = vme_user_remove,
+};
+
+
+static int __init vme_user_init(void)
+{
+ int retval = 0;
+ int i;
+ struct vme_device_id *ids;
+
+ printk(KERN_INFO "VME User Space Access Driver\n");
+
+ if (bus_num == 0) {
+ printk(KERN_ERR "%s: No cards, skipping registration\n",
+ driver_name);
+ goto err_nocard;
+ }
+
+ /* Let's start by supporting one bus, we can support more than one
+ * in future revisions if that ever becomes necessary.
+ */
+ if (bus_num > USER_BUS_MAX) {
+ printk(KERN_ERR "%s: Driver only able to handle %d PIO2 "
+ "Cards\n", driver_name, USER_BUS_MAX);
+ bus_num = USER_BUS_MAX;
+ }
+
+
+ /* Dynamically create the bind table based on module parameters */
+ ids = kmalloc(sizeof(struct vme_device_id) * (bus_num + 1), GFP_KERNEL);
+ if (ids == NULL) {
+ printk(KERN_ERR "%s: Unable to allocate ID table\n",
+ driver_name);
+ goto err_id;
+ }
+
+ memset(ids, 0, (sizeof(struct vme_device_id) * (bus_num + 1)));
+
+ for (i = 0; i < bus_num; i++) {
+ ids[i].bus = bus[i];
+ /*
+ * We register the driver against the slot occupied by *this*
+ * card, since it's really a low level way of controlling
+ * the VME bridge
+ */
+ ids[i].slot = VME_SLOT_CURRENT;
+ }
+
+ vme_user_driver.bind_table = ids;
+
+ retval = vme_register_driver(&vme_user_driver);
+ if (retval != 0)
+ goto err_reg;
+
+ return retval;
+
+ vme_unregister_driver(&vme_user_driver);
+err_reg:
+ kfree(ids);
+err_id:
+err_nocard:
+ return retval;
+}
+
+/*
+ * In this simple access driver, the old behaviour is being preserved as much
+ * as practical. We will therefore reserve the buffers and request the images
+ * here so that we don't have to do it later.
+ */
+static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
+{
+ int i, err;
+ char name[8];
+
+ /* Save pointer to the bridge device */
+ if (vme_user_bridge != NULL) {
+ printk(KERN_ERR "%s: Driver can only be loaded for 1 device\n",
+ driver_name);
+ err = -EINVAL;
+ goto err_dev;
+ }
+ vme_user_bridge = dev;
+
+ /* Initialise descriptors */
+ for (i = 0; i < VME_DEVS; i++) {
+ image[i].kern_buf = NULL;
+ image[i].pci_buf = 0;
+ init_MUTEX(&(image[i].sem));
+ image[i].device = NULL;
+ image[i].resource = NULL;
+ image[i].users = 0;
+ }
+
+ /* Initialise statistics counters */
+ reset_counters();
+
+ /* Assign major and minor numbers for the driver */
+ err = register_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS,
+ driver_name);
+ if (err) {
+ printk(KERN_WARNING "%s: Error getting Major Number %d for "
+ "driver.\n", driver_name, VME_MAJOR);
+ goto err_region;
+ }
+
+ /* Register the driver as a char device */
+ vme_user_cdev = cdev_alloc();
+ vme_user_cdev->ops = &vme_user_fops;
+ vme_user_cdev->owner = THIS_MODULE;
+ err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS);
+ if (err) {
+ printk(KERN_WARNING "%s: cdev_all failed\n", driver_name);
+ goto err_char;
+ }
+
+ /* Request slave resources and allocate buffers (128kB wide) */
+ for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
+ /* XXX Need to properly request attributes */
+ image[i].resource = vme_slave_request(vme_user_bridge,
+ VME_A16, VME_SCT);
+ if (image[i].resource == NULL) {
+ printk(KERN_WARNING "Unable to allocate slave "
+ "resource\n");
+ goto err_slave;
+ }
+ image[i].size_buf = PCI_BUF_SIZE;
+ image[i].kern_buf = vme_alloc_consistent(image[i].resource,
+ image[i].size_buf, &(image[i].pci_buf));
+ if (image[i].kern_buf == NULL) {
+ printk(KERN_WARNING "Unable to allocate memory for "
+ "buffer\n");
+ image[i].pci_buf = 0;
+ vme_slave_free(image[i].resource);
+ err = -ENOMEM;
+ goto err_slave;
+ }
+ }
+
+ /*
+ * Request master resources allocate page sized buffers for small
+ * reads and writes
+ */
+ for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
+ /* XXX Need to properly request attributes */
+ image[i].resource = vme_master_request(vme_user_bridge,
+ VME_A32, VME_SCT, VME_D32);
+ if (image[i].resource == NULL) {
+ printk(KERN_WARNING "Unable to allocate master "
+ "resource\n");
+ goto err_master;
+ }
+ }
+
+ /* Create sysfs entries - on udev systems this creates the dev files */
+ vme_user_sysfs_class = class_create(THIS_MODULE, driver_name);
+ if (IS_ERR(vme_user_sysfs_class)) {
+ printk(KERN_ERR "Error creating vme_user class.\n");
+ err = PTR_ERR(vme_user_sysfs_class);
+ goto err_class;
+ }
+
+ /* Add sysfs Entries */
+ for (i=0; i<VME_DEVS; i++) {
+ switch (type[i]) {
+ case MASTER_MINOR:
+ sprintf(name,"bus/vme/m%%d");
+ break;
+ case CONTROL_MINOR:
+ sprintf(name,"bus/vme/ctl");
+ break;
+ case SLAVE_MINOR:
+ sprintf(name,"bus/vme/s%%d");
+ break;
+ default:
+ err = -EINVAL;
+ goto err_sysfs;
+ break;
+ }
+
+ image[i].device =
+ device_create(vme_user_sysfs_class, NULL,
+ MKDEV(VME_MAJOR, i), NULL, name,
+ (type[i] == SLAVE_MINOR)? i - (MASTER_MAX + 1) : i);
+ if (IS_ERR(image[i].device)) {
+ printk("%s: Error creating sysfs device\n",
+ driver_name);
+ err = PTR_ERR(image[i].device);
+ goto err_sysfs;
+ }
+ }
+
+ return 0;
+
+ /* Ensure counter set correcty to destroy all sysfs devices */
+ i = VME_DEVS;
+err_sysfs:
+ while (i > 0){
+ i--;
+ device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
+ }
+ class_destroy(vme_user_sysfs_class);
+
+ /* Ensure counter set correcty to unalloc all master windows */
+ i = MASTER_MAX + 1;
+err_master:
+ while (i > MASTER_MINOR) {
+ i--;
+ vme_master_free(image[i].resource);
+ }
+
+ /*
+ * Ensure counter set correcty to unalloc all slave windows and buffers
+ */
+ i = SLAVE_MAX + 1;
+err_slave:
+ while (i > SLAVE_MINOR) {
+ i--;
+ vme_slave_free(image[i].resource);
+ buf_unalloc(i);
+ }
+err_class:
+ cdev_del(vme_user_cdev);
+err_char:
+ unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
+err_region:
+err_dev:
+ return err;
+}
+
+static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
+{
+ int i;
+
+ /* Remove sysfs Entries */
+ for(i=0; i<VME_DEVS; i++) {
+ device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
+ }
+ class_destroy(vme_user_sysfs_class);
+
+ for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
+ vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0);
+ vme_slave_free(image[i].resource);
+ buf_unalloc(i);
+ }
+
+ /* Unregister device driver */
+ cdev_del(vme_user_cdev);
+
+ /* Unregiser the major and minor device numbers */
+ unregister_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS);
+
+ return 0;
+}
+
+static void __exit vme_user_exit(void)
+{
+ vme_unregister_driver(&vme_user_driver);
+
+ kfree(vme_user_driver.bind_table);
+}
+
+
+MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected");
+module_param_array(bus, int, &bus_num, 0);
+
+MODULE_DESCRIPTION("VME User Space Access Driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
+MODULE_LICENSE("GPL");
+
+module_init(vme_user_init);
+module_exit(vme_user_exit);
diff --git a/drivers/staging/vme/devices/vme_user.h b/drivers/staging/vme/devices/vme_user.h
new file mode 100644
index 000000000000..ede77d7e766b
--- /dev/null
+++ b/drivers/staging/vme/devices/vme_user.h
@@ -0,0 +1,52 @@
+#ifndef _VME_USER_H_
+#define _VME_USER_H_
+
+#define USER_BUS_MAX 1
+
+/*
+ * VMEbus Master Window Configuration Structure
+ */
+struct vme_master {
+ int enable; /* State of Window */
+ unsigned long long vme_addr; /* Starting Address on the VMEbus */
+ unsigned long long size; /* Window Size */
+ vme_address_t aspace; /* Address Space */
+ vme_cycle_t cycle; /* Cycle properties */
+ vme_width_t dwidth; /* Maximum Data Width */
+#if 0
+ char prefetchEnable; /* Prefetch Read Enable State */
+ int prefetchSize; /* Prefetch Read Size (Cache Lines) */
+ char wrPostEnable; /* Write Post State */
+#endif
+};
+
+
+/*
+ * IOCTL Commands and structures
+ */
+
+/* Magic number for use in ioctls */
+#define VME_IOC_MAGIC 0xAE
+
+
+/* VMEbus Slave Window Configuration Structure */
+struct vme_slave {
+ int enable; /* State of Window */
+ unsigned long long vme_addr; /* Starting Address on the VMEbus */
+ unsigned long long size; /* Window Size */
+ vme_address_t aspace; /* Address Space */
+ vme_cycle_t cycle; /* Cycle properties */
+#if 0
+ char wrPostEnable; /* Write Post State */
+ char rmwLock; /* Lock PCI during RMW Cycles */
+ char data64BitCapable; /* non-VMEbus capable of 64-bit Data */
+#endif
+};
+
+#define VME_GET_SLAVE _IOR(VME_IOC_MAGIC, 1, struct vme_slave)
+#define VME_SET_SLAVE _IOW(VME_IOC_MAGIC, 2, struct vme_slave)
+#define VME_GET_MASTER _IOR(VME_IOC_MAGIC, 3, struct vme_master)
+#define VME_SET_MASTER _IOW(VME_IOC_MAGIC, 4, struct vme_master)
+
+#endif /* _VME_USER_H_ */
+
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
new file mode 100644
index 000000000000..477a1adfd0e9
--- /dev/null
+++ b/drivers/staging/vme/vme.c
@@ -0,0 +1,1497 @@
+/*
+ * VME Bridge Framework
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/syscalls.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+#include "vme.h"
+#include "vme_bridge.h"
+
+/* Bitmask and mutex to keep track of bridge numbers */
+static unsigned int vme_bus_numbers;
+DEFINE_MUTEX(vme_bus_num_mtx);
+
+static void __exit vme_exit (void);
+static int __init vme_init (void);
+
+
+/*
+ * Find the bridge resource associated with a specific device resource
+ */
+static struct vme_bridge *dev_to_bridge(struct device *dev)
+{
+ return dev->platform_data;
+}
+
+/*
+ * Find the bridge that the resource is associated with.
+ */
+static struct vme_bridge *find_bridge(struct vme_resource *resource)
+{
+ /* Get list to search */
+ switch (resource->type) {
+ case VME_MASTER:
+ return list_entry(resource->entry, struct vme_master_resource,
+ list)->parent;
+ break;
+ case VME_SLAVE:
+ return list_entry(resource->entry, struct vme_slave_resource,
+ list)->parent;
+ break;
+ case VME_DMA:
+ return list_entry(resource->entry, struct vme_dma_resource,
+ list)->parent;
+ break;
+ case VME_LM:
+ return list_entry(resource->entry, struct vme_lm_resource,
+ list)->parent;
+ break;
+ default:
+ printk(KERN_ERR "Unknown resource type\n");
+ return NULL;
+ break;
+ }
+}
+
+/*
+ * Allocate a contiguous block of memory for use by the driver. This is used to
+ * create the buffers for the slave windows.
+ *
+ * XXX VME bridges could be available on buses other than PCI. At the momment
+ * this framework only supports PCI devices.
+ */
+void * vme_alloc_consistent(struct vme_resource *resource, size_t size,
+ dma_addr_t *dma)
+{
+ struct vme_bridge *bridge;
+ struct pci_dev *pdev;
+
+ if(resource == NULL) {
+ printk("No resource\n");
+ return NULL;
+ }
+
+ bridge = find_bridge(resource);
+ if(bridge == NULL) {
+ printk("Can't find bridge\n");
+ return NULL;
+ }
+
+ /* Find pci_dev container of dev */
+ if (bridge->parent == NULL) {
+ printk("Dev entry NULL\n");
+ return NULL;
+ }
+ pdev = container_of(bridge->parent, struct pci_dev, dev);
+
+ return pci_alloc_consistent(pdev, size, dma);
+}
+EXPORT_SYMBOL(vme_alloc_consistent);
+
+/*
+ * Free previously allocated contiguous block of memory.
+ *
+ * XXX VME bridges could be available on buses other than PCI. At the momment
+ * this framework only supports PCI devices.
+ */
+void vme_free_consistent(struct vme_resource *resource, size_t size,
+ void *vaddr, dma_addr_t dma)
+{
+ struct vme_bridge *bridge;
+ struct pci_dev *pdev;
+
+ if(resource == NULL) {
+ printk("No resource\n");
+ return;
+ }
+
+ bridge = find_bridge(resource);
+ if(bridge == NULL) {
+ printk("Can't find bridge\n");
+ return;
+ }
+
+ /* Find pci_dev container of dev */
+ pdev = container_of(bridge->parent, struct pci_dev, dev);
+
+ pci_free_consistent(pdev, size, vaddr, dma);
+}
+EXPORT_SYMBOL(vme_free_consistent);
+
+size_t vme_get_size(struct vme_resource *resource)
+{
+ int enabled, retval;
+ unsigned long long base, size;
+ dma_addr_t buf_base;
+ vme_address_t aspace;
+ vme_cycle_t cycle;
+ vme_width_t dwidth;
+
+ switch (resource->type) {
+ case VME_MASTER:
+ retval = vme_master_get(resource, &enabled, &base, &size,
+ &aspace, &cycle, &dwidth);
+
+ return size;
+ break;
+ case VME_SLAVE:
+ retval = vme_slave_get(resource, &enabled, &base, &size,
+ &buf_base, &aspace, &cycle);
+
+ return size;
+ break;
+ case VME_DMA:
+ return 0;
+ break;
+ default:
+ printk(KERN_ERR "Unknown resource type\n");
+ return 0;
+ break;
+ }
+}
+EXPORT_SYMBOL(vme_get_size);
+
+static int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
+ unsigned long long size)
+{
+ int retval = 0;
+
+ switch (aspace) {
+ case VME_A16:
+ if (((vme_base + size) > VME_A16_MAX) ||
+ (vme_base > VME_A16_MAX))
+ retval = -EFAULT;
+ break;
+ case VME_A24:
+ if (((vme_base + size) > VME_A24_MAX) ||
+ (vme_base > VME_A24_MAX))
+ retval = -EFAULT;
+ break;
+ case VME_A32:
+ if (((vme_base + size) > VME_A32_MAX) ||
+ (vme_base > VME_A32_MAX))
+ retval = -EFAULT;
+ break;
+ case VME_A64:
+ /*
+ * Any value held in an unsigned long long can be used as the
+ * base
+ */
+ break;
+ case VME_CRCSR:
+ if (((vme_base + size) > VME_CRCSR_MAX) ||
+ (vme_base > VME_CRCSR_MAX))
+ retval = -EFAULT;
+ break;
+ case VME_USER1:
+ case VME_USER2:
+ case VME_USER3:
+ case VME_USER4:
+ /* User Defined */
+ break;
+ default:
+ printk("Invalid address space\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * Request a slave image with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource * vme_slave_request(struct device *dev,
+ vme_address_t address, vme_cycle_t cycle)
+{
+ struct vme_bridge *bridge;
+ struct list_head *slave_pos = NULL;
+ struct vme_slave_resource *allocated_image = NULL;
+ struct vme_slave_resource *slave_image = NULL;
+ struct vme_resource *resource = NULL;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ goto err_bus;
+ }
+
+ /* Loop through slave resources */
+ list_for_each(slave_pos, &(bridge->slave_resources)) {
+ slave_image = list_entry(slave_pos,
+ struct vme_slave_resource, list);
+
+ if (slave_image == NULL) {
+ printk("Registered NULL Slave resource\n");
+ continue;
+ }
+
+ /* Find an unlocked and compatible image */
+ mutex_lock(&(slave_image->mtx));
+ if(((slave_image->address_attr & address) == address) &&
+ ((slave_image->cycle_attr & cycle) == cycle) &&
+ (slave_image->locked == 0)) {
+
+ slave_image->locked = 1;
+ mutex_unlock(&(slave_image->mtx));
+ allocated_image = slave_image;
+ break;
+ }
+ mutex_unlock(&(slave_image->mtx));
+ }
+
+ /* No free image */
+ if (allocated_image == NULL)
+ goto err_image;
+
+ resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+ if (resource == NULL) {
+ printk(KERN_WARNING "Unable to allocate resource structure\n");
+ goto err_alloc;
+ }
+ resource->type = VME_SLAVE;
+ resource->entry = &(allocated_image->list);
+
+ return resource;
+
+err_alloc:
+ /* Unlock image */
+ mutex_lock(&(slave_image->mtx));
+ slave_image->locked = 0;
+ mutex_unlock(&(slave_image->mtx));
+err_image:
+err_bus:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_slave_request);
+
+int vme_slave_set (struct vme_resource *resource, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_slave_resource *image;
+ int retval;
+
+ if (resource->type != VME_SLAVE) {
+ printk("Not a slave resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_slave_resource, list);
+
+ if (bridge->slave_set == NULL) {
+ printk("Function not supported\n");
+ return -ENOSYS;
+ }
+
+ if(!(((image->address_attr & aspace) == aspace) &&
+ ((image->cycle_attr & cycle) == cycle))) {
+ printk("Invalid attributes\n");
+ return -EINVAL;
+ }
+
+ retval = vme_check_window(aspace, vme_base, size);
+ if(retval)
+ return retval;
+
+ return bridge->slave_set(image, enabled, vme_base, size, buf_base,
+ aspace, cycle);
+}
+EXPORT_SYMBOL(vme_slave_set);
+
+int vme_slave_get (struct vme_resource *resource, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_slave_resource *image;
+
+ if (resource->type != VME_SLAVE) {
+ printk("Not a slave resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_slave_resource, list);
+
+ if (bridge->slave_get == NULL) {
+ printk("vme_slave_get not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->slave_get(image, enabled, vme_base, size, buf_base,
+ aspace, cycle);
+}
+EXPORT_SYMBOL(vme_slave_get);
+
+void vme_slave_free(struct vme_resource *resource)
+{
+ struct vme_slave_resource *slave_image;
+
+ if (resource->type != VME_SLAVE) {
+ printk("Not a slave resource\n");
+ return;
+ }
+
+ slave_image = list_entry(resource->entry, struct vme_slave_resource,
+ list);
+ if (slave_image == NULL) {
+ printk("Can't find slave resource\n");
+ return;
+ }
+
+ /* Unlock image */
+ mutex_lock(&(slave_image->mtx));
+ if (slave_image->locked == 0)
+ printk(KERN_ERR "Image is already free\n");
+
+ slave_image->locked = 0;
+ mutex_unlock(&(slave_image->mtx));
+
+ /* Free up resource memory */
+ kfree(resource);
+}
+EXPORT_SYMBOL(vme_slave_free);
+
+/*
+ * Request a master image with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource * vme_master_request(struct device *dev,
+ vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
+{
+ struct vme_bridge *bridge;
+ struct list_head *master_pos = NULL;
+ struct vme_master_resource *allocated_image = NULL;
+ struct vme_master_resource *master_image = NULL;
+ struct vme_resource *resource = NULL;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ goto err_bus;
+ }
+
+ /* Loop through master resources */
+ list_for_each(master_pos, &(bridge->master_resources)) {
+ master_image = list_entry(master_pos,
+ struct vme_master_resource, list);
+
+ if (master_image == NULL) {
+ printk(KERN_WARNING "Registered NULL master resource\n");
+ continue;
+ }
+
+ /* Find an unlocked and compatible image */
+ spin_lock(&(master_image->lock));
+ if(((master_image->address_attr & address) == address) &&
+ ((master_image->cycle_attr & cycle) == cycle) &&
+ ((master_image->width_attr & dwidth) == dwidth) &&
+ (master_image->locked == 0)) {
+
+ master_image->locked = 1;
+ spin_unlock(&(master_image->lock));
+ allocated_image = master_image;
+ break;
+ }
+ spin_unlock(&(master_image->lock));
+ }
+
+ /* Check to see if we found a resource */
+ if (allocated_image == NULL) {
+ printk(KERN_ERR "Can't find a suitable resource\n");
+ goto err_image;
+ }
+
+ resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+ if (resource == NULL) {
+ printk(KERN_ERR "Unable to allocate resource structure\n");
+ goto err_alloc;
+ }
+ resource->type = VME_MASTER;
+ resource->entry = &(allocated_image->list);
+
+ return resource;
+
+ kfree(resource);
+err_alloc:
+ /* Unlock image */
+ spin_lock(&(master_image->lock));
+ master_image->locked = 0;
+ spin_unlock(&(master_image->lock));
+err_image:
+err_bus:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_master_request);
+
+int vme_master_set (struct vme_resource *resource, int enabled,
+ unsigned long long vme_base, unsigned long long size,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_master_resource *image;
+ int retval;
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_master_resource, list);
+
+ if (bridge->master_set == NULL) {
+ printk("vme_master_set not supported\n");
+ return -EINVAL;
+ }
+
+ if(!(((image->address_attr & aspace) == aspace) &&
+ ((image->cycle_attr & cycle) == cycle) &&
+ ((image->width_attr & dwidth) == dwidth))) {
+ printk("Invalid attributes\n");
+ return -EINVAL;
+ }
+
+ retval = vme_check_window(aspace, vme_base, size);
+ if(retval)
+ return retval;
+
+ return bridge->master_set(image, enabled, vme_base, size, aspace,
+ cycle, dwidth);
+}
+EXPORT_SYMBOL(vme_master_set);
+
+int vme_master_get (struct vme_resource *resource, int *enabled,
+ unsigned long long *vme_base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_master_resource *image;
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_master_resource, list);
+
+ if (bridge->master_get == NULL) {
+ printk("vme_master_set not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->master_get(image, enabled, vme_base, size, aspace,
+ cycle, dwidth);
+}
+EXPORT_SYMBOL(vme_master_get);
+
+/*
+ * Read data out of VME space into a buffer.
+ */
+ssize_t vme_master_read (struct vme_resource *resource, void *buf, size_t count,
+ loff_t offset)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_master_resource *image;
+ size_t length;
+
+ if (bridge->master_read == NULL) {
+ printk("Reading from resource not supported\n");
+ return -EINVAL;
+ }
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_master_resource, list);
+
+ length = vme_get_size(resource);
+
+ if (offset > length) {
+ printk("Invalid Offset\n");
+ return -EFAULT;
+ }
+
+ if ((offset + count) > length)
+ count = length - offset;
+
+ return bridge->master_read(image, buf, count, offset);
+
+}
+EXPORT_SYMBOL(vme_master_read);
+
+/*
+ * Write data out to VME space from a buffer.
+ */
+ssize_t vme_master_write (struct vme_resource *resource, void *buf,
+ size_t count, loff_t offset)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_master_resource *image;
+ size_t length;
+
+ if (bridge->master_write == NULL) {
+ printk("Writing to resource not supported\n");
+ return -EINVAL;
+ }
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_master_resource, list);
+
+ length = vme_get_size(resource);
+
+ if (offset > length) {
+ printk("Invalid Offset\n");
+ return -EFAULT;
+ }
+
+ if ((offset + count) > length)
+ count = length - offset;
+
+ return bridge->master_write(image, buf, count, offset);
+}
+EXPORT_SYMBOL(vme_master_write);
+
+/*
+ * Perform RMW cycle to provided location.
+ */
+unsigned int vme_master_rmw (struct vme_resource *resource, unsigned int mask,
+ unsigned int compare, unsigned int swap, loff_t offset)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_master_resource *image;
+
+ if (bridge->master_rmw == NULL) {
+ printk("Writing to resource not supported\n");
+ return -EINVAL;
+ }
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return -EINVAL;
+ }
+
+ image = list_entry(resource->entry, struct vme_master_resource, list);
+
+ return bridge->master_rmw(image, mask, compare, swap, offset);
+}
+EXPORT_SYMBOL(vme_master_rmw);
+
+void vme_master_free(struct vme_resource *resource)
+{
+ struct vme_master_resource *master_image;
+
+ if (resource->type != VME_MASTER) {
+ printk("Not a master resource\n");
+ return;
+ }
+
+ master_image = list_entry(resource->entry, struct vme_master_resource,
+ list);
+ if (master_image == NULL) {
+ printk("Can't find master resource\n");
+ return;
+ }
+
+ /* Unlock image */
+ spin_lock(&(master_image->lock));
+ if (master_image->locked == 0)
+ printk(KERN_ERR "Image is already free\n");
+
+ master_image->locked = 0;
+ spin_unlock(&(master_image->lock));
+
+ /* Free up resource memory */
+ kfree(resource);
+}
+EXPORT_SYMBOL(vme_master_free);
+
+/*
+ * Request a DMA controller with specific attributes, return some unique
+ * identifier.
+ */
+struct vme_resource *vme_request_dma(struct device *dev)
+{
+ struct vme_bridge *bridge;
+ struct list_head *dma_pos = NULL;
+ struct vme_dma_resource *allocated_ctrlr = NULL;
+ struct vme_dma_resource *dma_ctrlr = NULL;
+ struct vme_resource *resource = NULL;
+
+ /* XXX Not checking resource attributes */
+ printk(KERN_ERR "No VME resource Attribute tests done\n");
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ goto err_bus;
+ }
+
+ /* Loop through DMA resources */
+ list_for_each(dma_pos, &(bridge->dma_resources)) {
+ dma_ctrlr = list_entry(dma_pos,
+ struct vme_dma_resource, list);
+
+ if (dma_ctrlr == NULL) {
+ printk("Registered NULL DMA resource\n");
+ continue;
+ }
+
+ /* Find an unlocked controller */
+ mutex_lock(&(dma_ctrlr->mtx));
+ if(dma_ctrlr->locked == 0) {
+ dma_ctrlr->locked = 1;
+ mutex_unlock(&(dma_ctrlr->mtx));
+ allocated_ctrlr = dma_ctrlr;
+ break;
+ }
+ mutex_unlock(&(dma_ctrlr->mtx));
+ }
+
+ /* Check to see if we found a resource */
+ if (allocated_ctrlr == NULL)
+ goto err_ctrlr;
+
+ resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+ if (resource == NULL) {
+ printk(KERN_WARNING "Unable to allocate resource structure\n");
+ goto err_alloc;
+ }
+ resource->type = VME_DMA;
+ resource->entry = &(allocated_ctrlr->list);
+
+ return resource;
+
+err_alloc:
+ /* Unlock image */
+ mutex_lock(&(dma_ctrlr->mtx));
+ dma_ctrlr->locked = 0;
+ mutex_unlock(&(dma_ctrlr->mtx));
+err_ctrlr:
+err_bus:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_request_dma);
+
+/*
+ * Start new list
+ */
+struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
+{
+ struct vme_dma_resource *ctrlr;
+ struct vme_dma_list *dma_list;
+
+ if (resource->type != VME_DMA) {
+ printk("Not a DMA resource\n");
+ return NULL;
+ }
+
+ ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
+
+ dma_list = (struct vme_dma_list *)kmalloc(
+ sizeof(struct vme_dma_list), GFP_KERNEL);
+ if(dma_list == NULL) {
+ printk("Unable to allocate memory for new dma list\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(&(dma_list->entries));
+ dma_list->parent = ctrlr;
+ mutex_init(&(dma_list->mtx));
+
+ return dma_list;
+}
+EXPORT_SYMBOL(vme_new_dma_list);
+
+/*
+ * Create "Pattern" type attributes
+ */
+struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
+ vme_pattern_t type)
+{
+ struct vme_dma_attr *attributes;
+ struct vme_dma_pattern *pattern_attr;
+
+ attributes = (struct vme_dma_attr *)kmalloc(
+ sizeof(struct vme_dma_attr), GFP_KERNEL);
+ if(attributes == NULL) {
+ printk("Unable to allocate memory for attributes structure\n");
+ goto err_attr;
+ }
+
+ pattern_attr = (struct vme_dma_pattern *)kmalloc(
+ sizeof(struct vme_dma_pattern), GFP_KERNEL);
+ if(pattern_attr == NULL) {
+ printk("Unable to allocate memory for pattern attributes\n");
+ goto err_pat;
+ }
+
+ attributes->type = VME_DMA_PATTERN;
+ attributes->private = (void *)pattern_attr;
+
+ pattern_attr->pattern = pattern;
+ pattern_attr->type = type;
+
+ return attributes;
+
+ kfree(pattern_attr);
+err_pat:
+ kfree(attributes);
+err_attr:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_dma_pattern_attribute);
+
+/*
+ * Create "PCI" type attributes
+ */
+struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
+{
+ struct vme_dma_attr *attributes;
+ struct vme_dma_pci *pci_attr;
+
+ /* XXX Run some sanity checks here */
+
+ attributes = (struct vme_dma_attr *)kmalloc(
+ sizeof(struct vme_dma_attr), GFP_KERNEL);
+ if(attributes == NULL) {
+ printk("Unable to allocate memory for attributes structure\n");
+ goto err_attr;
+ }
+
+ pci_attr = (struct vme_dma_pci *)kmalloc(sizeof(struct vme_dma_pci),
+ GFP_KERNEL);
+ if(pci_attr == NULL) {
+ printk("Unable to allocate memory for pci attributes\n");
+ goto err_pci;
+ }
+
+
+
+ attributes->type = VME_DMA_PCI;
+ attributes->private = (void *)pci_attr;
+
+ pci_attr->address = address;
+
+ return attributes;
+
+ kfree(pci_attr);
+err_pci:
+ kfree(attributes);
+err_attr:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_dma_pci_attribute);
+
+/*
+ * Create "VME" type attributes
+ */
+struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
+{
+ struct vme_dma_attr *attributes;
+ struct vme_dma_vme *vme_attr;
+
+ /* XXX Run some sanity checks here */
+
+ attributes = (struct vme_dma_attr *)kmalloc(
+ sizeof(struct vme_dma_attr), GFP_KERNEL);
+ if(attributes == NULL) {
+ printk("Unable to allocate memory for attributes structure\n");
+ goto err_attr;
+ }
+
+ vme_attr = (struct vme_dma_vme *)kmalloc(sizeof(struct vme_dma_vme),
+ GFP_KERNEL);
+ if(vme_attr == NULL) {
+ printk("Unable to allocate memory for vme attributes\n");
+ goto err_vme;
+ }
+
+ attributes->type = VME_DMA_VME;
+ attributes->private = (void *)vme_attr;
+
+ vme_attr->address = address;
+ vme_attr->aspace = aspace;
+ vme_attr->cycle = cycle;
+ vme_attr->dwidth = dwidth;
+
+ return attributes;
+
+ kfree(vme_attr);
+err_vme:
+ kfree(attributes);
+err_attr:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_dma_vme_attribute);
+
+/*
+ * Free attribute
+ */
+void vme_dma_free_attribute(struct vme_dma_attr *attributes)
+{
+ kfree(attributes->private);
+ kfree(attributes);
+}
+EXPORT_SYMBOL(vme_dma_free_attribute);
+
+int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
+ struct vme_dma_attr *dest, size_t count)
+{
+ struct vme_bridge *bridge = list->parent->parent;
+ int retval;
+
+ if (bridge->dma_list_add == NULL) {
+ printk("Link List DMA generation not supported\n");
+ return -EINVAL;
+ }
+
+ if (mutex_trylock(&(list->mtx))) {
+ printk("Link List already submitted\n");
+ return -EINVAL;
+ }
+
+ retval = bridge->dma_list_add(list, src, dest, count);
+
+ mutex_unlock(&(list->mtx));
+
+ return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_add);
+
+int vme_dma_list_exec(struct vme_dma_list *list)
+{
+ struct vme_bridge *bridge = list->parent->parent;
+ int retval;
+
+ if (bridge->dma_list_exec == NULL) {
+ printk("Link List DMA execution not supported\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&(list->mtx));
+
+ retval = bridge->dma_list_exec(list);
+
+ mutex_unlock(&(list->mtx));
+
+ return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_exec);
+
+int vme_dma_list_free(struct vme_dma_list *list)
+{
+ struct vme_bridge *bridge = list->parent->parent;
+ int retval;
+
+ if (bridge->dma_list_empty == NULL) {
+ printk("Emptying of Link Lists not supported\n");
+ return -EINVAL;
+ }
+
+ if (mutex_trylock(&(list->mtx))) {
+ printk("Link List in use\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Empty out all of the entries from the dma list. We need to go to the
+ * low level driver as dma entries are driver specific.
+ */
+ retval = bridge->dma_list_empty(list);
+ if (retval) {
+ printk("Unable to empty link-list entries\n");
+ mutex_unlock(&(list->mtx));
+ return retval;
+ }
+ mutex_unlock(&(list->mtx));
+ kfree(list);
+
+ return retval;
+}
+EXPORT_SYMBOL(vme_dma_list_free);
+
+int vme_dma_free(struct vme_resource *resource)
+{
+ struct vme_dma_resource *ctrlr;
+
+ if (resource->type != VME_DMA) {
+ printk("Not a DMA resource\n");
+ return -EINVAL;
+ }
+
+ ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
+
+ if (mutex_trylock(&(ctrlr->mtx))) {
+ printk("Resource busy, can't free\n");
+ return -EBUSY;
+ }
+
+ if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) {
+ printk("Resource still processing transfers\n");
+ mutex_unlock(&(ctrlr->mtx));
+ return -EBUSY;
+ }
+
+ ctrlr->locked = 0;
+
+ mutex_unlock(&(ctrlr->mtx));
+
+ return 0;
+}
+EXPORT_SYMBOL(vme_dma_free);
+
+int vme_request_irq(struct device *dev, int level, int statid,
+ void (*callback)(int level, int vector, void *priv_data),
+ void *priv_data)
+{
+ struct vme_bridge *bridge;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ return -EINVAL;
+ }
+
+ if((level < 1) || (level > 7)) {
+ printk(KERN_WARNING "Invalid interrupt level\n");
+ return -EINVAL;
+ }
+
+ if (bridge->request_irq == NULL) {
+ printk("Registering interrupts not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->request_irq(level, statid, callback, priv_data);
+}
+EXPORT_SYMBOL(vme_request_irq);
+
+void vme_free_irq(struct device *dev, int level, int statid)
+{
+ struct vme_bridge *bridge;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ return;
+ }
+
+ if((level < 1) || (level > 7)) {
+ printk(KERN_WARNING "Invalid interrupt level\n");
+ return;
+ }
+
+ if (bridge->free_irq == NULL) {
+ printk("Freeing interrupts not supported\n");
+ return;
+ }
+
+ bridge->free_irq(level, statid);
+}
+EXPORT_SYMBOL(vme_free_irq);
+
+int vme_generate_irq(struct device *dev, int level, int statid)
+{
+ struct vme_bridge *bridge;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ return -EINVAL;
+ }
+
+ if((level < 1) || (level > 7)) {
+ printk(KERN_WARNING "Invalid interrupt level\n");
+ return -EINVAL;
+ }
+
+ if (bridge->generate_irq == NULL) {
+ printk("Interrupt generation not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->generate_irq(level, statid);
+}
+EXPORT_SYMBOL(vme_generate_irq);
+
+/*
+ * Request the location monitor, return resource or NULL
+ */
+struct vme_resource *vme_lm_request(struct device *dev)
+{
+ struct vme_bridge *bridge;
+ struct list_head *lm_pos = NULL;
+ struct vme_lm_resource *allocated_lm = NULL;
+ struct vme_lm_resource *lm = NULL;
+ struct vme_resource *resource = NULL;
+
+ bridge = dev_to_bridge(dev);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ goto err_bus;
+ }
+
+ /* Loop through DMA resources */
+ list_for_each(lm_pos, &(bridge->lm_resources)) {
+ lm = list_entry(lm_pos,
+ struct vme_lm_resource, list);
+
+ if (lm == NULL) {
+ printk(KERN_ERR "Registered NULL Location Monitor "
+ "resource\n");
+ continue;
+ }
+
+ /* Find an unlocked controller */
+ mutex_lock(&(lm->mtx));
+ if (lm->locked == 0) {
+ lm->locked = 1;
+ mutex_unlock(&(lm->mtx));
+ allocated_lm = lm;
+ break;
+ }
+ mutex_unlock(&(lm->mtx));
+ }
+
+ /* Check to see if we found a resource */
+ if (allocated_lm == NULL)
+ goto err_lm;
+
+ resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+ if (resource == NULL) {
+ printk(KERN_ERR "Unable to allocate resource structure\n");
+ goto err_alloc;
+ }
+ resource->type = VME_LM;
+ resource->entry = &(allocated_lm->list);
+
+ return resource;
+
+err_alloc:
+ /* Unlock image */
+ mutex_lock(&(lm->mtx));
+ lm->locked = 0;
+ mutex_unlock(&(lm->mtx));
+err_lm:
+err_bus:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_lm_request);
+
+int vme_lm_count(struct vme_resource *resource)
+{
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ return lm->monitors;
+}
+EXPORT_SYMBOL(vme_lm_count);
+
+int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
+ vme_address_t aspace, vme_cycle_t cycle)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (bridge->lm_set == NULL) {
+ printk(KERN_ERR "vme_lm_set not supported\n");
+ return -EINVAL;
+ }
+
+ /* XXX Check parameters */
+
+ return lm->parent->lm_set(lm, lm_base, aspace, cycle);
+}
+EXPORT_SYMBOL(vme_lm_set);
+
+int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
+ vme_address_t *aspace, vme_cycle_t *cycle)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (bridge->lm_get == NULL) {
+ printk(KERN_ERR "vme_lm_get not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->lm_get(lm, lm_base, aspace, cycle);
+}
+EXPORT_SYMBOL(vme_lm_get);
+
+int vme_lm_attach(struct vme_resource *resource, int monitor,
+ void (*callback)(int))
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (bridge->lm_attach == NULL) {
+ printk(KERN_ERR "vme_lm_attach not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->lm_attach(lm, monitor, callback);
+}
+EXPORT_SYMBOL(vme_lm_attach);
+
+int vme_lm_detach(struct vme_resource *resource, int monitor)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (bridge->lm_detach == NULL) {
+ printk(KERN_ERR "vme_lm_detach not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->lm_detach(lm, monitor);
+}
+EXPORT_SYMBOL(vme_lm_detach);
+
+void vme_lm_free(struct vme_resource *resource)
+{
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (mutex_trylock(&(lm->mtx))) {
+ printk(KERN_ERR "Resource busy, can't free\n");
+ return;
+ }
+
+ /* XXX Check to see that there aren't any callbacks still attached */
+
+ lm->locked = 0;
+
+ mutex_unlock(&(lm->mtx));
+}
+EXPORT_SYMBOL(vme_lm_free);
+
+int vme_slot_get(struct device *bus)
+{
+ struct vme_bridge *bridge;
+
+ bridge = dev_to_bridge(bus);
+ if (bridge == NULL) {
+ printk(KERN_ERR "Can't find VME bus\n");
+ return -EINVAL;
+ }
+
+ if (bridge->slot_get == NULL) {
+ printk("vme_slot_get not supported\n");
+ return -EINVAL;
+ }
+
+ return bridge->slot_get();
+}
+EXPORT_SYMBOL(vme_slot_get);
+
+
+/* - Bridge Registration --------------------------------------------------- */
+
+static int vme_alloc_bus_num(void)
+{
+ int i;
+
+ mutex_lock(&vme_bus_num_mtx);
+ for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
+ if (((vme_bus_numbers >> i) & 0x1) == 0) {
+ vme_bus_numbers |= (0x1 << i);
+ break;
+ }
+ }
+ mutex_unlock(&vme_bus_num_mtx);
+
+ return i;
+}
+
+static void vme_free_bus_num(int bus)
+{
+ mutex_lock(&vme_bus_num_mtx);
+ vme_bus_numbers |= ~(0x1 << bus);
+ mutex_unlock(&vme_bus_num_mtx);
+}
+
+int vme_register_bridge (struct vme_bridge *bridge)
+{
+ struct device *dev;
+ int retval;
+ int i;
+
+ bridge->num = vme_alloc_bus_num();
+
+ /* This creates 32 vme "slot" devices. This equates to a slot for each
+ * ID available in a system conforming to the ANSI/VITA 1-1994
+ * specification.
+ */
+ for (i = 0; i < VME_SLOTS_MAX; i++) {
+ dev = &(bridge->dev[i]);
+ memset(dev, 0, sizeof(struct device));
+
+ dev->parent = bridge->parent;
+ dev->bus = &(vme_bus_type);
+ /*
+ * We save a pointer to the bridge in platform_data so that we
+ * can get to it later. We keep driver_data for use by the
+ * driver that binds against the slot
+ */
+ dev->platform_data = bridge;
+ dev_set_name(dev, "vme-%x.%x", bridge->num, i + 1);
+
+ retval = device_register(dev);
+ if(retval)
+ goto err_reg;
+ }
+
+ return retval;
+
+ i = VME_SLOTS_MAX;
+err_reg:
+ while (i > -1) {
+ dev = &(bridge->dev[i]);
+ device_unregister(dev);
+ }
+ vme_free_bus_num(bridge->num);
+ return retval;
+}
+EXPORT_SYMBOL(vme_register_bridge);
+
+void vme_unregister_bridge (struct vme_bridge *bridge)
+{
+ int i;
+ struct device *dev;
+
+
+ for (i = 0; i < VME_SLOTS_MAX; i++) {
+ dev = &(bridge->dev[i]);
+ device_unregister(dev);
+ }
+ vme_free_bus_num(bridge->num);
+}
+EXPORT_SYMBOL(vme_unregister_bridge);
+
+
+/* - Driver Registration --------------------------------------------------- */
+
+int vme_register_driver (struct vme_driver *drv)
+{
+ drv->driver.name = drv->name;
+ drv->driver.bus = &vme_bus_type;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(vme_register_driver);
+
+void vme_unregister_driver (struct vme_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(vme_unregister_driver);
+
+/* - Bus Registration ------------------------------------------------------ */
+
+int vme_calc_slot(struct device *dev)
+{
+ struct vme_bridge *bridge;
+ int num;
+
+ bridge = dev_to_bridge(dev);
+
+ /* Determine slot number */
+ num = 0;
+ while(num < VME_SLOTS_MAX) {
+ if(&(bridge->dev[num]) == dev) {
+ break;
+ }
+ num++;
+ }
+ if (num == VME_SLOTS_MAX) {
+ dev_err(dev, "Failed to identify slot\n");
+ num = 0;
+ goto err_dev;
+ }
+ num++;
+
+err_dev:
+ return num;
+}
+
+static struct vme_driver *dev_to_vme_driver(struct device *dev)
+{
+ if(dev->driver == NULL)
+ printk("Bugger dev->driver is NULL\n");
+
+ return container_of(dev->driver, struct vme_driver, driver);
+}
+
+static int vme_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct vme_bridge *bridge;
+ struct vme_driver *driver;
+ int i, num;
+
+ bridge = dev_to_bridge(dev);
+ driver = container_of(drv, struct vme_driver, driver);
+
+ num = vme_calc_slot(dev);
+ if (!num)
+ goto err_dev;
+
+ if (driver->bind_table == NULL) {
+ dev_err(dev, "Bind table NULL\n");
+ goto err_table;
+ }
+
+ i = 0;
+ while((driver->bind_table[i].bus != 0) ||
+ (driver->bind_table[i].slot != 0)) {
+
+ if (bridge->num == driver->bind_table[i].bus) {
+ if (num == driver->bind_table[i].slot)
+ return 1;
+
+ if (driver->bind_table[i].slot == VME_SLOT_ALL)
+ return 1;
+
+ if ((driver->bind_table[i].slot == VME_SLOT_CURRENT) &&
+ (num == vme_slot_get(dev)))
+ return 1;
+ }
+ i++;
+ }
+
+err_dev:
+err_table:
+ return 0;
+}
+
+static int vme_bus_probe(struct device *dev)
+{
+ struct vme_bridge *bridge;
+ struct vme_driver *driver;
+ int retval = -ENODEV;
+
+ driver = dev_to_vme_driver(dev);
+ bridge = dev_to_bridge(dev);
+
+ if(driver->probe != NULL) {
+ retval = driver->probe(dev, bridge->num, vme_calc_slot(dev));
+ }
+
+ return retval;
+}
+
+static int vme_bus_remove(struct device *dev)
+{
+ struct vme_bridge *bridge;
+ struct vme_driver *driver;
+ int retval = -ENODEV;
+
+ driver = dev_to_vme_driver(dev);
+ bridge = dev_to_bridge(dev);
+
+ if(driver->remove != NULL) {
+ retval = driver->remove(dev, bridge->num, vme_calc_slot(dev));
+ }
+
+ return retval;
+}
+
+struct bus_type vme_bus_type = {
+ .name = "vme",
+ .match = vme_bus_match,
+ .probe = vme_bus_probe,
+ .remove = vme_bus_remove,
+};
+EXPORT_SYMBOL(vme_bus_type);
+
+static int __init vme_init (void)
+{
+ return bus_register(&vme_bus_type);
+}
+
+static void __exit vme_exit (void)
+{
+ bus_unregister(&vme_bus_type);
+}
+
+MODULE_DESCRIPTION("VME bridge driver framework");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
+MODULE_LICENSE("GPL");
+
+module_init(vme_init);
+module_exit(vme_exit);
diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h
new file mode 100644
index 000000000000..6206e91d1992
--- /dev/null
+++ b/drivers/staging/vme/vme.h
@@ -0,0 +1,161 @@
+#ifndef _VME_H_
+#define _VME_H_
+
+/* Resource Type */
+enum vme_resource_type {
+ VME_MASTER,
+ VME_SLAVE,
+ VME_DMA,
+ VME_LM
+};
+
+/* VME Address Spaces */
+typedef u32 vme_address_t;
+#define VME_A16 0x1
+#define VME_A24 0x2
+#define VME_A32 0x4
+#define VME_A64 0x8
+#define VME_CRCSR 0x10
+#define VME_USER1 0x20
+#define VME_USER2 0x40
+#define VME_USER3 0x80
+#define VME_USER4 0x100
+
+#define VME_A16_MAX 0x10000ULL
+#define VME_A24_MAX 0x1000000ULL
+#define VME_A32_MAX 0x100000000ULL
+#define VME_A64_MAX 0x10000000000000000ULL
+#define VME_CRCSR_MAX 0x1000000ULL
+
+
+/* VME Cycle Types */
+typedef u32 vme_cycle_t;
+#define VME_SCT 0x1
+#define VME_BLT 0x2
+#define VME_MBLT 0x4
+#define VME_2eVME 0x8
+#define VME_2eSST 0x10
+#define VME_2eSSTB 0x20
+
+#define VME_2eSST160 0x100
+#define VME_2eSST267 0x200
+#define VME_2eSST320 0x400
+
+#define VME_SUPER 0x1000
+#define VME_USER 0x2000
+#define VME_PROG 0x4000
+#define VME_DATA 0x8000
+
+/* VME Data Widths */
+typedef u32 vme_width_t;
+#define VME_D8 0x1
+#define VME_D16 0x2
+#define VME_D32 0x4
+#define VME_D64 0x8
+
+/* Arbitration Scheduling Modes */
+typedef u32 vme_arbitration_t;
+#define VME_R_ROBIN_MODE 0x1
+#define VME_PRIORITY_MODE 0x2
+
+typedef u32 vme_dma_t;
+#define VME_DMA_PATTERN (1<<0)
+#define VME_DMA_PCI (1<<1)
+#define VME_DMA_VME (1<<2)
+
+typedef u32 vme_pattern_t;
+#define VME_DMA_PATTERN_BYTE (1<<0)
+#define VME_DMA_PATTERN_WORD (1<<1)
+#define VME_DMA_PATTERN_INCREMENT (1<<2)
+
+struct vme_dma_attr {
+ vme_dma_t type;
+ void *private;
+};
+
+struct vme_resource {
+ enum vme_resource_type type;
+ struct list_head *entry;
+};
+
+extern struct bus_type vme_bus_type;
+
+#define VME_SLOT_CURRENT -1
+#define VME_SLOT_ALL -2
+
+struct vme_device_id {
+ int bus;
+ int slot;
+};
+
+struct vme_driver {
+ struct list_head node;
+ char *name;
+ const struct vme_device_id *bind_table;
+ int (*probe) (struct device *, int, int);
+ int (*remove) (struct device *, int, int);
+ void (*shutdown) (void);
+ struct device_driver driver;
+};
+
+void * vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *);
+void vme_free_consistent(struct vme_resource *, size_t, void *,
+ dma_addr_t);
+
+size_t vme_get_size(struct vme_resource *);
+
+struct vme_resource * vme_slave_request(struct device *, vme_address_t, vme_cycle_t);
+int vme_slave_set (struct vme_resource *, int, unsigned long long,
+ unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t);
+int vme_slave_get (struct vme_resource *, int *, unsigned long long *,
+ unsigned long long *, dma_addr_t *, vme_address_t *, vme_cycle_t *);
+void vme_slave_free(struct vme_resource *);
+
+struct vme_resource * vme_master_request(struct device *, vme_address_t, vme_cycle_t,
+ vme_width_t);
+int vme_master_set (struct vme_resource *, int, unsigned long long,
+ unsigned long long, vme_address_t, vme_cycle_t, vme_width_t);
+int vme_master_get (struct vme_resource *, int *, unsigned long long *,
+ unsigned long long *, vme_address_t *, vme_cycle_t *, vme_width_t *);
+ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t);
+ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t);
+unsigned int vme_master_rmw (struct vme_resource *, unsigned int, unsigned int,
+ unsigned int, loff_t);
+void vme_master_free(struct vme_resource *);
+
+struct vme_resource *vme_request_dma(struct device *);
+struct vme_dma_list *vme_new_dma_list(struct vme_resource *);
+struct vme_dma_attr *vme_dma_pattern_attribute(u32, vme_pattern_t);
+struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t);
+struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, vme_address_t,
+ vme_cycle_t, vme_width_t);
+void vme_dma_free_attribute(struct vme_dma_attr *);
+int vme_dma_list_add(struct vme_dma_list *, struct vme_dma_attr *,
+ struct vme_dma_attr *, size_t);
+int vme_dma_list_exec(struct vme_dma_list *);
+int vme_dma_list_free(struct vme_dma_list *);
+int vme_dma_free(struct vme_resource *);
+
+int vme_request_irq(struct device *, int, int,
+ void (*callback)(int, int, void *), void *);
+void vme_free_irq(struct device *, int, int);
+int vme_generate_irq(struct device *, int, int);
+
+struct vme_resource * vme_lm_request(struct device *);
+int vme_lm_count(struct vme_resource *);
+int vme_lm_set(struct vme_resource *, unsigned long long, vme_address_t,
+ vme_cycle_t);
+int vme_lm_get(struct vme_resource *, unsigned long long *, vme_address_t *,
+ vme_cycle_t *);
+int vme_lm_attach(struct vme_resource *, int, void (*callback)(int));
+int vme_lm_detach(struct vme_resource *, int);
+void vme_lm_free(struct vme_resource *);
+
+int vme_slot_get(struct device *);
+
+int vme_register_driver (struct vme_driver *);
+void vme_unregister_driver (struct vme_driver *);
+
+
+#endif /* _VME_H_ */
+
diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt
new file mode 100644
index 000000000000..591eba5c9036
--- /dev/null
+++ b/drivers/staging/vme/vme_api.txt
@@ -0,0 +1,372 @@
+ VME Device Driver API
+ =====================
+
+Driver registration
+===================
+
+As with other subsystems within the Linux kernel, VME device drivers register
+with the VME subsystem, typically called from the devices init routine. This is
+achieved via a call to the follwoing function:
+
+ int vme_register_driver (struct vme_driver *driver);
+
+If driver registration is successful this function returns zero, if an error
+occurred a negative error code will be returned.
+
+A pointer to a structure of type 'vme_driver' must be provided to the
+registration function. The structure is as follows:
+
+ struct vme_driver {
+ struct list_head node;
+ char *name;
+ const struct vme_device_id *bind_table;
+ int (*probe) (struct device *, int, int);
+ int (*remove) (struct device *, int, int);
+ void (*shutdown) (void);
+ struct device_driver driver;
+ };
+
+At the minimum, the '.name', '.probe' and '.bind_table' elements of this
+structure should be correctly set. The '.name' element is a pointer to a string
+holding the device driver's name. The '.probe' element should contain a pointer
+to the probe routine.
+
+The arguments of the probe routine are as follows:
+
+ probe(struct device *dev, int bus, int slot);
+
+The '.bind_table' is a pointer to an array of type 'vme_device_id':
+
+ struct vme_device_id {
+ int bus;
+ int slot;
+ };
+
+Each structure in this array should provide a bus and slot number where the core
+should probe, using the driver's probe routine, for a device on the specified
+VME bus.
+
+The VME subsystem supports a single VME driver per 'slot'. There are considered
+to be 32 slots per bus, one for each slot-ID as defined in the ANSI/VITA 1-1994
+specification and are analogious to the physical slots on the VME backplane.
+
+A function is also provided to unregister the driver from the VME core and is
+usually called from the device driver's exit routine:
+
+ void vme_unregister_driver (struct vme_driver *driver);
+
+
+Resource management
+===================
+
+Once a driver has registered with the VME core the provided probe routine will
+be called for each of the bus/slot combination that becomes valid as VME buses
+are themselves registered. The probe routine is passed a pointer to the devices
+device structure. This pointer should be saved, it will be required for
+requesting VME resources.
+
+The driver can request ownership of one or more master windows, slave windows
+and/or dma channels. Rather than allowing the device driver to request a
+specific window or DMA channel (which may be used by a different driver) this
+driver allows a resource to be assigned based on the required attributes of the
+driver in question:
+
+ struct vme_resource * vme_master_request(struct device *dev,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t width);
+
+ struct vme_resource * vme_slave_request(struct device *dev,
+ vme_address_t aspace, vme_cycle_t cycle);
+
+ struct vme_resource *vme_request_dma(struct device *dev);
+
+For slave windows these attributes are split into those of type 'vme_address_t'
+and 'vme_cycle_t'. Master windows add a further set of attributes 'vme_cycle_t'.
+These attributes are defined as bitmasks and as such any combination of the
+attributes can be requested for a single window, the core will assign a window
+that meets the requirements, returning a pointer of type vme_resource that
+should be used to identify the allocated resource when it is used. If an
+unallocated window fitting the requirements can not be found a NULL pointer will
+be returned.
+
+Functions are also provided to free window allocations once they are no longer
+required. These functions should be passed the pointer to the resource provided
+during resource allocation:
+
+ void vme_master_free(struct vme_resource *res);
+
+ void vme_slave_free(struct vme_resource *res);
+
+ void vme_dma_free(struct vme_resource *res);
+
+
+Master windows
+==============
+
+Master windows provide access from the local processor[s] out onto the VME bus.
+The number of windows available and the available access modes is dependant on
+the underlying chipset. A window must be configured before it can be used.
+
+
+Master window configuration
+---------------------------
+
+Once a master window has been assigned the following functions can be used to
+configure it and retrieve the current settings:
+
+ int vme_master_set (struct vme_resource *res, int enabled,
+ unsigned long long base, unsigned long long size,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t width);
+
+ int vme_master_get (struct vme_resource *res, int *enabled,
+ unsigned long long *base, unsigned long long *size,
+ vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *width);
+
+The address spaces, transfer widths and cycle types are the same as described
+under resource management, however some of the options are mutually exclusive.
+For example, only one address space may be specified.
+
+These functions return 0 on success or an error code should the call fail.
+
+
+Master window access
+--------------------
+
+The following functions can be used to read from and write to configured master
+windows. These functions return the number of bytes copied:
+
+ ssize_t vme_master_read(struct vme_resource *res, void *buf,
+ size_t count, loff_t offset);
+
+ ssize_t vme_master_write(struct vme_resource *res, void *buf,
+ size_t count, loff_t offset);
+
+In addition to simple reads and writes, a function is provided to do a
+read-modify-write transaction. This function returns the original value of the
+VME bus location :
+
+ unsigned int vme_master_rmw (struct vme_resource *res,
+ unsigned int mask, unsigned int compare, unsigned int swap,
+ loff_t offset);
+
+This functions by reading the offset, applying the mask. If the bits selected in
+the mask match with the values of the corresponding bits in the compare field,
+the value of swap is written the specified offset.
+
+
+Slave windows
+=============
+
+Slave windows provide devices on the VME bus access into mapped portions of the
+local memory. The number of windows available and the access modes that can be
+used is dependant on the underlying chipset. A window must be configured before
+it can be used.
+
+
+Slave window configuration
+--------------------------
+
+Once a slave window has been assigned the following functions can be used to
+configure it and retrieve the current settings:
+
+ int vme_slave_set (struct vme_resource *res, int enabled,
+ unsigned long long base, unsigned long long size,
+ dma_addr_t mem, vme_address_t aspace, vme_cycle_t cycle);
+
+ int vme_slave_get (struct vme_resource *res, int *enabled,
+ unsigned long long *base, unsigned long long *size,
+ dma_addr_t *mem, vme_address_t *aspace, vme_cycle_t *cycle);
+
+The address spaces, transfer widths and cycle types are the same as described
+under resource management, however some of the options are mutually exclusive.
+For example, only one address space may be specified.
+
+These functions return 0 on success or an error code should the call fail.
+
+
+Slave window buffer allocation
+------------------------------
+
+Functions are provided to allow the user to allocate and free a contiguous
+buffers which will be accessible by the VME bridge. These functions do not have
+to be used, other methods can be used to allocate a buffer, though care must be
+taken to ensure that they are contiguous and accessible by the VME bridge:
+
+ void * vme_alloc_consistent(struct vme_resource *res, size_t size,
+ dma_addr_t *mem);
+
+ void vme_free_consistent(struct vme_resource *res, size_t size,
+ void *virt, dma_addr_t mem);
+
+
+Slave window access
+-------------------
+
+Slave windows map local memory onto the VME bus, the standard methods for
+accessing memory should be used.
+
+
+DMA channels
+============
+
+The VME DMA transfer provides the ability to run link-list DMA transfers. The
+API introduces the concept of DMA lists. Each DMA list is a link-list which can
+be passed to a DMA controller. Multiple lists can be created, extended,
+executed, reused and destroyed.
+
+
+List Management
+---------------
+
+The following functions are provided to create and destroy DMA lists. Execution
+of a list will not automatically destroy the list, thus enabling a list to be
+reused for repetitive tasks:
+
+ struct vme_dma_list *vme_new_dma_list(struct vme_resource *res);
+
+ int vme_dma_list_free(struct vme_dma_list *list);
+
+
+List Population
+---------------
+
+An item can be added to a list using the following function ( the source and
+destination attributes need to be created before calling this function, this is
+covered under "Transfer Attributes"):
+
+ int vme_dma_list_add(struct vme_dma_list *list,
+ struct vme_dma_attr *src, struct vme_dma_attr *dest,
+ size_t count);
+
+
+Transfer Attributes
+-------------------
+
+The attributes for the source and destination are handled separately from adding
+an item to a list. This is due to the diverse attributes required for each type
+of source and destination. There are functions to create attributes for PCI, VME
+and pattern sources and destinations (where appropriate):
+
+Pattern source:
+
+ struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
+ vme_pattern_t type);
+
+PCI source or destination:
+
+ struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t mem);
+
+VME source or destination:
+
+ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long base,
+ vme_address_t aspace, vme_cycle_t cycle, vme_width_t width);
+
+The following function should be used to free an attribute:
+
+ void vme_dma_free_attribute(struct vme_dma_attr *attr);
+
+
+List Execution
+--------------
+
+The following function queues a list for execution. The function will return
+once the list has been executed:
+
+ int vme_dma_list_exec(struct vme_dma_list *list);
+
+
+Interrupts
+==========
+
+The VME API provides functions to attach and detach callbacks to specific VME
+level and status ID combinations and for the generation of VME interrupts with
+specific VME level and status IDs.
+
+
+Attaching Interrupt Handlers
+----------------------------
+
+The following functions can be used to attach and free a specific VME level and
+status ID combination. Any given combination can only be assigned a single
+callback function. A void pointer parameter is provided, the value of which is
+passed to the callback function, the use of this pointer is user undefined:
+
+ int vme_request_irq(struct device *dev, int level, int statid,
+ void (*callback)(int, int, void *), void *priv);
+
+ void vme_free_irq(struct device *dev, int level, int statid);
+
+The callback parameters are as follows. Care must be taken in writing a callback
+function, callback functions run in interrupt context:
+
+ void callback(int level, int statid, void *priv);
+
+
+Interrupt Generation
+--------------------
+
+The following function can be used to generate a VME interrupt at a given VME
+level and VME status ID:
+
+ int vme_generate_irq(struct device *dev, int level, int statid);
+
+
+Location monitors
+=================
+
+The VME API provides the following functionality to configure the location
+monitor.
+
+
+Location Monitor Management
+---------------------------
+
+The following functions are provided to request the use of a block of location
+monitors and to free them after they are no longer required:
+
+ struct vme_resource * vme_lm_request(struct device *dev);
+
+ void vme_lm_free(struct vme_resource * res);
+
+Each block may provide a number of location monitors, monitoring adjacent
+locations. The following function can be used to determine how many locations
+are provided:
+
+ int vme_lm_count(struct vme_resource * res);
+
+
+Location Monitor Configuration
+------------------------------
+
+Once a bank of location monitors has been allocated, the following functions
+are provided to configure the location and mode of the location monitor:
+
+ int vme_lm_set(struct vme_resource *res, unsigned long long base,
+ vme_address_t aspace, vme_cycle_t cycle);
+
+ int vme_lm_get(struct vme_resource *res, unsigned long long *base,
+ vme_address_t *aspace, vme_cycle_t *cycle);
+
+
+Location Monitor Use
+--------------------
+
+The following functions allow a callback to be attached and detached from each
+location monitor location. Each location monitor can monitor a number of
+adjacent locations:
+
+ int vme_lm_attach(struct vme_resource *res, int num,
+ void (*callback)(int));
+
+ int vme_lm_detach(struct vme_resource *res, int num);
+
+The callback function is declared as follows.
+
+ void callback(int num);
+
+
+Slot Detection
+==============
+
+This function returns the slot ID of the provided bridge.
+
+ int vme_slot_get(struct device *dev);
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h
new file mode 100644
index 000000000000..e43cc19103b3
--- /dev/null
+++ b/drivers/staging/vme/vme_bridge.h
@@ -0,0 +1,261 @@
+#ifndef _VME_BRIDGE_H_
+#define _VME_BRIDGE_H_
+
+#define VME_CRCSR_BUF_SIZE (508*1024)
+#define VME_SLOTS_MAX 32
+/*
+ * Resource structures
+ */
+struct vme_master_resource {
+ struct list_head list;
+ struct vme_bridge *parent;
+ /*
+ * We are likely to need to access the VME bus in interrupt context, so
+ * protect master routines with a spinlock rather than a mutex.
+ */
+ spinlock_t lock;
+ int locked;
+ int number;
+ vme_address_t address_attr;
+ vme_cycle_t cycle_attr;
+ vme_width_t width_attr;
+ struct resource pci_resource; /* XXX Rename to be bus agnostic */
+ void *kern_base;
+};
+
+struct vme_slave_resource {
+ struct list_head list;
+ struct vme_bridge *parent;
+ struct mutex mtx;
+ int locked;
+ int number;
+ vme_address_t address_attr;
+ vme_cycle_t cycle_attr;
+};
+
+struct vme_dma_pattern {
+ u32 pattern;
+ vme_pattern_t type;
+};
+
+struct vme_dma_pci {
+ dma_addr_t address;
+};
+
+struct vme_dma_vme {
+ unsigned long long address;
+ vme_address_t aspace;
+ vme_cycle_t cycle;
+ vme_width_t dwidth;
+};
+
+struct vme_dma_list {
+ struct list_head list;
+ struct vme_dma_resource *parent;
+ struct list_head entries;
+ struct mutex mtx;
+};
+
+struct vme_dma_resource {
+ struct list_head list;
+ struct vme_bridge *parent;
+ struct mutex mtx;
+ int locked;
+ int number;
+ struct list_head pending;
+ struct list_head running;
+};
+
+struct vme_lm_resource {
+ struct list_head list;
+ struct vme_bridge *parent;
+ struct mutex mtx;
+ int locked;
+ int number;
+ int monitors;
+};
+
+struct vme_bus_error {
+ struct list_head list;
+ unsigned long long address;
+ u32 attributes;
+};
+
+struct vme_callback {
+ void (*func)(int, int, void*);
+ void *priv_data;
+};
+
+struct vme_irq {
+ int count;
+ struct vme_callback callback[255];
+};
+
+/* Allow 16 characters for name (including null character) */
+#define VMENAMSIZ 16
+
+/* This structure stores all the information about one bridge
+ * The structure should be dynamically allocated by the driver and one instance
+ * of the structure should be present for each VME chip present in the system.
+ *
+ * Currently we assume that all chips are PCI-based
+ */
+struct vme_bridge {
+ char name[VMENAMSIZ];
+ int num;
+ struct list_head master_resources;
+ struct list_head slave_resources;
+ struct list_head dma_resources;
+ struct list_head lm_resources;
+
+ struct list_head vme_errors; /* List for errors generated on VME */
+
+ /* Bridge Info - XXX Move to private structure? */
+ struct device *parent; /* Generic device struct (pdev->dev for PCI) */
+ void * base; /* Base Address of device registers */
+
+ struct device dev[VME_SLOTS_MAX]; /* Device registered with
+ * device model on VME bus
+ */
+
+ /* Interrupt callbacks */
+ struct vme_irq irq[7];
+
+ /* Slave Functions */
+ int (*slave_get) (struct vme_slave_resource *, int *,
+ unsigned long long *, unsigned long long *, dma_addr_t *,
+ vme_address_t *, vme_cycle_t *);
+ int (*slave_set) (struct vme_slave_resource *, int, unsigned long long,
+ unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t);
+
+ /* Master Functions */
+ int (*master_get) (struct vme_master_resource *, int *,
+ unsigned long long *, unsigned long long *, vme_address_t *,
+ vme_cycle_t *, vme_width_t *);
+ int (*master_set) (struct vme_master_resource *, int,
+ unsigned long long, unsigned long long, vme_address_t,
+ vme_cycle_t, vme_width_t);
+ ssize_t (*master_read) (struct vme_master_resource *, void *, size_t,
+ loff_t);
+ ssize_t (*master_write) (struct vme_master_resource *, void *, size_t,
+ loff_t);
+ unsigned int (*master_rmw) (struct vme_master_resource *, unsigned int,
+ unsigned int, unsigned int, loff_t);
+
+ /* DMA Functions */
+ int (*dma_list_add) (struct vme_dma_list *, struct vme_dma_attr *,
+ struct vme_dma_attr *, size_t);
+ int (*dma_list_exec) (struct vme_dma_list *);
+ int (*dma_list_empty) (struct vme_dma_list *);
+
+ /* Interrupt Functions */
+ int (*request_irq) (int, int, void (*cback)(int, int, void*), void *);
+ void (*free_irq) (int, int);
+ int (*generate_irq) (int, int);
+
+ /* Location monitor functions */
+ int (*lm_set) (struct vme_lm_resource *, unsigned long long,
+ vme_address_t, vme_cycle_t);
+ int (*lm_get) (struct vme_lm_resource *, unsigned long long *,
+ vme_address_t *, vme_cycle_t *);
+ int (*lm_attach) (struct vme_lm_resource *, int, void (*callback)(int));
+ int (*lm_detach) (struct vme_lm_resource *, int);
+
+ /* CR/CSR space functions */
+ int (*slot_get) (void);
+ /* Use standard master read and write functions to access CR/CSR */
+
+#if 0
+ int (*set_prefetch) (void);
+ int (*get_prefetch) (void);
+ int (*set_arbiter) (void);
+ int (*get_arbiter) (void);
+ int (*set_requestor) (void);
+ int (*get_requestor) (void);
+#endif
+};
+
+int vme_register_bridge (struct vme_bridge *);
+void vme_unregister_bridge (struct vme_bridge *);
+
+#endif /* _VME_BRIDGE_H_ */
+
+#if 0
+/*
+ * VMEbus GET INFO Arg Structure
+ */
+struct vmeInfoCfg {
+ int vmeSlotNum; /* VME slot number of interest */
+ int boardResponded; /* Board responded */
+ char sysConFlag; /* System controller flag */
+ int vmeControllerID; /* Vendor/device ID of VME bridge */
+ int vmeControllerRev; /* Revision of VME bridge */
+ char osName[8]; /* Name of OS e.g. "Linux" */
+ int vmeSharedDataValid; /* Validity of data struct */
+ int vmeDriverRev; /* Revision of VME driver */
+ unsigned int vmeAddrHi[8]; /* Address on VME bus */
+ unsigned int vmeAddrLo[8]; /* Address on VME bus */
+ unsigned int vmeSize[8]; /* Size on VME bus */
+ unsigned int vmeAm[8]; /* Address modifier on VME bus */
+ int reserved; /* For future use */
+};
+typedef struct vmeInfoCfg vmeInfoCfg_t;
+
+/*
+ * VMEbus Requester Arg Structure
+ */
+struct vmeRequesterCfg {
+ int requestLevel; /* Requester Bus Request Level */
+ char fairMode; /* Requester Fairness Mode Indicator */
+ int releaseMode; /* Requester Bus Release Mode */
+ int timeonTimeoutTimer; /* Master Time-on Time-out Timer */
+ int timeoffTimeoutTimer; /* Master Time-off Time-out Timer */
+ int reserved; /* For future use */
+};
+typedef struct vmeRequesterCfg vmeRequesterCfg_t;
+
+/*
+ * VMEbus Arbiter Arg Structure
+ */
+struct vmeArbiterCfg {
+ vme_arbitration_t arbiterMode; /* Arbitration Scheduling Algorithm */
+ char arbiterTimeoutFlag; /* Arbiter Time-out Timer Indicator */
+ int globalTimeoutTimer; /* VMEbus Global Time-out Timer */
+ char noEarlyReleaseFlag; /* No Early Release on BBUSY */
+ int reserved; /* For future use */
+};
+typedef struct vmeArbiterCfg vmeArbiterCfg_t;
+
+
+/*
+ * VMEbus RMW Configuration Data
+ */
+struct vmeRmwCfg {
+ unsigned int targetAddrU; /* VME Address (Upper) to trigger RMW cycle */
+ unsigned int targetAddr; /* VME Address (Lower) to trigger RMW cycle */
+ vme_address_t addrSpace; /* VME Address Space */
+ int enableMask; /* Bit mask defining the bits of interest */
+ int compareData; /* Data to be compared with the data read */
+ int swapData; /* Data written to the VMEbus on success */
+ int maxAttempts; /* Maximum times to try */
+ int numAttempts; /* Number of attempts before success */
+ int reserved; /* For future use */
+
+};
+typedef struct vmeRmwCfg vmeRmwCfg_t;
+
+/*
+ * VMEbus Location Monitor Arg Structure
+ */
+struct vmeLmCfg {
+ unsigned int addrU; /* Location Monitor Address upper */
+ unsigned int addr; /* Location Monitor Address lower */
+ vme_address_t addrSpace; /* Address Space */
+ int userAccessType; /* User/Supervisor Access Type */
+ int dataAccessType; /* Data/Program Access Type */
+ int lmWait; /* Time to wait for access */
+ int lmEvents; /* Lm event mask */
+ int reserved; /* For future use */
+};
+typedef struct vmeLmCfg vmeLmCfg_t;
+#endif