| /* Copyright 2007, 2008 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; |
| } |
| |