-
-
Save swrenn/f1283a0c03d765ab72ae0767627e9636 to your computer and use it in GitHub Desktop.
Raspberry Pi QPU Timeout Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <errno.h> | |
#include <fcntl.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
enum { | |
FW_SUCCESS = 0, | |
FW_TIMEOUT = 1 << 31, | |
}; | |
enum { | |
STATUS_REQUEST = 0, | |
STATUS_SUCCESS = 0x80000000, | |
STATUS_ERROR = 0x80000001, | |
}; | |
enum { | |
DIRECT = 1 << 2, // Bus alias 0xCxxxxxxx | |
L2COHERENT = 2 << 2, // Bus alias 0x8xxxxxxx | |
L2ALLOC = 3 << 2, // Bus alias 0x4xxxxxxx | |
}; | |
enum { | |
TAG_PROPERTY_END = 0, | |
TAG_MEM_ALLOC = 0x0003000c, | |
TAG_MEM_LOCK = 0x0003000d, | |
TAG_MEM_UNLOCK = 0x0003000e, | |
TAG_MEM_FREE = 0x0003000f, | |
TAG_EXEC_CODE = 0x00030010, | |
TAG_EXEC_QPU = 0x00030011, | |
TAG_QPU_ENABLE = 0x00030012, | |
}; | |
int | |
main(int argc, char **argv) { | |
int ret; | |
errno = 0; | |
int vcio_fd = open("/dev/vcio", O_RDWR); | |
if (vcio_fd == -1) { | |
printf("%s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} | |
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC); | |
if (mem_fd == -1) { | |
printf("%s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} | |
// | |
// Enable QPUs | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data; | |
uint32_t end; | |
} enable = { | |
.msg_sz = sizeof(enable), | |
.status = STATUS_REQUEST, | |
.tag = TAG_QPU_ENABLE, | |
.data_sz = sizeof(enable.data), | |
.data = 1, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&enable); | |
if (ret == -1) { | |
printf("Enable: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (enable.status != STATUS_SUCCESS) { | |
printf("Enable: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
// | |
// Allocate Memory | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data[3]; | |
uint32_t end; | |
} alloc = { | |
.msg_sz = sizeof(alloc), | |
.status = STATUS_REQUEST, | |
.tag = TAG_MEM_ALLOC, | |
.data_sz = sizeof(alloc.data), | |
.data = {4096 /*alloc size*/, 4096 /*page size*/, DIRECT}, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&alloc); | |
if (ret == -1) { | |
printf("Alloc: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (alloc.status != STATUS_SUCCESS) { | |
printf("Alloc: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
uint32_t handle = alloc.data[0]; | |
// | |
// Lock Memory | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data; | |
uint32_t end; | |
} lock = { | |
.msg_sz = sizeof(lock), | |
.status = STATUS_REQUEST, | |
.tag = TAG_MEM_LOCK, | |
.data_sz = sizeof(lock.data), | |
.data = handle, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&lock); | |
if (ret == -1) { | |
printf("Lock: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (lock.status != STATUS_SUCCESS) { | |
printf("Lock: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
uint32_t bus = lock.data; | |
// | |
// Prepare Control Buffer | |
// | |
void *vp = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, bus); | |
if (vp == MAP_FAILED) { | |
printf("%s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} | |
char *to = vp; | |
char *from = to + 2048; | |
uint32_t bus_to = bus; | |
uint32_t bus_from = bus + 2048; | |
uint32_t program[] = { | |
// .include <vc4.qinc> | |
// | |
// mov vw_setup, vpm_setup(0,0,h32(0)) | |
// mov vpm, elem_num | |
// | |
// mov vw_setup, vdw_setup_0(1,16,dma_h32(0,0)) | |
// mov vw_setup, vdw_setup_1(0) | |
// | |
// ldi vw_addr, <address> | |
// read vw_wait | |
// | |
// mov irq, 1 | |
// thrend | |
// nop | |
// nop | |
0x00000a00, 0xe0021c67, 0x159a7d80, 0x10020c27, 0x80904000, | |
0xe0021c67, 0xc0000000, 0xe0021c67, bus_from, 0xe0021ca7, | |
0x009f2000, 0x100009e7, 0x00000001, 0xe00209a7, 0x009e7000, | |
0x300009e7, 0x009e7000, 0x100009e7, 0x009e7000, 0x100009e7, | |
}; | |
memcpy(to, &program, sizeof(program)); | |
*(uint32_t *)(to + sizeof(program)) = 0; // Uniforms address | |
*(uint32_t *)(to + sizeof(program) + 4) = bus; // Program address | |
// | |
// Execute | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data[4]; | |
uint32_t end; | |
} execute = { | |
.msg_sz = sizeof(execute), | |
.status = STATUS_REQUEST, | |
.tag = TAG_EXEC_QPU, | |
.data_sz = sizeof(execute.data), | |
.data = | |
{ | |
1, // Tasks | |
bus_to + sizeof(program), // Control | |
0, // No flush | |
10000, // Timeout (ms) | |
}, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&execute); | |
if (ret == -1) { | |
printf("Execute: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (execute.status != STATUS_SUCCESS) { | |
printf("Execute: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
// | |
// Check Result | |
// | |
uint32_t expected[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; | |
ret = memcmp(from, expected, sizeof(expected)); | |
if (ret != 0) { | |
printf("Execute: Incorrect result\n"); | |
} | |
// | |
// Unlock Memory | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data; | |
uint32_t end; | |
} unlock = { | |
.msg_sz = sizeof(unlock), | |
.status = STATUS_REQUEST, | |
.tag = TAG_MEM_UNLOCK, | |
.data_sz = sizeof(unlock.data), | |
.data = handle, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&unlock); | |
if (ret == -1) { | |
printf("Unlock: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (unlock.status != STATUS_SUCCESS) { | |
printf("Unlock: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
// | |
// Free Memory | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data; | |
uint32_t end; | |
} free = { | |
.msg_sz = sizeof(free), | |
.status = STATUS_REQUEST, | |
.tag = TAG_MEM_FREE, | |
.data_sz = sizeof(free.data), | |
.data = handle, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&free); | |
if (ret == -1) { | |
printf("Free: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (free.status != STATUS_SUCCESS) { | |
printf("Free: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
// | |
// Disable QPUs | |
// | |
struct { | |
uint32_t msg_sz; | |
uint32_t status; | |
uint32_t tag; | |
uint32_t data_sz; | |
uint32_t resp_sz; | |
uint32_t data; | |
uint32_t end; | |
} disable = { | |
.msg_sz = sizeof(disable), | |
.status = STATUS_REQUEST, | |
.tag = TAG_QPU_ENABLE, | |
.data_sz = sizeof(disable.data), | |
.data = 0, | |
.end = TAG_PROPERTY_END, | |
}; | |
ret = ioctl(vcio_fd, _IOWR(100, 0, char *), (void *)&disable); | |
if (ret == -1) { | |
printf("Disable: %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} else if (disable.status != STATUS_SUCCESS) { | |
printf("Disable: Unspecified error"); | |
return EXIT_FAILURE; | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment