Skip to content

Instantly share code, notes, and snippets.

@swrenn
Created October 6, 2021 04:30
Show Gist options
  • Save swrenn/f1283a0c03d765ab72ae0767627e9636 to your computer and use it in GitHub Desktop.
Save swrenn/f1283a0c03d765ab72ae0767627e9636 to your computer and use it in GitHub Desktop.
Raspberry Pi QPU Timeout Example
#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