libspe2  0.9a
dma.c
Go to the documentation of this file.
1 /*
2  * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
3  * Copyright (C) 2005 IBM Corp.
4  *
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; either version 2.1 of the License,
8  * or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include <sys/poll.h>
28 
29 #include "create.h"
30 #include "dma.h"
31 
32 static int spe_read_tag_status_block(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status);
33 static int spe_read_tag_status_noblock(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status);
34 
35 static int issue_mfc_command(spe_context_ptr_t spectx, unsigned lsa, void *ea,
36  unsigned size, unsigned tag, unsigned tid, unsigned rid,
37  enum mfc_cmd cmd)
38 {
39  int ret;
40 
41  DEBUG_PRINTF("queuing DMA %x %lx %x %x %x %x %x\n", lsa,
42  (unsigned long)ea, size, tag, tid, rid, (unsigned)cmd);
43 
44  /* tag 16-31 are reserved by kernel */
45  if (tag > 0x0f || tid > 0xff || rid > 0xff) {
46  errno = EINVAL;
47  return -1;
48  }
49 
50  if (spectx->base_private->flags & SPE_MAP_PS) {
51  volatile struct spe_mfc_command_area *cmd_area =
52  spectx->base_private->mfc_mmap_base;
53  unsigned int eal = (uintptr_t) ea & 0xFFFFFFFF;
54  unsigned int eah = (unsigned long long)(uintptr_t) ea >> 32;
56  spectx->base_private->active_tagmask |= 1 << tag;
57  DEBUG_PRINTF("set active tagmask = 0x%04x, tag=%i\n",spectx->base_private->active_tagmask,tag);
58  while ((cmd_area->MFC_QStatus & 0x0000FFFF) == 0) ;
59  do {
60  cmd_area->MFC_LSA = lsa;
61  cmd_area->MFC_EAH = eah;
62  cmd_area->MFC_EAL = eal;
63  cmd_area->MFC_Size_Tag = (size << 16) | tag;
64  cmd_area->MFC_ClassID_CMD = (tid << 24) | (rid << 16) | cmd;
65 
66  ret = cmd_area->MFC_CMDStatus & 0x00000003;
67  } while (ret); // at least one of the two bits is set
69  return 0;
70  }
71  else {
72  int fd;
73  fd = _base_spe_open_if_closed(spectx, FD_MFC, 0);
74  if (fd != -1) {
75  struct mfc_command_parameter_area parm = {
76  .lsa = lsa,
77  .ea = (unsigned long) ea,
78  .size = size,
79  .tag = tag,
80  .class = (tid << 8) | rid,
81  .cmd = cmd,
82  };
83  ret = write(fd, &parm, sizeof (parm));
84  if ((ret < 0) && (errno != EIO)) {
85  perror("spe_do_mfc_put: internal error");
86  }
87  return ret < 0 ? -1 : 0;
88  }
89  }
90  /* the kernel does not support DMA */
91  return 1;
92 }
93 
94 static int spe_do_mfc_put(spe_context_ptr_t spectx, unsigned src, void *dst,
95  unsigned size, unsigned tag, unsigned tid, unsigned rid,
96  enum mfc_cmd cmd)
97 {
98  int ret;
99  ret = issue_mfc_command(spectx, src, dst, size, tag, tid, rid, cmd);
100  if (ret <= 0) {
101  return ret;
102  }
103  else {
104  /* the kernel does not support DMA, so just copy directly */
105  memcpy(dst, spectx->base_private->mem_mmap_base + src, size);
106  return 0;
107  }
108 }
109 
110 static int spe_do_mfc_get(spe_context_ptr_t spectx, unsigned int dst, void *src,
111  unsigned int size, unsigned int tag, unsigned tid, unsigned rid,
112  enum mfc_cmd cmd)
113 {
114  int ret;
115  ret = issue_mfc_command(spectx, dst, src, size, tag, tid, rid, cmd);
116  if (ret <= 0) {
117  return ret;
118  }
119  else {
120  /* the kernel does not support DMA, so just copy directly */
121  memcpy(spectx->base_private->mem_mmap_base + dst, src, size);
122  return 0;
123  }
124 }
125 
127  unsigned int ls,
128  void *ea,
129  unsigned int size,
130  unsigned int tag,
131  unsigned int tid,
132  unsigned int rid)
133 {
134  return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUT);
135 }
136 
138  unsigned int ls,
139  void *ea,
140  unsigned int size,
141  unsigned int tag,
142  unsigned int tid,
143  unsigned int rid)
144 {
145  return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUTB);
146 }
147 
149  unsigned int ls,
150  void *ea,
151  unsigned int size,
152  unsigned int tag,
153  unsigned int tid,
154  unsigned int rid)
155 {
156  return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUTF);
157 }
158 
159 
161  unsigned int ls,
162  void *ea,
163  unsigned int size,
164  unsigned int tag,
165  unsigned int tid,
166  unsigned int rid)
167 {
168  return spe_do_mfc_get(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_GET);
169 }
170 
172  unsigned int ls,
173  void *ea,
174  unsigned int size,
175  unsigned int tag,
176  unsigned int tid,
177  unsigned int rid)
178 {
179  return spe_do_mfc_get(spectx, ls, ea, size, tag, rid, rid, MFC_CMD_GETB);
180 }
181 
183  unsigned int ls,
184  void *ea,
185  unsigned int size,
186  unsigned int tag,
187  unsigned int tid,
188  unsigned int rid)
189 {
190  return spe_do_mfc_get(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_GETF);
191 }
192 
193 static int spe_mfcio_tag_status_read_all(spe_context_ptr_t spectx,
194  unsigned int mask, unsigned int *tag_status)
195 {
196  int fd;
197 
198  if (spectx->base_private->flags & SPE_MAP_PS) {
199  return spe_read_tag_status_block(spectx, mask, tag_status);
200  } else {
201  fd = _base_spe_open_if_closed(spectx, FD_MFC, 0);
202  if (fd == -1) {
203  return -1;
204  }
205 
206  if (fsync(fd) != 0) {
207  return -1;
208  }
209 
210  return spe_read_tag_status_block(spectx, mask, tag_status);
211  }
212 }
213 
214 static int spe_mfcio_tag_status_read_any(spe_context_ptr_t spectx,
215  unsigned int mask, unsigned int *tag_status)
216 {
217  return spe_read_tag_status_block(spectx, mask, tag_status);
218 }
219 
220 static int spe_mfcio_tag_status_read_immediate(spe_context_ptr_t spectx,
221  unsigned int mask, unsigned int *tag_status)
222 {
223  return spe_read_tag_status_noblock(spectx, mask, tag_status);
224 }
225 
226 
227 
228 /* MFC Read tag status functions
229  *
230  */
231 static int spe_read_tag_status_block(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status)
232 {
233  if (spectx->base_private->flags & SPE_MAP_PS) {
234  volatile struct spe_mfc_command_area *cmd_area =
235  spectx->base_private->mfc_mmap_base;
237  cmd_area->Prxy_QueryMask = mask;
238  __asm__ ("eieio");
239  do {
240  *tag_status = cmd_area->Prxy_TagStatus;
241  spectx->base_private->active_tagmask ^= *tag_status;
242  DEBUG_PRINTF("unset active tagmask = 0x%04x, tag_status = 0x%04x\n",
243  spectx->base_private->active_tagmask,*tag_status);
244  } while (*tag_status ^ mask);
246  return 0;
247  } else {
248  int fd;
249  fd = _base_spe_open_if_closed(spectx, FD_MFC, 0);
250  if (fd == -1) {
251  return -1;
252  }
253 
254  if (read(fd,tag_status,4) == 4) {
255  return 0;
256  }
257  }
258  return -1;
259 }
260 
261 static int spe_read_tag_status_noblock(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status)
262 {
263  unsigned int ret;
264 
265  if (spectx->base_private->flags & SPE_MAP_PS) {
266  volatile struct spe_mfc_command_area *cmd_area =
267  spectx->base_private->mfc_mmap_base;
268 
270  cmd_area->Prxy_QueryMask = mask;
271  __asm__ ("eieio");
272  *tag_status = cmd_area->Prxy_TagStatus;
273  spectx->base_private->active_tagmask ^= *tag_status;
274  DEBUG_PRINTF("unset active tagmask = 0x%04x, tag_status = 0x%04x\n",
275  spectx->base_private->active_tagmask,*tag_status);
277  return 0;
278  } else {
279  struct pollfd poll_fd;
280  int fd;
281 
282  fd = _base_spe_open_if_closed(spectx, FD_MFC, 0);
283  if (fd == -1) {
284  return -1;
285  }
286 
287  poll_fd.fd = fd;
288  poll_fd.events = POLLIN;
289 
290  ret = poll(&poll_fd, 1, 0);
291 
292  if (ret < 0)
293  return -1;
294 
295  if (ret == 0 || !(poll_fd.revents & POLLIN)) {
296  *tag_status = 0;
297  return 0;
298  }
299 
300  if (read(fd,tag_status,4) == 4) {
301  return 0;
302  }
303  }
304  return -1;
305 }
306 
307 int _base_spe_mfcio_tag_status_read(spe_context_ptr_t spectx, unsigned int mask, unsigned int behavior, unsigned int *tag_status)
308 {
309  if ( mask != 0 ) {
310  if (!(spectx->base_private->flags & SPE_MAP_PS))
311  mask = 0;
312  } else {
313  if ((spectx->base_private->flags & SPE_MAP_PS))
314  mask = spectx->base_private->active_tagmask;
315  }
316 
317  if (!tag_status) {
318  errno = EINVAL;
319  return -1;
320  }
321 
322  switch (behavior) {
323  case SPE_TAG_ALL:
324  return spe_mfcio_tag_status_read_all(spectx, mask, tag_status);
325  case SPE_TAG_ANY:
326  return spe_mfcio_tag_status_read_any(spectx, mask, tag_status);
327  case SPE_TAG_IMMEDIATE:
328  return spe_mfcio_tag_status_read_immediate(spectx, mask, tag_status);
329  default:
330  errno = EINVAL;
331  return -1;
332  }
333 }
334 
336 {
337  int ret, fd;
338  unsigned int data = 1; /* Any value can be written here */
339 
340  volatile struct spe_mssync_area *mss_area =
342 
343  if (spectx->base_private->flags & SPE_MAP_PS) {
344  mss_area->MFC_MSSync = data;
345  return 0;
346  } else {
347  fd = _base_spe_open_if_closed(spectx, FD_MSS, 0);
348  if (fd != -1) {
349  ret = write(fd, &data, sizeof (data));
350  if ((ret < 0) && (errno != EIO)) {
351  perror("spe_mssync_start: internal error");
352  }
353  return ret < 0 ? -1 : 0;
354  } else
355  return -1;
356  }
357 }
358 
360 {
361  int ret, fd;
362  unsigned int data;
363 
364  volatile struct spe_mssync_area *mss_area =
366 
367  if (spectx->base_private->flags & SPE_MAP_PS) {
368  return mss_area->MFC_MSSync;
369  } else {
370  fd = _base_spe_open_if_closed(spectx, FD_MSS, 0);
371  if (fd != -1) {
372  ret = read(fd, &data, sizeof (data));
373  if ((ret < 0) && (errno != EIO)) {
374  perror("spe_mssync_start: internal error");
375  }
376  return ret < 0 ? -1 : data;
377  } else
378  return -1;
379  }
380 }
381 
382 
unsigned int MFC_Size_Tag
Definition: cbea_map.h:39
int _base_spe_mfcio_getb(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:171
int _base_spe_mfcio_put(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:126
int _base_spe_mssync_status(spe_context_ptr_t spectx)
Definition: dma.c:359
int _base_spe_mssync_start(spe_context_ptr_t spectx)
Definition: dma.c:335
#define DEBUG_PRINTF(fmt, args...)
Definition: elf_loader.c:45
int _base_spe_mfcio_get(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:160
unsigned int MFC_EAH
Definition: cbea_map.h:37
void * mssync_mmap_base
Definition: spebase.h:87
int _base_spe_open_if_closed(struct spe_context *spe, enum fd_name fdesc, int locked)
Definition: create.c:101
void * mfc_mmap_base
Definition: spebase.h:86
int _base_spe_mfcio_tag_status_read(spe_context_ptr_t spectx, unsigned int mask, unsigned int behavior, unsigned int *tag_status)
Definition: dma.c:307
int _base_spe_mfcio_putb(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:137
void _base_spe_context_unlock(spe_context_ptr_t spe, enum fd_name fdesc)
Definition: create.c:96
int _base_spe_mfcio_getf(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:182
#define SPE_MAP_PS
Definition: spebase.h:53
Definition: spebase.h:54
unsigned int MFC_MSSync
Definition: cbea_map.h:31
unsigned int MFC_CMDStatus
Definition: cbea_map.h:42
int _base_spe_mfcio_putf(spe_context_ptr_t spectx, unsigned int ls, void *ea, unsigned int size, unsigned int tag, unsigned int tid, unsigned int rid)
Definition: dma.c:148
struct spe_context_base_priv * base_private
Definition: libspe2-types.h:76
unsigned int flags
Definition: spebase.h:74
#define SPE_TAG_ALL
#define SPE_TAG_IMMEDIATE
void * mem_mmap_base
Definition: spebase.h:85
unsigned int MFC_EAL
Definition: cbea_map.h:38
unsigned int MFC_QStatus
Definition: cbea_map.h:45
unsigned int MFC_LSA
Definition: cbea_map.h:36
void _base_spe_context_lock(spe_context_ptr_t spe, enum fd_name fdesc)
Definition: create.c:91
unsigned int MFC_ClassID_CMD
Definition: cbea_map.h:41
#define SPE_TAG_ANY
mfc_cmd
Definition: dma.h:37
unsigned int Prxy_QueryMask
Definition: cbea_map.h:49
unsigned int Prxy_TagStatus
Definition: cbea_map.h:51