forked from paulscherrerinstitute/tosca
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtoscaDevLib.c
335 lines (295 loc) · 10.1 KB
/
toscaDevLib.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#include <stdlib.h>
#include <devLibVME.h>
#include <epicsMutex.h>
#include <epicsTypes.h>
#include "toscaMap.h"
#include "toscaIntr.h"
#include "toscaReg.h"
#include <epicsExport.h>
#ifndef S_dev_badCRCSR
#define S_dev_badCRCSR S_dev_badA24
#endif
#include "symbolname.h"
/* EPICS has no way to request VME supervisory or user mode. Use Supervisory for all maps. */
#define VME_DEFAULT_MODE VME_SUPER
#define TOSCA_DEBUG_NAME toscaDevLib
#include "toscaDebug.h"
epicsExportAddress(int, toscaDevLibDebug);
/** VME mapping *****************/
const char* addrTypeName[] = {"atVMEA16","atVMEA24","atVMEA32","atISA","atVMECSR"};
long toscaDevLibMapAddr(
epicsAddressType addrType,
unsigned int options,
size_t vmeAddress,
size_t size,
volatile void **ppPhysicalAddress)
{
volatile void *mapAddress;
/* toscaMap() keeps track of and shares already existing maps.
No need to track already existing maps here.
*/
if (addrType >= atLast)
{
debug("illegal addrType %d", addrType);
return S_dev_badArgument;
}
debug("addrType=%s, options=%#x, vmeAddress=%#zx, size=%#zx, ppPhysicalAddress=%p",
addrTypeName[addrType], options, vmeAddress, size, ppPhysicalAddress);
if (vmeAddress + size < vmeAddress)
{
debug("address size overflow");
return S_dev_badArgument;
}
switch (addrType)
{
case atVMEA16:
{
if (vmeAddress + size > 0x10000ULL)
{
debug("A16 address %#zx out of range", vmeAddress + size);
return S_dev_badA16;
}
/* Map full A16 (64KiB). */
mapAddress = toscaMap(VME_A16 | VME_DEFAULT_MODE, 0, 0x10000, 0);
if (mapAddress) mapAddress += vmeAddress;
break;
}
case atVMEA24:
{
if (vmeAddress + size > 0x1000000ULL)
{
debug("A24 address %#zx out of range", vmeAddress + size);
return S_dev_badA24;
}
/* Map full A24 space because why not. */
mapAddress = toscaMap(VME_A24, 0, 0x1000000, 0) + vmeAddress;
break;
}
case atVMEA32:
#if __WORDSIZE > 32
if (vmeAddress + size > 0x100000000ULL)
{
debug("A32 address %#zx out of range", vmeAddress + size);
return S_dev_badA32;
}
#endif
mapAddress = toscaMap(VME_A32 | VME_DEFAULT_MODE, vmeAddress, size, 0);
break;
case atVMECSR:
if (vmeAddress + size > 0x1000000ULL)
{
debug("CRCSR address %#zx out of range", vmeAddress + size);
return S_dev_badCRCSR;
}
/* Map full CRCSR space because it needs to be scanned completely anyway. */
mapAddress = toscaMap(VME_CRCSR, 0, 0x1000000, 0) + vmeAddress;
break;
default:
return S_dev_uknAddrType;
}
if (!mapAddress)
{
debug("toscaMap failed");
return S_dev_addrMapFail;
}
*ppPhysicalAddress = mapAddress;
debug("%s:%#zx[%#zx] mapped to %p",
addrTypeName[addrType], vmeAddress, size, mapAddress);
return S_dev_success;
}
/** VME probing *****************/
epicsMutexId probeMutex;
long toscaDevLibProbe(
int isWrite,
unsigned int wordSize,
volatile const void *ptr,
void *pValue)
{
toscaMapAddr_t vme_addr;
toscaMapVmeErr_t vme_err;
void* readptr;
unsigned int device;
unsigned int i;
epicsUInt32 readval;
if (isWrite)
readptr = &readval;
else
readptr = pValue;
vme_addr = toscaMapLookupAddr(ptr);
if (!vme_addr.addrspace) return S_dev_addressNotFound;
device = vme_addr.addrspace>>16;
epicsMutexMustLock(probeMutex);
/* Read once to clear BERR bit. */
toscaGetVmeErr(device);
for (i = 1; i < 1000; i++) /* We don't want to loop forever. */
{
switch (wordSize)
{
case 1:
if (isWrite)
*(epicsUInt8 *)(ptr) = *(epicsUInt8 *)pValue;
else
*(epicsUInt8 *)readptr = *(epicsUInt8 *)(ptr);
break;
case 2:
if (isWrite)
*(epicsUInt16 *)(ptr) = *(epicsUInt16 *)pValue;
else
*(epicsUInt16 *)readptr = *(epicsUInt16 *)(ptr);
break;
case 4:
if (isWrite)
*(epicsUInt32 *)(ptr) = *(epicsUInt32 *)pValue;
else
*(epicsUInt32 *)readptr = *(epicsUInt32 *)(ptr);
break;
default:
epicsMutexUnlock(probeMutex);
return S_dev_badArgument;
}
vme_err = toscaGetVmeErr(device);
if (!vme_err.err) break; /* No error: success */
/* Now check if the error came from our access. */
debug("Our access was %s 0x%"PRIx64,
toscaAddrSpaceToStr(vme_addr.addrspace),
vme_addr.address);
if (vme_err.source == 0 && /* Error from PCIe, maybe our access. */
isWrite == vme_err.write) /* Read/write access matches. */
switch (vme_err.mode) /* Check address space of error. */
{
case 0: /* CRCSR */
debug("VME bus error at CRCSR 0x%"PRIx64, vme_err.address & 0xfffffc);
if ((vme_addr.addrspace & (VME_CRCSR|VME_A16|VME_A24|VME_A32)) == VME_CRCSR &&
((vme_err.address ^ vme_addr.address) & 0xfffffc) == 0)
{
epicsMutexUnlock(probeMutex);
return S_dev_noDevice;
}
break;
case 1: /* A16 */
debug("VME bus error at A16 0x%"PRIx64, vme_err.address & 0xfffc);
if ((vme_addr.addrspace & (VME_CRCSR|VME_A16|VME_A24|VME_A32)) == VME_A16 &&
((vme_err.address ^ vme_addr.address) & 0xfffc) == 0)
{
epicsMutexUnlock(probeMutex);
return S_dev_noDevice;
}
break;
case 2: /* A24 */
debug("VME bus error at A24 0x%"PRIx64, vme_err.address & 0xfffffc);
if ((vme_addr.addrspace & (VME_CRCSR|VME_A16|VME_A24|VME_A32)) == VME_A24 &&
((vme_err.address ^ vme_addr.address) & 0xfffffc) == 0)
{
epicsMutexUnlock(probeMutex);
return S_dev_noDevice;
}
break;
case 3: /* A32 */
debug("VME bus error at A32 0x%"PRIx64, vme_err.address & 0xfffffffc);
if ((vme_addr.addrspace & (VME_CRCSR|VME_A16|VME_A24|VME_A32)) == VME_A32 &&
((vme_err.address ^ vme_addr.address) & 0xfffffffc) == 0)
{
epicsMutexUnlock(probeMutex);
return S_dev_noDevice;
}
break;
}
debug("try again i=%d", i);
} /* Repeat until success or error matches our address */
/* ...or give up. All errors have always been on other addresses so far. */
epicsMutexUnlock(probeMutex);
return S_dev_success;
}
long toscaDevLibReadProbe(
unsigned int wordSize,
volatile const void *ptr,
void *pValue)
{
debug("wordSize=%d ptr=%p", wordSize, ptr);
return toscaDevLibProbe(0, wordSize, ptr, pValue);
}
long toscaDevLibWriteProbe(
unsigned int wordSize,
volatile void *ptr,
const void *pValue)
{
debug("wordSize=%d ptr=%p", wordSize, ptr);
return toscaDevLibProbe(1, wordSize, ptr, (void *)pValue);
}
/** VME interrupts *****************/
long toscaDevLibDisableInterruptLevelVME(unsigned int level)
{
if (level < 1 || level > 7) return S_dev_intEnFail;
toscaIntrDisable(TOSCA_VME_INTR(level));
return S_dev_success;
}
long toscaDevLibEnableInterruptLevelVME(unsigned int level)
{
if (level < 1 || level > 7) return S_dev_intDissFail;
toscaIntrEnable(TOSCA_VME_INTR(level));
return S_dev_success;
}
long toscaDevLibConnectInterrupt(
unsigned int vec,
void (*function)(),
void *parameter)
{
return toscaIntrConnectHandler(
vec < 256 ? TOSCA_VME_INTR_ANY_VEC(vec) : TOSCA_USER1_INTR(vec&31),
function, parameter);
}
long toscaDevLibDisconnectInterrupt(
unsigned int vec,
void (*function)())
{
return toscaIntrDisconnectHandler(
vec < 256 ? TOSCA_VME_INTR_ANY_VEC(vec) : TOSCA_USER1_INTR(vec&31),
function, NULL) ? S_dev_success : S_dev_vectorNotInUse;
}
int toscaDevLibInterruptInUseVME(unsigned int vec __attribute__((unused)))
{
/* Actually this asks if a new handler cannot be connected to vec.
Since we keep a linked list, a new handler can always be connected.
*/
return FALSE;
}
/** VME A24 DMA memory *****************/
void *toscaDevLibA24Malloc(size_t size __attribute__((unused)))
{
/* This function should allocate some DMA capable memory
* and map it into a A24 slave window.
* But TOSCA supports only A32 slave windows.
*/
return NULL;
}
void toscaDevLibA24Free(void *pBlock __attribute__((unused))) {};
/** Initialization *****************/
long toscaDevLibInit(void)
{
return S_dev_success;
}
/* compatibility with older versions of EPICS */
#if defined(pdevLibVirtualOS) && !defined(devLibVirtualOS)
#define devLibVirtualOS devLibVME
#endif
devLibVirtualOS toscaVirtualOS = {
toscaDevLibMapAddr,
toscaDevLibReadProbe,
toscaDevLibWriteProbe,
toscaDevLibConnectInterrupt,
toscaDevLibDisconnectInterrupt,
toscaDevLibEnableInterruptLevelVME,
toscaDevLibDisableInterruptLevelVME,
toscaDevLibA24Malloc,
toscaDevLibA24Free,
toscaDevLibInit,
#ifdef pdevLibVirtualOS
toscaDevLibInterruptInUseVME
#endif
};
static void toscaDevLibRegistrar ()
{
probeMutex = epicsMutexMustCreate();
pdevLibVirtualOS = &toscaVirtualOS;
}
epicsExportRegistrar(toscaDevLibRegistrar);