blob: 8202bf4217c58dcc24dbfc7a9916860401ed4806 [file] [log] [blame]
/* Copyright 2007-2013 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This file is part of the gdb testsuite.
Contributed by Markus Deuling <deuling@de.ibm.com>.
Tests for 'info spu' commands. */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <spu_mfcio.h>
/* PPE-assisted call interface. */
void
send_to_ppe (unsigned int signalcode, unsigned int opcode, void *data)
{
__vector unsigned int stopfunc =
{
signalcode, /* stop */
(opcode << 24) | (unsigned int) data,
0x4020007f, /* nop */
0x35000000 /* bi $0 */
};
void (*f) (void) = (void *) &stopfunc;
asm ("sync");
f ();
}
/* PPE-assisted call to mmap from SPU. */
unsigned long long
mmap_ea (unsigned long long start, size_t length,
int prot, int flags, int fd, off_t offset)
{
struct mmap_args
{
unsigned long long start __attribute__ ((aligned (16)));
size_t length __attribute__ ((aligned (16)));
int prot __attribute__ ((aligned (16)));
int flags __attribute__ ((aligned (16)));
int fd __attribute__ ((aligned (16)));
off_t offset __attribute__ ((aligned (16)));
} args;
args.start = start;
args.length = length;
args.prot = prot;
args.flags = flags;
args.fd = fd;
args.offset = offset;
send_to_ppe (0x2101, 11, &args);
return args.start;
}
/* This works only in a Linux environment with <= 1024 open
file descriptors for one process. Result is the file
descriptor for the current context if available. */
int
find_context_fd (void)
{
int dir_fd = -1;
int i;
for (i = 0; i < 1024; i++)
{
struct stat stat;
if (fstat (i, &stat) < 0)
break;
if (S_ISDIR (stat.st_mode))
dir_fd = dir_fd == -1 ? i : -2;
}
return dir_fd < 0 ? -1 : dir_fd;
}
/* Open the context file and return the file handler. */
int
open_context_file (int context_fd, char *name, int flags)
{
char buf[128];
if (context_fd < 0)
return -1;
sprintf (buf, "/proc/self/fd/%d/%s", context_fd, name);
return open (buf, flags);
}
int
do_event_test ()
{
spu_write_event_mask (MFC_MULTI_SRC_SYNC_EVENT); /* 0x1000 */ /* Marker Event */
spu_write_event_mask (MFC_PRIV_ATTN_EVENT); /* 0x0800 */
spu_write_event_mask (MFC_LLR_LOST_EVENT); /* 0x0400 */
spu_write_event_mask (MFC_SIGNAL_NOTIFY_1_EVENT); /* 0x0200 */
spu_write_event_mask (MFC_SIGNAL_NOTIFY_2_EVENT); /* 0x0100 */
spu_write_event_mask (MFC_OUT_MBOX_AVAILABLE_EVENT); /* 0x0080 */
spu_write_event_mask (MFC_OUT_INTR_MBOX_AVAILABLE_EVENT); /* 0x0040 */
spu_write_event_mask (MFC_DECREMENTER_EVENT); /* 0x0020 */
spu_write_event_mask (MFC_IN_MBOX_AVAILABLE_EVENT); /* 0x0010 */
spu_write_event_mask (MFC_COMMAND_QUEUE_AVAILABLE_EVENT); /* 0x0008 */
spu_write_event_mask (MFC_LIST_STALL_NOTIFY_EVENT); /* 0x0002 */
spu_write_event_mask (MFC_TAG_STATUS_UPDATE_EVENT); /* 0x0001 */
return 0;
}
int
do_dma_test ()
{
#define MAP_FAILED (-1ULL)
#define PROT_READ 0x1
#define MAP_PRIVATE 0x002
#define BSIZE 128
static char buf[BSIZE] __attribute__ ((aligned (128)));
char *file = "/var/tmp/tmp_buf";
struct stat fdstat;
int fd, cnt;
unsigned long long src;
/* Create a file and fill it with some bytes. */
fd = open (file, O_CREAT | O_RDWR | O_TRUNC, 0777);
if (fd == -1)
return -1;
memset ((void *)buf, '1', BSIZE);
write (fd, buf, BSIZE);
write (fd, buf, BSIZE);
memset ((void *)buf, 0, BSIZE);
if (fstat (fd, &fdstat) != 0
|| !fdstat.st_size)
return -2;
src = mmap_ea(0ULL, fdstat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (src == MAP_FAILED)
return -3;
/* Copy some data via DMA. */
mfc_get (&buf, src, BSIZE, 5, 0, 0); /* Marker DMA */
mfc_write_tag_mask (1<<5); /* Marker DMAWait */
spu_mfcstat (MFC_TAG_UPDATE_ALL);
/* Close the file. */
close (fd);
return cnt;
}
int
do_mailbox_test ()
{
/* Write to SPU Outbound Mailbox. */
if (spu_stat_out_mbox ()) /* Marker Mbox */
spu_write_out_mbox (0x12345678);
/* Write to SPU Outbound Interrupt Mailbox. */
if (spu_stat_out_intr_mbox ())
spu_write_out_intr_mbox (0x12345678);
return 0; /* Marker MboxEnd */
}
int
do_signal_test ()
{
struct stat fdstat;
int context_fd = find_context_fd ();
int ret, buf, fd;
buf = 23; /* Marker Signal */
/* Write to signal1. */
fd = open_context_file (context_fd, "signal1", O_RDWR);
if (fstat (fd, &fdstat) != 0)
return -1;
ret = write (fd, buf, sizeof (int));
close (fd); /* Marker Signal1 */
/* Write to signal2. */
fd = open_context_file (context_fd, "signal2", O_RDWR);
if (fstat (fd, &fdstat) != 0)
return -1;
ret = write (fd, buf, sizeof (int));
close (fd); /* Marker Signal2 */
/* Read signal1. */
if (spu_stat_signal1 ())
ret = spu_read_signal1 ();
/* Read signal2. */
if (spu_stat_signal2 ())
ret = spu_read_signal2 (); /* Marker SignalRead */
return 0;
}
int
main (unsigned long long speid, unsigned long long argp,
unsigned long long envp)
{
int res;
/* info spu event */
res = do_event_test ();
/* info spu dma */
res = do_dma_test ();
/* info spu mailbox */
res = do_mailbox_test ();
/* info spu signal */
res = do_signal_test ();
return 0;
}