Commit 31ff5b5c authored by Jens Korinth's avatar Jens Korinth
Browse files

WIP: Fixed basic Zynq implementation

parent b4c05351
......@@ -198,7 +198,6 @@ platform_res_t platform_create_device(platform_ctx_t *ctx,
if ((res = platform_devctx_init(ctx, dev_id, mode, &ctx->devctx[dev_id])) != PLATFORM_SUCCESS) {
ERR("could not initialize device context for #%03u: %s (%d)",
dev_id, platform_strerror(r), r);
platform_destroy_device(ctx, dev_id);
goto err_pdev;
}
if (pdctx) *pdctx = ctx->devctx[dev_id];
......
......@@ -27,7 +27,7 @@ platform_res_t platform_devctx_init(platform_ctx_t *ctx,
assert(fn);
platform_devctx_t *devctx = (platform_devctx_t *)calloc(sizeof(*devctx), 1);
if (! devctx) {
ERR("device #%03u: could not allocate memory for device context", dev_id);
DEVERR(dev_id, "could not allocate memory for device context");
return PERR_OUT_OF_MEMORY;
}
......@@ -37,49 +37,44 @@ platform_res_t platform_devctx_init(platform_ctx_t *ctx,
default_dops(&devctx->dops);
if ((res = platform_device_info(ctx, dev_id, &devctx->dev_info)) != PLATFORM_SUCCESS) {
ERR("device #%03u: could not get device information: %s (%d)",
dev_id, platform_strerror(res), res);
DEVERR(dev_id, "could not get device information: %s (%d)", platform_strerror(res), res);
free (devctx);
return res;
}
devctx->fd_ctrl = open(control_file(dev_id), O_RDWR);
if (devctx->fd_ctrl == -1) {
ERR("could not open %s: %s (%d)", fn, strerror(errno), errno);
DEVERR(dev_id, "could not open %s: %s (%d)", fn, strerror(errno), errno);
res = PERR_OPEN_DEV;
}
free(fn);
if ((res = platform_info(devctx, &devctx->info)) != PLATFORM_SUCCESS) {
ERR("device #%03u: could not get device info: %s (%d)",
dev_id, platform_strerror(res), res);
DEVERR(dev_id, "could not get device info: %s (%d)", platform_strerror(res), res);
goto err_info;
}
log_device_info(&devctx->info);
res = platform_addr_map_init(devctx, &devctx->info, &devctx->addrmap);
if (res != PLATFORM_SUCCESS) {
ERR("device #%03u: could not initialize platform address map: %s (%d)",
dev_id, platform_strerror(res), res);
DEVERR(dev_id, "could not initialize platform address map: %s (%d)", platform_strerror(res), res);
goto err_addr_map;
}
LOG(LPLL_INIT, "device #%03u: initialized device address map", dev_id);
DEVLOG(dev_id, LPLL_INIT, "device #%03u: initialized device address map");
res = platform_signaling_init(devctx, &devctx->signaling);
if (res != PLATFORM_SUCCESS) {
ERR("device #%03u: could not initialize signaling: %s (%d)",
dev_id, platform_strerror(res), res);
DEVERR(dev_id, "could not initialize signaling: %s (%d)", platform_strerror(res), res);
goto err_signaling;
}
LOG(LPLL_INIT, "device #%03u: initialized device signaling", dev_id);
DEVLOG(dev_id, LPLL_INIT, "initialized device signaling");
if ((res = zynq_init(devctx)) != PLATFORM_SUCCESS) {
ERR("found no matching platform definition for device #%03u", dev_id);
DEVERR(dev_id, "found no matching platform definition for device #%03u");
goto err_platform;
}
*pdctx = devctx;
LOG(LPLL_INIT, "device #%03u: context initialization finished", dev_id);
if (pdctx) *pdctx = devctx;
DEVLOG(dev_id, LPLL_INIT, "context initialization finished");
return PLATFORM_SUCCESS;
err_platform:
......@@ -96,14 +91,14 @@ void platform_devctx_deinit(platform_devctx_t *devctx)
{
if (devctx) {
platform_dev_id_t dev_id = devctx->dev_id;
LOG(LPLL_INIT, "device #%03u: destroying platform signaling ...", dev_id);
DEVLOG(dev_id, LPLL_INIT, "destroying platform signaling ...");
platform_signaling_deinit(devctx->signaling);
LOG(LPLL_INIT, "device #%03u: destroying platform address map ...", dev_id);
DEVLOG(dev_id, LPLL_INIT, "destroying platform address map ...");
platform_addr_map_deinit(devctx, devctx->addrmap);
close(devctx->fd_ctrl);
devctx->fd_ctrl = -1;
devctx->dev_id = -1;
free(devctx);
LOG(LPLL_INIT, "device #%03u: context destroyed, have a nice 'un", dev_id);
DEVLOG(dev_id, LPLL_INIT, "context destroyed, have a nice 'un");
}
}
......@@ -40,281 +40,116 @@
#include <platform_logging.h>
#include <platform_device_operations.h>
/*typedef struct zynq_platform {
int fd_gp0_map;
int fd_gp1_map;
int fd_status_map;
volatile void *gp0_map;
volatile void *gp1_map;
volatile void *status_map;
int fd_control;
typedef struct zynq_platform {
volatile void *gp0_map;
volatile void *gp1_map;
volatile void *status_map;
platform_devctx_t *devctx;
} zynq_platform_t;
static zynq_platform_t zynq_platform = {
.fd_gp0_map = -1,
.fd_gp1_map = -1,
.fd_status_map = -1,
.gp0_map = NULL,
.gp1_map = NULL,
.status_map = NULL,
.fd_control = -1,
.ctx = NULL,
};*/
.gp0_map = MAP_FAILED,
.gp1_map = MAP_FAILED,
.status_map = MAP_FAILED,
.devctx = NULL,
};
platform_res_t zynq_init(platform_devctx_t *devctx)
{
assert(devctx);
assert(devctx->dev_info.name);
if (! strncmp(ZYNQ_NAME, devctx->dev_info.name, strlen(ZYNQ_NAME))) {
LOG(LPLL_DEVICE, "device #%03u matches Zynq platform", devctx->dev_id);
return PLATFORM_SUCCESS;
}
LOG(LPLL_DEVICE, "device #%03u does not match Zynq platform", devctx->dev_id);
return PERR_INCOMPATIBLE_DEVICE;
}
void zynq_exit(platform_devctx_t *devctx)
{
}
/*static platform_res_t init_zynq(zynq_platform_t *p)
{
platform_res_t result;
p->fd_gp0_map = open("/dev/" ZYNQ_PLATFORM_DEVFILENAME "_gp0", O_RDWR);
if (p->fd_gp0_map != -1) {
p->gp0_map = mmap(
NULL,
ZYNQ_PLATFORM_GP0_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED,
p->fd_gp0_map,
0);
if (p->gp0_map == MAP_FAILED) {
ERR("could not mmap regmap: %s", strerror(errno));
return PERR_MMAP_DEV;
}
} else {
ERR("could not open '%s': %s",
"/dev/" ZYNQ_PLATFORM_DEVFILENAME "_gp0",
strerror(errno));
return PERR_OPEN_DEV;
}
p->fd_gp1_map = open("/dev/" ZYNQ_PLATFORM_DEVFILENAME "_gp1", O_RDWR);
if (p->fd_gp1_map != -1) {
p->gp1_map = mmap(
NULL,
ZYNQ_PLATFORM_GP1_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED,
p->fd_gp1_map,
0);
if (p->gp1_map == MAP_FAILED) {
ERR("could not mmap regmap: %s", strerror(errno));
return PERR_MMAP_DEV;
}
} else {
ERR("could not open '%s': %s",
"/dev/" ZYNQ_PLATFORM_DEVFILENAME "_gp1",
strerror(errno));
return PERR_OPEN_DEV;
}
p->fd_status_map = open("/dev/" ZYNQ_PLATFORM_DEVFILENAME "_tapasco_status", O_RDONLY);
if (p->fd_status_map != -1) {
p->status_map = mmap(
NULL,
PLATFORM_API_TAPASCO_STATUS_SIZE,
PROT_READ,
MAP_SHARED,
p->fd_status_map,
0);
if (p->status_map == MAP_FAILED) {
ERR("could not mmap regmap: %s", strerror(errno));
return PERR_MMAP_DEV;
}
} else {
ERR("could not open '%s': %s",
"/dev/" ZYNQ_PLATFORM_DEVFILENAME "_tapasco_status",
strerror(errno));
result = PERR_OPEN_DEV;
}
p->fd_control = open("/dev/" ZYNQ_PLATFORM_DEVFILENAME "_control", O_RDONLY);
if (! p->fd_control) {
ERR("could not open '%s': %s",
"/dev/" ZYNQ_PLATFORM_DEVFILENAME "_control",
strerror(errno));
return PERR_OPEN_DEV;
}
result = platform_context_init(&p->ctx);
if (result != PLATFORM_SUCCESS) return result;
result = platform_info(p->ctx, &(p->info));
if (result != PLATFORM_SUCCESS) return result;
LOG(LPLL_INIT, "platform initialization done");
return result;
}
static platform_res_t release_zynq(zynq_platform_t *p)
{
if (p->fd_control != -1) {
close(p->fd_control);
p->fd_control = -1;
}
if (p->fd_status_map != -1) {
if (p->status_map != NULL && p->status_map != MAP_FAILED) {
munmap((void *)p->status_map,
PLATFORM_API_TAPASCO_STATUS_SIZE);
p->status_map = NULL;
}
close(p->fd_status_map);
p->fd_status_map = -1;
p->status_map = NULL;
}
if (p->fd_gp1_map != -1) {
if (p->gp1_map != NULL && p->gp1_map != MAP_FAILED) {
munmap((void *)p->gp1_map, ZYNQ_PLATFORM_GP1_SIZE);
p->gp1_map = NULL;
}
close(p->fd_gp1_map);
p->fd_gp1_map = -1;
p->gp1_map = NULL;
}
if (p->fd_gp0_map != -1) {
if (p->gp0_map != NULL && p->gp0_map != MAP_FAILED) {
munmap((void *)p->gp0_map, ZYNQ_PLATFORM_GP0_SIZE);
p->gp0_map = NULL;
}
close(p->fd_gp0_map);
p->fd_gp0_map = -1;
p->gp0_map = NULL;
}
platform_deinit(p->ctx);
LOG(LPLL_INIT, "so long & thanks for all the fish, bye");
platform_logging_exit();
return PLATFORM_SUCCESS;
}
platform_res_t zynq_init()
static
void zynq_unmap()
{
platform_logging_init();
LOG(LPLL_INIT, "Platform API Version: %s", platform_version());
if (platform_check_version(version) != PLATFORM_SUCCESS) {
ERR("Platform API version mismatch: found %s, expected %s",
platform_version(), version);
return PERR_VERSION_MISMATCH;
if (zynq_platform.gp0_map != MAP_FAILED) {
munmap((void *)zynq_platform.gp0_map, ZYNQ_PLATFORM_GP0_SIZE);
}
platform_res_t const r = init_platform(&zynq_platform);
if (r != PLATFORM_SUCCESS) {
ERR("failed to initialize Zynq platform: %s (%d)",
platform_strerror(r), r);
platform_logging_exit();
if (zynq_platform.gp1_map != MAP_FAILED) {
munmap((void *)zynq_platform.gp1_map, ZYNQ_PLATFORM_GP1_SIZE);
}
*pctx = zynq_platform.ctx;
return r;
}
void platform_deinit(platform_devctx_t *ctx)
{
LOG(LPLL_INIT, "shutting down platform");
release_platform(&zynq_platform);
free(ctx);
}
static
platform_res_t zynq_alloc(platform_devctx_t *ctx,
size_t const len, platform_mem_addr_t *addr,
platform_alloc_flags_t const flags)
{
assert(addr);
struct zynq_ioctl_cmd_t cmd = { 0 };
cmd.id = -1;
cmd.length = len;
if (ioctl(zynq_platform.fd_control, ZYNQ_IOCTL_ALLOC, &cmd)) {
ERR("could not allocate: %s", strerror(errno));
return PERR_MEM_ALLOC;
if (zynq_platform.status_map != MAP_FAILED) {
munmap((void *)zynq_platform.status_map, ZYNQ_PLATFORM_STATUS_SIZE);
}
*addr = cmd.dma_addr;
LOG(LPLL_MM, "len = %zu bytes, dma = 0x%08lx", len,
(long unsigned) *addr);
return PLATFORM_SUCCESS;
DEVLOG(zynq_platform.devctx->dev_id, LPLL_DEVICE, "all I/O maps unmapped");
}
static
platform_res_t zynq_dealloc(platform_devctx_t *ctx,
platform_mem_addr_t const addr,
platform_alloc_flags_t const flags)
platform_res_t zynq_iomapping()
{
LOG(LPLL_MM, "dma_addr = 0x%08lx", (unsigned long) addr);
struct zynq_ioctl_cmd_t cmd = { 0 };
cmd.id = -1;
cmd.dma_addr = addr;
if (ioctl(zynq_platform.fd_control, ZYNQ_IOCTL_FREE, &cmd)) {
ERR("could not free: %s", strerror(errno));
return PERR_MEM_ALLOC;
assert(zynq_platform.devctx);
assert(zynq_platform.devctx->fd_ctrl);
zynq_platform.gp0_map = mmap(NULL,
ZYNQ_PLATFORM_GP0_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED,
zynq_platform.devctx->fd_ctrl,
ZYNQ_PLATFORM_GP0_BASE);
if (zynq_platform.gp0_map == MAP_FAILED) {
DEVERR(zynq_platform.devctx->dev_id, "could not map GP0: %s (%d)",
strerror(errno), errno);
zynq_unmap();
return PERR_MMAP_DEV;
}
zynq_platform.gp1_map = mmap(NULL,
ZYNQ_PLATFORM_GP0_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED,
zynq_platform.devctx->fd_ctrl,
ZYNQ_PLATFORM_GP1_BASE);
if (zynq_platform.gp1_map == MAP_FAILED) {
DEVERR(zynq_platform.devctx->dev_id, "could not map GP1: %s (%d)",
strerror(errno), errno);
zynq_unmap();
return PERR_MMAP_DEV;
}
zynq_platform.status_map = mmap(NULL,
ZYNQ_PLATFORM_STATUS_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED,
zynq_platform.devctx->fd_ctrl,
ZYNQ_PLATFORM_STATUS_BASE);
if (zynq_platform.status_map == MAP_FAILED) {
DEVERR(zynq_platform.devctx->dev_id, "could not map status core: %s (%d)",
strerror(errno), errno);
zynq_unmap();
return PERR_MMAP_DEV;
}
return PLATFORM_SUCCESS;
}
static
platform_res_t zynq_read_mem(platform_devctx_t const *ctx,
platform_mem_addr_t const start_addr,
size_t const no_of_bytes, void *data,
platform_mem_flags_t const flags)
platform_res_t zynq_init(platform_devctx_t *devctx)
{
LOG(LPLL_MEM, "start_addr = 0x%08lx, no_of_bytes = %zu",
(unsigned long) start_addr, no_of_bytes);
struct zynq_ioctl_cmd_t cmd = { 0 };
cmd.id = -1;
cmd.length = no_of_bytes;
cmd.dma_addr = start_addr;
cmd.data = data;
if (ioctl(zynq_platform.fd_control, ZYNQ_IOCTL_COPYFROM, &cmd)) {
ERR("could not read: %s", strerror(errno));
return PERR_MEM_NO_SUCH_HANDLE; // FIXME
assert(devctx);
assert(devctx->dev_info.name);
if (! strncmp(ZYNQ_NAME, devctx->dev_info.name, strlen(ZYNQ_NAME))) {
DEVLOG(devctx->dev_id, LPLL_DEVICE, "device #%03u matches Zynq platform");
zynq_platform.devctx = devctx;
return zynq_iomapping();
}
return PLATFORM_SUCCESS;
DEVLOG(devctx->dev_id, LPLL_DEVICE, "does not match Zynq platform");
return PERR_INCOMPATIBLE_DEVICE;
}
static
platform_res_t zynq_write_mem(platform_devctx_t const *ctx,
platform_mem_addr_t const start_addr,
size_t const no_of_bytes, void const*data,
platform_mem_flags_t const flags)
void zynq_exit(platform_devctx_t *devctx)
{
LOG(LPLL_MEM, "start_addr = 0x%08lx, no_of_bytes = %zu",
(unsigned long) start_addr, no_of_bytes);
struct zynq_ioctl_cmd_t cmd = { 0 };
cmd.id = -1;
cmd.length = no_of_bytes;
cmd.dma_addr = start_addr;
cmd.data = (void *)data;
if (ioctl(zynq_platform.fd_control, ZYNQ_IOCTL_COPYTO, &cmd)) {
ERR("could not write: %s", strerror(errno));
return PERR_MEM_NO_SUCH_HANDLE; // FIXME
}
return PLATFORM_SUCCESS;
zynq_unmap();
zynq_platform.devctx = NULL;
DEVLOG(devctx->dev_id, LPLL_DEVICE, "Zynq device released");
}
static
platform_res_t zynq_read_ctl(platform_devctx_t const *ctx,
platform_ctl_addr_t const addr,
size_t const no_of_bytes,
size_t const length,
void *data,
platform_ctl_flags_t const flags)
{
int i;
uint32_t *p = (uint32_t *)data;
volatile uint32_t *r;
LOG(LPLL_CTL, "addr = 0x%08lx, no_of_bytes = %zu",
(unsigned long)addr, no_of_bytes);
LOG(LPLL_CTL, "addr = 0x%08lx, length = %zu",
(unsigned long)addr, length);
#ifndef NDEBUG
if (no_of_bytes % 4) {
if (length % 4) {
ERR("error: invalid size!");
return PERR_CTL_INVALID_SIZE;
}
......@@ -326,16 +161,16 @@ platform_res_t zynq_read_ctl(platform_devctx_t const *ctx,
else if (ISBETWEEN(addr, ZYNQ_PLATFORM_GP1_BASE, ZYNQ_PLATFORM_GP1_HIGH))
r = (volatile uint32_t *)zynq_platform.gp1_map +
((addr - ZYNQ_PLATFORM_GP1_BASE) >> 2);
else if (ISBETWEEN(addr, PLATFORM_API_TAPASCO_STATUS_BASE,
PLATFORM_API_TAPASCO_STATUS_HIGH))
else if (ISBETWEEN(addr, ZYNQ_PLATFORM_STATUS_BASE,
ZYNQ_PLATFORM_STATUS_HIGH))
r = (volatile uint32_t *)zynq_platform.status_map + ((addr -
PLATFORM_API_TAPASCO_STATUS_BASE) >> 2);
ZYNQ_PLATFORM_STATUS_BASE) >> 2);
else {
ERR("invalid platform address: 0x%08lx", (unsigned long)addr);
return PERR_CTL_INVALID_ADDRESS;
}
for (i = 0; i < (no_of_bytes >> 2); ++i, ++p, ++r)
for (i = 0; i < (length >> 2); ++i, ++p, ++r)
*p = *r;
return PLATFORM_SUCCESS;
......@@ -343,19 +178,19 @@ platform_res_t zynq_read_ctl(platform_devctx_t const *ctx,
platform_res_t zynq_write_ctl(platform_devctx_t const *ctx,
platform_ctl_addr_t const addr,
size_t const no_of_bytes,
void const*data,
size_t const length,
void const *data,
platform_ctl_flags_t const flags)
{
int i;
uint32_t const *p = (uint32_t const *)data;
volatile uint32_t *r;
LOG(LPLL_CTL, "addr = 0x%08lx, no_of_bytes = %zu",
(unsigned long)addr, no_of_bytes);
LOG(LPLL_CTL, "addr = 0x%08lx, length = %zu",
(unsigned long)addr, length);
#ifndef NDEBUG
if (no_of_bytes % 4) {
ERR("invalid size: %zd", no_of_bytes);
if (length % 4) {
ERR("invalid size: %zd", length);
return PERR_CTL_INVALID_SIZE;
}
#endif
......@@ -371,17 +206,17 @@ platform_res_t zynq_write_ctl(platform_devctx_t const *ctx,
return PERR_CTL_INVALID_ADDRESS;
}
for (i = 0; i < (no_of_bytes >> 2); ++i, ++p, ++r)
for (i = 0; i < (length >> 2); ++i, ++p, ++r)
*r = *p;
return PLATFORM_SUCCESS;
}
static const struct platform_device_operations _zynq_dops = {
.alloc = zynq_alloc,
.dealloc = zynq_dealloc,
.read_mem = zynq_read_mem,
.write_mem = zynq_write_mem,
.alloc = default_alloc,
.dealloc = default_dealloc,
.read_mem = default_read_mem,
.write_mem = default_write_mem,
.read_ctl = zynq_read_ctl,
.write_ctl = zynq_write_ctl,
};*/
};
......@@ -6,6 +6,7 @@
#include "zynq_enumerate.h"
#include "zynq_device.h"
#include "zynq_platform.h"
#include "zynq_ioctl.h"
static const struct of_device_id zynq_ids[] = {
{ .compatible = ZYNQ_NAME, },
......@@ -14,9 +15,10 @@ static const struct of_device_id zynq_ids[] = {
static tlkm_device_t zynq_dev = {
.device = LIST_HEAD_INIT(zynq_dev.device),
.name = ZYNQ_NAME,
.init = zynq_device_init,
.exit = zynq_device_exit,
.name = ZYNQ_NAME,
.init = zynq_device_init,
.exit = zynq_device_exit,
.ioctl = zynq_ioctl,
};
ssize_t zynq_enumerate()
......
......@@ -169,8 +169,8 @@ long zynq_ioctl_read(struct tlkm_device_inst *inst, struct tlkm_dev_cmd *cmd)
} else if (cmd->dev_addr & ZYNQ_PLATFORM_STATUS_BASE) {
ptr = dev->tapasco_status + (cmd->dev_addr - ZYNQ_PLATFORM_STATUS_BASE);
}
if (ptr && copy_to_user((void __user *)cmd->user_addr, ptr, cmd->length)) {
DEVERR(inst->dev_id, "could not copy all bytes to user space");
if (ptr && (ret = copy_to_user((void __user *)cmd->user_addr, ptr, cmd->length))) {
DEVERR(inst->dev_id, "could not copy all bytes to user space: %ld", ret);
ret = -EAGAIN;
}
return ret;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment