Skip to content
Snippets Groups Projects
Commit 9f31e649 authored by Armin Luntzer's avatar Armin Luntzer
Browse files

Xentium: improve interface, add DMA support

parent d0663d79
No related branches found
No related tags found
No related merge requests found
......@@ -25,7 +25,7 @@ obj- := dummy.o
HOSTCC := xentium-clang
HOSTLD := xentium-ld
HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2
HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O3
HOSTCFLAGS +=-Idsp/xentium/include
HOSTCFLAGS += $(KERNELINCLUDE)
......@@ -33,7 +33,7 @@ HOSTLDFLAGS += -Tdsp/xentium/sysroot/lib/default.ld
HOSTLDFLAGS += --sysroot=dsp/xentium/sysroot
xen_libs:
xen_libs-objs := xen_printf.o data_proc_task.o lib/xen.o
xen_libs-objs := xen_printf.o data_proc_task.o lib/xen.o lib/dma.o
xen_dummy.xen : xen_libs
HOSTLOADLIBES_xen_dummy.xen :=
......
/**
* @file dsp/xentium/include/xdma.h
*/
#ifndef _DSP_XENTIUM_DMA_H_
#define _DSP_XENTIUM_DMA_H_
#include <stddef.h>
#include <noc_dma.h>
int xen_noc_dma_req_xfer(struct noc_dma_channel *c,
void *src, void *dst, uint16_t x_elem, uint16_t y_elem,
enum noc_dma_elem_size elem_size,
int16_t x_stride_src, int16_t x_stride_dst,
int16_t y_stride_src, int16_t y_stride_dst,
enum noc_dma_priority dma_priority, uint16_t mtu);
int xen_noc_dma_req_lin_xfer(struct noc_dma_channel *c,
void *src, void *dst,
uint16_t elem, enum noc_dma_elem_size elem_size,
enum noc_dma_priority dma_priority, uint16_t mtu);
#endif /* _DSP_XENTIUM_DMA_H_ */
......@@ -17,10 +17,14 @@ void xen_set_mail(size_t mbox, unsigned long msg);
unsigned long xen_get_mail(size_t mbox);
struct xen_msg_data *xen_wait_msg(void);
struct xen_msg_data *xen_wait_cmd(void);
void xen_send_msg(struct xen_msg_data *m);
void xen_wait_timer(int timer, unsigned long cycles);
void xen_wait_dma(void);
void *xen_get_base_addr(size_t xen_id);
#endif /* _DSP_XENTIUM_XEN_H_ */
/**
* @file dsp/xentium/lib/xdma.c
*
* These are mostly just duplicates of the noc_dma access functions...
*/
#include <errno.h>
#include <dma.h>
#define ioread32(X) __raw_readl(X)
#define iowrite32(val,X) __raw_writel(val,X)
static inline uint32_t __raw_readl(const volatile void *addr)
{
return (*(const volatile uint32_t *) addr);
}
static inline void __raw_writel(uint32_t l, volatile void *addr)
{
(*(volatile uint32_t *) addr) = l;
}
/**
* NoC DMA channel control register layout
* @see MPPB datasheet v4.03, p64
*/
__extension__
struct noc_dma_channel_ctrl {
union {
uint32_t ctrl;
struct {
uint32_t priority :1;
uint32_t irq_fwd :2;
uint32_t acc_sz :2;
uint32_t reserved :11;
uint32_t max_pkt_sz :16;
}__attribute__((packed));
};
};
/**
* NoC DMA channel configuration register layout
* @see MPPB datasheet v4.03, p63
*/
__extension__
struct noc_dma_channel {
union {
uint32_t start;
uint32_t status;
struct {
uint32_t start_status:1;
uint32_t res01 :31; /* reserved */
}__attribute__((packed));
};
union {
uint32_t control;
struct noc_dma_channel_ctrl ctrl;
};
uint32_t dst;
uint32_t src;
union {
uint32_t sizes;
struct {
uint16_t sz_y;
uint16_t sz_x;
}__attribute__((packed));
};
union {
uint32_t strides_x;
struct {
uint16_t str_x_src;
uint16_t str_x_dst;
}__attribute__((packed));
};
union {
uint32_t strides_y;
struct {
uint16_t str_y_src;
uint16_t str_y_dst;
}__attribute__((packed));
};
uint32_t res02[9];
}__attribute__((packed));
/**
* @brief check if a NoC DMA channel is in use
*
* @param chan a struct noc_dma_channel
*
* @returns 0 if not busy
*/
static int noc_dma_channel_busy(struct noc_dma_channel *chan)
{
return ioread32(&chan->status) & NOC_DMA_CHANNEL_BUSY;
}
/**
* @brief set source and destination strides in x
*
* @param chan a struct noc_dma_channel
* @param stride_src the source stride
* @param stride_dst the destination stride
*/
static void noc_dma_set_strides_x(struct noc_dma_channel *chan,
int16_t stride_src, int16_t stride_dst)
{
iowrite32(NOC_DMA_STRIDES(stride_src, stride_dst), &chan->strides_x);
}
/**
* @brief set source and destination strides in y
*
* @param chan a struct noc_dma_channel
* @param stride_src the source stride
* @param stride_dst the destination stride
*/
static void noc_dma_set_strides_y(struct noc_dma_channel *chan,
int16_t stride_src, int16_t stride_dst)
{
iowrite32(NOC_DMA_STRIDES(stride_src, stride_dst), &chan->strides_y);
}
/**
* @brief set transfer sizes in x and y
*
* @param chan a struct noc_dma_channel
* @param size_x the number of elements to transfer in x
* @param size_y the number of elements to transfer in y
*/
static void noc_dma_set_sizes(struct noc_dma_channel *chan,
int16_t size_x, uint16_t size_y)
{
iowrite32(NOC_DMA_SIZES(size_x, size_y), &chan->sizes);
}
/**
* @brief set transfer source address
*
* @param chan a struct noc_dma_channel
* @param src the source memory location
*/
static void noc_dma_set_src(struct noc_dma_channel *chan, void *src)
{
iowrite32((uint32_t) src, &chan->src);
}
/**
* @brief set transfer destination address
*
* @param chan a struct noc_dma_channel
* @param dst the destination memory location
*/
static void noc_dma_set_dst(struct noc_dma_channel *chan, void *dst)
{
iowrite32((uint32_t) dst, &chan->dst);
}
/**
* @brief start a DMA transfer
* @param chan a struct noc_dma_channel
*
* @returns 0 on success, -EBUSY if channel is active
*/
static int noc_dma_start_transfer(struct noc_dma_channel *chan)
{
if (noc_dma_channel_busy(chan))
return -EBUSY;
iowrite32(NOC_DMA_CHANNEL_START, &chan->start);
/* XXX remove once we figure out how to properly use the Xentium's
* DMA status bits
*/
while (noc_dma_channel_busy(chan));
return 0;
}
/**
* @brief sets the channel configuration for a transfer
*
* @param chan a struct noc_dma_channel
* @param max_pkt_size the maximum packet size to use during the transfer
* @param elem_size the size of a transfer element
* @param irq_fwd the irq notification mode on transfer completion
* @param priority the transfer priority
*
* @returns 0 on success, -EBUSY if channel is active
*/
static int noc_dma_set_config(struct noc_dma_channel *chan,
int16_t max_pkt_size,
enum noc_dma_elem_size elem_size,
enum noc_dma_irq_fwd irq_fwd,
enum noc_dma_priority priority)
{
struct noc_dma_channel_ctrl ctrl;
if (noc_dma_channel_busy(chan))
return -EBUSY;
ctrl.max_pkt_sz = max_pkt_size;
ctrl.acc_sz = elem_size;
ctrl.irq_fwd = irq_fwd;
ctrl.priority = priority;
iowrite32(ctrl.ctrl, &chan->ctrl);
return 0;
}
/**
* @brief initialises the data parameters for a one dimensional DMA transfer
*
* @param chan a struct noc_dma_channel
* @param chan a struct noc_dma_transfer
*
* @returns 0 on success, EINVAL on error, EBUSY if channel is busy
*/
static int noc_dma_init_transfer(struct noc_dma_channel *c,
struct noc_dma_transfer *t)
{
if (noc_dma_channel_busy(c))
return -EBUSY;
/* src == dst memory will result in a stuck DMA channel */
if (((int) t->dst & 0xF0000000) == ((int) t->src & 0xF0000000))
return -EINVAL;
/* no need to verify stride/size limits, they are implicity by type */
noc_dma_set_src(c, t->src);
noc_dma_set_dst(c, t->dst);
noc_dma_set_strides_x(c, t->x_stride_src, t->x_stride_dst);
noc_dma_set_strides_y(c, t->y_stride_src, t->y_stride_dst);
noc_dma_set_sizes(c, t->x_elem, t->y_elem);
noc_dma_set_config(c, t->mtu, t->elem_size, t->irq_fwd, t->priority);
return 0;
}
/**
* @brief request an arbitrary DMA transfer
*
* @param c the DMA channel to use
*
* @param src the source address
* @param dst the destination address
*
* @param x_elem the number of elements in x
* @param y_elem the number of elements in y
* @param size the element size (BYTE, HALFWORD, WORD, DOUBLEWORD)
*
* @param x_stride_src the width of stride in source x
* @param x_stride_dst the width of stride in destination x
*
* @param y_stride_src the width of stride in source y
* @param y_stride_dst the width of stride in destination y
*
* @param mtu the maximum transfer unit of a NoC packet
*
* @returns <0 on error
*/
int xen_noc_dma_req_xfer(struct noc_dma_channel *c,
void *src, void *dst, uint16_t x_elem, uint16_t y_elem,
enum noc_dma_elem_size elem_size,
int16_t x_stride_src, int16_t x_stride_dst,
int16_t y_stride_src, int16_t y_stride_dst,
enum noc_dma_priority dma_priority, uint16_t mtu)
{
int ret;
struct noc_dma_transfer t;
if (!src)
return -EINVAL;
if (!dst)
return -EINVAL;
if(!x_elem)
return -EINVAL;
if(!y_elem)
return -EINVAL;
t.src = src;
t.dst = dst;
t.x_elem = x_elem;
t.y_elem = y_elem;
t.elem_size = elem_size;
t.x_stride_src = x_stride_src;
t.x_stride_dst = x_stride_dst;
t.y_stride_src = y_stride_src;
t.y_stride_dst = y_stride_dst;
t.mtu = mtu;
t.irq_fwd = IN;
t.priority = dma_priority;
ret = noc_dma_init_transfer(c, &t);
if (ret)
return ret;
return noc_dma_start_transfer(c);
}
/**
* @brief request a linear array DMA transfer
*
* @param c the DMA channel to use
*
* @param src the source address
* @param dst the destination address
*
* @param elem the number of elements
* @param size the element size (BYTE, HALFWORD, WORD, DOUBLEWORD)
*
* @param mtu the maximum transfer unit of a NoC packet
*
* @returns <0 on error
*/
int xen_noc_dma_req_lin_xfer(struct noc_dma_channel *c,
void *src, void *dst,
uint16_t elem, enum noc_dma_elem_size elem_size,
enum noc_dma_priority dma_priority, uint16_t mtu)
{
return xen_noc_dma_req_xfer(c, src, dst, elem, 1, elem_size,
1, 1, 1, 1, LOW, mtu);
}
......@@ -48,23 +48,36 @@ unsigned long xen_get_mail(size_t mbox)
/**
* @brief wait for host to pass a data message for processing
* @brief wait for host to pass a command data message for processing
*
* @returns a data message pointer
*/
struct xen_msg_data *xen_wait_msg(void)
struct xen_msg_data *xen_wait_cmd(void)
{
struct xen_msg_data *m;
x_wait(XEN_MSG_MBOX_MASK);
x_wait(XEN_CMD_MBOX_MASK);
m = (struct xen_msg_data *) xen_get_mail(XEN_MSG_MBOX);
m = (struct xen_msg_data *) xen_get_mail(XEN_CMD_MBOX);
return m;
}
/**
* @brief pass a data message and signal the host
*
* @param m the message to pass
*/
void xen_send_msg(struct xen_msg_data *m)
{
xen_set_mail(XEN_MSG_MBOX, (unsigned long) m);
xen_signal_host();
}
/**
* @brief wait for a timer to count to 0
*
......@@ -83,3 +96,28 @@ void xen_wait_timer(int timer, unsigned long cycles)
while(xen_dev_local->timer[timer]);
}
/**
* @brief wait until the DMA status bit is low (i.e. transfer complete)
* *
*/
void xen_wait_dma(void)
{
/* XXX this doesn't seem to work sensibly, we can't x_wait() on the
* dma irq status bit, because it is set UNTIL we clear the
* dma_irq, and we'd apparently have to also clear the latter
* _before_ we even start the transfer. For now, it's easier to just
* wait on the channel status bit in noc_dma_start_transfer()
*/
}
/**
* @brief get the base address of a Xentium by its numeric index
*
* @returns the base address of the Xentium
*/
void *xen_get_base_addr(size_t idx)
{
return (void *) (XEN_BASE_ADDR + XEN_BLOCK_SIZE * idx);
}
#include <xen.h>
#include <dma.h>
#include <xen_printf.h>
#include <data_proc_net.h>
#define KERN_NAME "otherkernel"
#define KERN_STORAGE_BYTES 0
#define KERN_OP_CODE 0xb19b00b5
#define KERN_CRIT_TASK_LVL 12
/* actual configuration */
struct xen_kernel_cfg _xen_kernel_param __attribute__((used)) = {
KERN_NAME, KERN_OP_CODE,
KERN_CRIT_TASK_LVL,
NULL, KERN_STORAGE_BYTES,
};
static void process_task(struct xen_msg_data *m)
{
size_t n;
size_t i;
unsigned int *p;
volatile unsigned int *b;
struct xen_tcm *tcm_ext;
b = (volatile unsigned int *) xen_tcm_local;
tcm_ext = xen_get_base_addr(m->xen_id);
if (!m->t) {
m->cmd = TASK_DESTROY;
return;
}
n = pt_get_nmemb(m->t);
p = (unsigned int *) pt_get_data(m->t);
/* retrieve data to TCM XXX retval */
xen_noc_dma_req_lin_xfer(m->dma, p, tcm_ext, n, WORD, LOW, 256);
/* process */
for (i = 0; i < n; i++) {
b[i] *= 2;
}
/* back to main memory XXX retval */
xen_noc_dma_req_lin_xfer(m->dma, tcm_ext, p, n, WORD, LOW, 256);
m->cmd = TASK_SUCCESS;
}
int main(void)
{
struct xen_msg_data *m;
while (1) {
m = xen_wait_cmd();
switch (m->cmd) {
case TASK_STOP:
/* confirm abort */
xen_send_msg(m);
return 0;
default:
break;
}
process_task(m);
xen_send_msg(m);
}
return 0;
}
#include <xen.h>
#include <dma.h>
#include <xen_printf.h>
#include <data_proc_net.h>
#define KERN_NAME "xen_dummy"
#define KERN_STORAGE_BYTES 0
#define KERN_OP_CODE 0xdeadbeef
......@@ -21,33 +20,39 @@ struct xen_kernel_cfg _xen_kernel_param = {
static void process_task(struct xen_msg_data *m)
{
size_t n;
size_t i, j;
size_t i;
unsigned int *p;
volatile unsigned int *b;
struct xen_tcm *tcm_ext;
b = (volatile unsigned int *) xen_tcm_local;
tcm_ext = xen_get_base_addr(m->xen_id);
if (!m->t) {
m->cmd = TASK_DESTROY;
return;
}
#if 0
/* op code doesn't match, pass it on */
if (pt_get_pend_step_op_code(m->t) != _xen_kernel_param.op_code) {
m->cmd = TASK_SUCCESS;
return;
}
#endif
n = pt_get_nmemb(m->t);
p = (unsigned int *) pt_get_data(m->t);
#if 0
for (j = 0; j < 1000; j++) {
/* retrieve data to TCM XXX retval */
xen_noc_dma_req_lin_xfer(m->dma, p, tcm_ext, n, WORD, LOW, 256);
/* process */
for (i = 0; i < n; i++) {
p[i] += 1230;
}
b[i] += 1;
}
#endif
/* back to main memory XXX retval */
xen_noc_dma_req_lin_xfer(m->dma, tcm_ext, p, n, WORD, LOW, 256);
m->cmd = TASK_SUCCESS;
}
......@@ -57,25 +62,20 @@ int main(void)
{
struct xen_msg_data *m;
while (1) {
m = xen_wait_msg();
m = xen_wait_cmd();
switch (m->cmd) {
case TASK_STOP:
/* confirm abort */
x_printf("%s says bye!\n", _xen_kernel_param.name);
xen_signal_host();
xen_send_msg(m);
return 0;
default:
break;
}
//x_printf("Hello there %s\n", _xen_kernel_param.name);
process_task(m);
xen_set_mail(XEN_MSG_MBOX, (unsigned long) m);
xen_signal_host();
xen_send_msg(m);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment