]>
Commit | Line | Data |
---|---|---|
60479690 MW |
1 | /* |
2 | * Support for the Tundra Universe I/II VME-PCI Bridge Chips | |
3 | * | |
4 | * Author: Martyn Welch <martyn.welch@gefanuc.com> | |
5 | * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc. | |
6 | * | |
7 | * Based on work by Tom Armistead and Ajit Prem | |
8 | * Copyright 2004 Motorola Inc. | |
9 | * | |
10 | * Derived from ca91c042.c by Michael Wyrick | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. | |
16 | */ | |
17 | ||
18 | #include <linux/version.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/mm.h> | |
21 | #include <linux/types.h> | |
22 | #include <linux/errno.h> | |
23 | #include <linux/proc_fs.h> | |
24 | #include <linux/pci.h> | |
25 | #include <linux/dma-mapping.h> | |
26 | #include <linux/poll.h> | |
27 | #include <linux/interrupt.h> | |
28 | #include <linux/spinlock.h> | |
29 | #include <asm/time.h> | |
30 | #include <asm/io.h> | |
31 | #include <asm/uaccess.h> | |
32 | ||
33 | #include "../vme.h" | |
34 | #include "../vme_bridge.h" | |
35 | #include "vme_ca91cx42.h" | |
36 | ||
37 | extern struct vmeSharedData *vmechip_interboard_data; | |
38 | extern dma_addr_t vmechip_interboard_datap; | |
39 | extern const int vmechip_revision; | |
40 | extern const int vmechip_devid; | |
41 | extern const int vmechip_irq; | |
42 | extern int vmechip_irq_overhead_ticks; | |
43 | extern char *vmechip_baseaddr; | |
44 | extern const int vme_slotnum; | |
45 | extern int vme_syscon; | |
46 | extern unsigned int out_image_va[]; | |
47 | extern unsigned int vme_irqlog[8][0x100]; | |
48 | ||
49 | static int outCTL[] = { LSI0_CTL, LSI1_CTL, LSI2_CTL, LSI3_CTL, | |
50 | LSI4_CTL, LSI5_CTL, LSI6_CTL, LSI7_CTL | |
51 | }; | |
52 | ||
53 | static int outBS[] = { LSI0_BS, LSI1_BS, LSI2_BS, LSI3_BS, | |
54 | LSI4_BS, LSI5_BS, LSI6_BS, LSI7_BS | |
55 | }; | |
56 | ||
57 | static int outBD[] = { LSI0_BD, LSI1_BD, LSI2_BD, LSI3_BD, | |
58 | LSI4_BD, LSI5_BD, LSI6_BD, LSI7_BD | |
59 | }; | |
60 | ||
61 | static int outTO[] = { LSI0_TO, LSI1_TO, LSI2_TO, LSI3_TO, | |
62 | LSI4_TO, LSI5_TO, LSI6_TO, LSI7_TO | |
63 | }; | |
64 | ||
65 | static int inCTL[] = { VSI0_CTL, VSI1_CTL, VSI2_CTL, VSI3_CTL, | |
66 | VSI4_CTL, VSI5_CTL, VSI6_CTL, VSI7_CTL | |
67 | }; | |
68 | ||
69 | static int inBS[] = { VSI0_BS, VSI1_BS, VSI2_BS, VSI3_BS, | |
70 | VSI4_BS, VSI5_BS, VSI6_BS, VSI7_BS | |
71 | }; | |
72 | ||
73 | static int inBD[] = { VSI0_BD, VSI1_BD, VSI2_BD, VSI3_BD, | |
74 | VSI4_BD, VSI5_BD, VSI6_BD, VSI7_BD | |
75 | }; | |
76 | ||
77 | static int inTO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO, | |
78 | VSI4_TO, VSI5_TO, VSI6_TO, VSI7_TO | |
79 | }; | |
80 | static int vmevec[7] = { V1_STATID, V2_STATID, V3_STATID, V4_STATID, | |
81 | V5_STATID, V6_STATID, V7_STATID | |
82 | }; | |
83 | ||
84 | struct interrupt_counters { | |
85 | unsigned int acfail; | |
86 | unsigned int sysfail; | |
87 | unsigned int sw_int; | |
88 | unsigned int sw_iack; | |
89 | unsigned int verr; | |
90 | unsigned int lerr; | |
91 | unsigned int lm; | |
92 | unsigned int mbox; | |
93 | unsigned int dma; | |
94 | unsigned int virq[7]; | |
95 | unsigned int vown; | |
96 | }; | |
97 | ||
98 | extern wait_queue_head_t dma_queue[]; | |
99 | extern wait_queue_head_t lm_queue; | |
100 | extern wait_queue_head_t mbox_queue; | |
101 | ||
102 | extern int tb_speed; | |
103 | ||
104 | unsigned int uni_irq_time; | |
105 | unsigned int uni_dma_irq_time; | |
106 | unsigned int uni_lm_event; | |
107 | ||
108 | static spinlock_t lm_lock = SPIN_LOCK_UNLOCKED; | |
109 | ||
110 | static struct interrupt_counters Interrupt_counters = { 0, 0, | |
111 | 0, 0, 0, 0, | |
112 | 0, 0, 0, | |
113 | {0, 0, 0, 0, 0, 0, 0}, | |
114 | 0 | |
115 | }; | |
116 | ||
117 | #define read_register(offset) readl(vmechip_baseaddr + offset) | |
118 | #define write_register(value,offset) writel(value, vmechip_baseaddr + offset) | |
119 | #define read_register_word(offset) readw(vmechip_baseaddr + offset) | |
120 | #define write_register_word(value,offset) writew(value, vmechip_baseaddr + offset) | |
121 | ||
122 | int uni_procinfo(char *buf) | |
123 | { | |
124 | char *p; | |
125 | ||
126 | p = buf; | |
127 | ||
128 | p += sprintf(p, "\n"); | |
129 | { | |
130 | unsigned long misc_ctl; | |
131 | ||
132 | misc_ctl = read_register(MISC_CTL); | |
133 | p += sprintf(p, "MISC_CTL:\t\t\t0x%08lx\n", misc_ctl); | |
134 | p += sprintf(p, "VME Bus Time Out:\t\t"); | |
135 | switch ((misc_ctl & UNIV_BM_MISC_CTL_VBTO) >> | |
136 | UNIV_OF_MISC_CTL_VBTO) { | |
137 | case 0x0: | |
138 | p += sprintf(p, "Disabled\n"); | |
139 | break; | |
140 | case 0x1: | |
141 | p += sprintf(p, "16 us\n"); | |
142 | break; | |
143 | case 0x2: | |
144 | p += sprintf(p, "32 us\n"); | |
145 | break; | |
146 | case 0x3: | |
147 | p += sprintf(p, "64 us\n"); | |
148 | break; | |
149 | case 0x4: | |
150 | p += sprintf(p, "128 us\n"); | |
151 | break; | |
152 | case 0x5: | |
153 | p += sprintf(p, "256 us\n"); | |
154 | break; | |
155 | case 0x6: | |
156 | p += sprintf(p, "512 us\n"); | |
157 | break; | |
158 | case 0x7: | |
159 | p += sprintf(p, "1024 us\n"); | |
160 | break; | |
161 | default: | |
162 | p += sprintf(p, "Reserved Value, Undefined\n"); | |
163 | } | |
164 | p += sprintf(p, "VME Arbitration Time Out:\t"); | |
165 | switch ((misc_ctl & UNIV_BM_MISC_CTL_VARBTO) >> | |
166 | UNIV_OF_MISC_CTL_VARBTO) { | |
167 | case 0x0: | |
168 | p += sprintf(p, "Disabled"); | |
169 | break; | |
170 | case 0x1: | |
171 | p += sprintf(p, "16 us"); | |
172 | break; | |
173 | case 0x2: | |
174 | p += sprintf(p, "256 us"); | |
175 | break; | |
176 | default: | |
177 | p += sprintf(p, "Reserved Value, Undefined"); | |
178 | } | |
179 | if (misc_ctl & UNIV_BM_MISC_CTL_VARB) | |
180 | p += sprintf(p, ", Priority Arbitration\n"); | |
181 | else | |
182 | p += sprintf(p, ", Round Robin Arbitration\n"); | |
183 | p += sprintf(p, "\n"); | |
184 | } | |
185 | ||
186 | { | |
187 | unsigned int lmisc; | |
188 | unsigned int crt; | |
189 | unsigned int cwt; | |
190 | ||
191 | lmisc = read_register(LMISC); | |
192 | p += sprintf(p, "LMISC:\t\t\t\t0x%08x\n", lmisc); | |
193 | crt = (lmisc & UNIV_BM_LMISC_CRT) >> UNIV_OF_LMISC_CRT; | |
194 | cwt = (lmisc & UNIV_BM_LMISC_CWT) >> UNIV_OF_LMISC_CWT; | |
195 | p += sprintf(p, "Coupled Request Timer:\t\t"); | |
196 | switch (crt) { | |
197 | case 0x0: | |
198 | p += sprintf(p, "Disabled\n"); | |
199 | break; | |
200 | case 0x1: | |
201 | p += sprintf(p, "128 us\n"); | |
202 | break; | |
203 | case 0x2: | |
204 | p += sprintf(p, "256 us\n"); | |
205 | break; | |
206 | case 0x3: | |
207 | p += sprintf(p, "512 us\n"); | |
208 | break; | |
209 | case 0x4: | |
210 | p += sprintf(p, "1024 us\n"); | |
211 | break; | |
212 | case 0x5: | |
213 | p += sprintf(p, "2048 us\n"); | |
214 | break; | |
215 | case 0x6: | |
216 | p += sprintf(p, "4096 us\n"); | |
217 | break; | |
218 | default: | |
219 | p += sprintf(p, "Reserved\n"); | |
220 | } | |
221 | p += sprintf(p, "Coupled Window Timer:\t\t"); | |
222 | switch (cwt) { | |
223 | case 0x0: | |
224 | p += sprintf(p, "Disabled\n"); | |
225 | break; | |
226 | case 0x1: | |
227 | p += sprintf(p, "16 PCI Clocks\n"); | |
228 | break; | |
229 | case 0x2: | |
230 | p += sprintf(p, "32 PCI Clocks\n"); | |
231 | break; | |
232 | case 0x3: | |
233 | p += sprintf(p, "64 PCI Clocks\n"); | |
234 | break; | |
235 | case 0x4: | |
236 | p += sprintf(p, "128 PCI Clocks\n"); | |
237 | break; | |
238 | case 0x5: | |
239 | p += sprintf(p, "256 PCI Clocks\n"); | |
240 | break; | |
241 | case 0x6: | |
242 | p += sprintf(p, "512 PCI Clocks\n"); | |
243 | break; | |
244 | default: | |
245 | p += sprintf(p, "Reserved\n"); | |
246 | } | |
247 | p += sprintf(p, "\n"); | |
248 | } | |
249 | { | |
250 | unsigned int mast_ctl; | |
251 | ||
252 | mast_ctl = read_register(MAST_CTL); | |
253 | p += sprintf(p, "MAST_CTL:\t\t\t0x%08x\n", mast_ctl); | |
254 | { | |
255 | int retries; | |
256 | ||
257 | retries = ((mast_ctl & UNIV_BM_MAST_CTL_MAXRTRY) | |
258 | >> UNIV_OF_MAST_CTL_MAXRTRY) * 64; | |
259 | p += sprintf(p, "Max PCI Master Retries:\t\t"); | |
260 | if (retries) | |
261 | p += sprintf(p, "%d\n", retries); | |
262 | else | |
263 | p += sprintf(p, "Forever\n"); | |
264 | } | |
265 | ||
266 | p += sprintf(p, "Posted Write Transfer Count:\t"); | |
267 | switch ((mast_ctl & UNIV_BM_MAST_CTL_PWON) >> | |
268 | UNIV_OF_MAST_CTL_PWON) { | |
269 | case 0x0: | |
270 | p += sprintf(p, "128 Bytes\n"); | |
271 | break; | |
272 | case 0x1: | |
273 | p += sprintf(p, "256 Bytes\n"); | |
274 | break; | |
275 | case 0x2: | |
276 | p += sprintf(p, "512 Bytes\n"); | |
277 | break; | |
278 | case 0x3: | |
279 | p += sprintf(p, "1024 Bytes\n"); | |
280 | break; | |
281 | case 0x4: | |
282 | p += sprintf(p, "2048 Bytes\n"); | |
283 | break; | |
284 | case 0x5: | |
285 | p += sprintf(p, "4096 Bytes\n"); | |
286 | break; | |
287 | default: | |
288 | p += sprintf(p, "Undefined\n"); | |
289 | } | |
290 | ||
291 | p += sprintf(p, "VMEbus Request Level:\t\t"); | |
292 | switch ((mast_ctl & UNIV_BM_MAST_CTL_VRL) >> | |
293 | UNIV_OF_MAST_CTL_VRL) { | |
294 | case 0x0: | |
295 | p += sprintf(p, "Level 0\n"); | |
296 | case 0x1: | |
297 | p += sprintf(p, "Level 1\n"); | |
298 | case 0x2: | |
299 | p += sprintf(p, "Level 2\n"); | |
300 | case 0x3: | |
301 | p += sprintf(p, "Level 3\n"); | |
302 | } | |
303 | p += sprintf(p, "VMEbus Request Mode:\t\t"); | |
304 | if (mast_ctl & UNIV_BM_MAST_CTL_VRM) | |
305 | p += sprintf(p, "Fair Request Mode\n"); | |
306 | else | |
307 | p += sprintf(p, "Demand Request Mode\n"); | |
308 | p += sprintf(p, "VMEbus Release Mode:\t\t"); | |
309 | if (mast_ctl & UNIV_BM_MAST_CTL_VREL) | |
310 | p += sprintf(p, "Release on Request\n"); | |
311 | else | |
312 | p += sprintf(p, "Release when Done\n"); | |
313 | p += sprintf(p, "VMEbus Ownership Bit:\t\t"); | |
314 | if (mast_ctl & UNIV_BM_MAST_CTL_VOWN) | |
315 | p += sprintf(p, "Acquire and hold VMEbus\n"); | |
316 | else | |
317 | p += sprintf(p, "Release VMEbus\n"); | |
318 | p += sprintf(p, "VMEbus Ownership Bit Ack:\t"); | |
319 | if (mast_ctl & UNIV_BM_MAST_CTL_VOWN_ACK) | |
320 | p += sprintf(p, "Owning VMEbus\n"); | |
321 | else | |
322 | p += sprintf(p, "Not Owning VMEbus\n"); | |
323 | p += sprintf(p, "\n"); | |
324 | } | |
325 | { | |
326 | unsigned int misc_stat; | |
327 | ||
328 | misc_stat = read_register(MISC_STAT); | |
329 | p += sprintf(p, "MISC_STAT:\t\t\t0x%08x\n", misc_stat); | |
330 | p += sprintf(p, "Universe BBSY:\t\t\t"); | |
331 | if (misc_stat & UNIV_BM_MISC_STAT_MYBBSY) | |
332 | p += sprintf(p, "Negated\n"); | |
333 | else | |
334 | p += sprintf(p, "Asserted\n"); | |
335 | p += sprintf(p, "Transmit FIFO:\t\t\t"); | |
336 | if (misc_stat & UNIV_BM_MISC_STAT_TXFE) | |
337 | p += sprintf(p, "Empty\n"); | |
338 | else | |
339 | p += sprintf(p, "Not empty\n"); | |
340 | p += sprintf(p, "Receive FIFO:\t\t\t"); | |
341 | if (misc_stat & UNIV_BM_MISC_STAT_RXFE) | |
342 | p += sprintf(p, "Empty\n"); | |
343 | else | |
344 | p += sprintf(p, "Not Empty\n"); | |
345 | p += sprintf(p, "\n"); | |
346 | } | |
347 | ||
348 | p += sprintf(p, "Latency Timer:\t\t\t%02d Clocks\n\n", | |
349 | (read_register(UNIV_PCI_MISC0) & | |
350 | UNIV_BM_PCI_MISC0_LTIMER) >> UNIV_OF_PCI_MISC0_LTIMER); | |
351 | ||
352 | { | |
353 | unsigned int lint_en; | |
354 | unsigned int lint_stat; | |
355 | ||
356 | lint_en = read_register(LINT_EN); | |
357 | lint_stat = read_register(LINT_STAT); | |
358 | ||
359 | #define REPORT_IRQ(name,field) \ | |
360 | p += sprintf(p, (lint_en & UNIV_BM_LINT_##name) ? "Enabled" : "Masked"); \ | |
361 | p += sprintf(p, ", triggered %d times", Interrupt_counters.field); \ | |
362 | p += sprintf(p, (lint_stat & UNIV_BM_LINT_##name) ? ", irq now active\n" : "\n"); | |
363 | p += sprintf(p, "ACFAIL Interrupt:\t\t"); | |
364 | REPORT_IRQ(ACFAIL, acfail); | |
365 | p += sprintf(p, "SYSFAIL Interrupt:\t\t"); | |
366 | REPORT_IRQ(SYSFAIL, sysfail); | |
367 | p += sprintf(p, "SW_INT Interrupt:\t\t"); | |
368 | REPORT_IRQ(SW_INT, sw_int); | |
369 | p += sprintf(p, "SW_IACK Interrupt:\t\t"); | |
370 | REPORT_IRQ(SW_IACK, sw_iack); | |
371 | p += sprintf(p, "VERR Interrupt:\t\t\t"); | |
372 | REPORT_IRQ(VERR, verr); | |
373 | p += sprintf(p, "LERR Interrupt:\t\t\t"); | |
374 | REPORT_IRQ(LERR, lerr); | |
375 | p += sprintf(p, "LM Interrupt:\t\t\t"); | |
376 | REPORT_IRQ(LM, lm); | |
377 | p += sprintf(p, "MBOX Interrupt:\t\t\t"); | |
378 | REPORT_IRQ(MBOX, mbox); | |
379 | p += sprintf(p, "DMA Interrupt:\t\t\t"); | |
380 | REPORT_IRQ(DMA, dma); | |
381 | p += sprintf(p, "VIRQ7 Interrupt:\t\t"); | |
382 | REPORT_IRQ(VIRQ7, virq[7 - 1]); | |
383 | p += sprintf(p, "VIRQ6 Interrupt:\t\t"); | |
384 | REPORT_IRQ(VIRQ6, virq[6 - 1]); | |
385 | p += sprintf(p, "VIRQ5 Interrupt:\t\t"); | |
386 | REPORT_IRQ(VIRQ5, virq[5 - 1]); | |
387 | p += sprintf(p, "VIRQ4 Interrupt:\t\t"); | |
388 | REPORT_IRQ(VIRQ4, virq[4 - 1]); | |
389 | p += sprintf(p, "VIRQ3 Interrupt:\t\t"); | |
390 | REPORT_IRQ(VIRQ3, virq[3 - 1]); | |
391 | p += sprintf(p, "VIRQ2 Interrupt:\t\t"); | |
392 | REPORT_IRQ(VIRQ2, virq[2 - 1]); | |
393 | p += sprintf(p, "VIRQ1 Interrupt:\t\t"); | |
394 | REPORT_IRQ(VIRQ1, virq[1 - 1]); | |
395 | p += sprintf(p, "VOWN Interrupt:\t\t\t"); | |
396 | REPORT_IRQ(VOWN, vown); | |
397 | p += sprintf(p, "\n"); | |
398 | #undef REPORT_IRQ | |
399 | } | |
400 | { | |
401 | unsigned long vrai_ctl; | |
402 | ||
403 | vrai_ctl = read_register(VRAI_CTL); | |
404 | if (vrai_ctl & UNIV_BM_VRAI_CTL_EN) { | |
405 | unsigned int vrai_bs; | |
406 | ||
407 | vrai_bs = read_register(VRAI_BS); | |
408 | p += sprintf(p, | |
409 | "VME Register Image:\t\tEnabled at VME-Address 0x%x\n", | |
410 | vrai_bs); | |
411 | } else | |
412 | p += sprintf(p, "VME Register Image:\t\tDisabled\n"); | |
413 | } | |
414 | { | |
415 | unsigned int slsi; | |
416 | ||
417 | slsi = read_register(SLSI); | |
418 | if (slsi & UNIV_BM_SLSI_EN) { | |
419 | /* Not implemented */ | |
420 | } else { | |
421 | p += sprintf(p, "Special PCI Slave Image:\tDisabled\n"); | |
422 | } | |
423 | } | |
424 | { | |
425 | int i; | |
426 | ||
427 | for (i = 0; i < (vmechip_revision > 0 ? 8 : 4); i++) { | |
428 | unsigned int ctl, bs, bd, to, vstart, vend; | |
429 | ||
430 | ctl = readl(vmechip_baseaddr + outCTL[i]); | |
431 | bs = readl(vmechip_baseaddr + outBS[i]); | |
432 | bd = readl(vmechip_baseaddr + outBD[i]); | |
433 | to = readl(vmechip_baseaddr + outTO[i]); | |
434 | ||
435 | vstart = bs + to; | |
436 | vend = bd + to; | |
437 | ||
438 | p += sprintf(p, "PCI Slave Image %d:\t\t", i); | |
439 | if (ctl & UNIV_BM_LSI_CTL_EN) { | |
440 | p += sprintf(p, "Enabled"); | |
441 | if (ctl & UNIV_BM_LSI_CTL_PWEN) | |
442 | p += sprintf(p, | |
443 | ", Posted Write Enabled\n"); | |
444 | else | |
445 | p += sprintf(p, "\n"); | |
446 | p += sprintf(p, | |
447 | "\t\t\t\tPCI Addresses from 0x%x to 0x%x\n", | |
448 | bs, bd); | |
449 | p += sprintf(p, | |
450 | "\t\t\t\tVME Addresses from 0x%x to 0x%x\n", | |
451 | vstart, vend); | |
452 | } else | |
453 | p += sprintf(p, "Disabled\n"); | |
454 | } | |
455 | p += sprintf(p, "\n"); | |
456 | } | |
457 | { | |
458 | int i; | |
459 | for (i = 0; i < (vmechip_revision > 0 ? 8 : 4); i++) { | |
460 | unsigned int ctl, bs, bd, to, vstart, vend; | |
461 | ||
462 | ctl = readl(vmechip_baseaddr + inCTL[i]); | |
463 | bs = readl(vmechip_baseaddr + inBS[i]); | |
464 | bd = readl(vmechip_baseaddr + inBD[i]); | |
465 | to = readl(vmechip_baseaddr + inTO[i]); | |
466 | vstart = bs + to; | |
467 | vend = bd + to; | |
468 | p += sprintf(p, "VME Slave Image %d:\t\t", i); | |
469 | if (ctl & UNIV_BM_LSI_CTL_EN) { | |
470 | p += sprintf(p, "Enabled"); | |
471 | if (ctl & UNIV_BM_LSI_CTL_PWEN) | |
472 | p += sprintf(p, | |
473 | ", Posted Write Enabled\n"); | |
474 | else | |
475 | p += sprintf(p, "\n"); | |
476 | p += sprintf(p, | |
477 | "\t\t\t\tVME Addresses from 0x%x to 0x%x\n", | |
478 | bs, bd); | |
479 | p += sprintf(p, | |
480 | "\t\t\t\tPCI Addresses from 0x%x to 0x%x\n", | |
481 | vstart, vend); | |
482 | } else | |
483 | p += sprintf(p, "Disabled\n"); | |
484 | } | |
485 | } | |
486 | ||
487 | return p - buf; | |
488 | } | |
489 | ||
490 | //---------------------------------------------------------------------------- | |
491 | // uni_bus_error_chk() | |
492 | //---------------------------------------------------------------------------- | |
493 | int uni_bus_error_chk(int clrflag) | |
494 | { | |
495 | int tmp; | |
496 | tmp = readl(vmechip_baseaddr + PCI_COMMAND); | |
497 | if (tmp & 0x08000000) { // S_TA is Set | |
498 | if (clrflag) | |
499 | writel(tmp | 0x08000000, | |
500 | vmechip_baseaddr + PCI_COMMAND); | |
501 | return (1); | |
502 | } | |
503 | return (0); | |
504 | } | |
505 | ||
506 | //----------------------------------------------------------------------------- | |
507 | // Function : DMA_uni_irqhandler | |
508 | // Inputs : void | |
509 | // Outputs : void | |
510 | // Description: Saves DMA completion timestamp and then wakes up DMA queue | |
511 | //----------------------------------------------------------------------------- | |
512 | static void DMA_uni_irqhandler(void) | |
513 | { | |
514 | uni_dma_irq_time = uni_irq_time; | |
515 | wake_up(&dma_queue[0]); | |
516 | } | |
517 | ||
518 | //----------------------------------------------------------------------------- | |
519 | // Function : LERR_uni_irqhandler | |
520 | // Inputs : void | |
521 | // Outputs : void | |
522 | // Description: | |
523 | //----------------------------------------------------------------------------- | |
524 | static void LERR_uni_irqhandler(void) | |
525 | { | |
526 | int val; | |
527 | ||
528 | val = readl(vmechip_baseaddr + DGCS); | |
529 | ||
530 | if (!(val & 0x00000800)) { | |
531 | printk(KERN_ERR | |
532 | "ca91c042: LERR_uni_irqhandler DMA Read Error DGCS=%08X\n", | |
533 | val); | |
534 | ||
535 | } | |
536 | } | |
537 | ||
538 | //----------------------------------------------------------------------------- | |
539 | // Function : VERR_uni_irqhandler | |
540 | // Inputs : void | |
541 | // Outputs : void | |
542 | // Description: | |
543 | //----------------------------------------------------------------------------- | |
544 | static void VERR_uni_irqhandler(void) | |
545 | { | |
546 | int val; | |
547 | ||
548 | val = readl(vmechip_baseaddr + DGCS); | |
549 | ||
550 | if (!(val & 0x00000800)) { | |
551 | printk(KERN_ERR | |
552 | "ca91c042: VERR_uni_irqhandler DMA Read Error DGCS=%08X\n", | |
553 | val); | |
554 | } | |
555 | ||
556 | } | |
557 | ||
558 | //----------------------------------------------------------------------------- | |
559 | // Function : MB_uni_irqhandler | |
560 | // Inputs : void | |
561 | // Outputs : void | |
562 | // Description: | |
563 | //----------------------------------------------------------------------------- | |
564 | static void MB_uni_irqhandler(int mbox_mask) | |
565 | { | |
566 | if (vmechip_irq_overhead_ticks != 0) { | |
567 | wake_up(&mbox_queue); | |
568 | } | |
569 | } | |
570 | ||
571 | //----------------------------------------------------------------------------- | |
572 | // Function : LM_uni_irqhandler | |
573 | // Inputs : void | |
574 | // Outputs : void | |
575 | // Description: | |
576 | //----------------------------------------------------------------------------- | |
577 | static void LM_uni_irqhandler(int lm_mask) | |
578 | { | |
579 | uni_lm_event = lm_mask; | |
580 | wake_up(&lm_queue); | |
581 | } | |
582 | ||
583 | //----------------------------------------------------------------------------- | |
584 | // Function : VIRQ_uni_irqhandler | |
585 | // Inputs : void | |
586 | // Outputs : void | |
587 | // Description: | |
588 | //----------------------------------------------------------------------------- | |
589 | static void VIRQ_uni_irqhandler(int virq_mask) | |
590 | { | |
591 | int iackvec, i; | |
592 | ||
593 | for (i = 7; i > 0; i--) { | |
594 | if (virq_mask & (1 << i)) { | |
595 | Interrupt_counters.virq[i - 1]++; | |
596 | iackvec = readl(vmechip_baseaddr + vmevec[i - 1]); | |
597 | vme_irqlog[i][iackvec]++; | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
602 | //----------------------------------------------------------------------------- | |
603 | // Function : uni_irqhandler | |
604 | // Inputs : int irq, void *dev_id, struct pt_regs *regs | |
605 | // Outputs : void | |
606 | // Description: | |
607 | //----------------------------------------------------------------------------- | |
608 | static irqreturn_t uni_irqhandler(int irq, void *dev_id) | |
609 | { | |
610 | long stat, enable; | |
611 | ||
612 | if (dev_id != vmechip_baseaddr) | |
613 | return IRQ_NONE; | |
614 | ||
615 | uni_irq_time = get_tbl(); | |
616 | ||
617 | stat = readl(vmechip_baseaddr + LINT_STAT); | |
618 | writel(stat, vmechip_baseaddr + LINT_STAT); // Clear all pending ints | |
619 | enable = readl(vmechip_baseaddr + LINT_EN); | |
620 | stat = stat & enable; | |
621 | if (stat & 0x0100) { | |
622 | Interrupt_counters.dma++; | |
623 | DMA_uni_irqhandler(); | |
624 | } | |
625 | if (stat & 0x0200) { | |
626 | Interrupt_counters.lerr++; | |
627 | LERR_uni_irqhandler(); | |
628 | } | |
629 | if (stat & 0x0400) { | |
630 | Interrupt_counters.verr++; | |
631 | VERR_uni_irqhandler(); | |
632 | } | |
633 | if (stat & 0xF0000) { | |
634 | Interrupt_counters.mbox++; | |
635 | MB_uni_irqhandler((stat & 0xF0000) >> 16); | |
636 | } | |
637 | if (stat & 0xF00000) { | |
638 | Interrupt_counters.lm++; | |
639 | LM_uni_irqhandler((stat & 0xF00000) >> 20); | |
640 | } | |
641 | if (stat & 0x0000FE) { | |
642 | VIRQ_uni_irqhandler(stat & 0x0000FE); | |
643 | } | |
644 | if (stat & UNIV_BM_LINT_ACFAIL) { | |
645 | Interrupt_counters.acfail++; | |
646 | } | |
647 | if (stat & UNIV_BM_LINT_SYSFAIL) { | |
648 | Interrupt_counters.sysfail++; | |
649 | } | |
650 | if (stat & UNIV_BM_LINT_SW_INT) { | |
651 | Interrupt_counters.sw_int++; | |
652 | } | |
653 | if (stat & UNIV_BM_LINT_SW_IACK) { | |
654 | Interrupt_counters.sw_iack++; | |
655 | } | |
656 | if (stat & UNIV_BM_LINT_VOWN) { | |
657 | Interrupt_counters.vown++; | |
658 | } | |
659 | ||
660 | return IRQ_HANDLED; | |
661 | } | |
662 | ||
663 | //----------------------------------------------------------------------------- | |
664 | // Function : uni_generate_irq | |
665 | // Description: | |
666 | //----------------------------------------------------------------------------- | |
667 | int uni_generate_irq(virqInfo_t * vmeIrq) | |
668 | { | |
669 | int timeout; | |
670 | int looptimeout; | |
671 | ||
672 | timeout = vmeIrq->waitTime; | |
673 | if (timeout == 0) { | |
674 | timeout++; // Wait at least 1 tick... | |
675 | } | |
676 | looptimeout = HZ / 20; // try for 1/20 second | |
677 | ||
678 | vmeIrq->timeOutFlag = 0; | |
679 | ||
680 | // Validate & setup vector register. | |
681 | if (vmeIrq->vector & 1) { // Universe can only generate even vectors | |
682 | return (-EINVAL); | |
683 | } | |
684 | writel(vmeIrq->vector << 24, vmechip_baseaddr + STATID); | |
685 | ||
686 | // Assert VMEbus IRQ | |
687 | writel(1 << (vmeIrq->level + 24), vmechip_baseaddr + VINT_EN); | |
688 | ||
689 | // Wait for syscon to do iack | |
690 | while (readl(vmechip_baseaddr + VINT_STAT) & | |
691 | (1 << (vmeIrq->level + 24))) { | |
692 | set_current_state(TASK_INTERRUPTIBLE); | |
693 | schedule_timeout(looptimeout); | |
694 | timeout = timeout - looptimeout; | |
695 | if (timeout <= 0) { | |
696 | vmeIrq->timeOutFlag = 1; | |
697 | break; | |
698 | } | |
699 | } | |
700 | ||
701 | // Clear VMEbus IRQ bit | |
702 | writel(0, vmechip_baseaddr + VINT_EN); | |
703 | ||
704 | return (0); | |
705 | } | |
706 | ||
707 | //----------------------------------------------------------------------------- | |
708 | // Function : uni_set_arbiter | |
709 | // Description: | |
710 | //----------------------------------------------------------------------------- | |
711 | int uni_set_arbiter(vmeArbiterCfg_t * vmeArb) | |
712 | { | |
713 | int temp_ctl = 0; | |
714 | int vbto = 0; | |
715 | ||
716 | temp_ctl = readl(vmechip_baseaddr + MISC_CTL); | |
717 | temp_ctl &= 0x00FFFFFF; | |
718 | ||
719 | if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) { | |
720 | vbto = 7; | |
721 | } else if (vmeArb->globalTimeoutTimer > 1024) { | |
722 | return (-EINVAL); | |
723 | } else if (vmeArb->globalTimeoutTimer == 0) { | |
724 | vbto = 0; | |
725 | } else { | |
726 | vbto = 1; | |
727 | while ((16 * (1 << (vbto - 1))) < vmeArb->globalTimeoutTimer) { | |
728 | vbto += 1; | |
729 | } | |
730 | } | |
731 | temp_ctl |= (vbto << 28); | |
732 | ||
733 | if (vmeArb->arbiterMode == VME_PRIORITY_MODE) { | |
734 | temp_ctl |= 1 << 26; | |
735 | } | |
736 | ||
737 | if (vmeArb->arbiterTimeoutFlag) { | |
738 | temp_ctl |= 2 << 24; | |
739 | } | |
740 | ||
741 | writel(temp_ctl, vmechip_baseaddr + MISC_CTL); | |
742 | return (0); | |
743 | } | |
744 | ||
745 | //----------------------------------------------------------------------------- | |
746 | // Function : uni_get_arbiter | |
747 | // Description: | |
748 | //----------------------------------------------------------------------------- | |
749 | int uni_get_arbiter(vmeArbiterCfg_t * vmeArb) | |
750 | { | |
751 | int temp_ctl = 0; | |
752 | int vbto = 0; | |
753 | ||
754 | temp_ctl = readl(vmechip_baseaddr + MISC_CTL); | |
755 | ||
756 | vbto = (temp_ctl >> 28) & 0xF; | |
757 | if (vbto != 0) { | |
758 | vmeArb->globalTimeoutTimer = (16 * (1 << (vbto - 1))); | |
759 | } | |
760 | ||
761 | if (temp_ctl & (1 << 26)) { | |
762 | vmeArb->arbiterMode = VME_PRIORITY_MODE; | |
763 | } else { | |
764 | vmeArb->arbiterMode = VME_R_ROBIN_MODE; | |
765 | } | |
766 | ||
767 | if (temp_ctl & (3 << 24)) { | |
768 | vmeArb->arbiterTimeoutFlag = 1; | |
769 | } | |
770 | return (0); | |
771 | } | |
772 | ||
773 | //----------------------------------------------------------------------------- | |
774 | // Function : uni_set_requestor | |
775 | // Description: | |
776 | //----------------------------------------------------------------------------- | |
777 | int uni_set_requestor(vmeRequesterCfg_t * vmeReq) | |
778 | { | |
779 | int temp_ctl = 0; | |
780 | ||
781 | temp_ctl = readl(vmechip_baseaddr + MAST_CTL); | |
782 | temp_ctl &= 0xFF0FFFFF; | |
783 | ||
784 | if (vmeReq->releaseMode == 1) { | |
785 | temp_ctl |= (1 << 20); | |
786 | } | |
787 | ||
788 | if (vmeReq->fairMode == 1) { | |
789 | temp_ctl |= (1 << 21); | |
790 | } | |
791 | ||
792 | temp_ctl |= (vmeReq->requestLevel << 22); | |
793 | ||
794 | writel(temp_ctl, vmechip_baseaddr + MAST_CTL); | |
795 | return (0); | |
796 | } | |
797 | ||
798 | //----------------------------------------------------------------------------- | |
799 | // Function : uni_get_requestor | |
800 | // Description: | |
801 | //----------------------------------------------------------------------------- | |
802 | int uni_get_requestor(vmeRequesterCfg_t * vmeReq) | |
803 | { | |
804 | int temp_ctl = 0; | |
805 | ||
806 | temp_ctl = readl(vmechip_baseaddr + MAST_CTL); | |
807 | ||
808 | if (temp_ctl & (1 << 20)) { | |
809 | vmeReq->releaseMode = 1; | |
810 | } | |
811 | ||
812 | if (temp_ctl & (1 << 21)) { | |
813 | vmeReq->fairMode = 1; | |
814 | } | |
815 | ||
816 | vmeReq->requestLevel = (temp_ctl & 0xC00000) >> 22; | |
817 | ||
818 | return (0); | |
819 | } | |
820 | ||
821 | //----------------------------------------------------------------------------- | |
822 | // Function : uni_set_in_bound | |
823 | // Description: | |
824 | //----------------------------------------------------------------------------- | |
825 | int uni_set_in_bound(vmeInWindowCfg_t * vmeIn) | |
826 | { | |
827 | int temp_ctl = 0; | |
828 | ||
829 | // Verify input data | |
830 | if (vmeIn->windowNbr > 7) { | |
831 | return (-EINVAL); | |
832 | } | |
833 | if ((vmeIn->vmeAddrU) || (vmeIn->windowSizeU) || (vmeIn->pciAddrU)) { | |
834 | return (-EINVAL); | |
835 | } | |
836 | if ((vmeIn->vmeAddrL & 0xFFF) || | |
837 | (vmeIn->windowSizeL & 0xFFF) || (vmeIn->pciAddrL & 0xFFF)) { | |
838 | return (-EINVAL); | |
839 | } | |
840 | ||
841 | if (vmeIn->bcastRespond2esst) { | |
842 | return (-EINVAL); | |
843 | } | |
844 | switch (vmeIn->addrSpace) { | |
845 | case VME_A64: | |
846 | case VME_CRCSR: | |
847 | case VME_USER3: | |
848 | case VME_USER4: | |
849 | return (-EINVAL); | |
850 | case VME_A16: | |
851 | temp_ctl |= 0x00000; | |
852 | break; | |
853 | case VME_A24: | |
854 | temp_ctl |= 0x10000; | |
855 | break; | |
856 | case VME_A32: | |
857 | temp_ctl |= 0x20000; | |
858 | break; | |
859 | case VME_USER1: | |
860 | temp_ctl |= 0x60000; | |
861 | break; | |
862 | case VME_USER2: | |
863 | temp_ctl |= 0x70000; | |
864 | break; | |
865 | } | |
866 | ||
867 | // Disable while we are mucking around | |
868 | writel(0x00000000, vmechip_baseaddr + inCTL[vmeIn->windowNbr]); | |
869 | writel(vmeIn->vmeAddrL, vmechip_baseaddr + inBS[vmeIn->windowNbr]); | |
870 | writel(vmeIn->vmeAddrL + vmeIn->windowSizeL, | |
871 | vmechip_baseaddr + inBD[vmeIn->windowNbr]); | |
872 | writel(vmeIn->pciAddrL - vmeIn->vmeAddrL, | |
873 | vmechip_baseaddr + inTO[vmeIn->windowNbr]); | |
874 | ||
875 | // Setup CTL register. | |
876 | if (vmeIn->wrPostEnable) | |
877 | temp_ctl |= 0x40000000; | |
878 | if (vmeIn->prefetchEnable) | |
879 | temp_ctl |= 0x20000000; | |
880 | if (vmeIn->rmwLock) | |
881 | temp_ctl |= 0x00000040; | |
882 | if (vmeIn->data64BitCapable) | |
883 | temp_ctl |= 0x00000080; | |
884 | if (vmeIn->userAccessType & VME_USER) | |
885 | temp_ctl |= 0x00100000; | |
886 | if (vmeIn->userAccessType & VME_SUPER) | |
887 | temp_ctl |= 0x00200000; | |
888 | if (vmeIn->dataAccessType & VME_DATA) | |
889 | temp_ctl |= 0x00400000; | |
890 | if (vmeIn->dataAccessType & VME_PROG) | |
891 | temp_ctl |= 0x00800000; | |
892 | ||
893 | // Write ctl reg without enable | |
894 | writel(temp_ctl, vmechip_baseaddr + inCTL[vmeIn->windowNbr]); | |
895 | ||
896 | if (vmeIn->windowEnable) | |
897 | temp_ctl |= 0x80000000; | |
898 | ||
899 | writel(temp_ctl, vmechip_baseaddr + inCTL[vmeIn->windowNbr]); | |
900 | return (0); | |
901 | } | |
902 | ||
903 | //----------------------------------------------------------------------------- | |
904 | // Function : uni_get_in_bound | |
905 | // Description: | |
906 | //----------------------------------------------------------------------------- | |
907 | int uni_get_in_bound(vmeInWindowCfg_t * vmeIn) | |
908 | { | |
909 | int temp_ctl = 0; | |
910 | ||
911 | // Verify input data | |
912 | if (vmeIn->windowNbr > 7) { | |
913 | return (-EINVAL); | |
914 | } | |
915 | // Get Window mappings. | |
916 | vmeIn->vmeAddrL = readl(vmechip_baseaddr + inBS[vmeIn->windowNbr]); | |
917 | vmeIn->pciAddrL = vmeIn->vmeAddrL + | |
918 | readl(vmechip_baseaddr + inTO[vmeIn->windowNbr]); | |
919 | vmeIn->windowSizeL = readl(vmechip_baseaddr + inBD[vmeIn->windowNbr]) - | |
920 | vmeIn->vmeAddrL; | |
921 | ||
922 | temp_ctl = readl(vmechip_baseaddr + inCTL[vmeIn->windowNbr]); | |
923 | ||
924 | // Get Control & BUS attributes | |
925 | if (temp_ctl & 0x40000000) | |
926 | vmeIn->wrPostEnable = 1; | |
927 | if (temp_ctl & 0x20000000) | |
928 | vmeIn->prefetchEnable = 1; | |
929 | if (temp_ctl & 0x00000040) | |
930 | vmeIn->rmwLock = 1; | |
931 | if (temp_ctl & 0x00000080) | |
932 | vmeIn->data64BitCapable = 1; | |
933 | if (temp_ctl & 0x00100000) | |
934 | vmeIn->userAccessType |= VME_USER; | |
935 | if (temp_ctl & 0x00200000) | |
936 | vmeIn->userAccessType |= VME_SUPER; | |
937 | if (temp_ctl & 0x00400000) | |
938 | vmeIn->dataAccessType |= VME_DATA; | |
939 | if (temp_ctl & 0x00800000) | |
940 | vmeIn->dataAccessType |= VME_PROG; | |
941 | if (temp_ctl & 0x80000000) | |
942 | vmeIn->windowEnable = 1; | |
943 | ||
944 | switch ((temp_ctl & 0x70000) >> 16) { | |
945 | case 0x0: | |
946 | vmeIn->addrSpace = VME_A16; | |
947 | break; | |
948 | case 0x1: | |
949 | vmeIn->addrSpace = VME_A24; | |
950 | break; | |
951 | case 0x2: | |
952 | vmeIn->addrSpace = VME_A32; | |
953 | break; | |
954 | case 0x6: | |
955 | vmeIn->addrSpace = VME_USER1; | |
956 | break; | |
957 | case 0x7: | |
958 | vmeIn->addrSpace = VME_USER2; | |
959 | break; | |
960 | } | |
961 | ||
962 | return (0); | |
963 | } | |
964 | ||
965 | //----------------------------------------------------------------------------- | |
966 | // Function : uni_set_out_bound | |
967 | // Description: | |
968 | //----------------------------------------------------------------------------- | |
969 | int uni_set_out_bound(vmeOutWindowCfg_t * vmeOut) | |
970 | { | |
971 | int temp_ctl = 0; | |
972 | ||
973 | // Verify input data | |
974 | if (vmeOut->windowNbr > 7) { | |
975 | return (-EINVAL); | |
976 | } | |
977 | if ((vmeOut->xlatedAddrU) || (vmeOut->windowSizeU) | |
978 | || (vmeOut->pciBusAddrU)) { | |
979 | return (-EINVAL); | |
980 | } | |
981 | if ((vmeOut->xlatedAddrL & 0xFFF) || | |
982 | (vmeOut->windowSizeL & 0xFFF) || (vmeOut->pciBusAddrL & 0xFFF)) { | |
983 | return (-EINVAL); | |
984 | } | |
985 | if (vmeOut->bcastSelect2esst) { | |
986 | return (-EINVAL); | |
987 | } | |
988 | switch (vmeOut->addrSpace) { | |
989 | case VME_A64: | |
990 | case VME_USER3: | |
991 | case VME_USER4: | |
992 | return (-EINVAL); | |
993 | case VME_A16: | |
994 | temp_ctl |= 0x00000; | |
995 | break; | |
996 | case VME_A24: | |
997 | temp_ctl |= 0x10000; | |
998 | break; | |
999 | case VME_A32: | |
1000 | temp_ctl |= 0x20000; | |
1001 | break; | |
1002 | case VME_CRCSR: | |
1003 | temp_ctl |= 0x50000; | |
1004 | break; | |
1005 | case VME_USER1: | |
1006 | temp_ctl |= 0x60000; | |
1007 | break; | |
1008 | case VME_USER2: | |
1009 | temp_ctl |= 0x70000; | |
1010 | break; | |
1011 | } | |
1012 | ||
1013 | // Disable while we are mucking around | |
1014 | writel(0x00000000, vmechip_baseaddr + outCTL[vmeOut->windowNbr]); | |
1015 | writel(vmeOut->pciBusAddrL, | |
1016 | vmechip_baseaddr + outBS[vmeOut->windowNbr]); | |
1017 | writel(vmeOut->pciBusAddrL + vmeOut->windowSizeL, | |
1018 | vmechip_baseaddr + outBD[vmeOut->windowNbr]); | |
1019 | writel(vmeOut->xlatedAddrL - vmeOut->pciBusAddrL, | |
1020 | vmechip_baseaddr + outTO[vmeOut->windowNbr]); | |
1021 | ||
1022 | // Sanity check. | |
1023 | if (vmeOut->pciBusAddrL != | |
1024 | readl(vmechip_baseaddr + outBS[vmeOut->windowNbr])) { | |
1025 | printk(KERN_ERR | |
1026 | "ca91c042: out window: %x, failed to configure\n", | |
1027 | vmeOut->windowNbr); | |
1028 | return (-EINVAL); | |
1029 | } | |
1030 | ||
1031 | if (vmeOut->pciBusAddrL + vmeOut->windowSizeL != | |
1032 | readl(vmechip_baseaddr + outBD[vmeOut->windowNbr])) { | |
1033 | printk(KERN_ERR | |
1034 | "ca91c042: out window: %x, failed to configure\n", | |
1035 | vmeOut->windowNbr); | |
1036 | return (-EINVAL); | |
1037 | } | |
1038 | ||
1039 | if (vmeOut->xlatedAddrL - vmeOut->pciBusAddrL != | |
1040 | readl(vmechip_baseaddr + outTO[vmeOut->windowNbr])) { | |
1041 | printk(KERN_ERR | |
1042 | "ca91c042: out window: %x, failed to configure\n", | |
1043 | vmeOut->windowNbr); | |
1044 | return (-EINVAL); | |
1045 | } | |
1046 | // Setup CTL register. | |
1047 | if (vmeOut->wrPostEnable) | |
1048 | temp_ctl |= 0x40000000; | |
1049 | if (vmeOut->userAccessType & VME_SUPER) | |
1050 | temp_ctl |= 0x001000; | |
1051 | if (vmeOut->dataAccessType & VME_PROG) | |
1052 | temp_ctl |= 0x004000; | |
1053 | if (vmeOut->maxDataWidth == VME_D16) | |
1054 | temp_ctl |= 0x00400000; | |
1055 | if (vmeOut->maxDataWidth == VME_D32) | |
1056 | temp_ctl |= 0x00800000; | |
1057 | if (vmeOut->maxDataWidth == VME_D64) | |
1058 | temp_ctl |= 0x00C00000; | |
1059 | if (vmeOut->xferProtocol & (VME_BLT | VME_MBLT)) | |
1060 | temp_ctl |= 0x00000100; | |
1061 | ||
1062 | // Write ctl reg without enable | |
1063 | writel(temp_ctl, vmechip_baseaddr + outCTL[vmeOut->windowNbr]); | |
1064 | ||
1065 | if (vmeOut->windowEnable) | |
1066 | temp_ctl |= 0x80000000; | |
1067 | ||
1068 | writel(temp_ctl, vmechip_baseaddr + outCTL[vmeOut->windowNbr]); | |
1069 | return (0); | |
1070 | } | |
1071 | ||
1072 | //----------------------------------------------------------------------------- | |
1073 | // Function : uni_get_out_bound | |
1074 | // Description: | |
1075 | //----------------------------------------------------------------------------- | |
1076 | int uni_get_out_bound(vmeOutWindowCfg_t * vmeOut) | |
1077 | { | |
1078 | int temp_ctl = 0; | |
1079 | ||
1080 | // Verify input data | |
1081 | if (vmeOut->windowNbr > 7) { | |
1082 | return (-EINVAL); | |
1083 | } | |
1084 | // Get Window mappings. | |
1085 | vmeOut->pciBusAddrL = | |
1086 | readl(vmechip_baseaddr + outBS[vmeOut->windowNbr]); | |
1087 | vmeOut->xlatedAddrL = | |
1088 | vmeOut->pciBusAddrL + readl(vmechip_baseaddr + | |
1089 | outTO[vmeOut->windowNbr]); | |
1090 | vmeOut->windowSizeL = | |
1091 | readl(vmechip_baseaddr + outBD[vmeOut->windowNbr]) - | |
1092 | vmeOut->pciBusAddrL; | |
1093 | ||
1094 | temp_ctl = readl(vmechip_baseaddr + outCTL[vmeOut->windowNbr]); | |
1095 | ||
1096 | // Get Control & BUS attributes | |
1097 | if (temp_ctl & 0x40000000) | |
1098 | vmeOut->wrPostEnable = 1; | |
1099 | if (temp_ctl & 0x001000) | |
1100 | vmeOut->userAccessType = VME_SUPER; | |
1101 | else | |
1102 | vmeOut->userAccessType = VME_USER; | |
1103 | if (temp_ctl & 0x004000) | |
1104 | vmeOut->dataAccessType = VME_PROG; | |
1105 | else | |
1106 | vmeOut->dataAccessType = VME_DATA; | |
1107 | if (temp_ctl & 0x80000000) | |
1108 | vmeOut->windowEnable = 1; | |
1109 | ||
1110 | switch ((temp_ctl & 0x00C00000) >> 22) { | |
1111 | case 0: | |
1112 | vmeOut->maxDataWidth = VME_D8; | |
1113 | break; | |
1114 | case 1: | |
1115 | vmeOut->maxDataWidth = VME_D16; | |
1116 | break; | |
1117 | case 2: | |
1118 | vmeOut->maxDataWidth = VME_D32; | |
1119 | break; | |
1120 | case 3: | |
1121 | vmeOut->maxDataWidth = VME_D64; | |
1122 | break; | |
1123 | } | |
1124 | if (temp_ctl & 0x00000100) | |
1125 | vmeOut->xferProtocol = VME_BLT; | |
1126 | else | |
1127 | vmeOut->xferProtocol = VME_SCT; | |
1128 | ||
1129 | switch ((temp_ctl & 0x70000) >> 16) { | |
1130 | case 0x0: | |
1131 | vmeOut->addrSpace = VME_A16; | |
1132 | break; | |
1133 | case 0x1: | |
1134 | vmeOut->addrSpace = VME_A24; | |
1135 | break; | |
1136 | case 0x2: | |
1137 | vmeOut->addrSpace = VME_A32; | |
1138 | break; | |
1139 | case 0x5: | |
1140 | vmeOut->addrSpace = VME_CRCSR; | |
1141 | break; | |
1142 | case 0x6: | |
1143 | vmeOut->addrSpace = VME_USER1; | |
1144 | break; | |
1145 | case 0x7: | |
1146 | vmeOut->addrSpace = VME_USER2; | |
1147 | break; | |
1148 | } | |
1149 | ||
1150 | return (0); | |
1151 | } | |
1152 | ||
1153 | //----------------------------------------------------------------------------- | |
1154 | // Function : uni_setup_lm | |
1155 | // Description: | |
1156 | //----------------------------------------------------------------------------- | |
1157 | int uni_setup_lm(vmeLmCfg_t * vmeLm) | |
1158 | { | |
1159 | int temp_ctl = 0; | |
1160 | ||
1161 | if (vmeLm->addrU) { | |
1162 | return (-EINVAL); | |
1163 | } | |
1164 | switch (vmeLm->addrSpace) { | |
1165 | case VME_A64: | |
1166 | case VME_USER3: | |
1167 | case VME_USER4: | |
1168 | return (-EINVAL); | |
1169 | case VME_A16: | |
1170 | temp_ctl |= 0x00000; | |
1171 | break; | |
1172 | case VME_A24: | |
1173 | temp_ctl |= 0x10000; | |
1174 | break; | |
1175 | case VME_A32: | |
1176 | temp_ctl |= 0x20000; | |
1177 | break; | |
1178 | case VME_CRCSR: | |
1179 | temp_ctl |= 0x50000; | |
1180 | break; | |
1181 | case VME_USER1: | |
1182 | temp_ctl |= 0x60000; | |
1183 | break; | |
1184 | case VME_USER2: | |
1185 | temp_ctl |= 0x70000; | |
1186 | break; | |
1187 | } | |
1188 | ||
1189 | // Disable while we are mucking around | |
1190 | writel(0x00000000, vmechip_baseaddr + LM_CTL); | |
1191 | ||
1192 | writel(vmeLm->addr, vmechip_baseaddr + LM_BS); | |
1193 | ||
1194 | // Setup CTL register. | |
1195 | if (vmeLm->userAccessType & VME_SUPER) | |
1196 | temp_ctl |= 0x00200000; | |
1197 | if (vmeLm->userAccessType & VME_USER) | |
1198 | temp_ctl |= 0x00100000; | |
1199 | if (vmeLm->dataAccessType & VME_PROG) | |
1200 | temp_ctl |= 0x00800000; | |
1201 | if (vmeLm->dataAccessType & VME_DATA) | |
1202 | temp_ctl |= 0x00400000; | |
1203 | ||
1204 | uni_lm_event = 0; | |
1205 | ||
1206 | // Write ctl reg and enable | |
1207 | writel(0x80000000 | temp_ctl, vmechip_baseaddr + LM_CTL); | |
1208 | temp_ctl = readl(vmechip_baseaddr + LM_CTL); | |
1209 | ||
1210 | return (0); | |
1211 | } | |
1212 | ||
1213 | //----------------------------------------------------------------------------- | |
1214 | // Function : uni_wait_lm | |
1215 | // Description: | |
1216 | //----------------------------------------------------------------------------- | |
1217 | int uni_wait_lm(vmeLmCfg_t * vmeLm) | |
1218 | { | |
1219 | unsigned long flags; | |
1220 | unsigned int tmp; | |
1221 | ||
1222 | spin_lock_irqsave(&lm_lock, flags); | |
1223 | tmp = uni_lm_event; | |
1224 | spin_unlock_irqrestore(&lm_lock, flags); | |
1225 | if (tmp == 0) { | |
1226 | if (vmeLm->lmWait < 10) | |
1227 | vmeLm->lmWait = 10; | |
1228 | interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait); | |
1229 | } | |
1230 | writel(0x00000000, vmechip_baseaddr + LM_CTL); | |
1231 | vmeLm->lmEvents = uni_lm_event; | |
1232 | ||
1233 | return (0); | |
1234 | } | |
1235 | ||
1236 | #define SWIZZLE(X) ( ((X & 0xFF000000) >> 24) | ((X & 0x00FF0000) >> 8) | ((X & 0x0000FF00) << 8) | ((X & 0x000000FF) << 24)) | |
1237 | ||
1238 | //----------------------------------------------------------------------------- | |
1239 | // Function : uni_do_rmw | |
1240 | // Description: | |
1241 | //----------------------------------------------------------------------------- | |
1242 | int uni_do_rmw(vmeRmwCfg_t * vmeRmw) | |
1243 | { | |
1244 | int temp_ctl = 0; | |
1245 | int tempBS = 0; | |
1246 | int tempBD = 0; | |
1247 | int tempTO = 0; | |
1248 | int vmeBS = 0; | |
1249 | int vmeBD = 0; | |
1250 | int *rmw_pci_data_ptr = NULL; | |
1251 | int *vaDataPtr = NULL; | |
1252 | int i; | |
1253 | vmeOutWindowCfg_t vmeOut; | |
1254 | if (vmeRmw->maxAttempts < 1) { | |
1255 | return (-EINVAL); | |
1256 | } | |
1257 | if (vmeRmw->targetAddrU) { | |
1258 | return (-EINVAL); | |
1259 | } | |
1260 | // Find the PCI address that maps to the desired VME address | |
1261 | for (i = 0; i < 8; i++) { | |
1262 | temp_ctl = readl(vmechip_baseaddr + outCTL[i]); | |
1263 | if ((temp_ctl & 0x80000000) == 0) { | |
1264 | continue; | |
1265 | } | |
1266 | memset(&vmeOut, 0, sizeof(vmeOut)); | |
1267 | vmeOut.windowNbr = i; | |
1268 | uni_get_out_bound(&vmeOut); | |
1269 | if (vmeOut.addrSpace != vmeRmw->addrSpace) { | |
1270 | continue; | |
1271 | } | |
1272 | tempBS = readl(vmechip_baseaddr + outBS[i]); | |
1273 | tempBD = readl(vmechip_baseaddr + outBD[i]); | |
1274 | tempTO = readl(vmechip_baseaddr + outTO[i]); | |
1275 | vmeBS = tempBS + tempTO; | |
1276 | vmeBD = tempBD + tempTO; | |
1277 | if ((vmeRmw->targetAddr >= vmeBS) && | |
1278 | (vmeRmw->targetAddr < vmeBD)) { | |
1279 | rmw_pci_data_ptr = | |
1280 | (int *)(tempBS + (vmeRmw->targetAddr - vmeBS)); | |
1281 | vaDataPtr = | |
1282 | (int *)(out_image_va[i] + | |
1283 | (vmeRmw->targetAddr - vmeBS)); | |
1284 | break; | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | // If no window - fail. | |
1289 | if (rmw_pci_data_ptr == NULL) { | |
1290 | return (-EINVAL); | |
1291 | } | |
1292 | // Setup the RMW registers. | |
1293 | writel(0, vmechip_baseaddr + SCYC_CTL); | |
1294 | writel(SWIZZLE(vmeRmw->enableMask), vmechip_baseaddr + SCYC_EN); | |
1295 | writel(SWIZZLE(vmeRmw->compareData), vmechip_baseaddr + SCYC_CMP); | |
1296 | writel(SWIZZLE(vmeRmw->swapData), vmechip_baseaddr + SCYC_SWP); | |
1297 | writel((int)rmw_pci_data_ptr, vmechip_baseaddr + SCYC_ADDR); | |
1298 | writel(1, vmechip_baseaddr + SCYC_CTL); | |
1299 | ||
1300 | // Run the RMW cycle until either success or max attempts. | |
1301 | vmeRmw->numAttempts = 1; | |
1302 | while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) { | |
1303 | ||
1304 | if ((readl(vaDataPtr) & vmeRmw->enableMask) == | |
1305 | (vmeRmw->swapData & vmeRmw->enableMask)) { | |
1306 | ||
1307 | writel(0, vmechip_baseaddr + SCYC_CTL); | |
1308 | break; | |
1309 | ||
1310 | } | |
1311 | vmeRmw->numAttempts++; | |
1312 | } | |
1313 | ||
1314 | // If no success, set num Attempts to be greater than max attempts | |
1315 | if (vmeRmw->numAttempts > vmeRmw->maxAttempts) { | |
1316 | vmeRmw->numAttempts = vmeRmw->maxAttempts + 1; | |
1317 | } | |
1318 | ||
1319 | return (0); | |
1320 | } | |
1321 | ||
1322 | //----------------------------------------------------------------------------- | |
1323 | // Function : uniSetupDctlReg | |
1324 | // Description: | |
1325 | //----------------------------------------------------------------------------- | |
1326 | int uniSetupDctlReg(vmeDmaPacket_t * vmeDma, int *dctlregreturn) | |
1327 | { | |
1328 | unsigned int dctlreg = 0x80; | |
1329 | struct vmeAttr *vmeAttr; | |
1330 | ||
1331 | if (vmeDma->srcBus == VME_DMA_VME) { | |
1332 | dctlreg = 0; | |
1333 | vmeAttr = &vmeDma->srcVmeAttr; | |
1334 | } else { | |
1335 | dctlreg = 0x80000000; | |
1336 | vmeAttr = &vmeDma->dstVmeAttr; | |
1337 | } | |
1338 | ||
1339 | switch (vmeAttr->maxDataWidth) { | |
1340 | case VME_D8: | |
1341 | break; | |
1342 | case VME_D16: | |
1343 | dctlreg |= 0x00400000; | |
1344 | break; | |
1345 | case VME_D32: | |
1346 | dctlreg |= 0x00800000; | |
1347 | break; | |
1348 | case VME_D64: | |
1349 | dctlreg |= 0x00C00000; | |
1350 | break; | |
1351 | } | |
1352 | ||
1353 | switch (vmeAttr->addrSpace) { | |
1354 | case VME_A16: | |
1355 | break; | |
1356 | case VME_A24: | |
1357 | dctlreg |= 0x00010000; | |
1358 | break; | |
1359 | case VME_A32: | |
1360 | dctlreg |= 0x00020000; | |
1361 | break; | |
1362 | case VME_USER1: | |
1363 | dctlreg |= 0x00060000; | |
1364 | break; | |
1365 | case VME_USER2: | |
1366 | dctlreg |= 0x00070000; | |
1367 | break; | |
1368 | ||
1369 | case VME_A64: // not supported in Universe DMA | |
1370 | case VME_CRCSR: | |
1371 | case VME_USER3: | |
1372 | case VME_USER4: | |
1373 | return (-EINVAL); | |
1374 | break; | |
1375 | } | |
1376 | if (vmeAttr->userAccessType == VME_PROG) { | |
1377 | dctlreg |= 0x00004000; | |
1378 | } | |
1379 | if (vmeAttr->dataAccessType == VME_SUPER) { | |
1380 | dctlreg |= 0x00001000; | |
1381 | } | |
1382 | if (vmeAttr->xferProtocol != VME_SCT) { | |
1383 | dctlreg |= 0x00000100; | |
1384 | } | |
1385 | *dctlregreturn = dctlreg; | |
1386 | return (0); | |
1387 | } | |
1388 | ||
1389 | //----------------------------------------------------------------------------- | |
1390 | // Function : uni_start_dma | |
1391 | // Description: | |
1392 | //----------------------------------------------------------------------------- | |
1393 | unsigned int | |
1394 | uni_start_dma(int channel, unsigned int dgcsreg, TDMA_Cmd_Packet * vmeLL) | |
1395 | { | |
1396 | unsigned int val; | |
1397 | ||
1398 | // Setup registers as needed for direct or chained. | |
1399 | if (dgcsreg & 0x8000000) { | |
1400 | writel(0, vmechip_baseaddr + DTBC); | |
1401 | writel((unsigned int)vmeLL, vmechip_baseaddr + DCPP); | |
1402 | } else { | |
1403 | #if 0 | |
1404 | printk("Starting: DGCS = %08x\n", dgcsreg); | |
1405 | printk("Starting: DVA = %08x\n", readl(&vmeLL->dva)); | |
1406 | printk("Starting: DLV = %08x\n", readl(&vmeLL->dlv)); | |
1407 | printk("Starting: DTBC = %08x\n", readl(&vmeLL->dtbc)); | |
1408 | printk("Starting: DCTL = %08x\n", readl(&vmeLL->dctl)); | |
1409 | #endif | |
1410 | // Write registers | |
1411 | writel(readl(&vmeLL->dva), vmechip_baseaddr + DVA); | |
1412 | writel(readl(&vmeLL->dlv), vmechip_baseaddr + DLA); | |
1413 | writel(readl(&vmeLL->dtbc), vmechip_baseaddr + DTBC); | |
1414 | writel(readl(&vmeLL->dctl), vmechip_baseaddr + DCTL); | |
1415 | writel(0, vmechip_baseaddr + DCPP); | |
1416 | } | |
1417 | ||
1418 | // Start the operation | |
1419 | writel(dgcsreg, vmechip_baseaddr + DGCS); | |
1420 | val = get_tbl(); | |
1421 | writel(dgcsreg | 0x8000000F, vmechip_baseaddr + DGCS); | |
1422 | return (val); | |
1423 | } | |
1424 | ||
1425 | //----------------------------------------------------------------------------- | |
1426 | // Function : uni_setup_dma | |
1427 | // Description: | |
1428 | //----------------------------------------------------------------------------- | |
1429 | TDMA_Cmd_Packet *uni_setup_dma(vmeDmaPacket_t * vmeDma) | |
1430 | { | |
1431 | vmeDmaPacket_t *vmeCur; | |
1432 | int maxPerPage; | |
1433 | int currentLLcount; | |
1434 | TDMA_Cmd_Packet *startLL; | |
1435 | TDMA_Cmd_Packet *currentLL; | |
1436 | TDMA_Cmd_Packet *nextLL; | |
1437 | unsigned int dctlreg = 0; | |
1438 | ||
1439 | maxPerPage = PAGESIZE / sizeof(TDMA_Cmd_Packet) - 1; | |
1440 | startLL = (TDMA_Cmd_Packet *) __get_free_pages(GFP_KERNEL, 0); | |
1441 | if (startLL == 0) { | |
1442 | return (startLL); | |
1443 | } | |
1444 | // First allocate pages for descriptors and create linked list | |
1445 | vmeCur = vmeDma; | |
1446 | currentLL = startLL; | |
1447 | currentLLcount = 0; | |
1448 | while (vmeCur != 0) { | |
1449 | if (vmeCur->pNextPacket != 0) { | |
1450 | currentLL->dcpp = (unsigned int)(currentLL + 1); | |
1451 | currentLLcount++; | |
1452 | if (currentLLcount >= maxPerPage) { | |
1453 | currentLL->dcpp = | |
1454 | __get_free_pages(GFP_KERNEL, 0); | |
1455 | currentLLcount = 0; | |
1456 | } | |
1457 | currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp; | |
1458 | } else { | |
1459 | currentLL->dcpp = (unsigned int)0; | |
1460 | } | |
1461 | vmeCur = vmeCur->pNextPacket; | |
1462 | } | |
1463 | ||
1464 | // Next fill in information for each descriptor | |
1465 | vmeCur = vmeDma; | |
1466 | currentLL = startLL; | |
1467 | while (vmeCur != 0) { | |
1468 | if (vmeCur->srcBus == VME_DMA_VME) { | |
1469 | writel(vmeCur->srcAddr, ¤tLL->dva); | |
1470 | writel(vmeCur->dstAddr, ¤tLL->dlv); | |
1471 | } else { | |
1472 | writel(vmeCur->srcAddr, ¤tLL->dlv); | |
1473 | writel(vmeCur->dstAddr, ¤tLL->dva); | |
1474 | } | |
1475 | uniSetupDctlReg(vmeCur, &dctlreg); | |
1476 | writel(dctlreg, ¤tLL->dctl); | |
1477 | writel(vmeCur->byteCount, ¤tLL->dtbc); | |
1478 | ||
1479 | currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp; | |
1480 | vmeCur = vmeCur->pNextPacket; | |
1481 | } | |
1482 | ||
1483 | // Convert Links to PCI addresses. | |
1484 | currentLL = startLL; | |
1485 | while (currentLL != 0) { | |
1486 | nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp; | |
1487 | if (nextLL == 0) { | |
1488 | writel(1, ¤tLL->dcpp); | |
1489 | } else { | |
1490 | writel((unsigned int)virt_to_bus(nextLL), | |
1491 | ¤tLL->dcpp); | |
1492 | } | |
1493 | currentLL = nextLL; | |
1494 | } | |
1495 | ||
1496 | // Return pointer to descriptors list | |
1497 | return (startLL); | |
1498 | } | |
1499 | ||
1500 | //----------------------------------------------------------------------------- | |
1501 | // Function : uni_free_dma | |
1502 | // Description: | |
1503 | //----------------------------------------------------------------------------- | |
1504 | int uni_free_dma(TDMA_Cmd_Packet * startLL) | |
1505 | { | |
1506 | TDMA_Cmd_Packet *currentLL; | |
1507 | TDMA_Cmd_Packet *prevLL; | |
1508 | TDMA_Cmd_Packet *nextLL; | |
1509 | unsigned int dcppreg; | |
1510 | ||
1511 | // Convert Links to virtual addresses. | |
1512 | currentLL = startLL; | |
1513 | while (currentLL != 0) { | |
1514 | dcppreg = readl(¤tLL->dcpp); | |
1515 | dcppreg &= ~6; | |
1516 | if (dcppreg & 1) { | |
1517 | currentLL->dcpp = 0; | |
1518 | } else { | |
1519 | currentLL->dcpp = (unsigned int)bus_to_virt(dcppreg); | |
1520 | } | |
1521 | currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp; | |
1522 | } | |
1523 | ||
1524 | // Free all pages associated with the descriptors. | |
1525 | currentLL = startLL; | |
1526 | prevLL = currentLL; | |
1527 | while (currentLL != 0) { | |
1528 | nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp; | |
1529 | if (currentLL + 1 != nextLL) { | |
1530 | free_pages((int)prevLL, 0); | |
1531 | prevLL = nextLL; | |
1532 | } | |
1533 | currentLL = nextLL; | |
1534 | } | |
1535 | ||
1536 | // Return pointer to descriptors list | |
1537 | return (0); | |
1538 | } | |
1539 | ||
1540 | //----------------------------------------------------------------------------- | |
1541 | // Function : uni_do_dma | |
1542 | // Description: | |
1543 | //----------------------------------------------------------------------------- | |
1544 | int uni_do_dma(vmeDmaPacket_t * vmeDma) | |
1545 | { | |
1546 | unsigned int dgcsreg = 0; | |
1547 | unsigned int dctlreg = 0; | |
1548 | int val; | |
1549 | int channel, x; | |
1550 | vmeDmaPacket_t *curDma; | |
1551 | TDMA_Cmd_Packet *dmaLL; | |
1552 | ||
1553 | // Sanity check the VME chain. | |
1554 | channel = vmeDma->channel_number; | |
1555 | if (channel > 0) { | |
1556 | return (-EINVAL); | |
1557 | } | |
1558 | curDma = vmeDma; | |
1559 | while (curDma != 0) { | |
1560 | if (curDma->byteCount == 0) { | |
1561 | return (-EINVAL); | |
1562 | } | |
1563 | if (curDma->byteCount >= 0x1000000) { | |
1564 | return (-EINVAL); | |
1565 | } | |
1566 | if ((curDma->srcAddr & 7) != (curDma->dstAddr & 7)) { | |
1567 | return (-EINVAL); | |
1568 | } | |
1569 | switch (curDma->srcBus) { | |
1570 | case VME_DMA_PCI: | |
1571 | if (curDma->dstBus != VME_DMA_VME) { | |
1572 | return (-EINVAL); | |
1573 | } | |
1574 | break; | |
1575 | case VME_DMA_VME: | |
1576 | if (curDma->dstBus != VME_DMA_PCI) { | |
1577 | return (-EINVAL); | |
1578 | } | |
1579 | break; | |
1580 | default: | |
1581 | return (-EINVAL); | |
1582 | break; | |
1583 | } | |
1584 | if (uniSetupDctlReg(curDma, &dctlreg) < 0) { | |
1585 | return (-EINVAL); | |
1586 | } | |
1587 | ||
1588 | curDma = curDma->pNextPacket; | |
1589 | if (curDma == vmeDma) { // Endless Loop! | |
1590 | return (-EINVAL); | |
1591 | } | |
1592 | } | |
1593 | ||
1594 | // calculate control register | |
1595 | if (vmeDma->pNextPacket != 0) { | |
1596 | dgcsreg = 0x8000000; | |
1597 | } else { | |
1598 | dgcsreg = 0; | |
1599 | } | |
1600 | ||
1601 | for (x = 0; x < 8; x++) { // vme block size | |
1602 | if ((256 << x) >= vmeDma->maxVmeBlockSize) { | |
1603 | break; | |
1604 | } | |
1605 | } | |
1606 | if (x == 8) | |
1607 | x = 7; | |
1608 | dgcsreg |= (x << 20); | |
1609 | ||
1610 | if (vmeDma->vmeBackOffTimer) { | |
1611 | for (x = 1; x < 8; x++) { // vme timer | |
1612 | if ((16 << (x - 1)) >= vmeDma->vmeBackOffTimer) { | |
1613 | break; | |
1614 | } | |
1615 | } | |
1616 | if (x == 8) | |
1617 | x = 7; | |
1618 | dgcsreg |= (x << 16); | |
1619 | } | |
1620 | // Setup the dma chain | |
1621 | dmaLL = uni_setup_dma(vmeDma); | |
1622 | ||
1623 | // Start the DMA | |
1624 | if (dgcsreg & 0x8000000) { | |
1625 | vmeDma->vmeDmaStartTick = | |
1626 | uni_start_dma(channel, dgcsreg, | |
1627 | (TDMA_Cmd_Packet *) virt_to_phys(dmaLL)); | |
1628 | } else { | |
1629 | vmeDma->vmeDmaStartTick = | |
1630 | uni_start_dma(channel, dgcsreg, dmaLL); | |
1631 | } | |
1632 | ||
1633 | wait_event_interruptible(dma_queue[0], | |
1634 | readl(vmechip_baseaddr + DGCS) & 0x800); | |
1635 | ||
1636 | val = readl(vmechip_baseaddr + DGCS); | |
1637 | writel(val | 0xF00, vmechip_baseaddr + DGCS); | |
1638 | ||
1639 | vmeDma->vmeDmaStatus = 0; | |
1640 | vmeDma->vmeDmaStopTick = uni_dma_irq_time; | |
1641 | if (vmeDma->vmeDmaStopTick < vmeDma->vmeDmaStartTick) { | |
1642 | vmeDma->vmeDmaElapsedTime = | |
1643 | (0xFFFFFFFF - vmeDma->vmeDmaStartTick) + | |
1644 | vmeDma->vmeDmaStopTick; | |
1645 | } else { | |
1646 | vmeDma->vmeDmaElapsedTime = | |
1647 | vmeDma->vmeDmaStopTick - vmeDma->vmeDmaStartTick; | |
1648 | } | |
1649 | vmeDma->vmeDmaElapsedTime -= vmechip_irq_overhead_ticks; | |
1650 | vmeDma->vmeDmaElapsedTime /= (tb_speed / 1000000); | |
1651 | ||
1652 | if (!(val & 0x00000800)) { | |
1653 | vmeDma->vmeDmaStatus = val & 0x700; | |
1654 | printk(KERN_ERR | |
1655 | "ca91c042: DMA Error in DMA_uni_irqhandler DGCS=%08X\n", | |
1656 | val); | |
1657 | val = readl(vmechip_baseaddr + DCPP); | |
1658 | printk(KERN_ERR "ca91c042: DCPP=%08X\n", val); | |
1659 | val = readl(vmechip_baseaddr + DCTL); | |
1660 | printk(KERN_ERR "ca91c042: DCTL=%08X\n", val); | |
1661 | val = readl(vmechip_baseaddr + DTBC); | |
1662 | printk(KERN_ERR "ca91c042: DTBC=%08X\n", val); | |
1663 | val = readl(vmechip_baseaddr + DLA); | |
1664 | printk(KERN_ERR "ca91c042: DLA=%08X\n", val); | |
1665 | val = readl(vmechip_baseaddr + DVA); | |
1666 | printk(KERN_ERR "ca91c042: DVA=%08X\n", val); | |
1667 | ||
1668 | } | |
1669 | // Free the dma chain | |
1670 | uni_free_dma(dmaLL); | |
1671 | ||
1672 | return (0); | |
1673 | } | |
1674 | ||
1675 | //----------------------------------------------------------------------------- | |
1676 | // Function : uni_shutdown | |
1677 | // Description: Put VME bridge in quiescent state. | |
1678 | //----------------------------------------------------------------------------- | |
1679 | void uni_shutdown(void) | |
1680 | { | |
1681 | writel(0, vmechip_baseaddr + LINT_EN); // Turn off Ints | |
1682 | ||
1683 | // Turn off the windows | |
1684 | writel(0x00800000, vmechip_baseaddr + LSI0_CTL); | |
1685 | writel(0x00800000, vmechip_baseaddr + LSI1_CTL); | |
1686 | writel(0x00800000, vmechip_baseaddr + LSI2_CTL); | |
1687 | writel(0x00800000, vmechip_baseaddr + LSI3_CTL); | |
1688 | writel(0x00F00000, vmechip_baseaddr + VSI0_CTL); | |
1689 | writel(0x00F00000, vmechip_baseaddr + VSI1_CTL); | |
1690 | writel(0x00F00000, vmechip_baseaddr + VSI2_CTL); | |
1691 | writel(0x00F00000, vmechip_baseaddr + VSI3_CTL); | |
1692 | if (vmechip_revision >= 2) { | |
1693 | writel(0x00800000, vmechip_baseaddr + LSI4_CTL); | |
1694 | writel(0x00800000, vmechip_baseaddr + LSI5_CTL); | |
1695 | writel(0x00800000, vmechip_baseaddr + LSI6_CTL); | |
1696 | writel(0x00800000, vmechip_baseaddr + LSI7_CTL); | |
1697 | writel(0x00F00000, vmechip_baseaddr + VSI4_CTL); | |
1698 | writel(0x00F00000, vmechip_baseaddr + VSI5_CTL); | |
1699 | writel(0x00F00000, vmechip_baseaddr + VSI6_CTL); | |
1700 | writel(0x00F00000, vmechip_baseaddr + VSI7_CTL); | |
1701 | } | |
1702 | } | |
1703 | ||
1704 | //----------------------------------------------------------------------------- | |
1705 | // Function : uni_init() | |
1706 | // Description: | |
1707 | //----------------------------------------------------------------------------- | |
1708 | int uni_init(void) | |
1709 | { | |
1710 | int result; | |
1711 | unsigned int tmp; | |
1712 | unsigned int crcsr_addr; | |
1713 | unsigned int irqOverHeadStart; | |
1714 | int overHeadTicks; | |
1715 | ||
1716 | uni_shutdown(); | |
1717 | ||
1718 | // Write to Misc Register | |
1719 | // Set VME Bus Time-out | |
1720 | // Arbitration Mode | |
1721 | // DTACK Enable | |
1722 | tmp = readl(vmechip_baseaddr + MISC_CTL) & 0x0832BFFF; | |
1723 | tmp |= 0x76040000; | |
1724 | writel(tmp, vmechip_baseaddr + MISC_CTL); | |
1725 | if (tmp & 0x20000) { | |
1726 | vme_syscon = 1; | |
1727 | } else { | |
1728 | vme_syscon = 0; | |
1729 | } | |
1730 | ||
1731 | // Clear DMA status log | |
1732 | writel(0x00000F00, vmechip_baseaddr + DGCS); | |
1733 | // Clear and enable error log | |
1734 | writel(0x00800000, vmechip_baseaddr + L_CMDERR); | |
1735 | // Turn off location monitor | |
1736 | writel(0x00000000, vmechip_baseaddr + LM_CTL); | |
1737 | ||
1738 | // Initialize crcsr map | |
1739 | if (vme_slotnum != -1) { | |
1740 | writel(vme_slotnum << 27, vmechip_baseaddr + VCSR_BS); | |
1741 | } | |
1742 | crcsr_addr = readl(vmechip_baseaddr + VCSR_BS) >> 8; | |
1743 | writel((unsigned int)vmechip_interboard_datap - crcsr_addr, | |
1744 | vmechip_baseaddr + VCSR_TO); | |
1745 | if (vme_slotnum != -1) { | |
1746 | writel(0x80000000, vmechip_baseaddr + VCSR_CTL); | |
1747 | } | |
1748 | // Turn off interrupts | |
1749 | writel(0x00000000, vmechip_baseaddr + LINT_EN); // Disable interrupts in the Universe first | |
1750 | writel(0x00FFFFFF, vmechip_baseaddr + LINT_STAT); // Clear Any Pending Interrupts | |
1751 | writel(0x00000000, vmechip_baseaddr + VINT_EN); // Disable interrupts in the Universe first | |
1752 | ||
1753 | result = | |
1754 | request_irq(vmechip_irq, uni_irqhandler, IRQF_SHARED | IRQF_DISABLED, | |
1755 | "VMEBus (ca91c042)", vmechip_baseaddr); | |
1756 | if (result) { | |
1757 | printk(KERN_ERR | |
1758 | "ca91c042: can't get assigned pci irq vector %02X\n", | |
1759 | vmechip_irq); | |
1760 | return (0); | |
1761 | } else { | |
1762 | writel(0x0000, vmechip_baseaddr + LINT_MAP0); // Map all ints to 0 | |
1763 | writel(0x0000, vmechip_baseaddr + LINT_MAP1); // Map all ints to 0 | |
1764 | writel(0x0000, vmechip_baseaddr + LINT_MAP2); // Map all ints to 0 | |
1765 | } | |
1766 | ||
1767 | // Enable DMA, mailbox, VIRQ & LM Interrupts | |
1768 | if (vme_syscon) | |
1769 | tmp = 0x00FF07FE; | |
1770 | else | |
1771 | tmp = 0x00FF0700; | |
1772 | writel(tmp, vmechip_baseaddr + LINT_EN); | |
1773 | ||
1774 | // Do a quick sanity test of the bridge | |
1775 | if (readl(vmechip_baseaddr + LINT_EN) != tmp) { | |
1776 | return (0); | |
1777 | } | |
1778 | if (readl(vmechip_baseaddr + PCI_CLASS_REVISION) != 0x06800002) { | |
1779 | return (0); | |
1780 | } | |
1781 | for (tmp = 1; tmp < 0x80000000; tmp = tmp << 1) { | |
1782 | writel(tmp, vmechip_baseaddr + SCYC_EN); | |
1783 | writel(~tmp, vmechip_baseaddr + SCYC_CMP); | |
1784 | if (readl(vmechip_baseaddr + SCYC_EN) != tmp) { | |
1785 | return (0); | |
1786 | } | |
1787 | if (readl(vmechip_baseaddr + SCYC_CMP) != ~tmp) { | |
1788 | return (0); | |
1789 | } | |
1790 | } | |
1791 | ||
1792 | // do a mail box interrupt to calibrate the interrupt overhead. | |
1793 | ||
1794 | irqOverHeadStart = get_tbl(); | |
1795 | writel(0, vmechip_baseaddr + MBOX1); | |
1796 | for (tmp = 0; tmp < 10; tmp++) { | |
1797 | } | |
1798 | ||
1799 | irqOverHeadStart = get_tbl(); | |
1800 | writel(0, vmechip_baseaddr + MBOX1); | |
1801 | for (tmp = 0; tmp < 10; tmp++) { | |
1802 | } | |
1803 | ||
1804 | overHeadTicks = uni_irq_time - irqOverHeadStart; | |
1805 | if (overHeadTicks > 0) { | |
1806 | vmechip_irq_overhead_ticks = overHeadTicks; | |
1807 | } else { | |
1808 | vmechip_irq_overhead_ticks = 1; | |
1809 | } | |
1810 | return (1); | |
1811 | } |