blob: 61e706c0e00c6f6435d89ad5a23d9d887bd23bec [file] [log] [blame]
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001/*
2 * Support for the Tundra TSI148 VME-PCI Bridge Chip
3 *
Martyn Welch66bd8db2010-02-18 15:12:52 +00004 * Author: Martyn Welch <martyn.welch@ge.com>
5 * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
Martyn Welchd22b8ed2009-07-31 09:28:17 +01006 *
7 * Based on work by Tom Armistead and Ajit Prem
8 * Copyright 2004 Motorola Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
Martyn Welchd22b8ed2009-07-31 09:28:17 +010016#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/mm.h>
19#include <linux/types.h>
20#include <linux/errno.h>
21#include <linux/proc_fs.h>
22#include <linux/pci.h>
23#include <linux/poll.h>
24#include <linux/dma-mapping.h>
25#include <linux/interrupt.h>
26#include <linux/spinlock.h>
Greg Kroah-Hartman6af783c2009-10-12 15:00:08 -070027#include <linux/sched.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Martyn Welch79463282010-03-22 14:58:57 +000029#include <linux/time.h>
30#include <linux/io.h>
31#include <linux/uaccess.h>
Martyn Welchac1a4f22012-03-22 13:27:30 +000032#include <linux/byteorder/generic.h>
Greg Kroah-Hartmandb3b9e92012-04-26 12:34:58 -070033#include <linux/vme.h>
Martyn Welchd22b8ed2009-07-31 09:28:17 +010034
Martyn Welchd22b8ed2009-07-31 09:28:17 +010035#include "../vme_bridge.h"
36#include "vme_tsi148.h"
37
Martyn Welchd22b8ed2009-07-31 09:28:17 +010038static int tsi148_probe(struct pci_dev *, const struct pci_device_id *);
39static void tsi148_remove(struct pci_dev *);
Martyn Welchd22b8ed2009-07-31 09:28:17 +010040
41
Martyn Welch29848ac2010-02-18 15:13:05 +000042/* Module parameter */
Rusty Russell90ab5ee2012-01-13 09:32:20 +103043static bool err_chk;
Martyn Welch638f1992009-12-15 08:42:49 +000044static int geoid;
Martyn Welchd22b8ed2009-07-31 09:28:17 +010045
Vincent Bossier584721c2011-06-03 10:07:39 +010046static const char driver_name[] = "vme_tsi148";
Martyn Welchd22b8ed2009-07-31 09:28:17 +010047
Jingoo Hanc3a09c12013-12-03 08:29:48 +090048static const struct pci_device_id tsi148_ids[] = {
Martyn Welchd22b8ed2009-07-31 09:28:17 +010049 { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) },
50 { },
51};
52
53static struct pci_driver tsi148_driver = {
54 .name = driver_name,
55 .id_table = tsi148_ids,
56 .probe = tsi148_probe,
57 .remove = tsi148_remove,
58};
59
60static void reg_join(unsigned int high, unsigned int low,
61 unsigned long long *variable)
62{
63 *variable = (unsigned long long)high << 32;
64 *variable |= (unsigned long long)low;
65}
66
67static void reg_split(unsigned long long variable, unsigned int *high,
68 unsigned int *low)
69{
70 *low = (unsigned int)variable & 0xFFFFFFFF;
71 *high = (unsigned int)(variable >> 32);
72}
73
74/*
75 * Wakes up DMA queue.
76 */
Martyn Welch29848ac2010-02-18 15:13:05 +000077static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge,
78 int channel_mask)
Martyn Welchd22b8ed2009-07-31 09:28:17 +010079{
80 u32 serviced = 0;
81
82 if (channel_mask & TSI148_LCSR_INTS_DMA0S) {
Emilio G. Cota886953e2010-11-12 11:14:07 +000083 wake_up(&bridge->dma_queue[0]);
Martyn Welchd22b8ed2009-07-31 09:28:17 +010084 serviced |= TSI148_LCSR_INTC_DMA0C;
85 }
86 if (channel_mask & TSI148_LCSR_INTS_DMA1S) {
Emilio G. Cota886953e2010-11-12 11:14:07 +000087 wake_up(&bridge->dma_queue[1]);
Martyn Welchd22b8ed2009-07-31 09:28:17 +010088 serviced |= TSI148_LCSR_INTC_DMA1C;
89 }
90
91 return serviced;
92}
93
94/*
95 * Wake up location monitor queue
96 */
Martyn Welch29848ac2010-02-18 15:13:05 +000097static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
Martyn Welchd22b8ed2009-07-31 09:28:17 +010098{
99 int i;
100 u32 serviced = 0;
101
102 for (i = 0; i < 4; i++) {
Martyn Welch79463282010-03-22 14:58:57 +0000103 if (stat & TSI148_LCSR_INTS_LMS[i]) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100104 /* We only enable interrupts if the callback is set */
Martyn Welch29848ac2010-02-18 15:13:05 +0000105 bridge->lm_callback[i](i);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100106 serviced |= TSI148_LCSR_INTC_LMC[i];
107 }
108 }
109
110 return serviced;
111}
112
113/*
114 * Wake up mail box queue.
115 *
116 * XXX This functionality is not exposed up though API.
117 */
Martyn Welch48d93562010-03-22 14:58:50 +0000118static u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100119{
120 int i;
121 u32 val;
122 u32 serviced = 0;
Martyn Welch48d93562010-03-22 14:58:50 +0000123 struct tsi148_driver *bridge;
124
125 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100126
127 for (i = 0; i < 4; i++) {
Martyn Welch79463282010-03-22 14:58:57 +0000128 if (stat & TSI148_LCSR_INTS_MBS[i]) {
Martyn Welch29848ac2010-02-18 15:13:05 +0000129 val = ioread32be(bridge->base + TSI148_GCSR_MBOX[i]);
Martyn Welch48d93562010-03-22 14:58:50 +0000130 dev_err(tsi148_bridge->parent, "VME Mailbox %d received"
131 ": 0x%x\n", i, val);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100132 serviced |= TSI148_LCSR_INTC_MBC[i];
133 }
134 }
135
136 return serviced;
137}
138
139/*
140 * Display error & status message when PERR (PCI) exception interrupt occurs.
141 */
Martyn Welch48d93562010-03-22 14:58:50 +0000142static u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100143{
Martyn Welch48d93562010-03-22 14:58:50 +0000144 struct tsi148_driver *bridge;
145
146 bridge = tsi148_bridge->driver_priv;
147
148 dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, "
149 "attributes: %08x\n",
Martyn Welch29848ac2010-02-18 15:13:05 +0000150 ioread32be(bridge->base + TSI148_LCSR_EDPAU),
151 ioread32be(bridge->base + TSI148_LCSR_EDPAL),
Martyn Welch48d93562010-03-22 14:58:50 +0000152 ioread32be(bridge->base + TSI148_LCSR_EDPAT));
153
154 dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split "
155 "completion reg: %08x\n",
Martyn Welch29848ac2010-02-18 15:13:05 +0000156 ioread32be(bridge->base + TSI148_LCSR_EDPXA),
Martyn Welch48d93562010-03-22 14:58:50 +0000157 ioread32be(bridge->base + TSI148_LCSR_EDPXS));
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100158
Martyn Welch29848ac2010-02-18 15:13:05 +0000159 iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100160
161 return TSI148_LCSR_INTC_PERRC;
162}
163
164/*
165 * Save address and status when VME error interrupt occurs.
166 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000167static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100168{
169 unsigned int error_addr_high, error_addr_low;
170 unsigned long long error_addr;
171 u32 error_attrib;
Martyn Welche31c51e2013-06-11 11:20:17 +0100172 struct vme_bus_error *error = NULL;
Martyn Welch29848ac2010-02-18 15:13:05 +0000173 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100174
Martyn Welch29848ac2010-02-18 15:13:05 +0000175 bridge = tsi148_bridge->driver_priv;
176
177 error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU);
178 error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL);
179 error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100180
181 reg_join(error_addr_high, error_addr_low, &error_addr);
182
183 /* Check for exception register overflow (we have lost error data) */
Martyn Welch79463282010-03-22 14:58:57 +0000184 if (error_attrib & TSI148_LCSR_VEAT_VEOF) {
Martyn Welch48d93562010-03-22 14:58:50 +0000185 dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow "
186 "Occurred\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100187 }
188
Martyn Welche31c51e2013-06-11 11:20:17 +0100189 if (err_chk) {
190 error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC);
191 if (error) {
192 error->address = error_addr;
193 error->attributes = error_attrib;
194 list_add_tail(&error->list, &tsi148_bridge->vme_errors);
195 } else {
196 dev_err(tsi148_bridge->parent,
197 "Unable to alloc memory for VMEbus Error reporting\n");
198 }
199 }
200
201 if (!error) {
202 dev_err(tsi148_bridge->parent,
203 "VME Bus Error at address: 0x%llx, attributes: %08x\n",
204 error_addr, error_attrib);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100205 }
206
207 /* Clear Status */
Martyn Welch29848ac2010-02-18 15:13:05 +0000208 iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100209
210 return TSI148_LCSR_INTC_VERRC;
211}
212
213/*
214 * Wake up IACK queue.
215 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000216static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100217{
Emilio G. Cota886953e2010-11-12 11:14:07 +0000218 wake_up(&bridge->iack_queue);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100219
220 return TSI148_LCSR_INTC_IACKC;
221}
222
223/*
224 * Calling VME bus interrupt callback if provided.
225 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000226static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge,
227 u32 stat)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100228{
229 int vec, i, serviced = 0;
Martyn Welch29848ac2010-02-18 15:13:05 +0000230 struct tsi148_driver *bridge;
231
232 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100233
234 for (i = 7; i > 0; i--) {
235 if (stat & (1 << i)) {
236 /*
Martyn Welch79463282010-03-22 14:58:57 +0000237 * Note: Even though the registers are defined as
238 * 32-bits in the spec, we only want to issue 8-bit
239 * IACK cycles on the bus, read from offset 3.
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100240 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000241 vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100242
Martyn Welchc813f592009-10-29 16:34:54 +0000243 vme_irq_handler(tsi148_bridge, i, vec);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100244
245 serviced |= (1 << i);
246 }
247 }
248
249 return serviced;
250}
251
252/*
253 * Top level interrupt handler. Clears appropriate interrupt status bits and
254 * then calls appropriate sub handler(s).
255 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000256static irqreturn_t tsi148_irqhandler(int irq, void *ptr)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100257{
258 u32 stat, enable, serviced = 0;
Martyn Welch29848ac2010-02-18 15:13:05 +0000259 struct vme_bridge *tsi148_bridge;
260 struct tsi148_driver *bridge;
261
262 tsi148_bridge = ptr;
263
264 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100265
266 /* Determine which interrupts are unmasked and set */
Martyn Welch29848ac2010-02-18 15:13:05 +0000267 enable = ioread32be(bridge->base + TSI148_LCSR_INTEO);
268 stat = ioread32be(bridge->base + TSI148_LCSR_INTS);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100269
270 /* Only look at unmasked interrupts */
271 stat &= enable;
272
Martyn Welch79463282010-03-22 14:58:57 +0000273 if (unlikely(!stat))
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100274 return IRQ_NONE;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100275
276 /* Call subhandlers as appropriate */
277 /* DMA irqs */
278 if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S))
Martyn Welch29848ac2010-02-18 15:13:05 +0000279 serviced |= tsi148_DMA_irqhandler(bridge, stat);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100280
281 /* Location monitor irqs */
282 if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S |
283 TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S))
Martyn Welch29848ac2010-02-18 15:13:05 +0000284 serviced |= tsi148_LM_irqhandler(bridge, stat);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100285
286 /* Mail box irqs */
287 if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S |
288 TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S))
Martyn Welch48d93562010-03-22 14:58:50 +0000289 serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100290
291 /* PCI bus error */
292 if (stat & TSI148_LCSR_INTS_PERRS)
Martyn Welch48d93562010-03-22 14:58:50 +0000293 serviced |= tsi148_PERR_irqhandler(tsi148_bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100294
295 /* VME bus error */
296 if (stat & TSI148_LCSR_INTS_VERRS)
Martyn Welch29848ac2010-02-18 15:13:05 +0000297 serviced |= tsi148_VERR_irqhandler(tsi148_bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100298
299 /* IACK irq */
300 if (stat & TSI148_LCSR_INTS_IACKS)
Martyn Welch29848ac2010-02-18 15:13:05 +0000301 serviced |= tsi148_IACK_irqhandler(bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100302
303 /* VME bus irqs */
304 if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S |
305 TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S |
306 TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S |
307 TSI148_LCSR_INTS_IRQ1S))
Martyn Welch29848ac2010-02-18 15:13:05 +0000308 serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100309
310 /* Clear serviced interrupts */
Martyn Welch29848ac2010-02-18 15:13:05 +0000311 iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100312
313 return IRQ_HANDLED;
314}
315
Martyn Welch29848ac2010-02-18 15:13:05 +0000316static int tsi148_irq_init(struct vme_bridge *tsi148_bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100317{
318 int result;
319 unsigned int tmp;
320 struct pci_dev *pdev;
Martyn Welch29848ac2010-02-18 15:13:05 +0000321 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100322
Aaron Sierra177581fa2014-04-03 14:48:27 -0500323 pdev = to_pci_dev(tsi148_bridge->parent);
Martyn Welch29848ac2010-02-18 15:13:05 +0000324
325 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100326
327 /* Initialise list for VME bus errors */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000328 INIT_LIST_HEAD(&tsi148_bridge->vme_errors);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100329
Emilio G. Cota886953e2010-11-12 11:14:07 +0000330 mutex_init(&tsi148_bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +0000331
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100332 result = request_irq(pdev->irq,
333 tsi148_irqhandler,
334 IRQF_SHARED,
Martyn Welch29848ac2010-02-18 15:13:05 +0000335 driver_name, tsi148_bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100336 if (result) {
Martyn Welch48d93562010-03-22 14:58:50 +0000337 dev_err(tsi148_bridge->parent, "Can't get assigned pci irq "
338 "vector %02X\n", pdev->irq);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100339 return result;
340 }
341
342 /* Enable and unmask interrupts */
343 tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO |
344 TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO |
345 TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO |
346 TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO |
347 TSI148_LCSR_INTEO_IACKEO;
348
Martyn Welch29848ac2010-02-18 15:13:05 +0000349 /* This leaves the following interrupts masked.
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100350 * TSI148_LCSR_INTEO_VIEEO
351 * TSI148_LCSR_INTEO_SYSFLEO
352 * TSI148_LCSR_INTEO_ACFLEO
353 */
354
355 /* Don't enable Location Monitor interrupts here - they will be
356 * enabled when the location monitors are properly configured and
357 * a callback has been attached.
358 * TSI148_LCSR_INTEO_LM0EO
359 * TSI148_LCSR_INTEO_LM1EO
360 * TSI148_LCSR_INTEO_LM2EO
361 * TSI148_LCSR_INTEO_LM3EO
362 */
363
364 /* Don't enable VME interrupts until we add a handler, else the board
365 * will respond to it and we don't want that unless it knows how to
366 * properly deal with it.
367 * TSI148_LCSR_INTEO_IRQ7EO
368 * TSI148_LCSR_INTEO_IRQ6EO
369 * TSI148_LCSR_INTEO_IRQ5EO
370 * TSI148_LCSR_INTEO_IRQ4EO
371 * TSI148_LCSR_INTEO_IRQ3EO
372 * TSI148_LCSR_INTEO_IRQ2EO
373 * TSI148_LCSR_INTEO_IRQ1EO
374 */
375
376 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
377 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
378
379 return 0;
380}
381
Emilio G. Cotaa82ad052010-11-12 11:14:47 +0000382static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge,
383 struct pci_dev *pdev)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100384{
Emilio G. Cotaa82ad052010-11-12 11:14:47 +0000385 struct tsi148_driver *bridge = tsi148_bridge->driver_priv;
386
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100387 /* Turn off interrupts */
Martyn Welch29848ac2010-02-18 15:13:05 +0000388 iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO);
389 iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100390
391 /* Clear all interrupts */
Martyn Welch29848ac2010-02-18 15:13:05 +0000392 iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100393
394 /* Detach interrupt handler */
Emilio G. Cotaa82ad052010-11-12 11:14:47 +0000395 free_irq(pdev->irq, tsi148_bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100396}
397
398/*
399 * Check to see if an IACk has been received, return true (1) or false (0).
400 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000401static int tsi148_iack_received(struct tsi148_driver *bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100402{
403 u32 tmp;
404
Martyn Welch29848ac2010-02-18 15:13:05 +0000405 tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100406
407 if (tmp & TSI148_LCSR_VICR_IRQS)
408 return 0;
409 else
410 return 1;
411}
412
413/*
Martyn Welchc813f592009-10-29 16:34:54 +0000414 * Configure VME interrupt
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100415 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000416static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level,
Martyn Welch29848ac2010-02-18 15:13:05 +0000417 int state, int sync)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100418{
Martyn Welch75155022009-08-11 13:50:49 +0100419 struct pci_dev *pdev;
Martyn Welchc813f592009-10-29 16:34:54 +0000420 u32 tmp;
Martyn Welch29848ac2010-02-18 15:13:05 +0000421 struct tsi148_driver *bridge;
422
423 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100424
Martyn Welchc813f592009-10-29 16:34:54 +0000425 /* We need to do the ordering differently for enabling and disabling */
426 if (state == 0) {
Martyn Welch29848ac2010-02-18 15:13:05 +0000427 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100428 tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
Martyn Welch29848ac2010-02-18 15:13:05 +0000429 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
Martyn Welchdf455172009-08-05 17:38:31 +0100430
Martyn Welch29848ac2010-02-18 15:13:05 +0000431 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
Martyn Welchdf455172009-08-05 17:38:31 +0100432 tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
Martyn Welch29848ac2010-02-18 15:13:05 +0000433 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
Martyn Welch75155022009-08-11 13:50:49 +0100434
Martyn Welchc813f592009-10-29 16:34:54 +0000435 if (sync != 0) {
Aaron Sierra177581fa2014-04-03 14:48:27 -0500436 pdev = to_pci_dev(tsi148_bridge->parent);
Martyn Welchc813f592009-10-29 16:34:54 +0000437 synchronize_irq(pdev->irq);
438 }
439 } else {
Martyn Welch29848ac2010-02-18 15:13:05 +0000440 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
Martyn Welchc813f592009-10-29 16:34:54 +0000441 tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
Martyn Welch29848ac2010-02-18 15:13:05 +0000442 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
Martyn Welchc813f592009-10-29 16:34:54 +0000443
Martyn Welch29848ac2010-02-18 15:13:05 +0000444 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
Martyn Welchc813f592009-10-29 16:34:54 +0000445 tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
Martyn Welch29848ac2010-02-18 15:13:05 +0000446 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100447 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100448}
449
450/*
451 * Generate a VME bus interrupt at the requested level & vector. Wait for
452 * interrupt to be acked.
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100453 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000454static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level,
455 int statid)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100456{
457 u32 tmp;
Martyn Welch29848ac2010-02-18 15:13:05 +0000458 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100459
Martyn Welch29848ac2010-02-18 15:13:05 +0000460 bridge = tsi148_bridge->driver_priv;
461
Emilio G. Cota886953e2010-11-12 11:14:07 +0000462 mutex_lock(&bridge->vme_int);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100463
464 /* Read VICR register */
Martyn Welch29848ac2010-02-18 15:13:05 +0000465 tmp = ioread32be(bridge->base + TSI148_LCSR_VICR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100466
467 /* Set Status/ID */
468 tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) |
469 (statid & TSI148_LCSR_VICR_STID_M);
Martyn Welch29848ac2010-02-18 15:13:05 +0000470 iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100471
472 /* Assert VMEbus IRQ */
473 tmp = tmp | TSI148_LCSR_VICR_IRQL[level];
Martyn Welch29848ac2010-02-18 15:13:05 +0000474 iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100475
476 /* XXX Consider implementing a timeout? */
Martyn Welch29848ac2010-02-18 15:13:05 +0000477 wait_event_interruptible(bridge->iack_queue,
478 tsi148_iack_received(bridge));
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100479
Emilio G. Cota886953e2010-11-12 11:14:07 +0000480 mutex_unlock(&bridge->vme_int);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100481
482 return 0;
483}
484
485/*
486 * Find the first error in this address range
487 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000488static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge,
Martyn Welch6af04b02011-12-01 17:06:29 +0000489 u32 aspace, unsigned long long address, size_t count)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100490{
491 struct list_head *err_pos;
492 struct vme_bus_error *vme_err, *valid = NULL;
493 unsigned long long bound;
494
495 bound = address + count;
496
497 /*
498 * XXX We are currently not looking at the address space when parsing
499 * for errors. This is because parsing the Address Modifier Codes
500 * is going to be quite resource intensive to do properly. We
501 * should be OK just looking at the addresses and this is certainly
502 * much better than what we had before.
503 */
504 err_pos = NULL;
505 /* Iterate through errors */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000506 list_for_each(err_pos, &tsi148_bridge->vme_errors) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100507 vme_err = list_entry(err_pos, struct vme_bus_error, list);
Martyn Welch79463282010-03-22 14:58:57 +0000508 if ((vme_err->address >= address) &&
509 (vme_err->address < bound)) {
510
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100511 valid = vme_err;
512 break;
513 }
514 }
515
516 return valid;
517}
518
519/*
520 * Clear errors in the provided address range.
521 */
Martyn Welch29848ac2010-02-18 15:13:05 +0000522static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge,
Martyn Welch6af04b02011-12-01 17:06:29 +0000523 u32 aspace, unsigned long long address, size_t count)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100524{
525 struct list_head *err_pos, *temp;
526 struct vme_bus_error *vme_err;
527 unsigned long long bound;
528
529 bound = address + count;
530
531 /*
532 * XXX We are currently not looking at the address space when parsing
533 * for errors. This is because parsing the Address Modifier Codes
534 * is going to be quite resource intensive to do properly. We
535 * should be OK just looking at the addresses and this is certainly
536 * much better than what we had before.
537 */
538 err_pos = NULL;
539 /* Iterate through errors */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000540 list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100541 vme_err = list_entry(err_pos, struct vme_bus_error, list);
542
Martyn Welch79463282010-03-22 14:58:57 +0000543 if ((vme_err->address >= address) &&
544 (vme_err->address < bound)) {
545
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100546 list_del(err_pos);
547 kfree(vme_err);
548 }
549 }
550}
551
552/*
553 * Initialize a slave window with the requested attributes.
554 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000555static int tsi148_slave_set(struct vme_slave_resource *image, int enabled,
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100556 unsigned long long vme_base, unsigned long long size,
Martyn Welch6af04b02011-12-01 17:06:29 +0000557 dma_addr_t pci_base, u32 aspace, u32 cycle)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100558{
559 unsigned int i, addr = 0, granularity = 0;
560 unsigned int temp_ctl = 0;
561 unsigned int vme_base_low, vme_base_high;
562 unsigned int vme_bound_low, vme_bound_high;
563 unsigned int pci_offset_low, pci_offset_high;
564 unsigned long long vme_bound, pci_offset;
Martyn Welch48d93562010-03-22 14:58:50 +0000565 struct vme_bridge *tsi148_bridge;
Martyn Welch29848ac2010-02-18 15:13:05 +0000566 struct tsi148_driver *bridge;
567
Martyn Welch48d93562010-03-22 14:58:50 +0000568 tsi148_bridge = image->parent;
569 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100570
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100571 i = image->number;
572
573 switch (aspace) {
574 case VME_A16:
575 granularity = 0x10;
576 addr |= TSI148_LCSR_ITAT_AS_A16;
577 break;
578 case VME_A24:
579 granularity = 0x1000;
580 addr |= TSI148_LCSR_ITAT_AS_A24;
581 break;
582 case VME_A32:
583 granularity = 0x10000;
584 addr |= TSI148_LCSR_ITAT_AS_A32;
585 break;
586 case VME_A64:
587 granularity = 0x10000;
588 addr |= TSI148_LCSR_ITAT_AS_A64;
589 break;
590 case VME_CRCSR:
591 case VME_USER1:
592 case VME_USER2:
593 case VME_USER3:
594 case VME_USER4:
595 default:
Martyn Welch48d93562010-03-22 14:58:50 +0000596 dev_err(tsi148_bridge->parent, "Invalid address space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100597 return -EINVAL;
598 break;
599 }
600
601 /* Convert 64-bit variables to 2x 32-bit variables */
602 reg_split(vme_base, &vme_base_high, &vme_base_low);
603
604 /*
605 * Bound address is a valid address for the window, adjust
606 * accordingly
607 */
608 vme_bound = vme_base + size - granularity;
609 reg_split(vme_bound, &vme_bound_high, &vme_bound_low);
610 pci_offset = (unsigned long long)pci_base - vme_base;
611 reg_split(pci_offset, &pci_offset_high, &pci_offset_low);
612
613 if (vme_base_low & (granularity - 1)) {
Martyn Welch48d93562010-03-22 14:58:50 +0000614 dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100615 return -EINVAL;
616 }
617 if (vme_bound_low & (granularity - 1)) {
Martyn Welch48d93562010-03-22 14:58:50 +0000618 dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100619 return -EINVAL;
620 }
621 if (pci_offset_low & (granularity - 1)) {
Martyn Welch48d93562010-03-22 14:58:50 +0000622 dev_err(tsi148_bridge->parent, "Invalid PCI Offset "
623 "alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100624 return -EINVAL;
625 }
626
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100627 /* Disable while we are mucking around */
Martyn Welch29848ac2010-02-18 15:13:05 +0000628 temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100629 TSI148_LCSR_OFFSET_ITAT);
630 temp_ctl &= ~TSI148_LCSR_ITAT_EN;
Martyn Welch29848ac2010-02-18 15:13:05 +0000631 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100632 TSI148_LCSR_OFFSET_ITAT);
633
634 /* Setup mapping */
Martyn Welch29848ac2010-02-18 15:13:05 +0000635 iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100636 TSI148_LCSR_OFFSET_ITSAU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000637 iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100638 TSI148_LCSR_OFFSET_ITSAL);
Martyn Welch29848ac2010-02-18 15:13:05 +0000639 iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100640 TSI148_LCSR_OFFSET_ITEAU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000641 iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100642 TSI148_LCSR_OFFSET_ITEAL);
Martyn Welch29848ac2010-02-18 15:13:05 +0000643 iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100644 TSI148_LCSR_OFFSET_ITOFU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000645 iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100646 TSI148_LCSR_OFFSET_ITOFL);
647
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100648 /* Setup 2eSST speeds */
649 temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M;
650 switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
651 case VME_2eSST160:
652 temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160;
653 break;
654 case VME_2eSST267:
655 temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267;
656 break;
657 case VME_2eSST320:
658 temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320;
659 break;
660 }
661
662 /* Setup cycle types */
663 temp_ctl &= ~(0x1F << 7);
664 if (cycle & VME_BLT)
665 temp_ctl |= TSI148_LCSR_ITAT_BLT;
666 if (cycle & VME_MBLT)
667 temp_ctl |= TSI148_LCSR_ITAT_MBLT;
668 if (cycle & VME_2eVME)
669 temp_ctl |= TSI148_LCSR_ITAT_2eVME;
670 if (cycle & VME_2eSST)
671 temp_ctl |= TSI148_LCSR_ITAT_2eSST;
672 if (cycle & VME_2eSSTB)
673 temp_ctl |= TSI148_LCSR_ITAT_2eSSTB;
674
675 /* Setup address space */
676 temp_ctl &= ~TSI148_LCSR_ITAT_AS_M;
677 temp_ctl |= addr;
678
679 temp_ctl &= ~0xF;
680 if (cycle & VME_SUPER)
681 temp_ctl |= TSI148_LCSR_ITAT_SUPR ;
682 if (cycle & VME_USER)
683 temp_ctl |= TSI148_LCSR_ITAT_NPRIV;
684 if (cycle & VME_PROG)
685 temp_ctl |= TSI148_LCSR_ITAT_PGM;
686 if (cycle & VME_DATA)
687 temp_ctl |= TSI148_LCSR_ITAT_DATA;
688
689 /* Write ctl reg without enable */
Martyn Welch29848ac2010-02-18 15:13:05 +0000690 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100691 TSI148_LCSR_OFFSET_ITAT);
692
693 if (enabled)
694 temp_ctl |= TSI148_LCSR_ITAT_EN;
695
Martyn Welch29848ac2010-02-18 15:13:05 +0000696 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100697 TSI148_LCSR_OFFSET_ITAT);
698
699 return 0;
700}
701
702/*
703 * Get slave window configuration.
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100704 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000705static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled,
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100706 unsigned long long *vme_base, unsigned long long *size,
Martyn Welch6af04b02011-12-01 17:06:29 +0000707 dma_addr_t *pci_base, u32 *aspace, u32 *cycle)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100708{
709 unsigned int i, granularity = 0, ctl = 0;
710 unsigned int vme_base_low, vme_base_high;
711 unsigned int vme_bound_low, vme_bound_high;
712 unsigned int pci_offset_low, pci_offset_high;
713 unsigned long long vme_bound, pci_offset;
Martyn Welch29848ac2010-02-18 15:13:05 +0000714 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100715
Martyn Welch29848ac2010-02-18 15:13:05 +0000716 bridge = image->parent->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100717
718 i = image->number;
719
720 /* Read registers */
Martyn Welch29848ac2010-02-18 15:13:05 +0000721 ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100722 TSI148_LCSR_OFFSET_ITAT);
723
Martyn Welch29848ac2010-02-18 15:13:05 +0000724 vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100725 TSI148_LCSR_OFFSET_ITSAU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000726 vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100727 TSI148_LCSR_OFFSET_ITSAL);
Martyn Welch29848ac2010-02-18 15:13:05 +0000728 vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100729 TSI148_LCSR_OFFSET_ITEAU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000730 vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100731 TSI148_LCSR_OFFSET_ITEAL);
Martyn Welch29848ac2010-02-18 15:13:05 +0000732 pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100733 TSI148_LCSR_OFFSET_ITOFU);
Martyn Welch29848ac2010-02-18 15:13:05 +0000734 pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100735 TSI148_LCSR_OFFSET_ITOFL);
736
737 /* Convert 64-bit variables to 2x 32-bit variables */
738 reg_join(vme_base_high, vme_base_low, vme_base);
739 reg_join(vme_bound_high, vme_bound_low, &vme_bound);
740 reg_join(pci_offset_high, pci_offset_low, &pci_offset);
741
Joe Schultz098ced82014-04-03 14:47:55 -0500742 *pci_base = (dma_addr_t)(*vme_base + pci_offset);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100743
744 *enabled = 0;
745 *aspace = 0;
746 *cycle = 0;
747
748 if (ctl & TSI148_LCSR_ITAT_EN)
749 *enabled = 1;
750
751 if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) {
752 granularity = 0x10;
753 *aspace |= VME_A16;
754 }
755 if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) {
756 granularity = 0x1000;
757 *aspace |= VME_A24;
758 }
759 if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) {
760 granularity = 0x10000;
761 *aspace |= VME_A32;
762 }
763 if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) {
764 granularity = 0x10000;
765 *aspace |= VME_A64;
766 }
767
768 /* Need granularity before we set the size */
769 *size = (unsigned long long)((vme_bound - *vme_base) + granularity);
770
771
772 if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160)
773 *cycle |= VME_2eSST160;
774 if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267)
775 *cycle |= VME_2eSST267;
776 if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320)
777 *cycle |= VME_2eSST320;
778
779 if (ctl & TSI148_LCSR_ITAT_BLT)
780 *cycle |= VME_BLT;
781 if (ctl & TSI148_LCSR_ITAT_MBLT)
782 *cycle |= VME_MBLT;
783 if (ctl & TSI148_LCSR_ITAT_2eVME)
784 *cycle |= VME_2eVME;
785 if (ctl & TSI148_LCSR_ITAT_2eSST)
786 *cycle |= VME_2eSST;
787 if (ctl & TSI148_LCSR_ITAT_2eSSTB)
788 *cycle |= VME_2eSSTB;
789
790 if (ctl & TSI148_LCSR_ITAT_SUPR)
791 *cycle |= VME_SUPER;
792 if (ctl & TSI148_LCSR_ITAT_NPRIV)
793 *cycle |= VME_USER;
794 if (ctl & TSI148_LCSR_ITAT_PGM)
795 *cycle |= VME_PROG;
796 if (ctl & TSI148_LCSR_ITAT_DATA)
797 *cycle |= VME_DATA;
798
799 return 0;
800}
801
802/*
803 * Allocate and map PCI Resource
804 */
805static int tsi148_alloc_resource(struct vme_master_resource *image,
806 unsigned long long size)
807{
808 unsigned long long existing_size;
809 int retval = 0;
810 struct pci_dev *pdev;
Martyn Welch29848ac2010-02-18 15:13:05 +0000811 struct vme_bridge *tsi148_bridge;
812
813 tsi148_bridge = image->parent;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100814
Aaron Sierra177581fa2014-04-03 14:48:27 -0500815 pdev = to_pci_dev(tsi148_bridge->parent);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100816
Martyn Welch8fafb472010-02-18 15:13:12 +0000817 existing_size = (unsigned long long)(image->bus_resource.end -
818 image->bus_resource.start);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100819
820 /* If the existing size is OK, return */
Martyn Welch59c22902009-10-29 16:35:01 +0000821 if ((size != 0) && (existing_size == (size - 1)))
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100822 return 0;
823
824 if (existing_size != 0) {
825 iounmap(image->kern_base);
826 image->kern_base = NULL;
Ilia Mirkin794a8942011-03-13 00:29:13 -0500827 kfree(image->bus_resource.name);
Emilio G. Cota886953e2010-11-12 11:14:07 +0000828 release_resource(&image->bus_resource);
829 memset(&image->bus_resource, 0, sizeof(struct resource));
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100830 }
831
Martyn Welch59c22902009-10-29 16:35:01 +0000832 /* Exit here if size is zero */
Martyn Welch79463282010-03-22 14:58:57 +0000833 if (size == 0)
Martyn Welch59c22902009-10-29 16:35:01 +0000834 return 0;
Martyn Welch59c22902009-10-29 16:35:01 +0000835
Martyn Welch8fafb472010-02-18 15:13:12 +0000836 if (image->bus_resource.name == NULL) {
Julia Lawall0aa3f132010-05-30 22:27:46 +0200837 image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
Martyn Welch8fafb472010-02-18 15:13:12 +0000838 if (image->bus_resource.name == NULL) {
Martyn Welch48d93562010-03-22 14:58:50 +0000839 dev_err(tsi148_bridge->parent, "Unable to allocate "
840 "memory for resource name\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100841 retval = -ENOMEM;
842 goto err_name;
843 }
844 }
845
Martyn Welch8fafb472010-02-18 15:13:12 +0000846 sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name,
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100847 image->number);
848
Martyn Welch8fafb472010-02-18 15:13:12 +0000849 image->bus_resource.start = 0;
850 image->bus_resource.end = (unsigned long)size;
851 image->bus_resource.flags = IORESOURCE_MEM;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100852
853 retval = pci_bus_alloc_resource(pdev->bus,
Emilio G. Cota886953e2010-11-12 11:14:07 +0000854 &image->bus_resource, size, size, PCIBIOS_MIN_MEM,
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100855 0, NULL, NULL);
856 if (retval) {
Martyn Welch48d93562010-03-22 14:58:50 +0000857 dev_err(tsi148_bridge->parent, "Failed to allocate mem "
858 "resource for window %d size 0x%lx start 0x%lx\n",
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100859 image->number, (unsigned long)size,
Martyn Welch8fafb472010-02-18 15:13:12 +0000860 (unsigned long)image->bus_resource.start);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100861 goto err_resource;
862 }
863
864 image->kern_base = ioremap_nocache(
Martyn Welch8fafb472010-02-18 15:13:12 +0000865 image->bus_resource.start, size);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100866 if (image->kern_base == NULL) {
Martyn Welch48d93562010-03-22 14:58:50 +0000867 dev_err(tsi148_bridge->parent, "Failed to remap resource\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100868 retval = -ENOMEM;
869 goto err_remap;
870 }
871
872 return 0;
873
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100874err_remap:
Emilio G. Cota886953e2010-11-12 11:14:07 +0000875 release_resource(&image->bus_resource);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100876err_resource:
Martyn Welch8fafb472010-02-18 15:13:12 +0000877 kfree(image->bus_resource.name);
Emilio G. Cota886953e2010-11-12 11:14:07 +0000878 memset(&image->bus_resource, 0, sizeof(struct resource));
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100879err_name:
880 return retval;
881}
882
883/*
884 * Free and unmap PCI Resource
885 */
886static void tsi148_free_resource(struct vme_master_resource *image)
887{
888 iounmap(image->kern_base);
889 image->kern_base = NULL;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000890 release_resource(&image->bus_resource);
Martyn Welch8fafb472010-02-18 15:13:12 +0000891 kfree(image->bus_resource.name);
Emilio G. Cota886953e2010-11-12 11:14:07 +0000892 memset(&image->bus_resource, 0, sizeof(struct resource));
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100893}
894
895/*
896 * Set the attributes of an outbound window.
897 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +0000898static int tsi148_master_set(struct vme_master_resource *image, int enabled,
Martyn Welch6af04b02011-12-01 17:06:29 +0000899 unsigned long long vme_base, unsigned long long size, u32 aspace,
900 u32 cycle, u32 dwidth)
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100901{
902 int retval = 0;
903 unsigned int i;
904 unsigned int temp_ctl = 0;
905 unsigned int pci_base_low, pci_base_high;
906 unsigned int pci_bound_low, pci_bound_high;
907 unsigned int vme_offset_low, vme_offset_high;
908 unsigned long long pci_bound, vme_offset, pci_base;
Martyn Welch48d93562010-03-22 14:58:50 +0000909 struct vme_bridge *tsi148_bridge;
Martyn Welch29848ac2010-02-18 15:13:05 +0000910 struct tsi148_driver *bridge;
Joe Schultz226572b2014-04-03 14:48:16 -0500911 struct pci_bus_region region;
912 struct pci_dev *pdev;
Martyn Welch29848ac2010-02-18 15:13:05 +0000913
Martyn Welch48d93562010-03-22 14:58:50 +0000914 tsi148_bridge = image->parent;
915
916 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100917
Aaron Sierra177581fa2014-04-03 14:48:27 -0500918 pdev = to_pci_dev(tsi148_bridge->parent);
Joe Schultz226572b2014-04-03 14:48:16 -0500919
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100920 /* Verify input data */
921 if (vme_base & 0xFFFF) {
Martyn Welch48d93562010-03-22 14:58:50 +0000922 dev_err(tsi148_bridge->parent, "Invalid VME Window "
923 "alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100924 retval = -EINVAL;
925 goto err_window;
926 }
Martyn Welch59c22902009-10-29 16:35:01 +0000927
928 if ((size == 0) && (enabled != 0)) {
Martyn Welch48d93562010-03-22 14:58:50 +0000929 dev_err(tsi148_bridge->parent, "Size must be non-zero for "
930 "enabled windows\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100931 retval = -EINVAL;
932 goto err_window;
933 }
934
Emilio G. Cota886953e2010-11-12 11:14:07 +0000935 spin_lock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100936
937 /* Let's allocate the resource here rather than further up the stack as
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300938 * it avoids pushing loads of bus dependent stuff up the stack. If size
Martyn Welch59c22902009-10-29 16:35:01 +0000939 * is zero, any existing resource will be freed.
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100940 */
941 retval = tsi148_alloc_resource(image, size);
942 if (retval) {
Emilio G. Cota886953e2010-11-12 11:14:07 +0000943 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +0000944 dev_err(tsi148_bridge->parent, "Unable to allocate memory for "
Martyn Welch59c22902009-10-29 16:35:01 +0000945 "resource\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100946 goto err_res;
947 }
948
Martyn Welch59c22902009-10-29 16:35:01 +0000949 if (size == 0) {
950 pci_base = 0;
951 pci_bound = 0;
952 vme_offset = 0;
953 } else {
Joe Schultz226572b2014-04-03 14:48:16 -0500954 pcibios_resource_to_bus(pdev->bus, &region,
955 &image->bus_resource);
956 pci_base = region.start;
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100957
Martyn Welch59c22902009-10-29 16:35:01 +0000958 /*
959 * Bound address is a valid address for the window, adjust
960 * according to window granularity.
961 */
962 pci_bound = pci_base + (size - 0x10000);
963 vme_offset = vme_base - pci_base;
964 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100965
966 /* Convert 64-bit variables to 2x 32-bit variables */
967 reg_split(pci_base, &pci_base_high, &pci_base_low);
968 reg_split(pci_bound, &pci_bound_high, &pci_bound_low);
969 reg_split(vme_offset, &vme_offset_high, &vme_offset_low);
970
971 if (pci_base_low & 0xFFFF) {
Emilio G. Cota886953e2010-11-12 11:14:07 +0000972 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +0000973 dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100974 retval = -EINVAL;
975 goto err_gran;
976 }
977 if (pci_bound_low & 0xFFFF) {
Emilio G. Cota886953e2010-11-12 11:14:07 +0000978 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +0000979 dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100980 retval = -EINVAL;
981 goto err_gran;
982 }
983 if (vme_offset_low & 0xFFFF) {
Emilio G. Cota886953e2010-11-12 11:14:07 +0000984 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +0000985 dev_err(tsi148_bridge->parent, "Invalid VME Offset "
986 "alignment\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100987 retval = -EINVAL;
988 goto err_gran;
989 }
990
991 i = image->number;
992
993 /* Disable while we are mucking around */
Martyn Welch29848ac2010-02-18 15:13:05 +0000994 temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100995 TSI148_LCSR_OFFSET_OTAT);
996 temp_ctl &= ~TSI148_LCSR_OTAT_EN;
Martyn Welch29848ac2010-02-18 15:13:05 +0000997 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +0100998 TSI148_LCSR_OFFSET_OTAT);
999
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001000 /* Setup 2eSST speeds */
1001 temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M;
1002 switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
1003 case VME_2eSST160:
1004 temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160;
1005 break;
1006 case VME_2eSST267:
1007 temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267;
1008 break;
1009 case VME_2eSST320:
1010 temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320;
1011 break;
1012 }
1013
1014 /* Setup cycle types */
1015 if (cycle & VME_BLT) {
1016 temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1017 temp_ctl |= TSI148_LCSR_OTAT_TM_BLT;
1018 }
1019 if (cycle & VME_MBLT) {
1020 temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1021 temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT;
1022 }
1023 if (cycle & VME_2eVME) {
1024 temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1025 temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME;
1026 }
1027 if (cycle & VME_2eSST) {
1028 temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1029 temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
1030 }
1031 if (cycle & VME_2eSSTB) {
Martyn Welch48d93562010-03-22 14:58:50 +00001032 dev_warn(tsi148_bridge->parent, "Currently not setting "
1033 "Broadcast Select Registers\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001034 temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
1035 temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
1036 }
1037
1038 /* Setup data width */
1039 temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M;
1040 switch (dwidth) {
1041 case VME_D16:
1042 temp_ctl |= TSI148_LCSR_OTAT_DBW_16;
1043 break;
1044 case VME_D32:
1045 temp_ctl |= TSI148_LCSR_OTAT_DBW_32;
1046 break;
1047 default:
Emilio G. Cota886953e2010-11-12 11:14:07 +00001048 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +00001049 dev_err(tsi148_bridge->parent, "Invalid data width\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001050 retval = -EINVAL;
1051 goto err_dwidth;
1052 }
1053
1054 /* Setup address space */
1055 temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M;
1056 switch (aspace) {
1057 case VME_A16:
1058 temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16;
1059 break;
1060 case VME_A24:
1061 temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24;
1062 break;
1063 case VME_A32:
1064 temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32;
1065 break;
1066 case VME_A64:
1067 temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64;
1068 break;
1069 case VME_CRCSR:
1070 temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR;
1071 break;
1072 case VME_USER1:
1073 temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1;
1074 break;
1075 case VME_USER2:
1076 temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2;
1077 break;
1078 case VME_USER3:
1079 temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3;
1080 break;
1081 case VME_USER4:
1082 temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4;
1083 break;
1084 default:
Emilio G. Cota886953e2010-11-12 11:14:07 +00001085 spin_unlock(&image->lock);
Martyn Welch48d93562010-03-22 14:58:50 +00001086 dev_err(tsi148_bridge->parent, "Invalid address space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001087 retval = -EINVAL;
1088 goto err_aspace;
1089 break;
1090 }
1091
1092 temp_ctl &= ~(3<<4);
1093 if (cycle & VME_SUPER)
1094 temp_ctl |= TSI148_LCSR_OTAT_SUP;
1095 if (cycle & VME_PROG)
1096 temp_ctl |= TSI148_LCSR_OTAT_PGM;
1097
1098 /* Setup mapping */
Martyn Welch29848ac2010-02-18 15:13:05 +00001099 iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001100 TSI148_LCSR_OFFSET_OTSAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001101 iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001102 TSI148_LCSR_OFFSET_OTSAL);
Martyn Welch29848ac2010-02-18 15:13:05 +00001103 iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001104 TSI148_LCSR_OFFSET_OTEAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001105 iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001106 TSI148_LCSR_OFFSET_OTEAL);
Martyn Welch29848ac2010-02-18 15:13:05 +00001107 iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001108 TSI148_LCSR_OFFSET_OTOFU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001109 iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001110 TSI148_LCSR_OFFSET_OTOFL);
1111
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001112 /* Write ctl reg without enable */
Martyn Welch29848ac2010-02-18 15:13:05 +00001113 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001114 TSI148_LCSR_OFFSET_OTAT);
1115
1116 if (enabled)
1117 temp_ctl |= TSI148_LCSR_OTAT_EN;
1118
Martyn Welch29848ac2010-02-18 15:13:05 +00001119 iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001120 TSI148_LCSR_OFFSET_OTAT);
1121
Emilio G. Cota886953e2010-11-12 11:14:07 +00001122 spin_unlock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001123 return 0;
1124
1125err_aspace:
1126err_dwidth:
1127err_gran:
1128 tsi148_free_resource(image);
1129err_res:
1130err_window:
1131 return retval;
1132
1133}
1134
1135/*
1136 * Set the attributes of an outbound window.
1137 *
1138 * XXX Not parsing prefetch information.
1139 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001140static int __tsi148_master_get(struct vme_master_resource *image, int *enabled,
Martyn Welch6af04b02011-12-01 17:06:29 +00001141 unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
1142 u32 *cycle, u32 *dwidth)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001143{
1144 unsigned int i, ctl;
1145 unsigned int pci_base_low, pci_base_high;
1146 unsigned int pci_bound_low, pci_bound_high;
1147 unsigned int vme_offset_low, vme_offset_high;
1148
1149 unsigned long long pci_base, pci_bound, vme_offset;
Martyn Welch29848ac2010-02-18 15:13:05 +00001150 struct tsi148_driver *bridge;
1151
1152 bridge = image->parent->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001153
1154 i = image->number;
1155
Martyn Welch29848ac2010-02-18 15:13:05 +00001156 ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001157 TSI148_LCSR_OFFSET_OTAT);
1158
Martyn Welch29848ac2010-02-18 15:13:05 +00001159 pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001160 TSI148_LCSR_OFFSET_OTSAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001161 pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001162 TSI148_LCSR_OFFSET_OTSAL);
Martyn Welch29848ac2010-02-18 15:13:05 +00001163 pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001164 TSI148_LCSR_OFFSET_OTEAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001165 pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001166 TSI148_LCSR_OFFSET_OTEAL);
Martyn Welch29848ac2010-02-18 15:13:05 +00001167 vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001168 TSI148_LCSR_OFFSET_OTOFU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001169 vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001170 TSI148_LCSR_OFFSET_OTOFL);
1171
1172 /* Convert 64-bit variables to 2x 32-bit variables */
1173 reg_join(pci_base_high, pci_base_low, &pci_base);
1174 reg_join(pci_bound_high, pci_bound_low, &pci_bound);
1175 reg_join(vme_offset_high, vme_offset_low, &vme_offset);
1176
1177 *vme_base = pci_base + vme_offset;
1178 *size = (unsigned long long)(pci_bound - pci_base) + 0x10000;
1179
1180 *enabled = 0;
1181 *aspace = 0;
1182 *cycle = 0;
1183 *dwidth = 0;
1184
1185 if (ctl & TSI148_LCSR_OTAT_EN)
1186 *enabled = 1;
1187
1188 /* Setup address space */
1189 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16)
1190 *aspace |= VME_A16;
1191 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24)
1192 *aspace |= VME_A24;
1193 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32)
1194 *aspace |= VME_A32;
1195 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64)
1196 *aspace |= VME_A64;
1197 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR)
1198 *aspace |= VME_CRCSR;
1199 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1)
1200 *aspace |= VME_USER1;
1201 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2)
1202 *aspace |= VME_USER2;
1203 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3)
1204 *aspace |= VME_USER3;
1205 if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4)
1206 *aspace |= VME_USER4;
1207
1208 /* Setup 2eSST speeds */
1209 if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160)
1210 *cycle |= VME_2eSST160;
1211 if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267)
1212 *cycle |= VME_2eSST267;
1213 if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320)
1214 *cycle |= VME_2eSST320;
1215
1216 /* Setup cycle types */
Martyn Welch79463282010-03-22 14:58:57 +00001217 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001218 *cycle |= VME_SCT;
Martyn Welch79463282010-03-22 14:58:57 +00001219 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001220 *cycle |= VME_BLT;
Martyn Welch79463282010-03-22 14:58:57 +00001221 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001222 *cycle |= VME_MBLT;
Martyn Welch79463282010-03-22 14:58:57 +00001223 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001224 *cycle |= VME_2eVME;
Martyn Welch79463282010-03-22 14:58:57 +00001225 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001226 *cycle |= VME_2eSST;
Martyn Welch79463282010-03-22 14:58:57 +00001227 if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001228 *cycle |= VME_2eSSTB;
1229
1230 if (ctl & TSI148_LCSR_OTAT_SUP)
1231 *cycle |= VME_SUPER;
1232 else
1233 *cycle |= VME_USER;
1234
1235 if (ctl & TSI148_LCSR_OTAT_PGM)
1236 *cycle |= VME_PROG;
1237 else
1238 *cycle |= VME_DATA;
1239
1240 /* Setup data width */
1241 if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16)
1242 *dwidth = VME_D16;
1243 if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32)
1244 *dwidth = VME_D32;
1245
1246 return 0;
1247}
1248
1249
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001250static int tsi148_master_get(struct vme_master_resource *image, int *enabled,
Martyn Welch6af04b02011-12-01 17:06:29 +00001251 unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
1252 u32 *cycle, u32 *dwidth)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001253{
1254 int retval;
1255
Emilio G. Cota886953e2010-11-12 11:14:07 +00001256 spin_lock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001257
1258 retval = __tsi148_master_get(image, enabled, vme_base, size, aspace,
1259 cycle, dwidth);
1260
Emilio G. Cota886953e2010-11-12 11:14:07 +00001261 spin_unlock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001262
1263 return retval;
1264}
1265
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001266static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001267 size_t count, loff_t offset)
1268{
1269 int retval, enabled;
1270 unsigned long long vme_base, size;
Martyn Welch6af04b02011-12-01 17:06:29 +00001271 u32 aspace, cycle, dwidth;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001272 struct vme_bus_error *vme_err = NULL;
Martyn Welch29848ac2010-02-18 15:13:05 +00001273 struct vme_bridge *tsi148_bridge;
Jingoo Han4e8764d2013-08-19 16:40:15 +09001274 void __iomem *addr = image->kern_base + offset;
Martyn Welch363e2e62012-07-19 17:48:46 +01001275 unsigned int done = 0;
1276 unsigned int count32;
Martyn Welch29848ac2010-02-18 15:13:05 +00001277
1278 tsi148_bridge = image->parent;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001279
Emilio G. Cota886953e2010-11-12 11:14:07 +00001280 spin_lock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001281
Martyn Welch363e2e62012-07-19 17:48:46 +01001282 /* The following code handles VME address alignment. We cannot use
Martyn Welcha2a720e2014-02-06 13:35:36 +00001283 * memcpy_xxx here because it may cut data transfers in to 8-bit
1284 * cycles when D16 or D32 cycles are required on the VME bus.
Martyn Welch363e2e62012-07-19 17:48:46 +01001285 * On the other hand, the bridge itself assures that the maximum data
1286 * cycle configured for the transfer is used and splits it
1287 * automatically for non-aligned addresses, so we don't want the
1288 * overhead of needlessly forcing small transfers for the entire cycle.
1289 */
1290 if ((uintptr_t)addr & 0x1) {
1291 *(u8 *)buf = ioread8(addr);
1292 done += 1;
1293 if (done == count)
1294 goto out;
1295 }
Martyn Welchf0342e62014-02-07 15:48:56 +00001296 if ((uintptr_t)(addr + done) & 0x2) {
Martyn Welch363e2e62012-07-19 17:48:46 +01001297 if ((count - done) < 2) {
1298 *(u8 *)(buf + done) = ioread8(addr + done);
1299 done += 1;
1300 goto out;
1301 } else {
1302 *(u16 *)(buf + done) = ioread16(addr + done);
1303 done += 2;
1304 }
1305 }
1306
1307 count32 = (count - done) & ~0x3;
Martyn Welcha2a720e2014-02-06 13:35:36 +00001308 while (done < count32) {
1309 *(u32 *)(buf + done) = ioread32(addr + done);
1310 done += 4;
Martyn Welch363e2e62012-07-19 17:48:46 +01001311 }
1312
1313 if ((count - done) & 0x2) {
1314 *(u16 *)(buf + done) = ioread16(addr + done);
1315 done += 2;
1316 }
1317 if ((count - done) & 0x1) {
1318 *(u8 *)(buf + done) = ioread8(addr + done);
1319 done += 1;
1320 }
1321
1322out:
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001323 retval = count;
1324
1325 if (!err_chk)
1326 goto skip_chk;
1327
1328 __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
1329 &dwidth);
1330
Martyn Welch29848ac2010-02-18 15:13:05 +00001331 vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
1332 count);
Martyn Welch79463282010-03-22 14:58:57 +00001333 if (vme_err != NULL) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001334 dev_err(image->parent->parent, "First VME read error detected "
1335 "an at address 0x%llx\n", vme_err->address);
1336 retval = vme_err->address - (vme_base + offset);
1337 /* Clear down save errors in this address range */
Martyn Welch29848ac2010-02-18 15:13:05 +00001338 tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
1339 count);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001340 }
1341
1342skip_chk:
Emilio G. Cota886953e2010-11-12 11:14:07 +00001343 spin_unlock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001344
1345 return retval;
1346}
1347
1348
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001349static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001350 size_t count, loff_t offset)
1351{
1352 int retval = 0, enabled;
1353 unsigned long long vme_base, size;
Martyn Welch6af04b02011-12-01 17:06:29 +00001354 u32 aspace, cycle, dwidth;
Jingoo Han4e8764d2013-08-19 16:40:15 +09001355 void __iomem *addr = image->kern_base + offset;
Martyn Welch363e2e62012-07-19 17:48:46 +01001356 unsigned int done = 0;
1357 unsigned int count32;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001358
1359 struct vme_bus_error *vme_err = NULL;
Martyn Welch29848ac2010-02-18 15:13:05 +00001360 struct vme_bridge *tsi148_bridge;
1361 struct tsi148_driver *bridge;
1362
1363 tsi148_bridge = image->parent;
1364
1365 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001366
Emilio G. Cota886953e2010-11-12 11:14:07 +00001367 spin_lock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001368
Martyn Welch363e2e62012-07-19 17:48:46 +01001369 /* Here we apply for the same strategy we do in master_read
Martyn Welcha2a720e2014-02-06 13:35:36 +00001370 * function in order to assure the correct cycles.
Martyn Welch363e2e62012-07-19 17:48:46 +01001371 */
1372 if ((uintptr_t)addr & 0x1) {
1373 iowrite8(*(u8 *)buf, addr);
1374 done += 1;
1375 if (done == count)
1376 goto out;
1377 }
Martyn Welchf0342e62014-02-07 15:48:56 +00001378 if ((uintptr_t)(addr + done) & 0x2) {
Martyn Welch363e2e62012-07-19 17:48:46 +01001379 if ((count - done) < 2) {
1380 iowrite8(*(u8 *)(buf + done), addr + done);
1381 done += 1;
1382 goto out;
1383 } else {
1384 iowrite16(*(u16 *)(buf + done), addr + done);
1385 done += 2;
1386 }
1387 }
1388
1389 count32 = (count - done) & ~0x3;
Martyn Welcha2a720e2014-02-06 13:35:36 +00001390 while (done < count32) {
1391 iowrite32(*(u32 *)(buf + done), addr + done);
1392 done += 4;
Martyn Welch363e2e62012-07-19 17:48:46 +01001393 }
1394
1395 if ((count - done) & 0x2) {
1396 iowrite16(*(u16 *)(buf + done), addr + done);
1397 done += 2;
1398 }
1399 if ((count - done) & 0x1) {
1400 iowrite8(*(u8 *)(buf + done), addr + done);
1401 done += 1;
1402 }
1403
1404out:
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001405 retval = count;
1406
1407 /*
1408 * Writes are posted. We need to do a read on the VME bus to flush out
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001409 * all of the writes before we check for errors. We can't guarantee
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001410 * that reading the data we have just written is safe. It is believed
1411 * that there isn't any read, write re-ordering, so we can read any
1412 * location in VME space, so lets read the Device ID from the tsi148's
1413 * own registers as mapped into CR/CSR space.
1414 *
1415 * We check for saved errors in the written address range/space.
1416 */
1417
1418 if (!err_chk)
1419 goto skip_chk;
1420
1421 /*
1422 * Get window info first, to maximise the time that the buffers may
1423 * fluch on their own
1424 */
1425 __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle,
1426 &dwidth);
1427
Martyn Welch29848ac2010-02-18 15:13:05 +00001428 ioread16(bridge->flush_image->kern_base + 0x7F000);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001429
Martyn Welch29848ac2010-02-18 15:13:05 +00001430 vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset,
1431 count);
Martyn Welch79463282010-03-22 14:58:57 +00001432 if (vme_err != NULL) {
Martyn Welch48d93562010-03-22 14:58:50 +00001433 dev_warn(tsi148_bridge->parent, "First VME write error detected"
1434 " an at address 0x%llx\n", vme_err->address);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001435 retval = vme_err->address - (vme_base + offset);
1436 /* Clear down save errors in this address range */
Martyn Welch29848ac2010-02-18 15:13:05 +00001437 tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset,
1438 count);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001439 }
1440
1441skip_chk:
Emilio G. Cota886953e2010-11-12 11:14:07 +00001442 spin_unlock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001443
1444 return retval;
1445}
1446
1447/*
1448 * Perform an RMW cycle on the VME bus.
1449 *
1450 * Requires a previously configured master window, returns final value.
1451 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001452static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001453 unsigned int mask, unsigned int compare, unsigned int swap,
1454 loff_t offset)
1455{
1456 unsigned long long pci_addr;
1457 unsigned int pci_addr_high, pci_addr_low;
1458 u32 tmp, result;
1459 int i;
Martyn Welch29848ac2010-02-18 15:13:05 +00001460 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001461
Martyn Welch29848ac2010-02-18 15:13:05 +00001462 bridge = image->parent->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001463
1464 /* Find the PCI address that maps to the desired VME address */
1465 i = image->number;
1466
1467 /* Locking as we can only do one of these at a time */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001468 mutex_lock(&bridge->vme_rmw);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001469
1470 /* Lock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001471 spin_lock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001472
Martyn Welch29848ac2010-02-18 15:13:05 +00001473 pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001474 TSI148_LCSR_OFFSET_OTSAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001475 pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001476 TSI148_LCSR_OFFSET_OTSAL);
1477
1478 reg_join(pci_addr_high, pci_addr_low, &pci_addr);
1479 reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low);
1480
1481 /* Configure registers */
Martyn Welch29848ac2010-02-18 15:13:05 +00001482 iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN);
1483 iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC);
1484 iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS);
1485 iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU);
1486 iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001487
1488 /* Enable RMW */
Martyn Welch29848ac2010-02-18 15:13:05 +00001489 tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001490 tmp |= TSI148_LCSR_VMCTRL_RMWEN;
Martyn Welch29848ac2010-02-18 15:13:05 +00001491 iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001492
1493 /* Kick process off with a read to the required address. */
1494 result = ioread32be(image->kern_base + offset);
1495
1496 /* Disable RMW */
Martyn Welch29848ac2010-02-18 15:13:05 +00001497 tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001498 tmp &= ~TSI148_LCSR_VMCTRL_RMWEN;
Martyn Welch29848ac2010-02-18 15:13:05 +00001499 iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001500
Emilio G. Cota886953e2010-11-12 11:14:07 +00001501 spin_unlock(&image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001502
Emilio G. Cota886953e2010-11-12 11:14:07 +00001503 mutex_unlock(&bridge->vme_rmw);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001504
1505 return result;
1506}
1507
Martyn Welchac1a4f22012-03-22 13:27:30 +00001508static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr,
Martyn Welch6af04b02011-12-01 17:06:29 +00001509 u32 aspace, u32 cycle, u32 dwidth)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001510{
Martyn Welchac1a4f22012-03-22 13:27:30 +00001511 u32 val;
1512
1513 val = be32_to_cpu(*attr);
1514
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001515 /* Setup 2eSST speeds */
1516 switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
1517 case VME_2eSST160:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001518 val |= TSI148_LCSR_DSAT_2eSSTM_160;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001519 break;
1520 case VME_2eSST267:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001521 val |= TSI148_LCSR_DSAT_2eSSTM_267;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001522 break;
1523 case VME_2eSST320:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001524 val |= TSI148_LCSR_DSAT_2eSSTM_320;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001525 break;
1526 }
1527
1528 /* Setup cycle types */
Martyn Welch79463282010-03-22 14:58:57 +00001529 if (cycle & VME_SCT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001530 val |= TSI148_LCSR_DSAT_TM_SCT;
Martyn Welch79463282010-03-22 14:58:57 +00001531
1532 if (cycle & VME_BLT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001533 val |= TSI148_LCSR_DSAT_TM_BLT;
Martyn Welch79463282010-03-22 14:58:57 +00001534
1535 if (cycle & VME_MBLT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001536 val |= TSI148_LCSR_DSAT_TM_MBLT;
Martyn Welch79463282010-03-22 14:58:57 +00001537
1538 if (cycle & VME_2eVME)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001539 val |= TSI148_LCSR_DSAT_TM_2eVME;
Martyn Welch79463282010-03-22 14:58:57 +00001540
1541 if (cycle & VME_2eSST)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001542 val |= TSI148_LCSR_DSAT_TM_2eSST;
Martyn Welch79463282010-03-22 14:58:57 +00001543
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001544 if (cycle & VME_2eSSTB) {
Martyn Welch48d93562010-03-22 14:58:50 +00001545 dev_err(dev, "Currently not setting Broadcast Select "
1546 "Registers\n");
Martyn Welchac1a4f22012-03-22 13:27:30 +00001547 val |= TSI148_LCSR_DSAT_TM_2eSSTB;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001548 }
1549
1550 /* Setup data width */
1551 switch (dwidth) {
1552 case VME_D16:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001553 val |= TSI148_LCSR_DSAT_DBW_16;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001554 break;
1555 case VME_D32:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001556 val |= TSI148_LCSR_DSAT_DBW_32;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001557 break;
1558 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001559 dev_err(dev, "Invalid data width\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001560 return -EINVAL;
1561 }
1562
1563 /* Setup address space */
1564 switch (aspace) {
1565 case VME_A16:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001566 val |= TSI148_LCSR_DSAT_AMODE_A16;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001567 break;
1568 case VME_A24:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001569 val |= TSI148_LCSR_DSAT_AMODE_A24;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001570 break;
1571 case VME_A32:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001572 val |= TSI148_LCSR_DSAT_AMODE_A32;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001573 break;
1574 case VME_A64:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001575 val |= TSI148_LCSR_DSAT_AMODE_A64;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001576 break;
1577 case VME_CRCSR:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001578 val |= TSI148_LCSR_DSAT_AMODE_CRCSR;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001579 break;
1580 case VME_USER1:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001581 val |= TSI148_LCSR_DSAT_AMODE_USER1;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001582 break;
1583 case VME_USER2:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001584 val |= TSI148_LCSR_DSAT_AMODE_USER2;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001585 break;
1586 case VME_USER3:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001587 val |= TSI148_LCSR_DSAT_AMODE_USER3;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001588 break;
1589 case VME_USER4:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001590 val |= TSI148_LCSR_DSAT_AMODE_USER4;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001591 break;
1592 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001593 dev_err(dev, "Invalid address space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001594 return -EINVAL;
1595 break;
1596 }
1597
1598 if (cycle & VME_SUPER)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001599 val |= TSI148_LCSR_DSAT_SUP;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001600 if (cycle & VME_PROG)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001601 val |= TSI148_LCSR_DSAT_PGM;
1602
1603 *attr = cpu_to_be32(val);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001604
1605 return 0;
1606}
1607
Martyn Welchac1a4f22012-03-22 13:27:30 +00001608static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr,
Martyn Welch6af04b02011-12-01 17:06:29 +00001609 u32 aspace, u32 cycle, u32 dwidth)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001610{
Martyn Welchac1a4f22012-03-22 13:27:30 +00001611 u32 val;
1612
1613 val = be32_to_cpu(*attr);
1614
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001615 /* Setup 2eSST speeds */
1616 switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
1617 case VME_2eSST160:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001618 val |= TSI148_LCSR_DDAT_2eSSTM_160;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001619 break;
1620 case VME_2eSST267:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001621 val |= TSI148_LCSR_DDAT_2eSSTM_267;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001622 break;
1623 case VME_2eSST320:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001624 val |= TSI148_LCSR_DDAT_2eSSTM_320;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001625 break;
1626 }
1627
1628 /* Setup cycle types */
Martyn Welch79463282010-03-22 14:58:57 +00001629 if (cycle & VME_SCT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001630 val |= TSI148_LCSR_DDAT_TM_SCT;
Martyn Welch79463282010-03-22 14:58:57 +00001631
1632 if (cycle & VME_BLT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001633 val |= TSI148_LCSR_DDAT_TM_BLT;
Martyn Welch79463282010-03-22 14:58:57 +00001634
1635 if (cycle & VME_MBLT)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001636 val |= TSI148_LCSR_DDAT_TM_MBLT;
Martyn Welch79463282010-03-22 14:58:57 +00001637
1638 if (cycle & VME_2eVME)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001639 val |= TSI148_LCSR_DDAT_TM_2eVME;
Martyn Welch79463282010-03-22 14:58:57 +00001640
1641 if (cycle & VME_2eSST)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001642 val |= TSI148_LCSR_DDAT_TM_2eSST;
Martyn Welch79463282010-03-22 14:58:57 +00001643
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001644 if (cycle & VME_2eSSTB) {
Martyn Welch48d93562010-03-22 14:58:50 +00001645 dev_err(dev, "Currently not setting Broadcast Select "
1646 "Registers\n");
Martyn Welchac1a4f22012-03-22 13:27:30 +00001647 val |= TSI148_LCSR_DDAT_TM_2eSSTB;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001648 }
1649
1650 /* Setup data width */
1651 switch (dwidth) {
1652 case VME_D16:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001653 val |= TSI148_LCSR_DDAT_DBW_16;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001654 break;
1655 case VME_D32:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001656 val |= TSI148_LCSR_DDAT_DBW_32;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001657 break;
1658 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001659 dev_err(dev, "Invalid data width\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001660 return -EINVAL;
1661 }
1662
1663 /* Setup address space */
1664 switch (aspace) {
1665 case VME_A16:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001666 val |= TSI148_LCSR_DDAT_AMODE_A16;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001667 break;
1668 case VME_A24:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001669 val |= TSI148_LCSR_DDAT_AMODE_A24;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001670 break;
1671 case VME_A32:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001672 val |= TSI148_LCSR_DDAT_AMODE_A32;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001673 break;
1674 case VME_A64:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001675 val |= TSI148_LCSR_DDAT_AMODE_A64;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001676 break;
1677 case VME_CRCSR:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001678 val |= TSI148_LCSR_DDAT_AMODE_CRCSR;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001679 break;
1680 case VME_USER1:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001681 val |= TSI148_LCSR_DDAT_AMODE_USER1;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001682 break;
1683 case VME_USER2:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001684 val |= TSI148_LCSR_DDAT_AMODE_USER2;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001685 break;
1686 case VME_USER3:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001687 val |= TSI148_LCSR_DDAT_AMODE_USER3;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001688 break;
1689 case VME_USER4:
Martyn Welchac1a4f22012-03-22 13:27:30 +00001690 val |= TSI148_LCSR_DDAT_AMODE_USER4;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001691 break;
1692 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001693 dev_err(dev, "Invalid address space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001694 return -EINVAL;
1695 break;
1696 }
1697
1698 if (cycle & VME_SUPER)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001699 val |= TSI148_LCSR_DDAT_SUP;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001700 if (cycle & VME_PROG)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001701 val |= TSI148_LCSR_DDAT_PGM;
1702
1703 *attr = cpu_to_be32(val);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001704
1705 return 0;
1706}
1707
1708/*
1709 * Add a link list descriptor to the list
Martyn Welchac1a4f22012-03-22 13:27:30 +00001710 *
1711 * Note: DMA engine expects the DMA descriptor to be big endian.
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001712 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001713static int tsi148_dma_list_add(struct vme_dma_list *list,
1714 struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001715{
1716 struct tsi148_dma_entry *entry, *prev;
Martyn Welchac1a4f22012-03-22 13:27:30 +00001717 u32 address_high, address_low, val;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001718 struct vme_dma_pattern *pattern_attr;
1719 struct vme_dma_pci *pci_attr;
1720 struct vme_dma_vme *vme_attr;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001721 int retval = 0;
Martyn Welch48d93562010-03-22 14:58:50 +00001722 struct vme_bridge *tsi148_bridge;
1723
1724 tsi148_bridge = list->parent->parent;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001725
Martyn Welchbb9ea892010-02-18 16:22:13 +00001726 /* Descriptor must be aligned on 64-bit boundaries */
Martyn Welch79463282010-03-22 14:58:57 +00001727 entry = kmalloc(sizeof(struct tsi148_dma_entry), GFP_KERNEL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001728 if (entry == NULL) {
Martyn Welch48d93562010-03-22 14:58:50 +00001729 dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
1730 "dma resource structure\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001731 retval = -ENOMEM;
1732 goto err_mem;
1733 }
1734
1735 /* Test descriptor alignment */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001736 if ((unsigned long)&entry->descriptor & 0x7) {
Martyn Welch48d93562010-03-22 14:58:50 +00001737 dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 "
1738 "byte boundary as required: %p\n",
Emilio G. Cota886953e2010-11-12 11:14:07 +00001739 &entry->descriptor);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001740 retval = -EINVAL;
1741 goto err_align;
1742 }
1743
1744 /* Given we are going to fill out the structure, we probably don't
1745 * need to zero it, but better safe than sorry for now.
1746 */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001747 memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor));
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001748
1749 /* Fill out source part */
1750 switch (src->type) {
1751 case VME_DMA_PATTERN:
Kulikov Vasiliyc4d82fb2010-06-29 14:16:20 +04001752 pattern_attr = src->private;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001753
Martyn Welchac1a4f22012-03-22 13:27:30 +00001754 entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern);
1755
1756 val = TSI148_LCSR_DSAT_TYP_PAT;
1757
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001758 /* Default behaviour is 32 bit pattern */
Martyn Welch79463282010-03-22 14:58:57 +00001759 if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001760 val |= TSI148_LCSR_DSAT_PSZ;
Martyn Welch79463282010-03-22 14:58:57 +00001761
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001762 /* It seems that the default behaviour is to increment */
Martyn Welch79463282010-03-22 14:58:57 +00001763 if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
Martyn Welchac1a4f22012-03-22 13:27:30 +00001764 val |= TSI148_LCSR_DSAT_NIN;
1765 entry->descriptor.dsat = cpu_to_be32(val);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001766 break;
1767 case VME_DMA_PCI:
Kulikov Vasiliyc4d82fb2010-06-29 14:16:20 +04001768 pci_attr = src->private;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001769
1770 reg_split((unsigned long long)pci_attr->address, &address_high,
1771 &address_low);
Martyn Welchac1a4f22012-03-22 13:27:30 +00001772 entry->descriptor.dsau = cpu_to_be32(address_high);
1773 entry->descriptor.dsal = cpu_to_be32(address_low);
1774 entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001775 break;
1776 case VME_DMA_VME:
Kulikov Vasiliyc4d82fb2010-06-29 14:16:20 +04001777 vme_attr = src->private;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001778
1779 reg_split((unsigned long long)vme_attr->address, &address_high,
1780 &address_low);
Martyn Welchac1a4f22012-03-22 13:27:30 +00001781 entry->descriptor.dsau = cpu_to_be32(address_high);
1782 entry->descriptor.dsal = cpu_to_be32(address_low);
1783 entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001784
1785 retval = tsi148_dma_set_vme_src_attributes(
Emilio G. Cota886953e2010-11-12 11:14:07 +00001786 tsi148_bridge->parent, &entry->descriptor.dsat,
Martyn Welch48d93562010-03-22 14:58:50 +00001787 vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
Martyn Welch79463282010-03-22 14:58:57 +00001788 if (retval < 0)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001789 goto err_source;
1790 break;
1791 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001792 dev_err(tsi148_bridge->parent, "Invalid source type\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001793 retval = -EINVAL;
1794 goto err_source;
1795 break;
1796 }
1797
1798 /* Assume last link - this will be over-written by adding another */
Martyn Welchac1a4f22012-03-22 13:27:30 +00001799 entry->descriptor.dnlau = cpu_to_be32(0);
1800 entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001801
1802 /* Fill out destination part */
1803 switch (dest->type) {
1804 case VME_DMA_PCI:
Kulikov Vasiliyc4d82fb2010-06-29 14:16:20 +04001805 pci_attr = dest->private;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001806
1807 reg_split((unsigned long long)pci_attr->address, &address_high,
1808 &address_low);
Martyn Welchac1a4f22012-03-22 13:27:30 +00001809 entry->descriptor.ddau = cpu_to_be32(address_high);
1810 entry->descriptor.ddal = cpu_to_be32(address_low);
1811 entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001812 break;
1813 case VME_DMA_VME:
Kulikov Vasiliyc4d82fb2010-06-29 14:16:20 +04001814 vme_attr = dest->private;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001815
1816 reg_split((unsigned long long)vme_attr->address, &address_high,
1817 &address_low);
Martyn Welchac1a4f22012-03-22 13:27:30 +00001818 entry->descriptor.ddau = cpu_to_be32(address_high);
1819 entry->descriptor.ddal = cpu_to_be32(address_low);
1820 entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001821
1822 retval = tsi148_dma_set_vme_dest_attributes(
Emilio G. Cota886953e2010-11-12 11:14:07 +00001823 tsi148_bridge->parent, &entry->descriptor.ddat,
Martyn Welch48d93562010-03-22 14:58:50 +00001824 vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth);
Martyn Welch79463282010-03-22 14:58:57 +00001825 if (retval < 0)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001826 goto err_dest;
1827 break;
1828 default:
Martyn Welch48d93562010-03-22 14:58:50 +00001829 dev_err(tsi148_bridge->parent, "Invalid destination type\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001830 retval = -EINVAL;
1831 goto err_dest;
1832 break;
1833 }
1834
1835 /* Fill out count */
Martyn Welchac1a4f22012-03-22 13:27:30 +00001836 entry->descriptor.dcnt = cpu_to_be32((u32)count);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001837
1838 /* Add to list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001839 list_add_tail(&entry->list, &list->entries);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001840
1841 /* Fill out previous descriptors "Next Address" */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001842 if (entry->list.prev != &list->entries) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001843 prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
1844 list);
1845 /* We need the bus address for the pointer */
Martyn Welch3abc48a2012-03-22 13:27:29 +00001846 entry->dma_handle = dma_map_single(tsi148_bridge->parent,
1847 &entry->descriptor,
1848 sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
1849
Martyn Welchac1a4f22012-03-22 13:27:30 +00001850 reg_split((unsigned long long)entry->dma_handle, &address_high,
1851 &address_low);
1852 entry->descriptor.dnlau = cpu_to_be32(address_high);
1853 entry->descriptor.dnlal = cpu_to_be32(address_low);
1854
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001855 }
1856
1857 return 0;
1858
1859err_dest:
1860err_source:
1861err_align:
1862 kfree(entry);
1863err_mem:
1864 return retval;
1865}
1866
1867/*
1868 * Check to see if the provided DMA channel is busy.
1869 */
Martyn Welch29848ac2010-02-18 15:13:05 +00001870static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001871{
1872 u32 tmp;
Martyn Welch29848ac2010-02-18 15:13:05 +00001873 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001874
Martyn Welch29848ac2010-02-18 15:13:05 +00001875 bridge = tsi148_bridge->driver_priv;
1876
1877 tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001878 TSI148_LCSR_OFFSET_DSTA);
1879
1880 if (tmp & TSI148_LCSR_DSTA_BSY)
1881 return 0;
1882 else
1883 return 1;
1884
1885}
1886
1887/*
1888 * Execute a previously generated link list
1889 *
1890 * XXX Need to provide control register configuration.
1891 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001892static int tsi148_dma_list_exec(struct vme_dma_list *list)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001893{
1894 struct vme_dma_resource *ctrlr;
1895 int channel, retval = 0;
1896 struct tsi148_dma_entry *entry;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001897 u32 bus_addr_high, bus_addr_low;
1898 u32 val, dctlreg = 0;
Martyn Welch48d93562010-03-22 14:58:50 +00001899 struct vme_bridge *tsi148_bridge;
Martyn Welch29848ac2010-02-18 15:13:05 +00001900 struct tsi148_driver *bridge;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001901
1902 ctrlr = list->parent;
1903
Martyn Welch48d93562010-03-22 14:58:50 +00001904 tsi148_bridge = ctrlr->parent;
1905
1906 bridge = tsi148_bridge->driver_priv;
Martyn Welch29848ac2010-02-18 15:13:05 +00001907
Emilio G. Cota886953e2010-11-12 11:14:07 +00001908 mutex_lock(&ctrlr->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001909
1910 channel = ctrlr->number;
1911
Emilio G. Cota886953e2010-11-12 11:14:07 +00001912 if (!list_empty(&ctrlr->running)) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001913 /*
1914 * XXX We have an active DMA transfer and currently haven't
1915 * sorted out the mechanism for "pending" DMA transfers.
1916 * Return busy.
1917 */
1918 /* Need to add to pending here */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001919 mutex_unlock(&ctrlr->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001920 return -EBUSY;
1921 } else {
Emilio G. Cota886953e2010-11-12 11:14:07 +00001922 list_add(&list->list, &ctrlr->running);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001923 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001924
1925 /* Get first bus address and write into registers */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001926 entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001927 list);
1928
Martyn Welch3abc48a2012-03-22 13:27:29 +00001929 entry->dma_handle = dma_map_single(tsi148_bridge->parent,
1930 &entry->descriptor,
1931 sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001932
Emilio G. Cota886953e2010-11-12 11:14:07 +00001933 mutex_unlock(&ctrlr->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001934
Martyn Welch3abc48a2012-03-22 13:27:29 +00001935 reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001936
Martyn Welch29848ac2010-02-18 15:13:05 +00001937 iowrite32be(bus_addr_high, bridge->base +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001938 TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
Martyn Welch29848ac2010-02-18 15:13:05 +00001939 iowrite32be(bus_addr_low, bridge->base +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001940 TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
1941
Martyn Welchac1a4f22012-03-22 13:27:30 +00001942 dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
1943 TSI148_LCSR_OFFSET_DCTL);
1944
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001945 /* Start the operation */
Martyn Welch29848ac2010-02-18 15:13:05 +00001946 iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001947 TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
1948
Martyn Welch29848ac2010-02-18 15:13:05 +00001949 wait_event_interruptible(bridge->dma_queue[channel],
1950 tsi148_dma_busy(ctrlr->parent, channel));
Martyn Welchac1a4f22012-03-22 13:27:30 +00001951
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001952 /*
1953 * Read status register, this register is valid until we kick off a
1954 * new transfer.
1955 */
Martyn Welch29848ac2010-02-18 15:13:05 +00001956 val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001957 TSI148_LCSR_OFFSET_DSTA);
1958
1959 if (val & TSI148_LCSR_DSTA_VBE) {
Martyn Welch48d93562010-03-22 14:58:50 +00001960 dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001961 retval = -EIO;
1962 }
1963
1964 /* Remove list from running list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001965 mutex_lock(&ctrlr->mtx);
1966 list_del(&list->list);
1967 mutex_unlock(&ctrlr->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001968
1969 return retval;
1970}
1971
1972/*
1973 * Clean up a previously generated link list
1974 *
1975 * We have a separate function, don't assume that the chain can't be reused.
1976 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00001977static int tsi148_dma_list_empty(struct vme_dma_list *list)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001978{
1979 struct list_head *pos, *temp;
Martyn Welch79463282010-03-22 14:58:57 +00001980 struct tsi148_dma_entry *entry;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001981
Martyn Welch3abc48a2012-03-22 13:27:29 +00001982 struct vme_bridge *tsi148_bridge = list->parent->parent;
1983
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001984 /* detach and free each entry */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001985 list_for_each_safe(pos, temp, &list->entries) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001986 list_del(pos);
1987 entry = list_entry(pos, struct tsi148_dma_entry, list);
Martyn Welch3abc48a2012-03-22 13:27:29 +00001988
1989 dma_unmap_single(tsi148_bridge->parent, entry->dma_handle,
1990 sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001991 kfree(entry);
1992 }
1993
Martyn Welch79463282010-03-22 14:58:57 +00001994 return 0;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01001995}
1996
1997/*
1998 * All 4 location monitors reside at the same base - this is therefore a
1999 * system wide configuration.
2000 *
2001 * This does not enable the LM monitor - that should be done when the first
2002 * callback is attached and disabled when the last callback is removed.
2003 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00002004static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
Martyn Welch6af04b02011-12-01 17:06:29 +00002005 u32 aspace, u32 cycle)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002006{
2007 u32 lm_base_high, lm_base_low, lm_ctl = 0;
2008 int i;
Martyn Welch48d93562010-03-22 14:58:50 +00002009 struct vme_bridge *tsi148_bridge;
Martyn Welch29848ac2010-02-18 15:13:05 +00002010 struct tsi148_driver *bridge;
2011
Martyn Welch48d93562010-03-22 14:58:50 +00002012 tsi148_bridge = lm->parent;
2013
2014 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002015
Emilio G. Cota886953e2010-11-12 11:14:07 +00002016 mutex_lock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002017
2018 /* If we already have a callback attached, we can't move it! */
Martyn Welch42fb5032009-08-11 17:44:56 +01002019 for (i = 0; i < lm->monitors; i++) {
Martyn Welch29848ac2010-02-18 15:13:05 +00002020 if (bridge->lm_callback[i] != NULL) {
Emilio G. Cota886953e2010-11-12 11:14:07 +00002021 mutex_unlock(&lm->mtx);
Martyn Welch48d93562010-03-22 14:58:50 +00002022 dev_err(tsi148_bridge->parent, "Location monitor "
2023 "callback attached, can't reset\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002024 return -EBUSY;
2025 }
2026 }
2027
2028 switch (aspace) {
2029 case VME_A16:
2030 lm_ctl |= TSI148_LCSR_LMAT_AS_A16;
2031 break;
2032 case VME_A24:
2033 lm_ctl |= TSI148_LCSR_LMAT_AS_A24;
2034 break;
2035 case VME_A32:
2036 lm_ctl |= TSI148_LCSR_LMAT_AS_A32;
2037 break;
2038 case VME_A64:
2039 lm_ctl |= TSI148_LCSR_LMAT_AS_A64;
2040 break;
2041 default:
Emilio G. Cota886953e2010-11-12 11:14:07 +00002042 mutex_unlock(&lm->mtx);
Martyn Welch48d93562010-03-22 14:58:50 +00002043 dev_err(tsi148_bridge->parent, "Invalid address space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002044 return -EINVAL;
2045 break;
2046 }
2047
2048 if (cycle & VME_SUPER)
2049 lm_ctl |= TSI148_LCSR_LMAT_SUPR ;
2050 if (cycle & VME_USER)
2051 lm_ctl |= TSI148_LCSR_LMAT_NPRIV;
2052 if (cycle & VME_PROG)
2053 lm_ctl |= TSI148_LCSR_LMAT_PGM;
2054 if (cycle & VME_DATA)
2055 lm_ctl |= TSI148_LCSR_LMAT_DATA;
2056
2057 reg_split(lm_base, &lm_base_high, &lm_base_low);
2058
Martyn Welch29848ac2010-02-18 15:13:05 +00002059 iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU);
2060 iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL);
2061 iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002062
Emilio G. Cota886953e2010-11-12 11:14:07 +00002063 mutex_unlock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002064
2065 return 0;
2066}
2067
2068/* Get configuration of the callback monitor and return whether it is enabled
2069 * or disabled.
2070 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00002071static int tsi148_lm_get(struct vme_lm_resource *lm,
Martyn Welch6af04b02011-12-01 17:06:29 +00002072 unsigned long long *lm_base, u32 *aspace, u32 *cycle)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002073{
2074 u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0;
Martyn Welch29848ac2010-02-18 15:13:05 +00002075 struct tsi148_driver *bridge;
2076
2077 bridge = lm->parent->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002078
Emilio G. Cota886953e2010-11-12 11:14:07 +00002079 mutex_lock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002080
Martyn Welch29848ac2010-02-18 15:13:05 +00002081 lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU);
2082 lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL);
2083 lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002084
2085 reg_join(lm_base_high, lm_base_low, lm_base);
2086
2087 if (lm_ctl & TSI148_LCSR_LMAT_EN)
2088 enabled = 1;
2089
Martyn Welch79463282010-03-22 14:58:57 +00002090 if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002091 *aspace |= VME_A16;
Martyn Welch79463282010-03-22 14:58:57 +00002092
2093 if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002094 *aspace |= VME_A24;
Martyn Welch79463282010-03-22 14:58:57 +00002095
2096 if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002097 *aspace |= VME_A32;
Martyn Welch79463282010-03-22 14:58:57 +00002098
2099 if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002100 *aspace |= VME_A64;
Martyn Welch79463282010-03-22 14:58:57 +00002101
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002102
2103 if (lm_ctl & TSI148_LCSR_LMAT_SUPR)
2104 *cycle |= VME_SUPER;
2105 if (lm_ctl & TSI148_LCSR_LMAT_NPRIV)
2106 *cycle |= VME_USER;
2107 if (lm_ctl & TSI148_LCSR_LMAT_PGM)
2108 *cycle |= VME_PROG;
2109 if (lm_ctl & TSI148_LCSR_LMAT_DATA)
2110 *cycle |= VME_DATA;
2111
Emilio G. Cota886953e2010-11-12 11:14:07 +00002112 mutex_unlock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002113
2114 return enabled;
2115}
2116
2117/*
2118 * Attach a callback to a specific location monitor.
2119 *
2120 * Callback will be passed the monitor triggered.
2121 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00002122static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
Martyn Welch42fb5032009-08-11 17:44:56 +01002123 void (*callback)(int))
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002124{
2125 u32 lm_ctl, tmp;
Martyn Welch48d93562010-03-22 14:58:50 +00002126 struct vme_bridge *tsi148_bridge;
Martyn Welch29848ac2010-02-18 15:13:05 +00002127 struct tsi148_driver *bridge;
2128
Martyn Welch48d93562010-03-22 14:58:50 +00002129 tsi148_bridge = lm->parent;
2130
2131 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002132
Emilio G. Cota886953e2010-11-12 11:14:07 +00002133 mutex_lock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002134
2135 /* Ensure that the location monitor is configured - need PGM or DATA */
Martyn Welch29848ac2010-02-18 15:13:05 +00002136 lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002137 if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) {
Emilio G. Cota886953e2010-11-12 11:14:07 +00002138 mutex_unlock(&lm->mtx);
Martyn Welch48d93562010-03-22 14:58:50 +00002139 dev_err(tsi148_bridge->parent, "Location monitor not properly "
2140 "configured\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002141 return -EINVAL;
2142 }
2143
2144 /* Check that a callback isn't already attached */
Martyn Welch29848ac2010-02-18 15:13:05 +00002145 if (bridge->lm_callback[monitor] != NULL) {
Emilio G. Cota886953e2010-11-12 11:14:07 +00002146 mutex_unlock(&lm->mtx);
Martyn Welch48d93562010-03-22 14:58:50 +00002147 dev_err(tsi148_bridge->parent, "Existing callback attached\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002148 return -EBUSY;
2149 }
2150
2151 /* Attach callback */
Martyn Welch29848ac2010-02-18 15:13:05 +00002152 bridge->lm_callback[monitor] = callback;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002153
2154 /* Enable Location Monitor interrupt */
Martyn Welch29848ac2010-02-18 15:13:05 +00002155 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002156 tmp |= TSI148_LCSR_INTEN_LMEN[monitor];
Martyn Welch29848ac2010-02-18 15:13:05 +00002157 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002158
Martyn Welch29848ac2010-02-18 15:13:05 +00002159 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002160 tmp |= TSI148_LCSR_INTEO_LMEO[monitor];
Martyn Welch29848ac2010-02-18 15:13:05 +00002161 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002162
2163 /* Ensure that global Location Monitor Enable set */
2164 if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) {
2165 lm_ctl |= TSI148_LCSR_LMAT_EN;
Martyn Welch29848ac2010-02-18 15:13:05 +00002166 iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002167 }
2168
Emilio G. Cota886953e2010-11-12 11:14:07 +00002169 mutex_unlock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002170
2171 return 0;
2172}
2173
2174/*
2175 * Detach a callback function forn a specific location monitor.
2176 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00002177static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002178{
2179 u32 lm_en, tmp;
Martyn Welch29848ac2010-02-18 15:13:05 +00002180 struct tsi148_driver *bridge;
2181
2182 bridge = lm->parent->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002183
Emilio G. Cota886953e2010-11-12 11:14:07 +00002184 mutex_lock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002185
2186 /* Disable Location Monitor and ensure previous interrupts are clear */
Martyn Welch29848ac2010-02-18 15:13:05 +00002187 lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002188 lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor];
Martyn Welch29848ac2010-02-18 15:13:05 +00002189 iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002190
Martyn Welch29848ac2010-02-18 15:13:05 +00002191 tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002192 tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor];
Martyn Welch29848ac2010-02-18 15:13:05 +00002193 iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002194
2195 iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
Martyn Welch29848ac2010-02-18 15:13:05 +00002196 bridge->base + TSI148_LCSR_INTC);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002197
2198 /* Detach callback */
Martyn Welch29848ac2010-02-18 15:13:05 +00002199 bridge->lm_callback[monitor] = NULL;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002200
2201 /* If all location monitors disabled, disable global Location Monitor */
2202 if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
2203 TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) {
Martyn Welch29848ac2010-02-18 15:13:05 +00002204 tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002205 tmp &= ~TSI148_LCSR_LMAT_EN;
Martyn Welch29848ac2010-02-18 15:13:05 +00002206 iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002207 }
2208
Emilio G. Cota886953e2010-11-12 11:14:07 +00002209 mutex_unlock(&lm->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002210
2211 return 0;
2212}
2213
2214/*
2215 * Determine Geographical Addressing
2216 */
Emilio G. Cota5ade6c42010-11-12 11:15:00 +00002217static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002218{
Martyn Welch79463282010-03-22 14:58:57 +00002219 u32 slot = 0;
Martyn Welch29848ac2010-02-18 15:13:05 +00002220 struct tsi148_driver *bridge;
2221
2222 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002223
Martyn Welch638f1992009-12-15 08:42:49 +00002224 if (!geoid) {
Martyn Welch29848ac2010-02-18 15:13:05 +00002225 slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT);
Martyn Welch638f1992009-12-15 08:42:49 +00002226 slot = slot & TSI148_LCSR_VSTAT_GA_M;
2227 } else
2228 slot = geoid;
2229
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002230 return (int)slot;
2231}
2232
H Hartley Sweeten lin8a508ff2012-05-02 17:08:38 -07002233static void *tsi148_alloc_consistent(struct device *parent, size_t size,
Manohar Vanga7f58f022011-08-10 11:33:46 +02002234 dma_addr_t *dma)
2235{
2236 struct pci_dev *pdev;
2237
2238 /* Find pci_dev container of dev */
Aaron Sierra177581fa2014-04-03 14:48:27 -05002239 pdev = to_pci_dev(parent);
Manohar Vanga7f58f022011-08-10 11:33:46 +02002240
2241 return pci_alloc_consistent(pdev, size, dma);
2242}
2243
H Hartley Sweeten lin8a508ff2012-05-02 17:08:38 -07002244static void tsi148_free_consistent(struct device *parent, size_t size,
2245 void *vaddr, dma_addr_t dma)
Manohar Vanga7f58f022011-08-10 11:33:46 +02002246{
2247 struct pci_dev *pdev;
2248
2249 /* Find pci_dev container of dev */
Aaron Sierra177581fa2014-04-03 14:48:27 -05002250 pdev = to_pci_dev(parent);
Manohar Vanga7f58f022011-08-10 11:33:46 +02002251
2252 pci_free_consistent(pdev, size, vaddr, dma);
2253}
2254
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002255/*
2256 * Configure CR/CSR space
2257 *
2258 * Access to the CR/CSR can be configured at power-up. The location of the
2259 * CR/CSR registers in the CR/CSR address space is determined by the boards
2260 * Auto-ID or Geographic address. This function ensures that the window is
2261 * enabled at an offset consistent with the boards geopgraphic address.
2262 *
2263 * Each board has a 512kB window, with the highest 4kB being used for the
2264 * boards registers, this means there is a fix length 508kB window which must
2265 * be mapped onto PCI memory.
2266 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002267static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge,
2268 struct pci_dev *pdev)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002269{
2270 u32 cbar, crat, vstat;
2271 u32 crcsr_bus_high, crcsr_bus_low;
2272 int retval;
Martyn Welch29848ac2010-02-18 15:13:05 +00002273 struct tsi148_driver *bridge;
2274
2275 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002276
2277 /* Allocate mem for CR/CSR image */
Martyn Welch29848ac2010-02-18 15:13:05 +00002278 bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE,
Emilio G. Cota886953e2010-11-12 11:14:07 +00002279 &bridge->crcsr_bus);
Martyn Welch29848ac2010-02-18 15:13:05 +00002280 if (bridge->crcsr_kernel == NULL) {
Martyn Welch48d93562010-03-22 14:58:50 +00002281 dev_err(tsi148_bridge->parent, "Failed to allocate memory for "
2282 "CR/CSR image\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002283 return -ENOMEM;
2284 }
2285
Martyn Welch29848ac2010-02-18 15:13:05 +00002286 memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002287
Martyn Welch29848ac2010-02-18 15:13:05 +00002288 reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002289
Martyn Welch29848ac2010-02-18 15:13:05 +00002290 iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU);
2291 iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002292
2293 /* Ensure that the CR/CSR is configured at the correct offset */
Martyn Welch29848ac2010-02-18 15:13:05 +00002294 cbar = ioread32be(bridge->base + TSI148_CBAR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002295 cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3;
2296
Martyn Welch29848ac2010-02-18 15:13:05 +00002297 vstat = tsi148_slot_get(tsi148_bridge);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002298
2299 if (cbar != vstat) {
Martyn Welch638f1992009-12-15 08:42:49 +00002300 cbar = vstat;
Martyn Welch48d93562010-03-22 14:58:50 +00002301 dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n");
Martyn Welch29848ac2010-02-18 15:13:05 +00002302 iowrite32be(cbar<<3, bridge->base + TSI148_CBAR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002303 }
Martyn Welch48d93562010-03-22 14:58:50 +00002304 dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002305
Martyn Welch29848ac2010-02-18 15:13:05 +00002306 crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
Martyn Welch29817952013-06-11 17:03:14 +01002307 if (crat & TSI148_LCSR_CRAT_EN)
2308 dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n");
2309 else {
Martyn Welch48d93562010-03-22 14:58:50 +00002310 dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002311 iowrite32be(crat | TSI148_LCSR_CRAT_EN,
Martyn Welch29848ac2010-02-18 15:13:05 +00002312 bridge->base + TSI148_LCSR_CRAT);
Martyn Welch29817952013-06-11 17:03:14 +01002313 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002314
2315 /* If we want flushed, error-checked writes, set up a window
2316 * over the CR/CSR registers. We read from here to safely flush
2317 * through VME writes.
2318 */
Martyn Welch79463282010-03-22 14:58:57 +00002319 if (err_chk) {
Martyn Welch29848ac2010-02-18 15:13:05 +00002320 retval = tsi148_master_set(bridge->flush_image, 1,
2321 (vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT,
2322 VME_D16);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002323 if (retval)
Martyn Welch48d93562010-03-22 14:58:50 +00002324 dev_err(tsi148_bridge->parent, "Configuring flush image"
2325 " failed\n");
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002326 }
2327
2328 return 0;
2329
2330}
2331
Martyn Welch29848ac2010-02-18 15:13:05 +00002332static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge,
2333 struct pci_dev *pdev)
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002334{
2335 u32 crat;
Martyn Welch29848ac2010-02-18 15:13:05 +00002336 struct tsi148_driver *bridge;
2337
2338 bridge = tsi148_bridge->driver_priv;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002339
2340 /* Turn off CR/CSR space */
Martyn Welch29848ac2010-02-18 15:13:05 +00002341 crat = ioread32be(bridge->base + TSI148_LCSR_CRAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002342 iowrite32be(crat & ~TSI148_LCSR_CRAT_EN,
Martyn Welch29848ac2010-02-18 15:13:05 +00002343 bridge->base + TSI148_LCSR_CRAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002344
2345 /* Free image */
Martyn Welch29848ac2010-02-18 15:13:05 +00002346 iowrite32be(0, bridge->base + TSI148_LCSR_CROU);
2347 iowrite32be(0, bridge->base + TSI148_LCSR_CROL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002348
Martyn Welch29848ac2010-02-18 15:13:05 +00002349 pci_free_consistent(pdev, VME_CRCSR_BUF_SIZE, bridge->crcsr_kernel,
2350 bridge->crcsr_bus);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002351}
2352
2353static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2354{
2355 int retval, i, master_num;
2356 u32 data;
Wei Yongjunb49c32b2012-08-21 12:19:01 +08002357 struct list_head *pos = NULL, *n;
Martyn Welch29848ac2010-02-18 15:13:05 +00002358 struct vme_bridge *tsi148_bridge;
2359 struct tsi148_driver *tsi148_device;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002360 struct vme_master_resource *master_image;
2361 struct vme_slave_resource *slave_image;
2362 struct vme_dma_resource *dma_ctrlr;
Martyn Welch42fb5032009-08-11 17:44:56 +01002363 struct vme_lm_resource *lm;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002364
2365 /* If we want to support more than one of each bridge, we need to
2366 * dynamically generate this so we get one per device
2367 */
Julia Lawall7a6cb0d2010-05-13 22:00:05 +02002368 tsi148_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002369 if (tsi148_bridge == NULL) {
2370 dev_err(&pdev->dev, "Failed to allocate memory for device "
2371 "structure\n");
2372 retval = -ENOMEM;
2373 goto err_struct;
2374 }
2375
Julia Lawall7a6cb0d2010-05-13 22:00:05 +02002376 tsi148_device = kzalloc(sizeof(struct tsi148_driver), GFP_KERNEL);
Martyn Welch29848ac2010-02-18 15:13:05 +00002377 if (tsi148_device == NULL) {
2378 dev_err(&pdev->dev, "Failed to allocate memory for device "
2379 "structure\n");
2380 retval = -ENOMEM;
2381 goto err_driver;
2382 }
2383
Martyn Welch29848ac2010-02-18 15:13:05 +00002384 tsi148_bridge->driver_priv = tsi148_device;
2385
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002386 /* Enable the device */
2387 retval = pci_enable_device(pdev);
2388 if (retval) {
2389 dev_err(&pdev->dev, "Unable to enable device\n");
2390 goto err_enable;
2391 }
2392
2393 /* Map Registers */
2394 retval = pci_request_regions(pdev, driver_name);
2395 if (retval) {
2396 dev_err(&pdev->dev, "Unable to reserve resources\n");
2397 goto err_resource;
2398 }
2399
2400 /* map registers in BAR 0 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002401 tsi148_device->base = ioremap_nocache(pci_resource_start(pdev, 0),
2402 4096);
2403 if (!tsi148_device->base) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002404 dev_err(&pdev->dev, "Unable to remap CRG region\n");
2405 retval = -EIO;
2406 goto err_remap;
2407 }
2408
2409 /* Check to see if the mapping worked out */
Martyn Welch29848ac2010-02-18 15:13:05 +00002410 data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002411 if (data != PCI_VENDOR_ID_TUNDRA) {
2412 dev_err(&pdev->dev, "CRG region check failed\n");
2413 retval = -EIO;
2414 goto err_test;
2415 }
2416
2417 /* Initialize wait queues & mutual exclusion flags */
Emilio G. Cota886953e2010-11-12 11:14:07 +00002418 init_waitqueue_head(&tsi148_device->dma_queue[0]);
2419 init_waitqueue_head(&tsi148_device->dma_queue[1]);
2420 init_waitqueue_head(&tsi148_device->iack_queue);
2421 mutex_init(&tsi148_device->vme_int);
2422 mutex_init(&tsi148_device->vme_rmw);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002423
Emilio G. Cota886953e2010-11-12 11:14:07 +00002424 tsi148_bridge->parent = &pdev->dev;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002425 strcpy(tsi148_bridge->name, driver_name);
2426
2427 /* Setup IRQ */
2428 retval = tsi148_irq_init(tsi148_bridge);
2429 if (retval != 0) {
2430 dev_err(&pdev->dev, "Chip Initialization failed.\n");
2431 goto err_irq;
2432 }
2433
2434 /* If we are going to flush writes, we need to read from the VME bus.
2435 * We need to do this safely, thus we read the devices own CR/CSR
2436 * register. To do this we must set up a window in CR/CSR space and
2437 * hence have one less master window resource available.
2438 */
2439 master_num = TSI148_MAX_MASTER;
Martyn Welch79463282010-03-22 14:58:57 +00002440 if (err_chk) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002441 master_num--;
Martyn Welch29848ac2010-02-18 15:13:05 +00002442
Julia Lawall32414872010-05-11 20:26:57 +02002443 tsi148_device->flush_image =
Martyn Welch29848ac2010-02-18 15:13:05 +00002444 kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL);
2445 if (tsi148_device->flush_image == NULL) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002446 dev_err(&pdev->dev, "Failed to allocate memory for "
2447 "flush resource structure\n");
2448 retval = -ENOMEM;
2449 goto err_master;
2450 }
Martyn Welch29848ac2010-02-18 15:13:05 +00002451 tsi148_device->flush_image->parent = tsi148_bridge;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002452 spin_lock_init(&tsi148_device->flush_image->lock);
Martyn Welch29848ac2010-02-18 15:13:05 +00002453 tsi148_device->flush_image->locked = 1;
2454 tsi148_device->flush_image->number = master_num;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002455 memset(&tsi148_device->flush_image->bus_resource, 0,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002456 sizeof(struct resource));
Martyn Welch29848ac2010-02-18 15:13:05 +00002457 tsi148_device->flush_image->kern_base = NULL;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002458 }
2459
2460 /* Add master windows to list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00002461 INIT_LIST_HEAD(&tsi148_bridge->master_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002462 for (i = 0; i < master_num; i++) {
Martyn Welch79463282010-03-22 14:58:57 +00002463 master_image = kmalloc(sizeof(struct vme_master_resource),
2464 GFP_KERNEL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002465 if (master_image == NULL) {
2466 dev_err(&pdev->dev, "Failed to allocate memory for "
2467 "master resource structure\n");
2468 retval = -ENOMEM;
2469 goto err_master;
2470 }
2471 master_image->parent = tsi148_bridge;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002472 spin_lock_init(&master_image->lock);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002473 master_image->locked = 0;
2474 master_image->number = i;
2475 master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
2476 VME_A64;
2477 master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
2478 VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
2479 VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
2480 VME_PROG | VME_DATA;
2481 master_image->width_attr = VME_D16 | VME_D32;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002482 memset(&master_image->bus_resource, 0,
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002483 sizeof(struct resource));
2484 master_image->kern_base = NULL;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002485 list_add_tail(&master_image->list,
2486 &tsi148_bridge->master_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002487 }
2488
2489 /* Add slave windows to list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00002490 INIT_LIST_HEAD(&tsi148_bridge->slave_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002491 for (i = 0; i < TSI148_MAX_SLAVE; i++) {
Martyn Welch79463282010-03-22 14:58:57 +00002492 slave_image = kmalloc(sizeof(struct vme_slave_resource),
2493 GFP_KERNEL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002494 if (slave_image == NULL) {
2495 dev_err(&pdev->dev, "Failed to allocate memory for "
2496 "slave resource structure\n");
2497 retval = -ENOMEM;
2498 goto err_slave;
2499 }
2500 slave_image->parent = tsi148_bridge;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002501 mutex_init(&slave_image->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002502 slave_image->locked = 0;
2503 slave_image->number = i;
2504 slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
2505 VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
2506 VME_USER3 | VME_USER4;
2507 slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
2508 VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
2509 VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
2510 VME_PROG | VME_DATA;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002511 list_add_tail(&slave_image->list,
2512 &tsi148_bridge->slave_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002513 }
2514
2515 /* Add dma engines to list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00002516 INIT_LIST_HEAD(&tsi148_bridge->dma_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002517 for (i = 0; i < TSI148_MAX_DMA; i++) {
Martyn Welch79463282010-03-22 14:58:57 +00002518 dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource),
2519 GFP_KERNEL);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002520 if (dma_ctrlr == NULL) {
2521 dev_err(&pdev->dev, "Failed to allocate memory for "
2522 "dma resource structure\n");
2523 retval = -ENOMEM;
2524 goto err_dma;
2525 }
2526 dma_ctrlr->parent = tsi148_bridge;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002527 mutex_init(&dma_ctrlr->mtx);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002528 dma_ctrlr->locked = 0;
2529 dma_ctrlr->number = i;
Martyn Welch4f723df2010-02-18 15:12:58 +00002530 dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
2531 VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME |
2532 VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
2533 VME_DMA_PATTERN_TO_MEM;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002534 INIT_LIST_HEAD(&dma_ctrlr->pending);
2535 INIT_LIST_HEAD(&dma_ctrlr->running);
2536 list_add_tail(&dma_ctrlr->list,
2537 &tsi148_bridge->dma_resources);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002538 }
2539
Martyn Welch42fb5032009-08-11 17:44:56 +01002540 /* Add location monitor to list */
Emilio G. Cota886953e2010-11-12 11:14:07 +00002541 INIT_LIST_HEAD(&tsi148_bridge->lm_resources);
Martyn Welch42fb5032009-08-11 17:44:56 +01002542 lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
2543 if (lm == NULL) {
2544 dev_err(&pdev->dev, "Failed to allocate memory for "
2545 "location monitor resource structure\n");
2546 retval = -ENOMEM;
2547 goto err_lm;
2548 }
2549 lm->parent = tsi148_bridge;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002550 mutex_init(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01002551 lm->locked = 0;
2552 lm->number = 1;
2553 lm->monitors = 4;
Emilio G. Cota886953e2010-11-12 11:14:07 +00002554 list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
Martyn Welch42fb5032009-08-11 17:44:56 +01002555
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002556 tsi148_bridge->slave_get = tsi148_slave_get;
2557 tsi148_bridge->slave_set = tsi148_slave_set;
2558 tsi148_bridge->master_get = tsi148_master_get;
2559 tsi148_bridge->master_set = tsi148_master_set;
2560 tsi148_bridge->master_read = tsi148_master_read;
2561 tsi148_bridge->master_write = tsi148_master_write;
2562 tsi148_bridge->master_rmw = tsi148_master_rmw;
2563 tsi148_bridge->dma_list_add = tsi148_dma_list_add;
2564 tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
2565 tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
Martyn Welchc813f592009-10-29 16:34:54 +00002566 tsi148_bridge->irq_set = tsi148_irq_set;
2567 tsi148_bridge->irq_generate = tsi148_irq_generate;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002568 tsi148_bridge->lm_set = tsi148_lm_set;
2569 tsi148_bridge->lm_get = tsi148_lm_get;
2570 tsi148_bridge->lm_attach = tsi148_lm_attach;
2571 tsi148_bridge->lm_detach = tsi148_lm_detach;
2572 tsi148_bridge->slot_get = tsi148_slot_get;
Manohar Vanga7f58f022011-08-10 11:33:46 +02002573 tsi148_bridge->alloc_consistent = tsi148_alloc_consistent;
2574 tsi148_bridge->free_consistent = tsi148_free_consistent;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002575
Martyn Welch29848ac2010-02-18 15:13:05 +00002576 data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002577 dev_info(&pdev->dev, "Board is%s the VME system controller\n",
Martyn Welch79463282010-03-22 14:58:57 +00002578 (data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not");
Martyn Welch29848ac2010-02-18 15:13:05 +00002579 if (!geoid)
Martyn Welch638f1992009-12-15 08:42:49 +00002580 dev_info(&pdev->dev, "VME geographical address is %d\n",
2581 data & TSI148_LCSR_VSTAT_GA_M);
Martyn Welch29848ac2010-02-18 15:13:05 +00002582 else
Martyn Welch638f1992009-12-15 08:42:49 +00002583 dev_info(&pdev->dev, "VME geographical address is set to %d\n",
2584 geoid);
Martyn Welch29848ac2010-02-18 15:13:05 +00002585
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002586 dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
2587 err_chk ? "enabled" : "disabled");
2588
Wei Yongjun0686ab72013-06-19 10:42:35 +08002589 retval = tsi148_crcsr_init(tsi148_bridge, pdev);
2590 if (retval) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002591 dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
2592 goto err_crcsr;
Martyn Welch48397372010-03-22 14:58:43 +00002593 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002594
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002595 retval = vme_register_bridge(tsi148_bridge);
2596 if (retval != 0) {
2597 dev_err(&pdev->dev, "Chip Registration failed.\n");
2598 goto err_reg;
2599 }
2600
Martyn Welch29848ac2010-02-18 15:13:05 +00002601 pci_set_drvdata(pdev, tsi148_bridge);
2602
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002603 /* Clear VME bus "board fail", and "power-up reset" lines */
Martyn Welch29848ac2010-02-18 15:13:05 +00002604 data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002605 data &= ~TSI148_LCSR_VSTAT_BRDFL;
2606 data |= TSI148_LCSR_VSTAT_CPURST;
Martyn Welch29848ac2010-02-18 15:13:05 +00002607 iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002608
2609 return 0;
2610
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002611err_reg:
Martyn Welch29848ac2010-02-18 15:13:05 +00002612 tsi148_crcsr_exit(tsi148_bridge, pdev);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002613err_crcsr:
Martyn Welch42fb5032009-08-11 17:44:56 +01002614err_lm:
2615 /* resources are stored in link list */
Wei Yongjunb49c32b2012-08-21 12:19:01 +08002616 list_for_each_safe(pos, n, &tsi148_bridge->lm_resources) {
Martyn Welch42fb5032009-08-11 17:44:56 +01002617 lm = list_entry(pos, struct vme_lm_resource, list);
2618 list_del(pos);
2619 kfree(lm);
2620 }
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002621err_dma:
2622 /* resources are stored in link list */
Wei Yongjunb49c32b2012-08-21 12:19:01 +08002623 list_for_each_safe(pos, n, &tsi148_bridge->dma_resources) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002624 dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
2625 list_del(pos);
2626 kfree(dma_ctrlr);
2627 }
2628err_slave:
2629 /* resources are stored in link list */
Wei Yongjunb49c32b2012-08-21 12:19:01 +08002630 list_for_each_safe(pos, n, &tsi148_bridge->slave_resources) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002631 slave_image = list_entry(pos, struct vme_slave_resource, list);
2632 list_del(pos);
2633 kfree(slave_image);
2634 }
2635err_master:
2636 /* resources are stored in link list */
Wei Yongjunb49c32b2012-08-21 12:19:01 +08002637 list_for_each_safe(pos, n, &tsi148_bridge->master_resources) {
Martyn Welch79463282010-03-22 14:58:57 +00002638 master_image = list_entry(pos, struct vme_master_resource,
2639 list);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002640 list_del(pos);
2641 kfree(master_image);
2642 }
2643
Emilio G. Cotaa82ad052010-11-12 11:14:47 +00002644 tsi148_irq_exit(tsi148_bridge, pdev);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002645err_irq:
2646err_test:
Martyn Welch29848ac2010-02-18 15:13:05 +00002647 iounmap(tsi148_device->base);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002648err_remap:
2649 pci_release_regions(pdev);
2650err_resource:
2651 pci_disable_device(pdev);
2652err_enable:
Martyn Welch29848ac2010-02-18 15:13:05 +00002653 kfree(tsi148_device);
2654err_driver:
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002655 kfree(tsi148_bridge);
2656err_struct:
2657 return retval;
2658
2659}
2660
2661static void tsi148_remove(struct pci_dev *pdev)
2662{
2663 struct list_head *pos = NULL;
Emilio G. Cotab558ba22010-11-12 11:14:34 +00002664 struct list_head *tmplist;
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002665 struct vme_master_resource *master_image;
2666 struct vme_slave_resource *slave_image;
2667 struct vme_dma_resource *dma_ctrlr;
2668 int i;
Martyn Welch29848ac2010-02-18 15:13:05 +00002669 struct tsi148_driver *bridge;
2670 struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev);
2671
2672 bridge = tsi148_bridge->driver_priv;
2673
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002674
2675 dev_dbg(&pdev->dev, "Driver is being unloaded.\n");
2676
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002677 /*
2678 * Shutdown all inbound and outbound windows.
2679 */
2680 for (i = 0; i < 8; i++) {
Martyn Welch29848ac2010-02-18 15:13:05 +00002681 iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002682 TSI148_LCSR_OFFSET_ITAT);
Martyn Welch29848ac2010-02-18 15:13:05 +00002683 iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] +
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002684 TSI148_LCSR_OFFSET_OTAT);
2685 }
2686
2687 /*
2688 * Shutdown Location monitor.
2689 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002690 iowrite32be(0, bridge->base + TSI148_LCSR_LMAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002691
2692 /*
2693 * Shutdown CRG map.
2694 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002695 iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002696
2697 /*
2698 * Clear error status.
2699 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002700 iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT);
2701 iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT);
2702 iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002703
2704 /*
2705 * Remove VIRQ interrupt (if any)
2706 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002707 if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800)
2708 iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002709
2710 /*
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002711 * Map all Interrupts to PCI INTA
2712 */
Martyn Welch29848ac2010-02-18 15:13:05 +00002713 iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1);
2714 iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002715
Emilio G. Cotaa82ad052010-11-12 11:14:47 +00002716 tsi148_irq_exit(tsi148_bridge, pdev);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002717
2718 vme_unregister_bridge(tsi148_bridge);
2719
Martyn Welch29848ac2010-02-18 15:13:05 +00002720 tsi148_crcsr_exit(tsi148_bridge, pdev);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002721
2722 /* resources are stored in link list */
Emilio G. Cotab558ba22010-11-12 11:14:34 +00002723 list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002724 dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
2725 list_del(pos);
2726 kfree(dma_ctrlr);
2727 }
2728
2729 /* resources are stored in link list */
Emilio G. Cotab558ba22010-11-12 11:14:34 +00002730 list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) {
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002731 slave_image = list_entry(pos, struct vme_slave_resource, list);
2732 list_del(pos);
2733 kfree(slave_image);
2734 }
2735
2736 /* resources are stored in link list */
Emilio G. Cotab558ba22010-11-12 11:14:34 +00002737 list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) {
Martyn Welch638f1992009-12-15 08:42:49 +00002738 master_image = list_entry(pos, struct vme_master_resource,
2739 list);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002740 list_del(pos);
2741 kfree(master_image);
2742 }
2743
Martyn Welch29848ac2010-02-18 15:13:05 +00002744 iounmap(bridge->base);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002745
2746 pci_release_regions(pdev);
2747
2748 pci_disable_device(pdev);
2749
Martyn Welch29848ac2010-02-18 15:13:05 +00002750 kfree(tsi148_bridge->driver_priv);
2751
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002752 kfree(tsi148_bridge);
2753}
2754
Wei Yongjun01c07142012-10-18 23:12:50 +08002755module_pci_driver(tsi148_driver);
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002756
2757MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes");
2758module_param(err_chk, bool, 0);
2759
Martyn Welch638f1992009-12-15 08:42:49 +00002760MODULE_PARM_DESC(geoid, "Override geographical addressing");
2761module_param(geoid, int, 0);
2762
Martyn Welchd22b8ed2009-07-31 09:28:17 +01002763MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge");
2764MODULE_LICENSE("GPL");