1d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
2d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Support for the Tundra TSI148 VME-PCI Bridge Chip
3d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
466bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com>
566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
6d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
7d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Based on work by Tom Armistead and Ajit Prem
8d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Copyright 2004 Motorola Inc.
9d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
10d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * This program is free software; you can redistribute  it and/or modify it
11d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * under  the terms of  the GNU General  Public License as published by the
12d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Free Software Foundation;  either version 2 of the  License, or (at your
13d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * option) any later version.
14d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
15d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
16d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/module.h>
17d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/moduleparam.h>
18d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/mm.h>
19d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/types.h>
20d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/errno.h>
21d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/proc_fs.h>
22d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/pci.h>
23d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/poll.h>
24d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/dma-mapping.h>
25d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/interrupt.h>
26d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include <linux/spinlock.h>
276af783c8ba3418a8ffc50f1266d9b1e35a3322dbGreg Kroah-Hartman#include <linux/sched.h>
285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
297946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch#include <linux/time.h>
307946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch#include <linux/io.h>
317946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch#include <linux/uaccess.h>
32d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
33d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include "../vme.h"
34d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include "../vme_bridge.h"
35d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch#include "vme_tsi148.h"
36d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
37d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic int __init tsi148_init(void);
38d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic int tsi148_probe(struct pci_dev *, const struct pci_device_id *);
39d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void tsi148_remove(struct pci_dev *);
40d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void __exit tsi148_exit(void);
41d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
42d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
4329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch/* Module parameter */
4490ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool err_chk;
45638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welchstatic int geoid;
46d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
47584721cab2bdd26f63bfeca60c83f5e6b8eee7d0Vincent Bossierstatic const char driver_name[] = "vme_tsi148";
48d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
49270b64bb4cf27a2ad7819bad89d8c9d8a66ba1b8Namhyung Kimstatic DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = {
50d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	{ PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
51d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	{ },
52d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch};
53d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
54d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic struct pci_driver tsi148_driver = {
55d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	.name = driver_name,
56d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	.id_table = tsi148_ids,
57d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	.probe = tsi148_probe,
58d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	.remove = tsi148_remove,
59d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch};
60d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
61d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void reg_join(unsigned int high, unsigned int low,
62d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long *variable)
63d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
64d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*variable = (unsigned long long)high << 32;
65d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*variable |= (unsigned long long)low;
66d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
67d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
68d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void reg_split(unsigned long long variable, unsigned int *high,
69d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int *low)
70d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
71d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*low = (unsigned int)variable & 0xFFFFFFFF;
72d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*high = (unsigned int)(variable >> 32);
73d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
74d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
75d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
76d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Wakes up DMA queue.
77d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
7829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
7929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	int channel_mask)
80d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
81d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 serviced = 0;
82d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
83d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
84886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		wake_up(&bridge->dma_queue[0]);
85d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		serviced |= TSI148_LCSR_INTC_DMA0C;
86d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
87d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
88886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		wake_up(&bridge->dma_queue[1]);
89d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		serviced |= TSI148_LCSR_INTC_DMA1C;
90d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
91d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
92d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return serviced;
93d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
94d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
95d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
96d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Wake up location monitor queue
97d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
9829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
99d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
100d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int i;
101d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 serviced = 0;
102d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
103d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < 4; i++) {
1047946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if (stat & TSI148_LCSR_INTS_LMS[i]) {
105d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			/* We only enable interrupts if the callback is set */
10629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			bridge->lm_callback[i](i);
107d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			serviced |= TSI148_LCSR_INTC_LMC[i];
108d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
109d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
110d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
111d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return serviced;
112d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
113d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
114d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
115d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Wake up mail box queue.
116d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
117d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * XXX This functionality is not exposed up though API.
118d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
11948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welchstatic u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat)
120d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
121d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int i;
122d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 val;
123d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 serviced = 0;
12448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct tsi148_driver *bridge;
12548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
12648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
127d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
128d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < 4; i++) {
1297946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if (stat & TSI148_LCSR_INTS_MBS[i]) {
13029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			val = ioread32be(bridge->base +	TSI148_GCSR_MBOX[i]);
13148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			dev_err(tsi148_bridge->parent, "VME Mailbox %d received"
13248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch				": 0x%x\n", i, val);
133d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			serviced |= TSI148_LCSR_INTC_MBC[i];
134d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
135d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
136d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
137d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return serviced;
138d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
139d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
140d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
141d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Display error & status message when PERR (PCI) exception interrupt occurs.
142d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
14348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welchstatic u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge)
144d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
14548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct tsi148_driver *bridge;
14648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
14748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
14848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
14948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, "
15048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		"attributes: %08x\n",
15129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		ioread32be(bridge->base + TSI148_LCSR_EDPAU),
15229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		ioread32be(bridge->base + TSI148_LCSR_EDPAL),
15348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		ioread32be(bridge->base + TSI148_LCSR_EDPAT));
15448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
15548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split "
15648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		"completion reg: %08x\n",
15729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		ioread32be(bridge->base + TSI148_LCSR_EDPXA),
15848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		ioread32be(bridge->base + TSI148_LCSR_EDPXS));
159d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
16029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT);
161d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
162d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return TSI148_LCSR_INTC_PERRC;
163d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
164d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
165d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
166d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Save address and status when VME error interrupt occurs.
167d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
16829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
169d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
170d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int error_addr_high, error_addr_low;
171d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long error_addr;
172d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 error_attrib;
173d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_bus_error *error;
17429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
17529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
17629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
177d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
17829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU);
17929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL);
18029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT);
181d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
182d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(error_addr_high, error_addr_low, &error_addr);
183d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
184d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Check for exception register overflow (we have lost error data) */
1857946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (error_attrib & TSI148_LCSR_VEAT_VEOF) {
18648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow "
18748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"Occurred\n");
188d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
189d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1907946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC);
191d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (error) {
192d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		error->address = error_addr;
193d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		error->attributes = error_attrib;
194886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		list_add_tail(&error->list, &tsi148_bridge->vme_errors);
195d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	} else {
19648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Unable to alloc memory for "
19748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"VMEbus Error reporting\n");
19848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "VME Bus Error at address: "
19948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"0x%llx, attributes: %08x\n", error_addr, error_attrib);
200d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
201d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
202d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Clear Status */
20329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT);
204d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
205d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return TSI148_LCSR_INTC_VERRC;
206d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
207d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
208d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
209d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Wake up IACK queue.
210d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
21129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
212d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
213886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	wake_up(&bridge->iack_queue);
214d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
215d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return TSI148_LCSR_INTC_IACKC;
216d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
217d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
218d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
219d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Calling VME bus interrupt callback if provided.
220d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
22129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge,
22229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	u32 stat)
223d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
224d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int vec, i, serviced = 0;
22529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
22629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
22729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
228d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
229d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 7; i > 0; i--) {
230d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		if (stat & (1 << i)) {
231d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			/*
2327946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			 * Note: Even though the registers are defined as
2337946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			 * 32-bits in the spec, we only want to issue 8-bit
2347946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			 * IACK cycles on the bus, read from offset 3.
235d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			 */
23629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3);
237d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
238c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			vme_irq_handler(tsi148_bridge, i, vec);
239d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
240d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			serviced |= (1 << i);
241d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
242d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
243d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
244d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return serviced;
245d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
246d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
247d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
248d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Top level interrupt handler.  Clears appropriate interrupt status bits and
249d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * then calls appropriate sub handler(s).
250d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
25129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic irqreturn_t tsi148_irqhandler(int irq, void *ptr)
252d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
253d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 stat, enable, serviced = 0;
25429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge;
25529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
25629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
25729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_bridge = ptr;
25829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
25929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
260d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
261d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Determine which interrupts are unmasked and set */
26229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	enable = ioread32be(bridge->base + TSI148_LCSR_INTEO);
26329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	stat = ioread32be(bridge->base + TSI148_LCSR_INTS);
264d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
265d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Only look at unmasked interrupts */
266d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	stat &= enable;
267d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2687946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (unlikely(!stat))
269d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return IRQ_NONE;
270d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
271d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Call subhandlers as appropriate */
272d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* DMA irqs */
273d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
27429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		serviced |= tsi148_DMA_irqhandler(bridge, stat);
275d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
276d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Location monitor irqs */
277d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
278d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
27929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		serviced |= tsi148_LM_irqhandler(bridge, stat);
280d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
281d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Mail box irqs */
282d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
283d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
28448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat);
285d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
286d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* PCI bus error */
287d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & TSI148_LCSR_INTS_PERRS)
28848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		serviced |= tsi148_PERR_irqhandler(tsi148_bridge);
289d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
290d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* VME bus error */
291d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & TSI148_LCSR_INTS_VERRS)
29229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		serviced |= tsi148_VERR_irqhandler(tsi148_bridge);
293d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
294d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* IACK irq */
295d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & TSI148_LCSR_INTS_IACKS)
29629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		serviced |= tsi148_IACK_irqhandler(bridge);
297d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
298d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* VME bus irqs */
299d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
300d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
301d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
302d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_IRQ1S))
30329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat);
304d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
305d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Clear serviced interrupts */
30629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC);
307d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
308d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return IRQ_HANDLED;
309d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
310d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
31129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
312d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
313d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int result;
314d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int tmp;
315d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct pci_dev *pdev;
31629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
31729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
31829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
319d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
32029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
321d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
322d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Initialise list for VME bus errors */
323886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&tsi148_bridge->vme_errors);
324d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
325886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&tsi148_bridge->irq_mtx);
326c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
327d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	result = request_irq(pdev->irq,
328d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			     tsi148_irqhandler,
329d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			     IRQF_SHARED,
33029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			     driver_name, tsi148_bridge);
331d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (result) {
33248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Can't get assigned pci irq "
33348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"vector %02X\n", pdev->irq);
334d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return result;
335d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
336d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
337d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Enable and unmask interrupts */
338d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO |
339d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO |
340d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO |
341d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
342d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_INTEO_IACKEO;
343d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
34429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	/* This leaves the following interrupts masked.
345d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_VIEEO
346d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_SYSFLEO
347d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_ACFLEO
348d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
349d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
350d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Don't enable Location Monitor interrupts here - they will be
351d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * enabled when the location monitors are properly configured and
352d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * a callback has been attached.
353d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_LM0EO
354d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_LM1EO
355d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_LM2EO
356d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_LM3EO
357d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
358d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
359d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Don't enable VME interrupts until we add a handler, else the board
360d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * will respond to it and we don't want that unless it knows how to
361d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * properly deal with it.
362d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ7EO
363d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ6EO
364d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ5EO
365d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ4EO
366d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ3EO
367d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ2EO
368d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * TSI148_LCSR_INTEO_IRQ1EO
369d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
370d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
371d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
372d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
373d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
374d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
375d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
376d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
377a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cotastatic void tsi148_irq_exit(struct vme_bridge *tsi148_bridge,
378a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota	struct pci_dev *pdev)
379d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
380a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota	struct tsi148_driver *bridge = tsi148_bridge->driver_priv;
381a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota
382d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Turn off interrupts */
38329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
38429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
385d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
386d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Clear all interrupts */
38729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
388d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
389d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Detach interrupt handler */
390a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota	free_irq(pdev->irq, tsi148_bridge);
391d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
392d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
393d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
394d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Check to see if an IACk has been received, return true (1) or false (0).
395d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
3965ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_iack_received(struct tsi148_driver *bridge)
397d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
398d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 tmp;
399d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
40029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
401d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
402d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (tmp & TSI148_LCSR_VICR_IRQS)
403d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return 0;
404d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	else
405d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return 1;
406d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
407d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
408d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
409c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch * Configure VME interrupt
410d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
4115ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
41229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	int state, int sync)
413d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
41475155020c8dc3aa38f8cabc95f17ccd8389c37b6Martyn Welch	struct pci_dev *pdev;
415c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	u32 tmp;
41629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
41729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
41829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
419d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
420c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* We need to do the ordering differently for enabling and disabling */
421c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (state == 0) {
42229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
423d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
42429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
425df45517536eb010ce2b3c4c7b75c1a02bdb10018Martyn Welch
42629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
427df45517536eb010ce2b3c4c7b75c1a02bdb10018Martyn Welch		tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
42829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
42975155020c8dc3aa38f8cabc95f17ccd8389c37b6Martyn Welch
430c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		if (sync != 0) {
431c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			pdev = container_of(tsi148_bridge->parent,
432c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch				struct pci_dev, dev);
43375155020c8dc3aa38f8cabc95f17ccd8389c37b6Martyn Welch
434c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			synchronize_irq(pdev->irq);
435c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		}
436c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	} else {
43729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
438c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
43929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
440df45517536eb010ce2b3c4c7b75c1a02bdb10018Martyn Welch
44129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
442c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
44329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
444c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	}
445d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
446d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
447d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
448d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Generate a VME bus interrupt at the requested level & vector. Wait for
449d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * interrupt to be acked.
450d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
4515ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level,
4525ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cota	int statid)
453d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
454d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 tmp;
45529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
45629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
45729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
458d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
459886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->vme_int);
460d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
461d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Read VICR register */
46229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
463d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
464d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Set Status/ID */
465d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
466d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		(statid & TSI148_LCSR_VICR_STID_M);
46729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
468d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
469d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Assert VMEbus IRQ */
470d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
47129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
472d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
473d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* XXX Consider implementing a timeout? */
47429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	wait_event_interruptible(bridge->iack_queue,
47529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_iack_received(bridge));
476d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
477886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->vme_int);
478d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
479d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
480d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
481d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
482d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
483d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Find the first error in this address range
484d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
48529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
4866af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, unsigned long long address, size_t count)
487d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
488d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct list_head *err_pos;
489d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_bus_error *vme_err, *valid = NULL;
490d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long bound;
491d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
492d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	bound = address + count;
493d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
494d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
495d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * XXX We are currently not looking at the address space when parsing
496d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     for errors. This is because parsing the Address Modifier Codes
497d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     is going to be quite resource intensive to do properly. We
498d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     should be OK just looking at the addresses and this is certainly
499d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     much better than what we had before.
500d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
501d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	err_pos = NULL;
502d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Iterate through errors */
503886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(err_pos, &tsi148_bridge->vme_errors) {
504d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		vme_err = list_entry(err_pos, struct vme_bus_error, list);
5057946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if ((vme_err->address >= address) &&
5067946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			(vme_err->address < bound)) {
5077946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
508d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			valid = vme_err;
509d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			break;
510d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
511d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
512d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
513d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return valid;
514d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
515d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
516d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
517d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Clear errors in the provided address range.
518d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
51929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
5206af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, unsigned long long address, size_t count)
521d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
522d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct list_head *err_pos, *temp;
523d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_bus_error *vme_err;
524d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long bound;
525d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
526d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	bound = address + count;
527d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
528d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
529d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * XXX We are currently not looking at the address space when parsing
530d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     for errors. This is because parsing the Address Modifier Codes
531d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     is going to be quite resource intensive to do properly. We
532d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     should be OK just looking at the addresses and this is certainly
533d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *     much better than what we had before.
534d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
535d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	err_pos = NULL;
536d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Iterate through errors */
537886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) {
538d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		vme_err = list_entry(err_pos, struct vme_bus_error, list);
539d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
5407946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if ((vme_err->address >= address) &&
5417946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			(vme_err->address < bound)) {
5427946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
543d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			list_del(err_pos);
544d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			kfree(vme_err);
545d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
546d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
547d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
548d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
549d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
550d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Initialize a slave window with the requested attributes.
551d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
5525ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
553d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long vme_base, unsigned long long size,
5546af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	dma_addr_t pci_base, u32 aspace, u32 cycle)
555d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
556d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int i, addr = 0, granularity = 0;
557d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int temp_ctl = 0;
558d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_base_low, vme_base_high;
559d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_bound_low, vme_bound_high;
560d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_offset_low, pci_offset_high;
561d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long vme_bound, pci_offset;
56248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
56329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
56429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
56548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = image->parent;
56648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
567d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
568d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	i = image->number;
569d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
570d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (aspace) {
571d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A16:
572d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10;
573d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		addr |= TSI148_LCSR_ITAT_AS_A16;
574d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
575d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A24:
576d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x1000;
577d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		addr |= TSI148_LCSR_ITAT_AS_A24;
578d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
579d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A32:
580d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10000;
581d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		addr |= TSI148_LCSR_ITAT_AS_A32;
582d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
583d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A64:
584d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10000;
585d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		addr |= TSI148_LCSR_ITAT_AS_A64;
586d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
587d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_CRCSR:
588d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER1:
589d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER2:
590d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER3:
591d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER4:
592d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
59348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid address space\n");
594d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
595d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
596d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
597d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
598d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Convert 64-bit variables to 2x 32-bit variables */
599d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(vme_base, &vme_base_high, &vme_base_low);
600d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
601d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
602d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * Bound address is a valid address for the window, adjust
603d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * accordingly
604d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
605d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	vme_bound = vme_base + size - granularity;
606d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(vme_bound, &vme_bound_high, &vme_bound_low);
607d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_offset = (unsigned long long)pci_base - vme_base;
608d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(pci_offset, &pci_offset_high, &pci_offset_low);
609d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
610d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (vme_base_low & (granularity - 1)) {
61148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n");
612d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
613d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
614d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (vme_bound_low & (granularity - 1)) {
61548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n");
616d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
617d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
618d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (pci_offset_low & (granularity - 1)) {
61948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid PCI Offset "
62048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"alignment\n");
621d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
622d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
623d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
624d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*  Disable while we are mucking around */
62529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
626d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITAT);
627d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_ITAT_EN;
62829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
629d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITAT);
630d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
631d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup mapping */
63229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] +
633d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITSAU);
63429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] +
635d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITSAL);
63629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] +
637d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITEAU);
63829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] +
639d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITEAL);
64029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] +
641d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITOFU);
64229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] +
643d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITOFL);
644d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
645d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup 2eSST speeds */
646d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
647d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
648d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST160:
649d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160;
650d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
651d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST267:
652d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267;
653d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
654d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST320:
655d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320;
656d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
657d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
658d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
659d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup cycle types */
660d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~(0x1F << 7);
661d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_BLT)
662d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_BLT;
663d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_MBLT)
664d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_MBLT;
665d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eVME)
666d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eVME;
667d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSST)
668d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eSST;
669d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSSTB)
670d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_2eSSTB;
671d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
672d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup address space */
673d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_ITAT_AS_M;
674d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl |= addr;
675d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
676d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~0xF;
677d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_SUPER)
678d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_SUPR ;
679d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_USER)
680d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_NPRIV;
681d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_PROG)
682d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_PGM;
683d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_DATA)
684d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_DATA;
685d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
686d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Write ctl reg without enable */
68729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
688d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITAT);
689d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
690d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (enabled)
691d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_ITAT_EN;
692d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
69329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
694d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITAT);
695d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
696d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
697d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
698d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
699d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
700d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Get slave window configuration.
701d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
7025ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
703d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long *vme_base, unsigned long long *size,
7046af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
705d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
706d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int i, granularity = 0, ctl = 0;
707d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_base_low, vme_base_high;
708d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_bound_low, vme_bound_high;
709d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_offset_low, pci_offset_high;
710d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long vme_bound, pci_offset;
71129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
712d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
71329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = image->parent->driver_priv;
714d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
715d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	i = image->number;
716d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
717d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Read registers */
71829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
719d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITAT);
720d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
72129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
722d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITSAU);
72329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
724d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITSAL);
72529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
726d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITEAU);
72729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
728d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITEAL);
72929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
730d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITOFU);
73129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
732d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_ITOFL);
733d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
734d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Convert 64-bit variables to 2x 32-bit variables */
735d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(vme_base_high, vme_base_low, vme_base);
736d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(vme_bound_high, vme_bound_low, &vme_bound);
737d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(pci_offset_high, pci_offset_low, &pci_offset);
738d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
739d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*pci_base = (dma_addr_t)vme_base + pci_offset;
740d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
741d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*enabled = 0;
742d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*aspace = 0;
743d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*cycle = 0;
744d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
745d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_EN)
746d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*enabled = 1;
747d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
748d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) {
749d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10;
750d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A16;
751d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
752d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) {
753d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x1000;
754d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A24;
755d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
756d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) {
757d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10000;
758d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A32;
759d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
760d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) {
761d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		granularity = 0x10000;
762d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A64;
763d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
764d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
765d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Need granularity before we set the size */
766d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
767d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
768d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
769d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160)
770d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST160;
771d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267)
772d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST267;
773d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320)
774d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST320;
775d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
776d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_BLT)
777d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_BLT;
778d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_MBLT)
779d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_MBLT;
780d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_2eVME)
781d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eVME;
782d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_2eSST)
783d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST;
784d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_2eSSTB)
785d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSSTB;
786d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
787d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_SUPR)
788d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_SUPER;
789d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_NPRIV)
790d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_USER;
791d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_PGM)
792d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_PROG;
793d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_ITAT_DATA)
794d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_DATA;
795d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
796d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
797d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
798d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
799d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
800d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Allocate and map PCI Resource
801d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
802d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic int tsi148_alloc_resource(struct vme_master_resource *image,
803d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long size)
804d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
805d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long existing_size;
806d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval = 0;
807d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct pci_dev *pdev;
80829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge;
80929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
81029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_bridge = image->parent;
811d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
81248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
813d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
8148fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	existing_size = (unsigned long long)(image->bus_resource.end -
8158fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch		image->bus_resource.start);
816d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
817d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If the existing size is OK, return */
81859c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	if ((size != 0) && (existing_size == (size - 1)))
819d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return 0;
820d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
821d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (existing_size != 0) {
822d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		iounmap(image->kern_base);
823d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		image->kern_base = NULL;
824794a8946ba2339af09dd1f39c8462c3611bebf77Ilia Mirkin		kfree(image->bus_resource.name);
825886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		release_resource(&image->bus_resource);
826886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		memset(&image->bus_resource, 0, sizeof(struct resource));
827d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
828d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
82959c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	/* Exit here if size is zero */
8307946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (size == 0)
83159c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		return 0;
83259c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch
8338fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	if (image->bus_resource.name == NULL) {
8340aa3f139cd5123ffb8f397b91d777635e9761c24Julia Lawall		image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
8358fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch		if (image->bus_resource.name == NULL) {
83648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			dev_err(tsi148_bridge->parent, "Unable to allocate "
83748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch				"memory for resource name\n");
838d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			retval = -ENOMEM;
839d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_name;
840d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
841d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
842d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
8438fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name,
844d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		image->number);
845d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
8468fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	image->bus_resource.start = 0;
8478fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	image->bus_resource.end = (unsigned long)size;
8488fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	image->bus_resource.flags = IORESOURCE_MEM;
849d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
850d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = pci_bus_alloc_resource(pdev->bus,
851886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		&image->bus_resource, size, size, PCIBIOS_MIN_MEM,
852d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		0, NULL, NULL);
853d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval) {
85448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Failed to allocate mem "
85548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"resource for window %d size 0x%lx start 0x%lx\n",
856d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			image->number, (unsigned long)size,
8578fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch			(unsigned long)image->bus_resource.start);
858d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_resource;
859d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
860d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
861d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	image->kern_base = ioremap_nocache(
8628fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch		image->bus_resource.start, size);
863d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (image->kern_base == NULL) {
86448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Failed to remap resource\n");
865d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -ENOMEM;
866d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_remap;
867d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
868d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
869d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
870d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
871d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_remap:
872886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	release_resource(&image->bus_resource);
873d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_resource:
8748fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	kfree(image->bus_resource.name);
875886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	memset(&image->bus_resource, 0, sizeof(struct resource));
876d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_name:
877d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
878d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
879d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
880d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
881d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Free and unmap PCI Resource
882d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
883d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void tsi148_free_resource(struct vme_master_resource *image)
884d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
885d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	iounmap(image->kern_base);
886d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	image->kern_base = NULL;
887886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	release_resource(&image->bus_resource);
8888fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch	kfree(image->bus_resource.name);
889886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	memset(&image->bus_resource, 0, sizeof(struct resource));
890d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
891d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
892d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
893d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Set the attributes of an outbound window.
894d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
8955ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_master_set(struct vme_master_resource *image, int enabled,
8966af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long vme_base, unsigned long long size, u32 aspace,
8976af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 cycle, u32 dwidth)
898d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
899d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval = 0;
900d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int i;
901d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int temp_ctl = 0;
902d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_base_low, pci_base_high;
903d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_bound_low, pci_bound_high;
904d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_offset_low, vme_offset_high;
905d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long pci_bound, vme_offset, pci_base;
90648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
90729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
90829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
90948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = image->parent;
91048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
91148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
912d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
913d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Verify input data */
914d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (vme_base & 0xFFFF) {
91548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid VME Window "
91648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"alignment\n");
917d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
918d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_window;
919d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
92059c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch
92159c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	if ((size == 0) && (enabled != 0)) {
92248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Size must be non-zero for "
92348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"enabled windows\n");
924d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
925d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_window;
926d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
927d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
928886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&image->lock);
929d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
930d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Let's allocate the resource here rather than further up the stack as
93125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * it avoids pushing loads of bus dependent stuff up the stack. If size
93259c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	 * is zero, any existing resource will be freed.
933d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
934d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = tsi148_alloc_resource(image, size);
935d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval) {
936886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
93748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Unable to allocate memory for "
93859c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch			"resource\n");
939d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_res;
940d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
941d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
94259c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	if (size == 0) {
94359c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		pci_base = 0;
94459c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		pci_bound = 0;
94559c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		vme_offset = 0;
94659c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	} else {
9478fafb47638012d93134d0ff38adcc5fc661beeb1Martyn Welch		pci_base = (unsigned long long)image->bus_resource.start;
94859c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch
94959c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		/*
95059c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		 * Bound address is a valid address for the window, adjust
95159c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		 * according to window granularity.
95259c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		 */
95359c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		pci_bound = pci_base + (size - 0x10000);
95459c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch		vme_offset = vme_base - pci_base;
95559c2290428dd93a4117aa453fc4c2be38da288c0Martyn Welch	}
956d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
957d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Convert 64-bit variables to 2x 32-bit variables */
958d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(pci_base, &pci_base_high, &pci_base_low);
959d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(pci_bound, &pci_bound_high, &pci_bound_low);
960d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
961d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
962d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (pci_base_low & 0xFFFF) {
963886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
96448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n");
965d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
966d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_gran;
967d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
968d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (pci_bound_low & 0xFFFF) {
969886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
97048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n");
971d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
972d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_gran;
973d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
974d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (vme_offset_low & 0xFFFF) {
975886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
97648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid VME Offset "
97748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"alignment\n");
978d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
979d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_gran;
980d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
981d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
982d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	i = image->number;
983d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
984d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Disable while we are mucking around */
98529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
986d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTAT);
987d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_OTAT_EN;
98829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
989d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTAT);
990d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
991d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup 2eSST speeds */
992d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
993d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
994d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST160:
995d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160;
996d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
997d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST267:
998d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267;
999d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1000d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST320:
1001d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320;
1002d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1003d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1004d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1005d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup cycle types */
1006d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_BLT) {
1007d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1008d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_TM_BLT;
1009d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1010d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_MBLT) {
1011d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1012d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT;
1013d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1014d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eVME) {
1015d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1016d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME;
1017d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1018d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSST) {
1019d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1020d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
1021d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1022d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSSTB) {
102348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_warn(tsi148_bridge->parent, "Currently not setting "
102448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"Broadcast Select Registers\n");
1025d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1026d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
1027d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1028d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1029d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup data width */
1030d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M;
1031d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (dwidth) {
1032d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D16:
1033d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_DBW_16;
1034d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1035d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D32:
1036d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
1037d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1038d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
1039886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
104048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid data width\n");
1041d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
1042d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_dwidth;
1043d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1044d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1045d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup address space */
1046d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M;
1047d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (aspace) {
1048d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A16:
1049d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16;
1050d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1051d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A24:
1052d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24;
1053d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1054d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A32:
1055d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32;
1056d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1057d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A64:
1058d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64;
1059d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1060d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_CRCSR:
1061d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR;
1062d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1063d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER1:
1064d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1;
1065d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1066d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER2:
1067d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2;
1068d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1069d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER3:
1070d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3;
1071d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1072d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER4:
1073d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
1074d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1075d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
1076886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&image->lock);
107748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid address space\n");
1078d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
1079d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_aspace;
1080d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1081d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1082d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1083d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	temp_ctl &= ~(3<<4);
1084d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_SUPER)
1085d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_SUP;
1086d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_PROG)
1087d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_PGM;
1088d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1089d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup mapping */
109029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] +
1091d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAU);
109229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] +
1093d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAL);
109429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] +
1095d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTEAU);
109629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] +
1097d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTEAL);
109829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] +
1099d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTOFU);
110029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] +
1101d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTOFL);
1102d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1103d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Write ctl reg without enable */
110429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
1105d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTAT);
1106d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1107d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (enabled)
1108d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		temp_ctl |= TSI148_LCSR_OTAT_EN;
1109d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
111029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
1111d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTAT);
1112d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1113886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&image->lock);
1114d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1115d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1116d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_aspace:
1117d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_dwidth:
1118d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_gran:
1119d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_free_resource(image);
1120d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_res:
1121d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_window:
1122d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1123d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1124d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1125d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1126d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1127d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Set the attributes of an outbound window.
1128d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
1129d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * XXX Not parsing prefetch information.
1130d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
11315ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
11326af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
11336af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 *cycle, u32 *dwidth)
1134d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1135d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int i, ctl;
1136d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_base_low, pci_base_high;
1137d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_bound_low, pci_bound_high;
1138d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int vme_offset_low, vme_offset_high;
1139d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1140d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long pci_base, pci_bound, vme_offset;
114129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
114229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
114329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = image->parent->driver_priv;
1144d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1145d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	i = image->number;
1146d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
114729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1148d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTAT);
1149d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
115029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1151d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAU);
115229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1153d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAL);
115429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1155d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTEAU);
115629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1157d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTEAL);
115829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1159d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTOFU);
116029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1161d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTOFL);
1162d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1163d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Convert 64-bit variables to 2x 32-bit variables */
1164d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(pci_base_high, pci_base_low, &pci_base);
1165d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(pci_bound_high, pci_bound_low, &pci_bound);
1166d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(vme_offset_high, vme_offset_low, &vme_offset);
1167d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1168d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*vme_base = pci_base + vme_offset;
1169d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*size = (unsigned long long)(pci_bound - pci_base) + 0x10000;
1170d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1171d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*enabled = 0;
1172d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*aspace = 0;
1173d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*cycle = 0;
1174d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	*dwidth = 0;
1175d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1176d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_OTAT_EN)
1177d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*enabled = 1;
1178d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1179d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup address space */
1180d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16)
1181d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A16;
1182d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24)
1183d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A24;
1184d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32)
1185d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A32;
1186d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64)
1187d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A64;
1188d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR)
1189d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_CRCSR;
1190d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1)
1191d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_USER1;
1192d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2)
1193d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_USER2;
1194d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3)
1195d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_USER3;
1196d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4)
1197d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_USER4;
1198d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1199d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup 2eSST speeds */
1200d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160)
1201d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST160;
1202d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267)
1203d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST267;
1204d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320)
1205d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST320;
1206d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1207d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup cycle types */
12087946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT)
1209d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_SCT;
12107946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT)
1211d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_BLT;
12127946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT)
1213d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_MBLT;
12147946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME)
1215d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eVME;
12167946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST)
1217d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSST;
12187946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB)
1219d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_2eSSTB;
1220d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1221d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_OTAT_SUP)
1222d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_SUPER;
1223d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	else
1224d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_USER;
1225d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1226d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (ctl & TSI148_LCSR_OTAT_PGM)
1227d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_PROG;
1228d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	else
1229d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_DATA;
1230d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1231d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup data width */
1232d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16)
1233d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*dwidth = VME_D16;
1234d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32)
1235d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*dwidth = VME_D32;
1236d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1237d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1238d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1239d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1240d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
12415ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_master_get(struct vme_master_resource *image, int *enabled,
12426af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
12436af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 *cycle, u32 *dwidth)
1244d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1245d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval;
1246d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1247886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&image->lock);
1248d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1249d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
1250d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		cycle, dwidth);
1251d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1252886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&image->lock);
1253d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1254d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1255d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1256d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
12575ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
1258d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	size_t count, loff_t offset)
1259d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1260d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval, enabled;
1261d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long vme_base, size;
12626af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, cycle, dwidth;
1263d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_bus_error *vme_err = NULL;
126429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge;
126529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
126629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_bridge = image->parent;
1267d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1268886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&image->lock);
1269d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1270d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count);
1271d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = count;
1272d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1273d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (!err_chk)
1274d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto skip_chk;
1275d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1276d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
1277d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		&dwidth);
1278d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
127929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
128029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		count);
12817946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (vme_err != NULL) {
1282d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(image->parent->parent, "First VME read error detected "
1283d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"an at address 0x%llx\n", vme_err->address);
1284d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = vme_err->address - (vme_base + offset);
1285d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* Clear down save errors in this address range */
128629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
128729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			count);
1288d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1289d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1290d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchskip_chk:
1291886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&image->lock);
1292d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1293d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1294d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1295d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1296d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
12975ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
1298d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	size_t count, loff_t offset)
1299d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1300d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval = 0, enabled;
1301d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long vme_base, size;
13026af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, cycle, dwidth;
1303d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1304d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_bus_error *vme_err = NULL;
130529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge;
130629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
130729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
130829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_bridge = image->parent;
130929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
131029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
1311d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1312886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&image->lock);
1313d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1314d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	memcpy_toio(image->kern_base + offset, buf, (unsigned int)count);
1315d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = count;
1316d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1317d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
1318d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * Writes are posted. We need to do a read on the VME bus to flush out
131925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * all of the writes before we check for errors. We can't guarantee
1320d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * that reading the data we have just written is safe. It is believed
1321d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * that there isn't any read, write re-ordering, so we can read any
1322d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * location in VME space, so lets read the Device ID from the tsi148's
1323d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * own registers as mapped into CR/CSR space.
1324d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *
1325d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * We check for saved errors in the written address range/space.
1326d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
1327d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1328d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (!err_chk)
1329d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto skip_chk;
1330d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1331d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
1332d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * Get window info first, to maximise the time that the buffers may
1333d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * fluch on their own
1334d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
1335d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	__tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
1336d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		&dwidth);
1337d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
133829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	ioread16(bridge->flush_image->kern_base + 0x7F000);
1339d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
134029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
134129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		count);
13427946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (vme_err != NULL) {
134348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_warn(tsi148_bridge->parent, "First VME write error detected"
134448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			" an at address 0x%llx\n", vme_err->address);
1345d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = vme_err->address - (vme_base + offset);
1346d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* Clear down save errors in this address range */
134729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
134829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			count);
1349d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1350d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1351d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchskip_chk:
1352886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&image->lock);
1353d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1354d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1355d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1356d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1357d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1358d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Perform an RMW cycle on the VME bus.
1359d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
1360d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Requires a previously configured master window, returns final value.
1361d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
13625ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic unsigned int tsi148_master_rmw(struct vme_master_resource *image,
1363d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int mask, unsigned int compare, unsigned int swap,
1364d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	loff_t offset)
1365d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1366d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned long long pci_addr;
1367d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	unsigned int pci_addr_high, pci_addr_low;
1368d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 tmp, result;
1369d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int i;
137029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
1371d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
137229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = image->parent->driver_priv;
1373d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1374d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Find the PCI address that maps to the desired VME address */
1375d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	i = image->number;
1376d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1377d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Locking as we can only do one of these at a time */
1378886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->vme_rmw);
1379d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1380d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Lock image */
1381886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&image->lock);
1382d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
138329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1384d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAU);
138529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
1386d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_OTSAL);
1387d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1388d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(pci_addr_high, pci_addr_low, &pci_addr);
1389d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
1390d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1391d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Configure registers */
139229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN);
139329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC);
139429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS);
139529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU);
139629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL);
1397d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1398d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Enable RMW */
139929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
1400d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp |= TSI148_LCSR_VMCTRL_RMWEN;
140129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
1402d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1403d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Kick process off with a read to the required address. */
1404d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	result = ioread32be(image->kern_base + offset);
1405d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1406d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Disable RMW */
140729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
1408d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
140929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
1410d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1411886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&image->lock);
1412d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1413886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->vme_rmw);
1414d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1415d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return result;
1416d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1417d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
141848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welchstatic int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
14196af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, u32 cycle, u32 dwidth)
1420d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1421d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup 2eSST speeds */
1422d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
1423d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST160:
1424d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_2eSSTM_160;
1425d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1426d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST267:
1427d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_2eSSTM_267;
1428d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1429d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST320:
1430d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_2eSSTM_320;
1431d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1432d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1433d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1434d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup cycle types */
14357946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_SCT)
1436d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_SCT;
14377946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
14387946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_BLT)
1439d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_BLT;
14407946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
14417946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_MBLT)
1442d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_MBLT;
14437946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
14447946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_2eVME)
1445d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_2eVME;
14467946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
14477946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_2eSST)
1448d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_2eSST;
14497946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
1450d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSSTB) {
145148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Currently not setting Broadcast Select "
145248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"Registers\n");
1453d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_TM_2eSSTB;
1454d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1455d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1456d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup data width */
1457d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (dwidth) {
1458d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D16:
1459d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_DBW_16;
1460d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1461d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D32:
1462d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_DBW_32;
1463d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1464d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
146548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Invalid data width\n");
1466d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
1467d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1468d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1469d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup address space */
1470d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (aspace) {
1471d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A16:
1472d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_A16;
1473d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1474d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A24:
1475d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_A24;
1476d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1477d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A32:
1478d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_A32;
1479d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1480d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A64:
1481d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_A64;
1482d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1483d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_CRCSR:
1484d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_CRCSR;
1485d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1486d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER1:
1487d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_USER1;
1488d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1489d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER2:
1490d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_USER2;
1491d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1492d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER3:
1493d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_USER3;
1494d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1495d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER4:
1496d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_AMODE_USER4;
1497d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1498d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
149948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Invalid address space\n");
1500d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
1501d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1502d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1503d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1504d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_SUPER)
1505d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_SUP;
1506d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_PROG)
1507d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DSAT_PGM;
1508d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1509d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1510d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1511d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
151248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welchstatic int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
15136af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, u32 cycle, u32 dwidth)
1514d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1515d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup 2eSST speeds */
1516d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
1517d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST160:
1518d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_2eSSTM_160;
1519d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1520d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST267:
1521d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_2eSSTM_267;
1522d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1523d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_2eSST320:
1524d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_2eSSTM_320;
1525d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1526d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1527d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1528d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup cycle types */
15297946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_SCT)
1530d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_SCT;
15317946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
15327946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_BLT)
1533d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_BLT;
15347946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
15357946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_MBLT)
1536d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_MBLT;
15377946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
15387946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_2eVME)
1539d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_2eVME;
15407946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
15417946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (cycle & VME_2eSST)
1542d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_2eSST;
15437946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
1544d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_2eSSTB) {
154548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Currently not setting Broadcast Select "
154648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"Registers\n");
1547d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_TM_2eSSTB;
1548d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1549d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1550d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup data width */
1551d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (dwidth) {
1552d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D16:
1553d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_DBW_16;
1554d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1555d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_D32:
1556d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_DBW_32;
1557d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1558d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
155948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Invalid data width\n");
1560d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
1561d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1562d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1563d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup address space */
1564d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (aspace) {
1565d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A16:
1566d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_A16;
1567d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1568d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A24:
1569d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_A24;
1570d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1571d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A32:
1572d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_A32;
1573d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1574d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A64:
1575d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_A64;
1576d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1577d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_CRCSR:
1578d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_CRCSR;
1579d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1580d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER1:
1581d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_USER1;
1582d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1583d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER2:
1584d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_USER2;
1585d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1586d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER3:
1587d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_USER3;
1588d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1589d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_USER4:
1590d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_AMODE_USER4;
1591d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1592d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
159348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(dev, "Invalid address space\n");
1594d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
1595d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1596d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1597d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1598d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_SUPER)
1599d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_SUP;
1600d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_PROG)
1601d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*attr |= TSI148_LCSR_DDAT_PGM;
1602d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1603d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1604d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1605d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1606d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1607d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Add a link list descriptor to the list
1608d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
16095ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_dma_list_add(struct vme_dma_list *list,
16105ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cota	struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
1611d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1612d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct tsi148_dma_entry *entry, *prev;
1613d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 address_high, address_low;
1614d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_pattern *pattern_attr;
1615d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_pci *pci_attr;
1616d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_vme *vme_attr;
1617d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	dma_addr_t desc_ptr;
1618d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval = 0;
161948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
162048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
162148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = list->parent->parent;
1622d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1623bb9ea89ec8a3d80a835d53afc388ad5f67fd3cb3Martyn Welch	/* Descriptor must be aligned on 64-bit boundaries */
16247946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	entry = kmalloc(sizeof(struct tsi148_dma_entry), GFP_KERNEL);
1625d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (entry == NULL) {
162648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
162748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"dma resource structure\n");
1628d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -ENOMEM;
1629d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_mem;
1630d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1631d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1632d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Test descriptor alignment */
1633886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if ((unsigned long)&entry->descriptor & 0x7) {
163448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 "
163548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"byte boundary as required: %p\n",
1636886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			&entry->descriptor);
1637d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
1638d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_align;
1639d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1640d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1641d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Given we are going to fill out the structure, we probably don't
1642d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * need to zero it, but better safe than sorry for now.
1643d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
1644886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor));
1645d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1646d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Fill out source part */
1647d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (src->type) {
1648d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_DMA_PATTERN:
1649c4d82fbb458e6c6eebcff84653563c9c5e9a530dKulikov Vasiliy		pattern_attr = src->private;
1650d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1651d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsal = pattern_attr->pattern;
1652d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
1653d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* Default behaviour is 32 bit pattern */
16547946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
1655d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			entry->descriptor.dsat |= TSI148_LCSR_DSAT_PSZ;
16567946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
1657d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* It seems that the default behaviour is to increment */
16587946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
1659d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			entry->descriptor.dsat |= TSI148_LCSR_DSAT_NIN;
16607946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
1661d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1662d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_DMA_PCI:
1663c4d82fbb458e6c6eebcff84653563c9c5e9a530dKulikov Vasiliy		pci_attr = src->private;
1664d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1665d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		reg_split((unsigned long long)pci_attr->address, &address_high,
1666d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			&address_low);
1667d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsau = address_high;
1668d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsal = address_low;
1669d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
1670d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1671d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_DMA_VME:
1672c4d82fbb458e6c6eebcff84653563c9c5e9a530dKulikov Vasiliy		vme_attr = src->private;
1673d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1674d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		reg_split((unsigned long long)vme_attr->address, &address_high,
1675d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			&address_low);
1676d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsau = address_high;
1677d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsal = address_low;
1678d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
1679d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1680d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = tsi148_dma_set_vme_src_attributes(
1681886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			tsi148_bridge->parent, &entry->descriptor.dsat,
168248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
16837946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if (retval < 0)
1684d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_source;
1685d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1686d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
168748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid source type\n");
1688d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
1689d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_source;
1690d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1691d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1692d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1693d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Assume last link - this will be over-written by adding another */
1694d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	entry->descriptor.dnlau = 0;
1695d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	entry->descriptor.dnlal = TSI148_LCSR_DNLAL_LLA;
1696d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1697d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1698d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Fill out destination part */
1699d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (dest->type) {
1700d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_DMA_PCI:
1701c4d82fbb458e6c6eebcff84653563c9c5e9a530dKulikov Vasiliy		pci_attr = dest->private;
1702d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1703d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		reg_split((unsigned long long)pci_attr->address, &address_high,
1704d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			&address_low);
1705d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddau = address_high;
1706d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddal = address_low;
1707d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
1708d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1709d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_DMA_VME:
1710c4d82fbb458e6c6eebcff84653563c9c5e9a530dKulikov Vasiliy		vme_attr = dest->private;
1711d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1712d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		reg_split((unsigned long long)vme_attr->address, &address_high,
1713d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			&address_low);
1714d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddau = address_high;
1715d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddal = address_low;
1716d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
1717d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1718d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = tsi148_dma_set_vme_dest_attributes(
1719886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			tsi148_bridge->parent, &entry->descriptor.ddat,
172048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
17217946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		if (retval < 0)
1722d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_dest;
1723d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1724d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
172548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid destination type\n");
1726d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EINVAL;
1727d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_dest;
1728d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1729d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1730d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1731d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Fill out count */
1732d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	entry->descriptor.dcnt = (u32)count;
1733d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1734d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Add to list */
1735886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_add_tail(&entry->list, &list->entries);
1736d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1737d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Fill out previous descriptors "Next Address" */
1738886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (entry->list.prev != &list->entries) {
1739d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
1740d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			list);
1741d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* We need the bus address for the pointer */
1742886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		desc_ptr = virt_to_bus(&entry->descriptor);
1743886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		reg_split(desc_ptr, &prev->descriptor.dnlau,
1744886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			&prev->descriptor.dnlal);
1745d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1746d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1747d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1748d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1749d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_dest:
1750d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_source:
1751d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_align:
1752d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(entry);
1753d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_mem:
1754d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1755d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1756d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1757d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1758d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Check to see if the provided DMA channel is busy.
1759d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
176029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
1761d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1762d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 tmp;
176329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
176429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
176529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
1766d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
176729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
1768d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_DSTA);
1769d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1770d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (tmp & TSI148_LCSR_DSTA_BSY)
1771d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return 0;
1772d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	else
1773d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return 1;
1774d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1775d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1776d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1777d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1778d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Execute a previously generated link list
1779d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
1780d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * XXX Need to provide control register configuration.
1781d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
17825ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_dma_list_exec(struct vme_dma_list *list)
1783d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1784d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_resource *ctrlr;
1785d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int channel, retval = 0;
1786d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct tsi148_dma_entry *entry;
1787d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	dma_addr_t bus_addr;
1788d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 bus_addr_high, bus_addr_low;
1789d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 val, dctlreg = 0;
179048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
179129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
1792d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1793d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	ctrlr = list->parent;
1794d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
179548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = ctrlr->parent;
179648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
179748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
179829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
1799886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&ctrlr->mtx);
1800d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1801d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	channel = ctrlr->number;
1802d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1803886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!list_empty(&ctrlr->running)) {
1804d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/*
1805d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		 * XXX We have an active DMA transfer and currently haven't
1806d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		 *     sorted out the mechanism for "pending" DMA transfers.
1807d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		 *     Return busy.
1808d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		 */
1809d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		/* Need to add to pending here */
1810886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&ctrlr->mtx);
1811d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EBUSY;
1812d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	} else {
1813886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		list_add(&list->list, &ctrlr->running);
1814d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1815d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1816d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Get first bus address and write into registers */
1817886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
1818d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list);
1819d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1820886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	bus_addr = virt_to_bus(&entry->descriptor);
1821d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1822886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&ctrlr->mtx);
1823d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1824d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
1825d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
182629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(bus_addr_high, bridge->base +
1827d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
182829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(bus_addr_low, bridge->base +
1829d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
1830d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1831d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Start the operation */
183229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
1833d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
1834d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
183529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	wait_event_interruptible(bridge->dma_queue[channel],
183629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_dma_busy(ctrlr->parent, channel));
1837d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
1838d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * Read status register, this register is valid until we kick off a
1839d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * new transfer.
1840d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
184129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
1842d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		TSI148_LCSR_OFFSET_DSTA);
1843d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1844d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (val & TSI148_LCSR_DSTA_VBE) {
184548d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val);
1846d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EIO;
1847d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1848d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1849d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Remove list from running list */
1850886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&ctrlr->mtx);
1851886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_del(&list->list);
1852886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&ctrlr->mtx);
1853d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1854d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
1855d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1856d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1857d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1858d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Clean up a previously generated link list
1859d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
1860d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * We have a separate function, don't assume that the chain can't be reused.
1861d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
18625ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_dma_list_empty(struct vme_dma_list *list)
1863d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1864d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct list_head *pos, *temp;
18657946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	struct tsi148_dma_entry *entry;
1866d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1867d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* detach and free each entry */
1868886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each_safe(pos, temp, &list->entries) {
1869d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
1870d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		entry = list_entry(pos, struct tsi148_dma_entry, list);
1871d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(entry);
1872d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1873d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
18747946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	return 0;
1875d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1876d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1877d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1878d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * All 4 location monitors reside at the same base - this is therefore a
1879d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * system wide configuration.
1880d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
1881d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * This does not enable the LM monitor - that should be done when the first
1882d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * callback is attached and disabled when the last callback is removed.
1883d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
18845ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
18856af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, u32 cycle)
1886d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1887d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 lm_base_high, lm_base_low, lm_ctl = 0;
1888d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int i;
188948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
189029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
189129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
189248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = lm->parent;
189348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
189448d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
1895d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1896886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
1897d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1898d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If we already have a callback attached, we can't move it! */
189942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	for (i = 0; i < lm->monitors; i++) {
190029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		if (bridge->lm_callback[i] != NULL) {
1901886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&lm->mtx);
190248d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			dev_err(tsi148_bridge->parent, "Location monitor "
190348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch				"callback attached, can't reset\n");
1904d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			return -EBUSY;
1905d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
1906d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1907d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1908d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	switch (aspace) {
1909d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A16:
1910d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_AS_A16;
1911d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1912d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A24:
1913d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_AS_A24;
1914d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1915d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A32:
1916d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_AS_A32;
1917d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1918d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	case VME_A64:
1919d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
1920d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1921d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	default:
1922886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&lm->mtx);
192348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Invalid address space\n");
1924d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
1925d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		break;
1926d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
1927d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1928d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_SUPER)
1929d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_SUPR ;
1930d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_USER)
1931d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_NPRIV;
1932d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_PROG)
1933d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_PGM;
1934d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cycle & VME_DATA)
1935d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_DATA;
1936d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1937d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_split(lm_base, &lm_base_high, &lm_base_low);
1938d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
193929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU);
194029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
194129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
1942d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1943886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
1944d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1945d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
1946d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1947d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1948d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/* Get configuration of the callback monitor and return whether it is enabled
1949d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * or disabled.
1950d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
19515ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_lm_get(struct vme_lm_resource *lm,
19526af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long *lm_base, u32 *aspace, u32 *cycle)
1953d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
1954d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
195529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
195629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
195729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = lm->parent->driver_priv;
1958d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1959886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
1960d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
196129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
196229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
196329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
1964d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1965d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	reg_join(lm_base_high, lm_base_low, lm_base);
1966d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1967d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (lm_ctl & TSI148_LCSR_LMAT_EN)
1968d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		enabled = 1;
1969d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
19707946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16)
1971d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A16;
19727946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
19737946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24)
1974d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A24;
19757946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
19767946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32)
1977d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A32;
19787946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
19797946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64)
1980d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*aspace |= VME_A64;
19817946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch
1982d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1983d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (lm_ctl & TSI148_LCSR_LMAT_SUPR)
1984d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_SUPER;
1985d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (lm_ctl & TSI148_LCSR_LMAT_NPRIV)
1986d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_USER;
1987d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (lm_ctl & TSI148_LCSR_LMAT_PGM)
1988d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_PROG;
1989d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (lm_ctl & TSI148_LCSR_LMAT_DATA)
1990d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		*cycle |= VME_DATA;
1991d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1992886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
1993d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1994d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return enabled;
1995d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
1996d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
1997d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
1998d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Attach a callback to a specific location monitor.
1999d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
2000d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Callback will be passed the monitor triggered.
2001d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
20025ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
200342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	void (*callback)(int))
2004d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2005d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 lm_ctl, tmp;
200648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	struct vme_bridge *tsi148_bridge;
200729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
200829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
200948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	tsi148_bridge = lm->parent;
201048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch
201148d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	bridge = tsi148_bridge->driver_priv;
2012d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2013886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
2014d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2015d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Ensure that the location monitor is configured - need PGM or DATA */
201629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
2017d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
2018886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&lm->mtx);
201948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Location monitor not properly "
202048d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"configured\n");
2021d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EINVAL;
2022d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2023d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2024d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Check that a callback isn't already attached */
202529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (bridge->lm_callback[monitor] != NULL) {
2026886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&lm->mtx);
202748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Existing callback attached\n");
2028d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -EBUSY;
2029d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2030d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2031d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Attach callback */
203229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge->lm_callback[monitor] = callback;
2033d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2034d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Enable Location Monitor interrupt */
203529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
2036d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
203729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
2038d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
203929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
2040d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
204129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
2042d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2043d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Ensure that global Location Monitor Enable set */
2044d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
2045d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		lm_ctl |= TSI148_LCSR_LMAT_EN;
204629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
2047d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2048d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2049886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
2050d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2051d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
2052d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2053d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2054d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
2055d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Detach a callback function forn a specific location monitor.
2056d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
20575ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
2058d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2059d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 lm_en, tmp;
206029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
206129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
206229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = lm->parent->driver_priv;
2063d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2064886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
2065d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2066d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Disable Location Monitor and ensure previous interrupts are clear */
206729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
2068d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
206929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN);
2070d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
207129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
2072d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
207329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
2074d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2075d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
207629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		 bridge->base + TSI148_LCSR_INTC);
2077d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2078d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Detach callback */
207929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge->lm_callback[monitor] = NULL;
2080d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2081d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If all location monitors disabled, disable global Location Monitor */
2082d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
2083d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
208429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT);
2085d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		tmp &= ~TSI148_LCSR_LMAT_EN;
208629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
2087d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2088d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2089886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
2090d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2091d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
2092d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2093d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2094d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
2095d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Determine Geographical Addressing
2096d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
20975ade6c4d79377efc371ac89db07e4f6594d1286aEmilio G. Cotastatic int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
2098d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
20997946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	u32 slot = 0;
210029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
210129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
210229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
2103d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2104638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch	if (!geoid) {
210529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT);
2106638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		slot = slot & TSI148_LCSR_VSTAT_GA_M;
2107638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch	} else
2108638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		slot = geoid;
2109638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch
2110d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return (int)slot;
2111d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2112d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
21137f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vangavoid *tsi148_alloc_consistent(struct device *parent, size_t size,
21147f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	dma_addr_t *dma)
21157f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga{
21167f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	struct pci_dev *pdev;
21177f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
21187f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	/* Find pci_dev container of dev */
21197f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	pdev = container_of(parent, struct pci_dev, dev);
21207f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
21217f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	return pci_alloc_consistent(pdev, size, dma);
21227f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga}
21237f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
21247f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vangavoid tsi148_free_consistent(struct device *parent, size_t size, void *vaddr,
21257f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	dma_addr_t dma)
21267f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga{
21277f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	struct pci_dev *pdev;
21287f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
21297f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	/* Find pci_dev container of dev */
21307f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	pdev = container_of(parent, struct pci_dev, dev);
21317f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
21327f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	pci_free_consistent(pdev, size, vaddr, dma);
21337f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga}
21347f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
2135d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic int __init tsi148_init(void)
2136d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2137d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return pci_register_driver(&tsi148_driver);
2138d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2139d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2140d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch/*
2141d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Configure CR/CSR space
2142d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
2143d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Access to the CR/CSR can be configured at power-up. The location of the
2144d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * CR/CSR registers in the CR/CSR address space is determined by the boards
2145d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Auto-ID or Geographic address. This function ensures that the window is
2146d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * enabled at an offset consistent with the boards geopgraphic address.
2147d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch *
2148d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * Each board has a 512kB window, with the highest 4kB being used for the
2149d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * boards registers, this means there is a fix length 508kB window which must
2150d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch * be mapped onto PCI memory.
2151d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch */
215229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
215329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct pci_dev *pdev)
2154d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2155d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 cbar, crat, vstat;
2156d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 crcsr_bus_high, crcsr_bus_low;
2157d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval;
215829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
215929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
216029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
2161d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2162d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Allocate mem for CR/CSR image */
216329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
2164886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		&bridge->crcsr_bus);
216529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (bridge->crcsr_kernel == NULL) {
216648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
216748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			"CR/CSR image\n");
2168d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		return -ENOMEM;
2169d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2170d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
217129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
2172d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
217329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
2174d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
217529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU);
217629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL);
2177d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2178d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Ensure that the CR/CSR is configured at the correct offset */
217929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	cbar = ioread32be(bridge->base + TSI148_CBAR);
2180d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
2181d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
218229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	vstat = tsi148_slot_get(tsi148_bridge);
2183d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2184d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (cbar != vstat) {
2185638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		cbar = vstat;
218648d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n");
218729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(cbar<<3, bridge->base + TSI148_CBAR);
2188d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
218948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch	dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar);
2190d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
219129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
2192d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (crat & TSI148_LCSR_CRAT_EN) {
219348d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n");
2194d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		iowrite32be(crat | TSI148_LCSR_CRAT_EN,
219529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			bridge->base + TSI148_LCSR_CRAT);
2196d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	} else
219748d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch		dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n");
2198d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2199d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If we want flushed, error-checked writes, set up a window
2200d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * over the CR/CSR registers. We read from here to safely flush
2201d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * through VME writes.
2202d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
22037946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (err_chk) {
220429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		retval = tsi148_master_set(bridge->flush_image, 1,
220529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			(vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT,
220629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			VME_D16);
2207d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		if (retval)
220848d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch			dev_err(tsi148_bridge->parent, "Configuring flush image"
220948d9356e7750d3efa3156eb3a76e7a4439774b12Martyn Welch				" failed\n");
2210d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2211d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2212d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
2213d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2214d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2215d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
221629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welchstatic void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge,
221729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct pci_dev *pdev)
2218d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2219d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 crat;
222029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
222129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
222229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
2223d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2224d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Turn off CR/CSR space */
222529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
2226d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
222729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		bridge->base + TSI148_LCSR_CRAT);
2228d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2229d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Free image */
223029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0, bridge->base + TSI148_LCSR_CROU);
223129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0, bridge->base + TSI148_LCSR_CROL);
2232d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
223329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
223429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		bridge->crcsr_bus);
2235d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2236d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2237d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2238d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2239d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int retval, i, master_num;
2240d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	u32 data;
2241d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct list_head *pos = NULL;
224229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge;
224329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *tsi148_device;
2244d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_master_resource *master_image;
2245d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_slave_resource *slave_image;
2246d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_resource *dma_ctrlr;
224742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
2248d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2249d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If we want to support more than one of each bridge, we need to
2250d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * dynamically generate this so we get one per device
2251d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
22527a6cb0d5497418599d2125b670926b75e673861cJulia Lawall	tsi148_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
2253d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (tsi148_bridge == NULL) {
2254d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Failed to allocate memory for device "
2255d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"structure\n");
2256d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -ENOMEM;
2257d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_struct;
2258d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2259d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
22607a6cb0d5497418599d2125b670926b75e673861cJulia Lawall	tsi148_device = kzalloc(sizeof(struct tsi148_driver), GFP_KERNEL);
226129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (tsi148_device == NULL) {
226229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		dev_err(&pdev->dev, "Failed to allocate memory for device "
226329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			"structure\n");
226429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		retval = -ENOMEM;
226529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		goto err_driver;
226629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	}
226729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
226829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_bridge->driver_priv = tsi148_device;
226929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
2270d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Enable the device */
2271d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = pci_enable_device(pdev);
2272d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval) {
2273d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Unable to enable device\n");
2274d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_enable;
2275d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2276d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2277d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Map Registers */
2278d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = pci_request_regions(pdev, driver_name);
2279d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval) {
2280d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Unable to reserve resources\n");
2281d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_resource;
2282d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2283d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2284d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* map registers in BAR 0 */
228529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
228629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		4096);
228729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (!tsi148_device->base) {
2288d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Unable to remap CRG region\n");
2289d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EIO;
2290d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_remap;
2291d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2292d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2293d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Check to see if the mapping worked out */
229429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
2295d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (data != PCI_VENDOR_ID_TUNDRA) {
2296d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "CRG region check failed\n");
2297d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		retval = -EIO;
2298d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_test;
2299d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2300d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2301d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Initialize wait queues & mutual exclusion flags */
2302886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	init_waitqueue_head(&tsi148_device->dma_queue[0]);
2303886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	init_waitqueue_head(&tsi148_device->dma_queue[1]);
2304886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	init_waitqueue_head(&tsi148_device->iack_queue);
2305886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&tsi148_device->vme_int);
2306886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&tsi148_device->vme_rmw);
2307d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2308886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	tsi148_bridge->parent = &pdev->dev;
2309d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	strcpy(tsi148_bridge->name, driver_name);
2310d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2311d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Setup IRQ */
2312d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = tsi148_irq_init(tsi148_bridge);
2313d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval != 0) {
2314d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Chip Initialization failed.\n");
2315d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_irq;
2316d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2317d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2318d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* If we are going to flush writes, we need to read from the VME bus.
2319d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * We need to do this safely, thus we read the devices own CR/CSR
2320d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * register. To do this we must set up a window in CR/CSR space and
2321d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 * hence have one less master window resource available.
2322d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
2323d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	master_num = TSI148_MAX_MASTER;
23247946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch	if (err_chk) {
2325d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_num--;
232629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
2327324148788bf3744d90fb6894ec5744eb0ca91b74Julia Lawall		tsi148_device->flush_image =
232829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL);
232929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		if (tsi148_device->flush_image == NULL) {
2330d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			dev_err(&pdev->dev, "Failed to allocate memory for "
2331d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"flush resource structure\n");
2332d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			retval = -ENOMEM;
2333d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_master;
2334d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
233529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->parent = tsi148_bridge;
2336886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_lock_init(&tsi148_device->flush_image->lock);
233729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->locked = 1;
233829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->number = master_num;
233929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 |
234029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			VME_A32 | VME_A64;
234129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->cycle_attr = VME_SCT | VME_BLT |
234229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB |
234329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER |
234429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch			VME_USER | VME_PROG | VME_DATA;
234529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->width_attr = VME_D16 | VME_D32;
2346886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		memset(&tsi148_device->flush_image->bus_resource, 0,
2347d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			sizeof(struct resource));
234829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		tsi148_device->flush_image->kern_base  = NULL;
2349d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2350d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2351d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Add master windows to list */
2352886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&tsi148_bridge->master_resources);
2353d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < master_num; i++) {
23547946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		master_image = kmalloc(sizeof(struct vme_master_resource),
23557946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			GFP_KERNEL);
2356d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		if (master_image == NULL) {
2357d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			dev_err(&pdev->dev, "Failed to allocate memory for "
2358d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"master resource structure\n");
2359d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			retval = -ENOMEM;
2360d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_master;
2361d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
2362d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->parent = tsi148_bridge;
2363886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_lock_init(&master_image->lock);
2364d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->locked = 0;
2365d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->number = i;
2366d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
2367d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_A64;
2368d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
2369d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
2370d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
2371d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_PROG | VME_DATA;
2372d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->width_attr = VME_D16 | VME_D32;
2373886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		memset(&master_image->bus_resource, 0,
2374d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			sizeof(struct resource));
2375d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		master_image->kern_base  = NULL;
2376886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		list_add_tail(&master_image->list,
2377886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			&tsi148_bridge->master_resources);
2378d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2379d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2380d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Add slave windows to list */
2381886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&tsi148_bridge->slave_resources);
2382d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < TSI148_MAX_SLAVE; i++) {
23837946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		slave_image = kmalloc(sizeof(struct vme_slave_resource),
23847946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			GFP_KERNEL);
2385d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		if (slave_image == NULL) {
2386d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			dev_err(&pdev->dev, "Failed to allocate memory for "
2387d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"slave resource structure\n");
2388d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			retval = -ENOMEM;
2389d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_slave;
2390d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
2391d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image->parent = tsi148_bridge;
2392886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_init(&slave_image->mtx);
2393d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image->locked = 0;
2394d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image->number = i;
2395d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
2396d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
2397d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_USER3 | VME_USER4;
2398d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
2399d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
2400d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
2401d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			VME_PROG | VME_DATA;
2402886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		list_add_tail(&slave_image->list,
2403886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			&tsi148_bridge->slave_resources);
2404d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2405d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2406d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Add dma engines to list */
2407886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&tsi148_bridge->dma_resources);
2408d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < TSI148_MAX_DMA; i++) {
24097946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
24107946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			GFP_KERNEL);
2411d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		if (dma_ctrlr == NULL) {
2412d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			dev_err(&pdev->dev, "Failed to allocate memory for "
2413d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			"dma resource structure\n");
2414d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			retval = -ENOMEM;
2415d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			goto err_dma;
2416d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		}
2417d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dma_ctrlr->parent = tsi148_bridge;
2418886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_init(&dma_ctrlr->mtx);
2419d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dma_ctrlr->locked = 0;
2420d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dma_ctrlr->number = i;
24214f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
24224f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch			VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
24234f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch			VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
24244f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch			VME_DMA_PATTERN_TO_MEM;
2425886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		INIT_LIST_HEAD(&dma_ctrlr->pending);
2426886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		INIT_LIST_HEAD(&dma_ctrlr->running);
2427886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		list_add_tail(&dma_ctrlr->list,
2428886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			&tsi148_bridge->dma_resources);
2429d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2430d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
243142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Add location monitor to list */
2432886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&tsi148_bridge->lm_resources);
243342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
243442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (lm == NULL) {
243542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		dev_err(&pdev->dev, "Failed to allocate memory for "
243642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		"location monitor resource structure\n");
243742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		retval = -ENOMEM;
243842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_lm;
243942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
244042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->parent = tsi148_bridge;
2441886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&lm->mtx);
244242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
244342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->number = 1;
244442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->monitors = 4;
2445886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
244642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
2447d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->slave_get = tsi148_slave_get;
2448d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->slave_set = tsi148_slave_set;
2449d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->master_get = tsi148_master_get;
2450d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->master_set = tsi148_master_set;
2451d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->master_read = tsi148_master_read;
2452d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->master_write = tsi148_master_write;
2453d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->master_rmw = tsi148_master_rmw;
2454d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->dma_list_add = tsi148_dma_list_add;
2455d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
2456d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
2457c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	tsi148_bridge->irq_set = tsi148_irq_set;
2458c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	tsi148_bridge->irq_generate = tsi148_irq_generate;
2459d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->lm_set = tsi148_lm_set;
2460d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->lm_get = tsi148_lm_get;
2461d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->lm_attach = tsi148_lm_attach;
2462d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->lm_detach = tsi148_lm_detach;
2463d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	tsi148_bridge->slot_get = tsi148_slot_get;
24647f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	tsi148_bridge->alloc_consistent = tsi148_alloc_consistent;
24657f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	tsi148_bridge->free_consistent = tsi148_free_consistent;
2466d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
246729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
2468d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
24697946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		(data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not");
247029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (!geoid)
2471638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		dev_info(&pdev->dev, "VME geographical address is %d\n",
2472638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch			data & TSI148_LCSR_VSTAT_GA_M);
247329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	else
2474638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		dev_info(&pdev->dev, "VME geographical address is set to %d\n",
2475638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch			geoid);
247629848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
2477d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
2478d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		err_chk ? "enabled" : "disabled");
2479d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
24804839737b3b6af2a9b3b960584f08177fbc9bf118Martyn Welch	if (tsi148_crcsr_init(tsi148_bridge, pdev)) {
2481d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
2482d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_crcsr;
24834839737b3b6af2a9b3b960584f08177fbc9bf118Martyn Welch	}
2484d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2485d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	retval = vme_register_bridge(tsi148_bridge);
2486d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	if (retval != 0) {
2487d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dev_err(&pdev->dev, "Chip Registration failed.\n");
2488d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		goto err_reg;
2489d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2490d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
249129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	pci_set_drvdata(pdev, tsi148_bridge);
249229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
2493d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* Clear VME bus "board fail", and "power-up reset" lines */
249429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
2495d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	data &= ~TSI148_LCSR_VSTAT_BRDFL;
2496d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	data |= TSI148_LCSR_VSTAT_CPURST;
249729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
2498d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2499d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return 0;
2500d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2501d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_reg:
250229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_crcsr_exit(tsi148_bridge, pdev);
2503d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_crcsr:
250442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_lm:
250542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* resources are stored in link list */
2506886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(pos, &tsi148_bridge->lm_resources) {
250742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		lm = list_entry(pos, struct vme_lm_resource, list);
250842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		list_del(pos);
250942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		kfree(lm);
251042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
2511d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_dma:
2512d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2513886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(pos, &tsi148_bridge->dma_resources) {
2514d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
2515d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2516d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(dma_ctrlr);
2517d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2518d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_slave:
2519d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2520886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(pos, &tsi148_bridge->slave_resources) {
2521d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image = list_entry(pos, struct vme_slave_resource, list);
2522d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2523d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(slave_image);
2524d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2525d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_master:
2526d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2527886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(pos, &tsi148_bridge->master_resources) {
25287946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch		master_image = list_entry(pos, struct vme_master_resource,
25297946328faf1dca9bfadf98f4579f95aafffaba0fMartyn Welch			list);
2530d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2531d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(master_image);
2532d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2533d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2534a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota	tsi148_irq_exit(tsi148_bridge, pdev);
2535d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_irq:
2536d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_test:
253729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iounmap(tsi148_device->base);
2538d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_remap:
2539d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_release_regions(pdev);
2540d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_resource:
2541d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_disable_device(pdev);
2542d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_enable:
254329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	kfree(tsi148_device);
254429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welcherr_driver:
2545d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	kfree(tsi148_bridge);
2546d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welcherr_struct:
2547d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	return retval;
2548d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2549d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2550d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2551d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void tsi148_remove(struct pci_dev *pdev)
2552d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2553d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct list_head *pos = NULL;
2554b558ba2f356c28269de179c4f7f6f179a4fa6a1dEmilio G. Cota	struct list_head *tmplist;
2555d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_master_resource *master_image;
2556d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_slave_resource *slave_image;
2557d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	struct vme_dma_resource *dma_ctrlr;
2558d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	int i;
255929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct tsi148_driver *bridge;
256029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev);
256129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
256229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge = tsi148_bridge->driver_priv;
2563d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2564d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
256529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
2566d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2567d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2568d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Shutdown all inbound and outbound windows.
2569d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
2570d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	for (i = 0; i < 8; i++) {
257129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] +
2572d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_OFFSET_ITAT);
257329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] +
2574d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch			TSI148_LCSR_OFFSET_OTAT);
2575d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2576d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2577d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2578d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Shutdown Location monitor.
2579d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
258029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0, bridge->base + TSI148_LCSR_LMAT);
2581d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2582d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2583d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Shutdown CRG map.
2584d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
258529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT);
2586d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2587d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2588d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Clear error status.
2589d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
259029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT);
259129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT);
259229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT);
2593d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2594d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2595d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Remove VIRQ interrupt (if any)
2596d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
259729848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800)
259829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR);
2599d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2600d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/*
2601d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 *  Map all Interrupts to PCI INTA
2602d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	 */
260329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
260429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
2605d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2606a82ad05ecd9dbd909509a332d3aa5f4ac439a054Emilio G. Cota	tsi148_irq_exit(tsi148_bridge, pdev);
2607d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2608d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	vme_unregister_bridge(tsi148_bridge);
2609d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
261029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	tsi148_crcsr_exit(tsi148_bridge, pdev);
2611d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2612d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2613b558ba2f356c28269de179c4f7f6f179a4fa6a1dEmilio G. Cota	list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
2614d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
2615d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2616d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(dma_ctrlr);
2617d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2618d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2619d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2620b558ba2f356c28269de179c4f7f6f179a4fa6a1dEmilio G. Cota	list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) {
2621d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		slave_image = list_entry(pos, struct vme_slave_resource, list);
2622d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2623d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(slave_image);
2624d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2625d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2626d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	/* resources are stored in link list */
2627b558ba2f356c28269de179c4f7f6f179a4fa6a1dEmilio G. Cota	list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) {
2628638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch		master_image = list_entry(pos, struct vme_master_resource,
2629638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch			list);
2630d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		list_del(pos);
2631d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch		kfree(master_image);
2632d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	}
2633d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
263429848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	iounmap(bridge->base);
2635d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2636d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_release_regions(pdev);
2637d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2638d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_disable_device(pdev);
2639d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
264029848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	kfree(tsi148_bridge->driver_priv);
264129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch
2642d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	kfree(tsi148_bridge);
2643d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2644d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2645d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchstatic void __exit tsi148_exit(void)
2646d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch{
2647d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch	pci_unregister_driver(&tsi148_driver);
2648d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch}
2649d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2650d22b8ed9a3b0a157b732580258ec16b729265953Martyn WelchMODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
2651d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchmodule_param(err_chk, bool, 0);
2652d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2653638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn WelchMODULE_PARM_DESC(geoid, "Override geographical addressing");
2654638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welchmodule_param(geoid, int, 0);
2655638f199db463a8f2b1535c45ab27d04bb1a55bafMartyn Welch
2656d22b8ed9a3b0a157b732580258ec16b729265953Martyn WelchMODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
2657d22b8ed9a3b0a157b732580258ec16b729265953Martyn WelchMODULE_LICENSE("GPL");
2658d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welch
2659d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchmodule_init(tsi148_init);
2660d22b8ed9a3b0a157b732580258ec16b729265953Martyn Welchmodule_exit(tsi148_exit);
2661