1/* Copyright 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; either version 3 of the License, or 6 (at your option) any later version. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 This file is part of the gdb testsuite. 17 18 Contributed by Markus Deuling <deuling@de.ibm.com>. 19 Tests for 'info spu' commands. */ 20 21#include <stdio.h> 22#include <string.h> 23#include <sys/types.h> 24#include <sys/stat.h> 25#include <fcntl.h> 26#include <spu_mfcio.h> 27 28 29/* PPE-assisted call interface. */ 30void 31send_to_ppe (unsigned int signalcode, unsigned int opcode, void *data) 32{ 33 __vector unsigned int stopfunc = 34 { 35 signalcode, /* stop */ 36 (opcode << 24) | (unsigned int) data, 37 0x4020007f, /* nop */ 38 0x35000000 /* bi $0 */ 39 }; 40 41 void (*f) (void) = (void *) &stopfunc; 42 asm ("sync"); 43 f (); 44} 45 46/* PPE-assisted call to mmap from SPU. */ 47unsigned long long 48mmap_ea (unsigned long long start, size_t length, 49 int prot, int flags, int fd, off_t offset) 50{ 51 struct mmap_args 52 { 53 unsigned long long start __attribute__ ((aligned (16))); 54 size_t length __attribute__ ((aligned (16))); 55 int prot __attribute__ ((aligned (16))); 56 int flags __attribute__ ((aligned (16))); 57 int fd __attribute__ ((aligned (16))); 58 off_t offset __attribute__ ((aligned (16))); 59 } args; 60 61 args.start = start; 62 args.length = length; 63 args.prot = prot; 64 args.flags = flags; 65 args.fd = fd; 66 args.offset = offset; 67 68 send_to_ppe (0x2101, 11, &args); 69 return args.start; 70} 71 72/* This works only in a Linux environment with <= 1024 open 73 file descriptors for one process. Result is the file 74 descriptor for the current context if available. */ 75int 76find_context_fd (void) 77{ 78 int dir_fd = -1; 79 int i; 80 81 for (i = 0; i < 1024; i++) 82 { 83 struct stat stat; 84 85 if (fstat (i, &stat) < 0) 86 break; 87 if (S_ISDIR (stat.st_mode)) 88 dir_fd = dir_fd == -1 ? i : -2; 89 } 90 return dir_fd < 0 ? -1 : dir_fd; 91} 92 93/* Open the context file and return the file handler. */ 94int 95open_context_file (int context_fd, char *name, int flags) 96{ 97 char buf[128]; 98 99 if (context_fd < 0) 100 return -1; 101 102 sprintf (buf, "/proc/self/fd/%d/%s", context_fd, name); 103 return open (buf, flags); 104} 105 106 107int 108do_event_test () 109{ 110 spu_write_event_mask (MFC_MULTI_SRC_SYNC_EVENT); /* 0x1000 */ /* Marker Event */ 111 spu_write_event_mask (MFC_PRIV_ATTN_EVENT); /* 0x0800 */ 112 spu_write_event_mask (MFC_LLR_LOST_EVENT); /* 0x0400 */ 113 spu_write_event_mask (MFC_SIGNAL_NOTIFY_1_EVENT); /* 0x0200 */ 114 spu_write_event_mask (MFC_SIGNAL_NOTIFY_2_EVENT); /* 0x0100 */ 115 spu_write_event_mask (MFC_OUT_MBOX_AVAILABLE_EVENT); /* 0x0080 */ 116 spu_write_event_mask (MFC_OUT_INTR_MBOX_AVAILABLE_EVENT); /* 0x0040 */ 117 spu_write_event_mask (MFC_DECREMENTER_EVENT); /* 0x0020 */ 118 spu_write_event_mask (MFC_IN_MBOX_AVAILABLE_EVENT); /* 0x0010 */ 119 spu_write_event_mask (MFC_COMMAND_QUEUE_AVAILABLE_EVENT); /* 0x0008 */ 120 spu_write_event_mask (MFC_LIST_STALL_NOTIFY_EVENT); /* 0x0002 */ 121 spu_write_event_mask (MFC_TAG_STATUS_UPDATE_EVENT); /* 0x0001 */ 122 123 return 0; 124} 125 126int 127do_dma_test () 128{ 129 #define MAP_FAILED (-1ULL) 130 #define PROT_READ 0x1 131 #define MAP_PRIVATE 0x002 132 #define BSIZE 128 133 static char buf[BSIZE] __attribute__ ((aligned (128))); 134 char *file = "/var/tmp/tmp_buf"; 135 struct stat fdstat; 136 int fd, cnt; 137 unsigned long long src; 138 139 /* Create a file and fill it with some bytes. */ 140 fd = open (file, O_CREAT | O_RDWR | O_TRUNC, 0777); 141 if (fd == -1) 142 return -1; 143 memset ((void *)buf, '1', BSIZE); 144 write (fd, buf, BSIZE); 145 write (fd, buf, BSIZE); 146 memset ((void *)buf, 0, BSIZE); 147 148 if (fstat (fd, &fdstat) != 0 149 || !fdstat.st_size) 150 return -2; 151 152 src = mmap_ea(0ULL, fdstat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 153 if (src == MAP_FAILED) 154 return -3; 155 156 /* Copy some data via DMA. */ 157 mfc_get (&buf, src, BSIZE, 5, 0, 0); /* Marker DMA */ 158 mfc_write_tag_mask (1<<5); /* Marker DMAWait */ 159 spu_mfcstat (MFC_TAG_UPDATE_ALL); 160 161 /* Close the file. */ 162 close (fd); 163 164 return cnt; 165} 166 167int 168do_mailbox_test () 169{ 170 /* Write to SPU Outbound Mailbox. */ 171 if (spu_stat_out_mbox ()) /* Marker Mbox */ 172 spu_write_out_mbox (0x12345678); 173 174 /* Write to SPU Outbound Interrupt Mailbox. */ 175 if (spu_stat_out_intr_mbox ()) 176 spu_write_out_intr_mbox (0x12345678); 177 178 return 0; /* Marker MboxEnd */ 179} 180 181int 182do_signal_test () 183{ 184 struct stat fdstat; 185 int context_fd = find_context_fd (); 186 int ret, buf, fd; 187 188 buf = 23; /* Marker Signal */ 189 /* Write to signal1. */ 190 fd = open_context_file (context_fd, "signal1", O_RDWR); 191 if (fstat (fd, &fdstat) != 0) 192 return -1; 193 ret = write (fd, buf, sizeof (int)); 194 close (fd); /* Marker Signal1 */ 195 196 /* Write to signal2. */ 197 fd = open_context_file (context_fd, "signal2", O_RDWR); 198 if (fstat (fd, &fdstat) != 0) 199 return -1; 200 ret = write (fd, buf, sizeof (int)); 201 close (fd); /* Marker Signal2 */ 202 203 /* Read signal1. */ 204 if (spu_stat_signal1 ()) 205 ret = spu_read_signal1 (); 206 207 /* Read signal2. */ 208 if (spu_stat_signal2 ()) 209 ret = spu_read_signal2 (); /* Marker SignalRead */ 210 211 return 0; 212} 213 214int 215main (unsigned long long speid, unsigned long long argp, 216 unsigned long long envp) 217{ 218 int res; 219 220 /* info spu event */ 221 res = do_event_test (); 222 223 /* info spu dma */ 224 res = do_dma_test (); 225 226 /* info spu mailbox */ 227 res = do_mailbox_test (); 228 229 /* info spu signal */ 230 res = do_signal_test (); 231 232 return 0; 233} 234 235