4 * @brief VME bus DMA support through TSI148 chip
6 * @author Copyright (C) 2009-2010 CERN. Yury GEORGIEVSKIY <ygeorgie@cern.ch>
8 * @date Created on 02/12/2009
10 * @section license_sec License
11 * Released under the GPL
13 #define _GNU_SOURCE /* asprintf rocks */
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
30 #define TSI148_LCSR_DSTA_VBE (1<<28) /* Error */
31 #define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */
32 #define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */
33 #define TSI148_LCSR_DSTA_DON (1<<25) /* Done */
34 #define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */
35 #define TSI148_LCSR_DSTA_ERRS (1<<20) /* Error Source */
36 #define TSI148_LCSR_DSTA_ERT (3<<16) /* Error Type */
37 #define TSI148_LCSR_DSTA_MASK 0x1f130000
39 unsigned int signum
; /* current signal number */
41 void sighandler(unsigned int sig
)
46 printf("\nBus error\n");
52 static __inline__
void __endian(const void *src
, void *dest
, unsigned int size
)
55 for (i
= 0; i
< size
; i
++)
56 ((unsigned char*)dest
)[i
] = ((unsigned char*)src
)[size
- i
- 1];
59 /* BE <-> LE convertion */
63 typeof(x) __val = (x); \
64 __endian(&(__val), &(__x), sizeof(__x)); \
69 * @brief Setup DMA description
71 * @param t -- operation type (r -- read, w -- write)
72 * @param ka -- VME address
73 * @param am -- VME address modifier
74 * @param dps -- Data Port Size (8, 16, 32, 64)
75 * @param buf -- user-space buffer to get/put data from/to
76 * @param eln -- number of elements to r/w
77 * @param d -- description table to init
79 static void setup_vme_desc(uint8_t t
, void *ka
, short am
, uint8_t dps
,
80 void *buf
, int eln
, struct vme_dma
*d
)
82 ulong vmeaddr
= (ulong
) ka
;
83 memset(d
, 0, sizeof(*d
));
85 if (t
== 'r') { /* read */
86 d
->dir
= VME_DMA_FROM_DEVICE
;
87 d
->src
.data_width
= dps
;
89 d
->src
.addrl
= (unsigned int) vmeaddr
;
90 d
->dst
.addrl
= (unsigned int) buf
;
92 d
->dir
= VME_DMA_TO_DEVICE
;
93 d
->dst
.data_width
= dps
;
95 d
->src
.addrl
= (unsigned int) buf
;
96 d
->dst
.addrl
= (unsigned int) vmeaddr
;
98 d
->length
= eln
* dps
/8; /* number of bytes to r/w */
99 d
->novmeinc
= 0; /* FIFO r/w (1 -- yes, 0 -- no) */
101 d
->ctrl
.pci_block_size
= VME_DMA_BSIZE_4096
;
102 d
->ctrl
.pci_backoff_time
= VME_DMA_BACKOFF_0
;
103 d
->ctrl
.vme_block_size
= VME_DMA_BSIZE_4096
;
104 d
->ctrl
.vme_backoff_time
= VME_DMA_BACKOFF_0
;
108 * @brief BE <-> LE converter
110 * @param rd -- register description
111 * @param eln -- number of elements to swap
112 * @param buf -- data to be swapped
114 static void swap_bytes(uint8_t dps
, void *buf
, int eln
)
124 w
= (uint16_t *) buf
;
125 while (eln
--) { *w
= _ENDIAN(*w
); w
++; }
128 dw
= (uint32_t *) buf
;
129 while (eln
--) { *dw
= _ENDIAN(*dw
); dw
++; }
132 llw
= (uint64_t *) buf
;
133 while (eln
--) { *llw
= _ENDIAN(*llw
); llw
++; }
139 * @brief Decode TSI148 DMA errors. Should go into vmebus lib.
141 * @param desc -- VME DMA description table
142 * @param ptr -- if not NULL, error string will go here
144 * @note ptr (if not NULL) should be freed afterwards by the caller
146 * @return 0 -- no DMA error
147 * @return -1 -- DMA error occurs
149 static int vme_dma_error_decode(struct vme_dma
*desc
, char **ptr
)
154 /* Do not care about masked stuff */
155 int stat
= desc
->status
& TSI148_LCSR_DSTA_MASK
;
157 if (stat
& TSI148_LCSR_DSTA_VBE
) {
158 i
= sprintf(p
, "%s", "VME DMA error\n");
161 if ((stat
& TSI148_LCSR_DSTA_ERRS
) == 0) {
162 switch (stat
& TSI148_LCSR_DSTA_ERT
) {
164 i
= sprintf(p
, "%s", "Bus error: SCT, BLT,"
165 " MBLT, 2eVME even data, 2eSST\n");
170 "Bus error: 2eVME odd data\n");
174 i
= sprintf(p
, "%s", "Slave termination:"
175 " 2eVME even data, 2eSST read\n");
179 i
= sprintf(p
, "%s", "Slave termination:"
180 " 2eVME odd data, 2eSST read"
181 " last word invalid\n");
188 i
= sprintf(p
, "%s", "PCI/X Bus Error\n");
193 if (stat
& TSI148_LCSR_DSTA_ABT
) {
194 i
= sprintf(p
, "%s", "VME DMA aborted\n");
199 if (stat
& TSI148_LCSR_DSTA_PAU
) {
200 i
= sprintf(p
, "%s", "DMA paused\n");
205 if (stat
& TSI148_LCSR_DSTA_DON
) {
206 i
= sprintf(p
, "%s", "DMA done\n");
211 if (stat
& TSI148_LCSR_DSTA_BSY
) {
212 i
= sprintf(p
, "%s", "DMA busy\n");
220 asprintf(ptr
, "%s", str
);
226 * @brief Perform DMA access
228 * @param t -- operation type (r -- read, w -- write)
229 * @param vmeaddr -- vme address to r/w
230 * @param am -- VME address modifier
231 * @param dps -- Data Port Size
232 * @param buf -- buffer to get/put data from/to
233 * @param eln -- number of elements to r/w
235 * @return -1 -- if FAILED
238 int do_dma(uint8_t t
, void *vmeaddr
, short am
, uint8_t dps
, void *buf
, int eln
)
242 int f
= open("/dev/vme_dma", O_RDWR
);
248 /* should swap in case of write operation */
249 swap_bytes(dps
, buf
, eln
);
251 setup_vme_desc(t
, vmeaddr
, am
, dps
, buf
, eln
, &d
);
253 if (ioctl(f
, VME_IOCTL_START_DMA
, &d
) < 0) {
254 perror("VME DMA access");
259 if (vme_dma_error_decode(&d
, &errstr
)) {
260 fprintf(stderr
, "%s\n", errstr
);
269 In case of read -- BE will come from VME
270 In case of write -- it was swapped by us at the beginning,
272 swap_bytes(dps
, buf
, eln
);
278 void get_obligitary_params(char *argv
[], void **vmeaddr
, int *am
, int *dps
)
280 sscanf(argv
[2], "%p", vmeaddr
);
281 sscanf(argv
[3], "%x", am
);
282 sscanf(argv
[4], "%d", dps
);
285 void do_read(int argc
, char *argv
[], char *envp
[])
299 printf("Usage: r <VME Address> <Address Modifier>"
300 " <Data Port Size> <number of elements>\n");
304 get_obligitary_params(argv
, &vmeaddr
, &am
, &dps
);
305 sscanf(argv
[5], "%d", &eln
);
307 if (!(buf
= calloc(eln
, dps
/8))) {
312 do_dma('r', vmeaddr
, am
, dps
, buf
, eln
);
314 printf("Read %d elements ", eln
);
317 printf("one byte long:\n");
319 for (i
= 0; i
< eln
; i
++, cp
++)
320 printf("[%d] --> %#x\n", i
, *cp
);
323 printf("2 bytes long:\n");
325 for (i
= 0; i
< eln
; i
++, sp
++)
326 printf("[%d] --> %#x\n", i
, *sp
);
329 printf("4 bytes long:\n");
331 for (i
= 0; i
< eln
; i
++, ip
++)
332 printf("[%d] --> %#x\n", i
, *ip
);
336 printf("8 bytes long:\n");
338 for (i
= 0; i
< eln
; i
++, lp
++)
339 printf("[%d] --> %#llx\n", i
, *lp
);
349 void *get_data_from_file(char *fn
)
351 printf("Should write data from '%s' file\n", fn
);
352 printf("Not supported yet!\n");
356 void *get_data_from_cmd_line(char *argv
[], int i
, int dps
, int eln
)
362 void *buf
= calloc(eln
, dps
/8);
368 sscanf(argv
[i
++], "%x", (int*)cp
++);
373 sscanf(argv
[i
++], "%hx", sp
++);
378 sscanf(argv
[i
++], "%x", ip
++);
383 sscanf(argv
[i
++], "%llx", lp
++);
390 void do_write(int argc
, char *argv
[], char *envp
[])
405 printf("Usage: w <VME Address> <Address Modifier>"
406 " <Data Port Size> [-- <elements to write>] [<filename>]\n");
410 while (strcmp(argv
[i
], "--")) {
412 buf
= get_data_from_file(argv
[i
]);
417 if (!(argc
- (++i
)) && !buf
)
420 get_obligitary_params(argv
, &vmeaddr
, &am
, &dps
);
424 buf
= get_data_from_cmd_line(argv
, i
, dps
, eln
);
427 printf("Will write %d element(s)@%p ", eln
, vmeaddr
);
431 printf("one byte long:\n");
434 printf("[%d] --> %#x\n", i
++, *cp
++);
437 printf("2 bytes long:\n");
440 printf("[%d] --> %#x\n", i
++, *sp
++);
443 printf("4 bytes long:\n");
446 printf("[%d] --> %#x\n", i
++, *ip
++);
449 printf("8 bytes long:\n");
452 printf("[%d] --> %#llx\n", i
++, *lp
++);
456 do_dma('w', vmeaddr
, am
, dps
, buf
, eln
);
459 int main(int argc
, char *argv
[], char *envp
[])
462 struct sigaction sigact
;
464 sigact
.sa_handler
= (void(*)(int))sighandler
;
465 sigemptyset(&sigact
.sa_mask
);
467 if (sigaction(SIGBUS
, &sigact
, (struct sigaction
*)NULL
)) {
468 perror("sigaction(1)");
472 if (sigaction(SIGSEGV
, &sigact
, (struct sigaction
*)NULL
)) {
473 perror("sigaction(1)");
478 sscanf(argv
[1], "%c", &op
);
482 do_read(argc
, argv
, envp
);
485 do_write(argc
, argv
, envp
);
488 printf("Wrong optype (%c)\n", op
);