Commit f240f4ce authored by Federico Vaga's avatar Federico Vaga

sw:*: re-design MQ interface

The HMQ architecture changed completely. For this reason it was impossible
to propose a step by step migration to the new architecture, instead I did
all the changes for all the layers in a single patch (@_@). It will not be
easy to review or to blame/bisect but I hope you understand that this was
the only way.

In this architecture there are HMQ dedicated to each soft-CPU. This improve
the soft-CPU determinism; it also simplifies the software layers which can take
a couple of assumption:
- each CPU has a set of dedicated HMQ
- each HMQ has an input and an output channel

At the driver level the main changes are on the organization of the HMQ devices
and the interrupt handlers for input and output. The removal of the synchronous
message ioctl(2) is another great improvement which simplifies the driver logic.

At the library level, the user does not need anymore to open and close HMQ
independently because this happens automatically when the user open the device.
The synchronous messages are implemented in this layer by using the driver
message filter to detect a synchronous answer (a convention to be decided later).

At the python level I reflected the library changes.

Broken things
=============
Due to the complexity of this patch, this breaks the following tools:
- mockturtle-ping
- mockturtle-buffer
- mockturtle-variable
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent d3d6ccf5
......@@ -3,6 +3,31 @@
#define TRTL_CONFIG_ROM_SIGNATURE 0x5452544c
#define TRTL_MAX_CPU 8 /**< Maximum number of CPU core in a bitstream */
#define TRTL_MAX_MQ_CHAN 8 /**< Maximum number of (H|R)MQ slots in a
bitstream */
#define TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT 16
#define TRTL_CONFIG_ROM_MQ_ENTRIES_MASK 0x00FF0000
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT 8
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK 0x0000FF00
#define TRTL_CONFIG_ROM_MQ_HEADER_SHIFT 0
#define TRTL_CONFIG_ROM_MQ_HEADER_MASK 0x000000FF
#define TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_ENTRIES_MASK) >> TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK) >> TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_HEADER(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_HEADER_MASK) >> TRTL_CONFIG_ROM_MQ_HEADER_SHIFT))
/**
* The synthesis configuration for a single MQ.
* Note that there is always an input and output channel for each declaration.
*/
struct trtl_config_rom_mq {
uint32_t sizes;
uint32_t endpoint_id;
};
/**
* The synthesis configuration ROM descriptor shows useful configuration
* options during synthesis.
......@@ -10,13 +35,18 @@
struct trtl_config_rom {
uint32_t signature; /**< we expect to see a known value */
uint32_t version; /**< Mock Turtle version */
uint32_t pad;
uint32_t pad1[1];
uint32_t clock_freq;
uint32_t flags;
uint32_t app_id; /**< Application ID */
uint32_t n_cpu; /**< number of CPU */
uint32_t smem_size; /**< shared memory size */
uint32_t hmq_width;
uint32_t mem_size[TRTL_MAX_CPU]; /**< memory size for each CPU */
uint32_t n_hmq[TRTL_MAX_CPU]; /**< number of HMQ for each CPU */
uint32_t n_rmq[TRTL_MAX_CPU]; /**< number of RMQ for each CPU */
uint32_t pad2[96];
struct trtl_config_rom_mq hmq[TRTL_MAX_CPU * TRTL_MAX_MQ_CHAN];
struct trtl_config_rom_mq rmq[TRTL_MAX_CPU * TRTL_MAX_MQ_CHAN];
};
#endif
......@@ -20,9 +20,9 @@
// Common for all incoming/outgoing slots in the queue
#define TRTL_MQ_BASE_GCR (0x0)
// Incoming slot base address, relative to BASE_HMQ
#define TRTL_MQ_BASE_IN(slot) (0x4000 + ((slot) << 16))
#define TRTL_MQ_BASE_IN 0x4000
// Outgoung slot base address, relative to BASE_HMQ
#define TRTL_MQ_BASE_OUT(slot) (0x8000 + ((slot) << 16))
#define TRTL_MQ_BASE_OUT 0x8000
// MQ slot registers, relative to the base address of each slot: TRTL_MQ_BASE_IN(slot_no) or TRTL_MQ_BASE_OUT(slot_no)
#define TRTL_MQ_SLOT_COMMAND 0
......@@ -100,17 +100,17 @@
// [23:16] Outgoing slots status. Each bit indicates a NOT FULL status of the corresponding outgoing slot (data can be sent).
#define TRTL_MQ_GCR_SLOT_STATUS_OUT_SHIFT 16
#define TRTL_MQ_GCR_SLOT_STATUS_OUT_MASK 0xffff0000
#define TRTL_MQ_GCR_SLOT_STATUS_OUT_MASK 0x00ff0000
// Layout of IRQ_MASK register
// [7:0] Incoming slots status interrupt mask. Each bit enables generation of interrupt on not EMPTY status of the corresponding incoming slot.
#define TRTL_MQ_GCR_IRQ_MASK_OUT_SHIFT 0
#define TRTL_MQ_GCR_IRQ_MASK_OUT_MASK 0xff
// [7:0] Outgoing slots status interrupt mask. Each bit enables generation of interrupt on EMPTY status of the corresponding slot.
#define TRTL_MQ_GCR_IRQ_MASK_OUT_SHIFT 16
#define TRTL_MQ_GCR_IRQ_MASK_OUT_MASK 0x00ff0000
// [23:16] Outgoing slots status interrupt mask. Each bit enables generation of interrupt on NOT FULL status of the corresponding outgoing slot.
#define TRTL_MQ_GCR_IRQ_MASK_IN_SHIFT 16
#define TRTL_MQ_GCR_IRQ_MASK_IN_MASK 0x00ff0000
// [23:16] Incoming slots status interrupt mask. Each bit enables generation of interrupt on NOT EMPTY status of the corresponding slot.
#define TRTL_MQ_GCR_IRQ_MASK_IN_SHIFT 0
#define TRTL_MQ_GCR_IRQ_MASK_IN_MASK 0x000000ff
// Layout of IRQ_COALSESCE register
// The register is left for future IRQ coalescing support (if ever needed)
......
......@@ -19,7 +19,9 @@
#ifndef __TRTL_COMMON_H__
#define __TRTL_COMMON_H__
#ifndef __KERNEL__
#include <string.h>
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
......@@ -53,6 +55,16 @@ enum trtl_msg_id_o {
TRTL_MSG_ID_BUF_GET_ANS,
};
/**
* HMQ headerd descriptor
*/
struct trtl_hmq_header {
uint32_t len;
uint32_t sync_id;
};
/**
* It describes the version running on the embedded CPU
*/
......
......@@ -21,13 +21,18 @@
#define __TRTL_USER_H__
/** @file mock-turtle.h */
#include "mockturtle-common.h"
#define TRTL_MAX_CARRIER 20 /**< Maximum number of WRNC components on a
single computer*/
#define TRTL_MAX_CPU 8 /**< Maximum number of CPU core in a WRNC bitstream */
#define TRTL_MAX_HMQ_SLOT 32 /**< Maximum number of HMQ slots in a
WRNC bitstream */
#define TRTL_MAX_PAYLOAD_SIZE 128
/**
* This value represents the maximum payload size (in words) of a single
* message. The true maximum size is set in the internal ROM, but to simplify
* the code here we set this to the maximum addressable payload: 4096 bytes
*/
#define TRTL_MAX_PAYLOAD_SIZE (4096 / 4)
/**
......@@ -50,21 +55,10 @@ enum trtl_smem_modifier {
* Messages descriptor
*/
struct trtl_msg {
uint32_t datalen; /**< payload length*/
uint32_t data[TRTL_MAX_PAYLOAD_SIZE]; /**< payload, free content
(no official protocol) */
struct trtl_hmq_header hdr;
uint32_t data[TRTL_MAX_PAYLOAD_SIZE]; /**< payload very maximum size */
};
/**
* Message descriptor used to send synchronous messages
*/
struct trtl_msg_sync {
struct trtl_msg *msg; /**< the message to send. It will be overwritten by
the synchronous answer */
uint16_t index_in; /**< where write the message */
uint16_t index_out; /**< where we expect the synchronous answer */
unsigned int timeout_ms; /**< time to wait for an answer in ms */
};
/**
* @enum trtl_msg_filter_operation_type
......@@ -73,14 +67,18 @@ struct trtl_msg_sync {
enum trtl_msg_filter_operation_type {
TRTL_MSG_FILTER_AND,
TRTL_MSG_FILTER_OR,
TRTL_MSG_FILTER_NOT,
TRTL_MSG_FILTER_EQ,
TRTL_MSG_FILTER_NEQ,
__TRTL_MSG_FILTER_MAX,
};
#define TRTL_MSG_FILTER_FLAG_PAYLOAD (1 << 0)
/**
* It describe a filter to apply to messages
*/
struct trtl_msg_filter {
unsigned long flags; /**< options for the filter */
uint32_t operation; /**< kind of operation to perform */
uint32_t word_offset; /**< offset of the word to check */
uint32_t mask; /**< mask to apply before the operation */
......@@ -104,7 +102,6 @@ struct trtl_smem_io {
* Available ioctl() messages
*/
enum trtl_ioctl_commands {
TRTL_MSG_SYNC, /**< send a synchronous message */
TRTL_SMEM_IO, /**< access to shared memory */
TRTL_MSG_FILTER_ADD, /**< add a message filter */
TRTL_MSG_FILTER_CLEAN, /**< remove all filters */
......@@ -112,8 +109,6 @@ enum trtl_ioctl_commands {
#define TRTL_IOCTL_MAGIC 's'
#define TRTL_IOCTL_MSG_SYNC _IOWR(TRTL_IOCTL_MAGIC, TRTL_MSG_SYNC, \
struct trtl_msg_sync)
#define TRTL_IOCTL_SMEM_IO _IOWR(TRTL_IOCTL_MAGIC, TRTL_SMEM_IO, \
struct trtl_smem_io)
......
This diff is collapsed.
......@@ -33,7 +33,7 @@
#define MAX_MQUEUE_SLOTS (TRTL_MAX_HMQ_SLOT / 2)
#define TRTL_MAX_CPU_MINORS (TRTL_MAX_CPU * TRTL_MAX_CARRIER)
#define TRTL_MAX_HMQ_MINORS (TRTL_MAX_HMQ_SLOT * TRTL_MAX_CARRIER)
#define TRTL_MAX_HMQ_MINORS (TRTL_MAX_MQ_CHAN * TRTL_MAX_CARRIER)
#define TRTL_MAX_MINORS (TRTL_MAX_CARRIER + TRTL_MAX_CPU_MINORS + TRTL_MAX_HMQ_MINORS)
#define TRTL_SMEM_MAX_SIZE 65536
......@@ -48,8 +48,6 @@
1 CPU is using it */
#define TRTL_FLAG_HMQ_SHR_USR (1 << 2) /**< Shared by users */
#define TRTL_FLAG_HMQ_SYNC_WAIT (1 << 3) /**< wait sync answer */
#define TRTL_FLAG_HMQ_SYNC_READY (1 << 4) /**< sync answer is ready */
extern struct class trtl_cdev_class;
......@@ -59,9 +57,19 @@ enum mock_turtle_versions {
/* TODO actually all versioning */
};
/**
* It enumerates the IRQ sources
* @TRTL_IRQ_HMQ_IN: incoming messages from soft-CPUs
* @TRTL_IRQ_HMQ_OUT: outgoing messages to soft-CPUs
* @TRTL_IRQ_HMQ_CON: messages in the console
* @TRTL_IRQ_HMQ_NOT: soft-CPU notifications
*/
enum mockturtle_irq_resource {
TRTL_IRQ_HMQ = 0,
TRTL_IRQ_DBG,
TRTL_IRQ_HMQ_IN = 0,
TRTL_IRQ_HMQ_OUT,
TRTL_IRQ_CON,
TRTL_IRQ_NOT,
};
enum mockturtle_mem_resource {
......@@ -108,28 +116,31 @@ struct trtl_msg_element {
* Circular buffer implementation for MockTurtle
*/
struct mturtle_hmq_buffer {
void *mem;
unsigned int size; /**< buffer size */
unsigned int ptr_w; /**< circular buffer head */
unsigned int ptr_r; /**< circular buffer tail - used only when the
buffer is used to transferm from host to mturtle.
Otherwise use the user->ptr_r */
unsigned int max_msg_size; /**< maximum message size storable in the
buffer. This is a temporary field; once
we move to the mturtle protocol we will
not need such field FIXME */
struct spinlock lock;
unsigned int idx_w;
unsigned int idx_r;
struct trtl_msg *msg;
struct trtl_msg msg_tmp;
unsigned int count;
};
/**
* Collection of HMQ statistics
* struct trtl_hmq_slot - slot description
* @header: slot header
* @payload:
*/
struct trtl_hmq_stats {
unsigned int count; /**< number of messages passed throught the HMQ */
struct trtl_hmq_slot {
struct trtl_hmq_header header;
uint32_t *payload;
};
/**
* It describe the status of a HMQ slot
* @msg_in: list of incoming messages
* @msg_out: list of outgoing messages
*/
struct trtl_hmq {
struct device dev;
......@@ -139,28 +150,26 @@ struct trtl_hmq {
uint32_t status; /**< describe the status of the HMQ slot from the
cpu point of view */
void *base_sr; /**< base address of the slot register */
void *base_in; /**< base address for incoming HMQ */
void *base_out; /**< base address for outgoing HMQ */
struct list_head list_msg_input; /**< list of messages to
input slot */
unsigned int n_input; /**< number of messages in the list */
struct spinlock lock; /**< to protect list read/write */
struct mutex mtx; /**< to protect operations on the HMQ */
struct mutex mtx_sync; /**< to protect sync messages on the HMQ */
wait_queue_head_t q_msg; /**< wait queue for synchronous messages */
wait_queue_head_t q_msg; /**< wait queue for messages */
struct list_head list_usr; /**< list of consumer of the output slot */
unsigned int n_user; /**< number of users in the list */
unsigned int waiting_seq; /**< sequence number to wait */
struct trtl_msg sync_answer; /**< synchronous answer message */
const struct trtl_config_rom_mq *cfg;
unsigned int max_width; /**< maximum words number per single buffer */
unsigned int max_depth; /**< maximum buffer queue length (HW) */
struct mturtle_hmq_buffer buf; /**< Circular buffer */
struct trtl_hmq_stats stats;
struct mturtle_hmq_buffer buf_in; /**< Circular buffer incoming
messages */
struct mturtle_hmq_buffer buf_out; /**< Circular buffer outgoing
messages */
};
/**
......@@ -176,6 +185,7 @@ struct trtl_hmq_user {
struct spinlock lock_filter; /**< to protect filter list read/write */
unsigned int ptr_r; /**< read pointer for the message circular buffer */
unsigned int idx_r;
};
......@@ -189,9 +199,8 @@ struct trtl_cpu {
struct dentry *dbg_msg; /**< debug messages interface */
struct circ_buf cbuf; /**< debug circular buffer */
struct spinlock lock;
struct trtl_hmq *hmq[TRTL_MAX_HMQ_SLOT]; /**< list of HMQ slots used by
struct trtl_hmq hmq[TRTL_MAX_MQ_CHAN]; /**< list of HMQ slots used by
this CPU */
struct device *tty_dev;
struct tty_port tty_port;
unsigned int tty_index;
......@@ -201,16 +210,10 @@ struct trtl_cpu {
* It describes the generic instance of a TRTL
*/
struct trtl_dev {
unsigned int app_id; /**< Application ID of the FPGA bitstream */
struct device dev;
unsigned int n_cpu; /**< number of CPU in the FPGA bitstream */
struct trtl_cpu cpu[TRTL_MAX_CPU]; /**< CPU instances */
unsigned int n_hmq_in; /**< number of input slots in the HMQ */
unsigned int n_hmq_out; /**< number of output slots in the HMQ */
struct trtl_hmq hmq_in[MAX_MQUEUE_SLOTS]; /**< HMQ input instances */
struct trtl_hmq hmq_out[MAX_MQUEUE_SLOTS]; /**< HMQ output instances */
void *base_core; /**< base address of the TRTL component */
void *base_csr; /**< base address of the Shared Control Register */
void *base_hmq; /**< base address of the HMQ */
......@@ -218,7 +221,7 @@ struct trtl_dev {
for the HMQ */
void *base_cfg; /**< base address for the configuration ROM */
void *base_smem; /**< base address of the Shared Memory */
uint32_t irq_mask; /**< IRQ mask in use */
uint64_t irq_mask; /**< IRQ mask in use */
enum trtl_smem_modifier mod; /**< smem operation modifier */
......@@ -226,8 +229,9 @@ struct trtl_dev {
uint32_t message_sequence; /**< message sequence number */
struct spinlock lock_cpu_sel;
struct spinlock lock_hmq_sel;
struct trtl_config_rom cfgrom; /**< synthesis configuration ROM */
const struct trtl_config_rom cfgrom; /**< synthesis configuration ROM */
};
static inline u32 trtl_ioread(struct trtl_dev *trtl, void *addr)
......@@ -243,17 +247,21 @@ static inline void trtl_iowrite(struct trtl_dev *trtl,
/* Global data */
extern struct device *minors[TRTL_MAX_MINORS];
extern int trtl_minor_get(struct device *dev, enum trtl_dev_type type);
extern void trtl_minor_put(struct device *dev);
/* CPU data */
extern const struct file_operations trtl_cpu_dbg_fops;
extern const struct file_operations trtl_cpu_fops;
extern const struct attribute_group *trtl_cpu_groups[];
extern void trtl_cpu_reset_set(struct trtl_dev *trtl, uint8_t mask);
/* HMQ */
extern int hmq_default_buf_size;
extern int hmq_shared;
extern const struct attribute_group *trtl_hmq_groups[];
extern int trtl_probe_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx);
extern void trtl_remove_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx);
extern const struct file_operations trtl_hmq_fops;
extern irqreturn_t trtl_irq_handler(int irq_core_base, void *arg);
extern irqreturn_t trtl_irq_handler_out(int irq_core_base, void *arg);
extern irqreturn_t trtl_irq_handler_in(int irq_core_base, void *arg);
/* TTY */
extern struct tty_driver trtl_tty_driver;
extern const struct tty_operations trtl_tty_ops;
......@@ -262,4 +270,5 @@ extern void trtl_tty_remove(struct trtl_dev *trtl);
extern struct class trtl_cdev_class;
#endif
This diff is collapsed.
......@@ -90,7 +90,7 @@ static irqreturn_t trtl_tty_handler(int irq, void *arg)
status = trtl_ioread(trtl, trtl->base_csr + MT_CPU_CSR_REG_DBG_POLL);
do_irq:
i = -1;
while (status && likely(++i < trtl->n_cpu)) {
while (status && likely(++i < trtl->cfgrom.n_cpu)) {
lock = spin_is_locked(&trtl->lock_cpu_sel);
if (!(status & 0x1) || lock) {
status >>= 1;
......@@ -108,7 +108,7 @@ do_irq:
}
/* Push all the collected characters */
for (i = 0; i < trtl->n_cpu; ++i) {
for (i = 0; i < trtl->cfgrom.n_cpu; ++i) {
if (!trtl->cpu[i].tty_port.tty) /* Not open */
continue;
......@@ -200,9 +200,9 @@ void trtl_tty_remove(struct trtl_dev *trtl)
/* Disable the interrupts on the Mock Turtle */
trtl_iowrite(trtl, 0x0, trtl->base_csr + MT_CPU_CSR_REG_DBG_IMSK);
free_irq(platform_get_irq(pdev, TRTL_IRQ_DBG), trtl);
free_irq(platform_get_irq(pdev, TRTL_IRQ_CON), trtl);
for (i = 0; i < trtl->n_cpu; ++i)
for (i = 0; i < trtl->cfgrom.n_cpu; ++i)
trtl_tty_port_exit(&trtl->cpu[i]);
}
......@@ -211,25 +211,28 @@ int trtl_tty_probe(struct trtl_dev *trtl)
{
struct platform_device *pdev = to_pdev_dev(trtl);
struct resource *r;
int i, err;
int i, err = 0;
for (i = 0; i < trtl->n_cpu; ++i) {
r = platform_get_resource(pdev, IORESOURCE_IRQ, TRTL_IRQ_CON);
if (!r) {
dev_warn(&trtl->dev,
"disable console: invalid interrupt source\n");
goto err; /* no error code, we can live without console */
}
for (i = 0; i < trtl->cfgrom.n_cpu; ++i) {
err = trtl_tty_port_init(&trtl->cpu[i]);
if (err)
goto err_port;
}
r = platform_get_resource(pdev, IORESOURCE_IRQ, TRTL_IRQ_DBG);
if (r) {
/* Enable debug interrupts */
err = request_irq(r->start, trtl_tty_handler, 0,
r->name, trtl);
if (err) {
dev_err(&trtl->dev,
"Cannot request IRQ %lld - we'll not receive debug messages\n",
r->start);
goto err_irq;
}
/* Enable debug interrupts */
err = request_irq(r->start, trtl_tty_handler, 0,
r->name, trtl);
if (err) {
dev_err(&trtl->dev,
"Cannot request IRQ %lld - disable console\n",
r->start);
goto err_irq;
}
return 0;
......@@ -238,5 +241,6 @@ err_irq:
err_port:
while(--i)
trtl_tty_port_exit(&trtl->cpu[i]);
err:
return err;
}
......@@ -19,7 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from .PyMockTurtle import TrtlHeader, TrtlMessage, TrtlConfig, \
TrtlCpu, TrtlHmq, TrtlSmem, TrtlDevice
TrtlCpu, TrtlHmq, TrtlSmem, TrtlDevice, \
TRTL_CONFIG_ROM_MAX_CPU, \
TRTL_CONFIG_ROM_MAX_HMQ, \
TRTL_CONFIG_ROM_MAX_RMQ
__all__ = (
"TrtlDevice",
......@@ -29,4 +32,7 @@ __all__ = (
"TrtlHeader",
"TrtlMessage",
"TrtlConfig",
"TRTL_CONFIG_ROM_MAX_CPU",
"TRTL_CONFIG_ROM_MAX_HMQ",
"TRTL_CONFIG_ROM_MAX_RMQ",
)
......@@ -30,8 +30,10 @@ struct trtl_desc {
char path[TRTL_PATH_LEN]; /**< path to device */
int fd_dev; /**< File Descriptor of the device */
int fd_cpu[TRTL_MAX_CPU]; /**< File Descriptor of the CPUs */
int fd_hmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN]; /**< File Descriptors for the HMQ */
struct trtl_config_rom cfgrom;/**< synthesis configuration */
struct trtl_dev *trtl_sync; /**< token for synchronous operations */
};
#endif
......@@ -20,6 +20,7 @@
#include <libmockturtle.h>
#include <errno.h>
/**
* It embeds the header into the message
* @param[in] msg the trtl message
......@@ -29,7 +30,7 @@ void trtl_message_header_set(struct trtl_msg *msg,
struct trtl_proto_header *hdr)
{
memcpy(msg->data, hdr, sizeof(struct trtl_proto_header));
msg->datalen = sizeof(struct trtl_proto_header) / 4;
msg->hdr.len = sizeof(struct trtl_proto_header) / 4;
}
/**
......@@ -64,7 +65,7 @@ void trtl_message_pack(struct trtl_msg *msg,
return;
memcpy(data + sizeof(struct trtl_proto_header), payload,
hdr->len * 4);
msg->datalen += hdr->len;
msg->hdr.len += hdr->len;
}
......@@ -114,7 +115,7 @@ void trtl_message_buffer_push(struct trtl_msg *msg,
hdr->len += 2 + (tlv->size / 4);
trtl_message_header_set(msg, hdr);
msg->datalen = hdr->len + sizeof(struct trtl_proto_header) / 4;
msg->hdr.len = hdr->len + sizeof(struct trtl_proto_header) / 4;
}
/**
......@@ -159,38 +160,21 @@ off_t trtl_message_buffer_pop(struct trtl_msg *msg, off_t offset,
* @param[in] hmq_out hmq slot index where you expect the answer
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_rt_version_get(struct trtl_dev *trtl, struct trtl_rt_version *version,
unsigned int hmq_in, unsigned int hmq_out)
int trtl_rt_version_get(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version)
{
struct trtl_proto_header hdr;
struct trtl_hmq *hmq;
struct trtl_msg msg;
int err;
memset(&msg, 0, sizeof(struct trtl_msg));
memset(&hdr, 0, sizeof(struct trtl_proto_header));
hdr.msg_id = TRTL_MSG_ID_VERS_REQ;
hdr.slot_io = (hmq_in << 4) | hmq_out;
hdr.flags = TRTL_HEAD_FLAG_SYNC | TRTL_HEAD_FLAG_RPC;
hdr.len = 0;
trtl_message_pack(&msg, &hdr, NULL);
hmq = trtl_hmq_open(trtl, hmq_in, TRTL_HMQ_INCOMING);
if (!hmq)
return -1;
/* Send the message and get answer */
err = trtl_hmq_send_and_receive_sync(hmq, hmq_out, &msg,
trtl_default_timeout_ms);
trtl_hmq_close(hmq);
/* FIXME with new protocol redefine messages to ACK/NACK */
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
trtl_message_unpack(&msg, &hdr, version);
if (hdr.msg_id != TRTL_MSG_ID_VERS_ANS) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
/* FIXME put the payload in the version field */
return 0;
}
......@@ -204,35 +188,17 @@ int trtl_rt_version_get(struct trtl_dev *trtl, struct trtl_rt_version *version,
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_rt_ping(struct trtl_dev *trtl,
unsigned int hmq_in, unsigned int hmq_out)
unsigned int idx_cpu,
unsigned int idx_hmq)
{
struct trtl_proto_header hdr;
struct trtl_hmq *hmq;
struct trtl_msg msg;
int err;
memset(&hdr, 0, sizeof(struct trtl_proto_header));
hdr.msg_id = TRTL_MSG_ID_PING;
hdr.slot_io = (hmq_in << 4) | hmq_out;
hdr.flags = TRTL_HEAD_FLAG_SYNC | TRTL_HEAD_FLAG_RPC;
hdr.len = 0;
trtl_message_pack(&msg, &hdr, NULL);
hmq = trtl_hmq_open(trtl, hmq_in, TRTL_HMQ_INCOMING);
if (!hmq)
return -1;
/* Send the message and get answer */
err = trtl_hmq_send_and_receive_sync(hmq, hmq_out, &msg,
trtl_default_timeout_ms);
/* FIXME with new protocol redefine messages to ACK/NACK */
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
trtl_hmq_close(hmq);
trtl_message_unpack(&msg, &hdr, NULL);
if (hdr.msg_id != TRTL_MSG_ID_ACK) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
}
......@@ -246,33 +212,9 @@ static inline int trtl_rt_variable(struct trtl_dev *trtl,
uint32_t *variables,
unsigned int n_variables)
{
struct trtl_msg msg;
struct trtl_hmq *hmq;
int err;
hmq = trtl_hmq_open(trtl, (hdr->slot_io >> 4 & 0xF), TRTL_HMQ_INCOMING);
if (!hmq)
return -1;
hdr->flags |= TRTL_HEAD_FLAG_RPC;
memset(&msg, 0, sizeof(struct trtl_msg));
/* Send asynchronous message, we do not wait for answers */
trtl_message_pack(&msg, hdr, variables);
if (hdr->flags & TRTL_HEAD_FLAG_SYNC) {
err = trtl_hmq_send_and_receive_sync(hmq, (hdr->slot_io & 0xF),
&msg, 1000);
if (err > 0)
trtl_message_unpack(&msg, hdr, variables);
if (err == 0)
err = -1;
} else {
err = trtl_hmq_send(hmq, &msg);
}
trtl_hmq_close(hmq);
return err < 0 ? -1 : 0;
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
......@@ -305,25 +247,14 @@ static inline int trtl_rt_variable(struct trtl_dev *trtl,
* @param[in] sync set if you want a synchronous message
*/
int trtl_rt_variable_set(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
uint32_t *variables,
unsigned int n_variables)
{
int err;
hdr->msg_id = TRTL_MSG_ID_VAR_SET;
hdr->len = n_variables * 2;
err = trtl_rt_variable(trtl, hdr, variables, n_variables);
if (err)
return err;
if ((hdr->flags & TRTL_HEAD_FLAG_SYNC) &&
hdr->msg_id != TRTL_MSG_ID_VAR_GET_ANS) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
......@@ -352,73 +283,14 @@ int trtl_rt_variable_set(struct trtl_dev *trtl,
* the number of indexes you have in the 'variables' fields
*/
int trtl_rt_variable_get(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
uint32_t *variables,
unsigned int n_variables)
{
int err;
hdr->msg_id = TRTL_MSG_ID_VAR_GET;
/* Getting variables is always synchronous */
hdr->flags |= TRTL_HEAD_FLAG_SYNC;
hdr->len = n_variables * 2;
err = trtl_rt_variable(trtl, hdr, variables, n_variables);
if (err)
return err;
if (hdr->msg_id != TRTL_MSG_ID_VAR_GET_ANS) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
}
/**
* Real implementation to read/write structures
*/
static int trtl_rt_buffer(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
struct trtl_structure_tlv *tlv,
unsigned int n_tlv)
{
struct trtl_msg msg;
struct trtl_hmq *hmq;
int err, i;
off_t offset = sizeof(struct trtl_proto_header) / 4;
hmq = trtl_hmq_open(trtl, (hdr->slot_io >> 4 & 0xF), TRTL_HMQ_INCOMING);
if (!hmq)
return -1;
hdr->flags |= TRTL_HEAD_FLAG_RPC;
memset(&msg, 0, sizeof(struct trtl_msg));
for (i = 0; i < n_tlv; ++i)
trtl_message_buffer_push(&msg, hdr, &tlv[i]);
if (hdr->flags & TRTL_HEAD_FLAG_SYNC) {
err = trtl_hmq_send_and_receive_sync(hmq, (hdr->slot_io & 0xF),
&msg, 1000);
if (err > 0) {
for (i = 0; i < n_tlv; ++i) {
offset = trtl_message_buffer_pop(&msg, offset,
hdr,
&tlv[i]);
if (offset < 0) {
err = -1;
break;
}
}
}
} else {
err = trtl_hmq_send(hmq, &msg);
}
trtl_hmq_close(hmq);
return err <= 0 ? -1 : 0;
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
......@@ -432,25 +304,14 @@ static int trtl_rt_buffer(struct trtl_dev *trtl,
* @param[in] n_tlv number of tlv structures
*/
int trtl_rt_buffer_set(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
unsigned int n_tlv)
{
int err;
hdr->len = 0;
hdr->msg_id = TRTL_MSG_ID_BUF_SET;
err = trtl_rt_buffer(trtl, hdr, tlv, n_tlv);
if (err)
return err;
if ((hdr->flags & TRTL_HEAD_FLAG_SYNC) &&
hdr->msg_id != TRTL_MSG_ID_BUF_GET_ANS) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
/**
......@@ -463,26 +324,14 @@ int trtl_rt_buffer_set(struct trtl_dev *trtl,
* @param[in] n_tlv number of tlv structures
*/
int trtl_rt_buffer_get(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
unsigned int n_tlv)
{
int err;
hdr->len = 0;
hdr->msg_id = TRTL_MSG_ID_BUF_GET;
/* Getting variables is always synchronous */
hdr->flags |= TRTL_HEAD_FLAG_SYNC;
err = trtl_rt_buffer(trtl, hdr, tlv, n_tlv);
if (err)
return err;
if (hdr->msg_id != TRTL_MSG_ID_BUF_GET_ANS) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
......
This diff is collapsed.
......@@ -41,6 +41,18 @@ struct trtl_dev;
#define TRTL_SYSFS_PATH_LEN 128
/**
* This structure mimic the pollfd structure for the Mock Turtle needs
*/
struct polltrtl {
struct trtl_dev *trtl;
unsigned int idx_cpu;
unsigned int idx_hmq;
short events; /**< like in pollfd poll(2) */
short revents; /**< like in pollfd poll(2) */
};
/**
* Debug descriptor. It is not obfuscated because it is meant for debugging
* purpose. This way, it leaves the user all the freedom to read/poll the
......@@ -55,6 +67,7 @@ struct trtl_dbg {
/**
* HMQ slot descriptor
* @deprecated it is not necessary anymore
*/
struct trtl_hmq {
struct trtl_dev *trtl; /**< where this slot belong to */
......@@ -75,8 +88,6 @@ struct trtl_hmq {
#define TRTL_HMQ_INCOMING (1 << 0)
#define TRTL_HMQ_OUTCOMING 0x0
#define TRTL_HMQ_EXCLUSIVE (1 << 1)
#define TRTL_HMQ_SHARED 0x0
/**
......@@ -89,6 +100,7 @@ enum trtl_error_number {
ETRTL_HMQ_CLOSE, /**< The HMQ is closed */
ETRTL_INVALID_MESSAGE, /**< Invalid message */
ETRTL_HMQ_READ, /**< Error while reading messages */
ETRTL_MSG_SYNC_FAILED,
__ETRTL_MAX,
};
......@@ -168,32 +180,46 @@ extern int trtl_cpu_is_enable(struct trtl_dev *trtl, unsigned int index,
* Functions to manage the HMQ slots: configuration and transmission
* @{
*/
extern struct trtl_hmq *trtl_hmq_open(struct trtl_dev *trtl,
unsigned int index,
unsigned long flags);
extern void trtl_hmq_close(struct trtl_hmq *hmq);
extern int trtl_hmq_share_set(struct trtl_dev *trtl, unsigned int dir,
unsigned int index, unsigned int status);
extern int trtl_hmq_share_get(struct trtl_dev *trtl, unsigned int dir,
unsigned int index, unsigned int *status);
extern int trtl_hmq_receive_n(struct trtl_hmq *hmq,
struct trtl_msg *msg, unsigned int n);
extern struct trtl_msg *trtl_hmq_receive(struct trtl_hmq *hmq);
extern int trtl_hmq_send(struct trtl_hmq *hmq, struct trtl_msg *msg);
extern int trtl_hmq_send_and_receive_sync(struct trtl_hmq *hmq,
unsigned int index_out,
struct trtl_msg *msg,
unsigned int timeout_ms);
extern int trtl_hmq_buffer_size_set(struct trtl_hmq *hmq, uint32_t size);
extern int trtl_hmq_buffer_size_get(struct trtl_hmq *hmq, uint32_t *size);
extern int trtl_hmq_msg_max_get(struct trtl_hmq *hmq, uint32_t *max);
/* FIXME to be tested */
extern int trtl_hmq_filter_add(struct trtl_hmq *hmq,
extern int trtl_hmq_filter_add(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_msg_filter *filter);
/* FIXME to be tested */
extern int trtl_hmq_filter_clean(struct trtl_hmq *hmq);
extern int trtl_hmq_filter_clean(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
extern int trtl_bind(struct trtl_dev *trtl, struct trtl_msg_filter *flt,
unsigned int length);
extern int trtl_hmq_fd(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
extern int trtl_msg_async_send(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_msg *msg,
unsigned int n);
extern int trtl_msg_async_recv(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_msg *msg,
unsigned int n);
extern int trtl_msg_poll(struct polltrtl *trtlp,
unsigned int npolls, int timeout);
extern int trtl_msg_sync(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_msg *msg_s,
struct trtl_msg *msg_r,
int timeout);
extern int trtl_hmq_flush(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
/**@}*/
/**
......@@ -237,22 +263,28 @@ extern off_t trtl_message_buffer_pop(struct trtl_msg *msg, off_t offset,
* @{
*/
extern int trtl_rt_version_get(struct trtl_dev *trtl,
struct trtl_rt_version *version,
unsigned int hmq_in, unsigned int hmq_out);
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version);
extern int trtl_rt_ping(struct trtl_dev *trtl,
unsigned int hmq_in, unsigned int hmq_out);
unsigned int idx_cpu,
unsigned int idx_hmq);
extern int trtl_rt_variable_set(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
uint32_t *var, unsigned int n_var);
extern int trtl_rt_variable_get(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
uint32_t *var, unsigned int n_var);
extern int trtl_rt_buffer_set(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
unsigned int n_tlv);
extern int trtl_rt_buffer_get(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
unsigned int n_tlv);
/**@}*/
......
......@@ -15,18 +15,10 @@
#ifndef __RT_MESSAGE_H
#define __RT_MESSAGE_H
#include <mockturtle-common.h>
#include <mockturtle-rt-common.h>
#ifdef WRNODE_RT
/**
* White-Rabbit Node-Core message descriptor
*/
struct trtl_msg {
uint32_t datalen; /**< payload length*/
uint32_t *data; /**< payload */
};
/**
* It claims an output slot. This means that you get exclusive access to
......@@ -41,7 +33,7 @@ static inline struct trtl_msg rt_mq_claim_out(struct trtl_proto_header *h)
mq_claim(remote, slot);
b.data = mq_map_out_buffer(remote, slot);
b.datalen = 0;
b.hdr.len = 0;
return b;
}
......@@ -69,7 +61,7 @@ static inline struct trtl_msg rt_mq_claim_in(struct trtl_proto_header *h)
int slot = (h->slot_io >> 4) & 0xF;
b.data = mq_map_in_buffer(0, slot);
b.datalen = h->len;
b.hdr.len = h->len;
return b;
}
......
......@@ -22,9 +22,15 @@
#include <hw/mockturtle_addresses.h>
#include "hw/mockturtle_cpu_lr.h"
#include <mockturtle-common.h>
#include "mockturtle-rt-serial.h"
struct trtl_msg {
struct trtl_hmq_header hdr;
uint32_t *data;
};
/**
* Read a 32bit word value from the given address
* @param[in] addr source address
......
......@@ -21,6 +21,10 @@
#include <hw/mockturtle_queue.h>
#include <hw/mockturtle_cpu_lr.h>
#define TRTL_MQ_SLOT_IN(slot) (TRTL_MQ_BASE_IN + ((slot) << 16))
// Outgoung slot base address, relative to BASE_HMQ
#define TRTL_MQ_SLOT_OUT(slot) (TRTL_MQ_BASE_OUT + ((slot) << 16))
/**
* List of Message Queue types
*/
......@@ -59,7 +63,7 @@ static inline void mq_writel(enum trtl_mq_type type, uint32_t val, uint32_t reg)
*/
static inline void mq_claim(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_CLAIM, TRTL_MQ_BASE_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_CLAIM, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
......@@ -69,7 +73,9 @@ static inline void mq_claim(enum trtl_mq_type type, int slot)
*/
static inline void mq_purge(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_BASE_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_IN(slot) + TRTL_MQ_SLOT_COMMAND);
}
......@@ -77,11 +83,10 @@ static inline void mq_purge(enum trtl_mq_type type, int slot)
* @copydoc TRTL_MQ_CMD_READY
* @param[in] type MQ type to use
* @param[in] slot slot number
* @param[in] count number of 32bit words to send
*/
static inline void mq_send(enum trtl_mq_type type, int slot, int count)
static inline void mq_send(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_READY | count, TRTL_MQ_BASE_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_READY, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
......@@ -92,7 +97,7 @@ static inline void mq_send(enum trtl_mq_type type, int slot, int count)
*/
static inline void mq_discard(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_DISCARD, TRTL_MQ_BASE_IN(slot));
mq_writel(type, TRTL_MQ_CMD_DISCARD, TRTL_MQ_SLOT_IN(slot));
}
......@@ -104,7 +109,7 @@ static inline void mq_discard(enum trtl_mq_type type, int slot)
static inline void *mq_map_out_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_BASE_OUT (slot) + TRTL_MQ_SLOT_DATA_START);
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_DATA_START);
}
......@@ -116,7 +121,7 @@ static inline void *mq_map_out_buffer(enum trtl_mq_type type, int slot)
static inline void *mq_map_in_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_BASE_IN (slot) + TRTL_MQ_SLOT_DATA_START);
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_DATA_START);
}
......@@ -128,7 +133,7 @@ static inline void *mq_map_in_buffer(enum trtl_mq_type type, int slot)
static inline void *mq_map_out_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_BASE_OUT (slot) + TRTL_MQ_SLOT_HEADER_START);
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_HEADER_START);
}
......@@ -140,7 +145,7 @@ static inline void *mq_map_out_header(enum trtl_mq_type type, int slot)
static inline void *mq_map_in_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_BASE_IN (slot) + TRTL_MQ_SLOT_HEADER_START);
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_HEADER_START);
}
/**
......@@ -151,6 +156,22 @@ static inline uint32_t mq_poll(void)
return *(volatile uint32_t *) (TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_POLL);
}
/**
* It gets the current status of all the Host Message Queues
*/
static inline uint32_t hmq_poll(void)
{
return (mq_poll() & 0xFFFF);
}
/**
* It gets the current status of all the Host Message Queues
*/
static inline uint32_t hmq_poll_in(void)
{
return (hmq_poll() & 0xFF);
}
/**
* It gets the current status of the Remote Message Queues
......
......@@ -49,16 +49,49 @@ static void help(char *name)
static void trtl_list_device_info(struct trtl_dev *trtl)
{
const struct trtl_config_rom *cfg;
int i;
int i, k;
cfg = trtl_config_get(trtl);
fprintf(stdout, "signature: 0x%08"PRIx32"\n", cfg->signature);
fprintf(stdout, "version: 0x%08"PRIx32"\n", cfg->version);
fprintf(stdout, "clock-freq: %"PRId32"\n", cfg->clock_freq);
fprintf(stdout, "flags: 0x%"PRIx32"\n", cfg->flags);
fprintf(stdout, "application-id: 0x%08"PRIx32"\n", cfg->app_id);
fprintf(stdout, "shm-size: %"PRId32"\n", cfg->smem_size);
fprintf(stdout, "cpus:\n");
for (i = 0; i < cfg->n_cpu; ++i) {
fprintf(stdout, "\t- index: %d\n", i);
fprintf(stdout, "\t mem-size: %d\n", cfg->mem_size[i]);
fprintf(stdout, "\t hmq:\n");
for (k = 0; k < cfg->n_hmq[i]; ++k) {
uint32_t sizes = cfg->hmq[i * TRTL_MAX_MQ_CHAN + k].sizes;
fprintf(stdout, "\t\t- index: %d\n", k);
fprintf(stdout, "\t\t width-header: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_HEADER(sizes));
fprintf(stdout, "\t\t width-payload: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes));
fprintf(stdout, "\t\t depth: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(sizes));
fprintf(stdout, "\t\t endpoint-id: %"PRId32"\n",
cfg->hmq[i * TRTL_MAX_MQ_CHAN + k].endpoint_id);
}
fprintf(stdout, "\t rmq:\n");
for (k = 0; k < cfg->n_rmq[i]; ++k) {
uint32_t sizes = cfg->rmq[i * TRTL_MAX_MQ_CHAN + k].sizes;
fprintf(stdout, "\t\t- index: %d\n", k);
fprintf(stdout, "\t\t width-header: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_HEADER(sizes));
fprintf(stdout, "\t\t width-payload: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes));
fprintf(stdout, "\t\t depth: %"PRId32"\n",
TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(sizes));
fprintf(stdout, "\t\t endpoint-id: %"PRId32"\n",
cfg->hmq[i * TRTL_MAX_MQ_CHAN + k].endpoint_id);
}
}
}
......
......@@ -46,19 +46,17 @@ enum operations {
int main(int argc, char *argv[])
{
struct trtl_proto_header hdr;
struct trtl_dev *trtl;
char c;
int err, n, dev_id = -1, val, v, i, k;
int err, n, dev_id = -1, v, i, k;
enum operations mode;
struct trtl_structure_tlv *tlv;
unsigned int n_tlv;
unsigned int n_tlv, idx_cpu = 0, idx_hmq = 0;;
uint32_t *data;
memset(&hdr, 0, sizeof(struct trtl_proto_header));
atexit(trtl_exit);
while ((c = getopt (argc, argv, "hD:i:o:")) != -1) {
while ((c = getopt (argc, argv, "hD:c:q:")) != -1) {
switch (c) {
default:
help(argv[0]);
......@@ -70,22 +68,19 @@ int main(int argc, char *argv[])
exit(1);
}
break;
case 'i':
n = sscanf(optarg, "%d", &val);
case 'c':
n = sscanf(optarg, "%d", &idx_cpu);
if (n != 1) {
fprintf(stderr, "Invalid HMQ number\n");
fprintf(stderr, "Invalid CPU index\n");
exit(1);
}
hdr.slot_io = (hdr.slot_io & ~0xF) | (val & 0xF);
break;
case 'o':
n = sscanf(optarg, "%d", &val);
case 'q':
n = sscanf(optarg, "%d", &idx_hmq);
if (n != 1) {
fprintf(stderr, "Invalid HMQ number\n");
fprintf(stderr, "Invalid HMQ index\n");
exit(1);
}
val = val << 4;
hdr.slot_io = (hdr.slot_io & ~0xF0) | (val & 0xF0);
break;
}
}
......@@ -179,16 +174,16 @@ int main(int argc, char *argv[])
switch (mode) {
case OP_READ:
err = trtl_rt_buffer_get(trtl, &hdr, tlv, n_tlv);
err = trtl_rt_buffer_get(trtl, idx_cpu, idx_hmq, tlv, n_tlv);
if (err) {
fprintf(stderr, "Cannot read buffer: %s\n",
trtl_strerror(errno));
break;
}
trtl_print_payload(&hdr, tlv);
/* trtl_print_payload(&hdr, tlv); */
break;
case OP_WRITE:
err = trtl_rt_buffer_set(trtl, &hdr, tlv, n_tlv);
err = trtl_rt_buffer_set(trtl, idx_cpu, idx_hmq, tlv, n_tlv);
break;
}
......
......@@ -29,24 +29,23 @@
#include <time.h>
#include <libgen.h>
#define MAX_DEV 4
#define MAX_SLOT 32
#define MAX_CPU 8
/**
* Maximum number of possible queue selection
*/
#define MAX_SELECTION (TRTL_MAX_CPU * TRTL_MAX_MQ_CHAN)
struct trtl_thread_desc {
struct trtl_dev *trtl;
uint32_t dev_id;
int cpu_index[MAX_CPU];
int n_cpu;
int slot_index[MAX_SLOT];
int n_slot;
/**
* Necessary context for a thread
*/
struct trtl_thread {
uint32_t devid;
int cpu;
int hmq;
int share;
int n;
};
static unsigned int cnt, n;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int timestamp = 0;
static int protocol;
......@@ -55,20 +54,15 @@ static void help()
fprintf(stderr, "\n");
fprintf(stderr, "mockturtle-messages -D 0x<hex-number> -i <number> [options]\n\n");
fprintf(stderr, "It dumps all messages from a given set of Mock-Turtle slots\n\n");
fprintf(stderr, "-D device identificator in hexadecimal format\n");
fprintf(stderr, "-i slot index\n");
fprintf(stderr, "-n number of total messages to read. The default is 0 (infinite)\n");
fprintf(stderr, "-q message queue selection string\n\t0x<devid>,<cpu>,<hmq>,<n>\n");
fprintf(stderr, "-t print message timestamp\n");
fprintf(stderr, "-s share all HMQ with other users\n");
fprintf(stderr, "-p parse protocol\n");
fprintf(stderr, "-h show this help\n");
fprintf(stderr, "\n");
fprintf(stderr,
"You can dump from several devices slots, so the arguments '-D' and '-i' may appear several times. The argument '-i' refers to the previous device id declared\n\n");
"e.g. Dumping messagges from slots 1 and 2 on CPU 1 of device 0x0402\n\n");
fprintf(stderr,
"e.g. Dumping messagges from slots 2 and 3 of devices 0x0402 and 0x0382\n\n");
fprintf(stderr,
" mockturtle-messages -D 0x0382 -i 2 -i 3 -D 0x0402 -i 2 -i 3\n\n");
" mockturtle-messages -q 0x0402,1,1 -q 0x0402,1,2\n\n");
exit(1);
}
......@@ -78,13 +72,13 @@ static void help()
* @param[in] trtl device to use
* @param[in] hmq slot to read
*/
static int dump_message(struct trtl_dev *trtl, struct trtl_hmq *hmq)
static int dump_message(struct polltrtl *p)
{
struct trtl_msg *wmsg;
struct trtl_msg wmsg;
time_t tm;
char stime[64];
struct tm *gm;
int i;
int i, ret;
if (timestamp) {
tm = time(NULL);
......@@ -92,28 +86,29 @@ static int dump_message(struct trtl_dev *trtl, struct trtl_hmq *hmq)
strftime(stime, 64,"%T", gm);
fprintf(stdout, "[%s] ", stime);
}
fprintf(stdout, "%s :", basename(hmq->syspath));
wmsg = trtl_hmq_receive(hmq);
if (!wmsg) {
fprintf(stdout, "%s cpu: %d hmq: %d:",
trtl_name_get(p->trtl), p->idx_cpu, p->idx_hmq);
ret = trtl_msg_async_recv(p->trtl, p->idx_cpu, p->idx_hmq, &wmsg, 1);
if (ret < 0) {
fprintf(stdout, " error : %s\n", trtl_strerror(errno));
return -1;
}
if (ret == 0)
return 0;
fprintf(stdout, "\n");
if (protocol) {
trtl_print_message(wmsg);
trtl_print_message(&wmsg);
} else {
for (i = 0; i < TRTL_MAX_PAYLOAD_SIZE; ++i) {
for (i = 0; i < wmsg.hdr.len; ++i) {
if (i % 4 == 0)
fprintf(stdout, "\n %04d :", i);
fprintf(stdout, " 0x%08x", wmsg->data[i]);
fprintf(stdout, " 0x%08x", wmsg.data[i]);
}
}
fprintf(stdout, "\n");
free(wmsg);
return 0;
}
......@@ -124,71 +119,50 @@ static int dump_message(struct trtl_dev *trtl, struct trtl_hmq *hmq)
*/
void *message_thread(void *arg)
{
struct trtl_thread_desc *th_data = arg;
struct pollfd p[MAX_SLOT];
struct trtl_dev *trtl = th_data->trtl;
struct trtl_hmq *hmq[th_data->n_slot];
int ret, err, i;
if (!th_data->n_slot)
return NULL;
struct trtl_thread *th = arg;
unsigned int cnt;
struct polltrtl p[1];
struct trtl_dev *trtl;
int ret, err;
/* Open the device */
if (!trtl)
trtl = trtl_open_by_id(th_data->dev_id);
trtl = trtl_open_by_id(th->devid);
if (!trtl) {
fprintf(stderr, "Cannot open Mock Turtle device: %s\n", trtl_strerror(errno));
pthread_exit(NULL);
}
/* Build the polling structures */
for (i = 0; i < th_data->n_slot; ++i) {
trtl_hmq_share_set(trtl, 0 , th_data->slot_index[i], 1);
/* trtl_hmq_share_set(trtl, 0 , th->share, 1); */
hmq[i] = trtl_hmq_open(trtl, th_data->slot_index[i],
TRTL_HMQ_OUTCOMING);
if (!hmq[i]) {
fprintf(stderr, "Cannot open HMQ: %s\n",
trtl_strerror(errno));
goto out;
}
p[i].fd = hmq[i]->fd;
p[i].events = POLLIN | POLLERR;
}
p[0].trtl = trtl;
p[0].idx_cpu = th->cpu;
p[0].idx_hmq = th->hmq;
p[0].events = POLLIN | POLLERR;
/* Start dumping messages */
while (n == 0 || n > cnt) {
while (th->n == 0 || th->n > cnt) {
/* Polling slots */
ret = poll(p, th_data->n_slot, 10);
ret = trtl_msg_poll(p, 1, 1000);
switch (ret) {
default:
/* Dump from the slot */
for (i = 0; i < th_data->n_slot; ++i) {
if (!(p[i].revents & POLLIN))
continue;
if (!(p[0].revents & POLLIN))
continue;
err = dump_message(trtl, hmq[i]);
if (err)
continue;
pthread_mutex_lock(&mtx);
cnt++;
pthread_mutex_unlock(&mtx);
}
err = dump_message(&p[0]);
if (err)
continue;
cnt++;
break;
case 0:
/* timeout */
break;
case -1:
/* error */
goto out;
/* error - force loop to close */
cnt = th->n;
}
}
out:
/* Close all message slots */
while (--i >= 0)
trtl_hmq_close(hmq[i]);
trtl_close(trtl);
return NULL;
}
......@@ -196,45 +170,41 @@ out:
int main(int argc, char *argv[])
{
struct trtl_thread_desc th_data[MAX_DEV], *last;
struct trtl_thread th[MAX_SELECTION], *tmp;
unsigned int th_idx = 0;
unsigned long i;
unsigned int di = 0;
int share = 0;
pthread_t tid_msg[MAX_DEV];
int err;
pthread_t tid_msg[MAX_SELECTION];
int err, ret;
char c;
atexit(trtl_exit);
memset(th_data, 0, sizeof(struct trtl_thread_desc) * MAX_DEV);
memset(th, 0, sizeof(struct trtl_thread) * MAX_SELECTION);
while ((c = getopt (argc, argv, "hi:D:n:tsp")) != -1) {
while ((c = getopt (argc, argv, "hq:tp")) != -1) {
switch (c) {
default:
help();
break;
case 's':
share = 1;
break;
case 'i':
/* Save slot index for each device id */
if (!last || last->n_slot >= MAX_SLOT)
case 'q':
tmp = &th[th_idx];
ret = sscanf(optarg, "0x%x,%d,%d,%d",
&tmp->devid, &tmp->cpu, &tmp->hmq, &tmp->n);
switch (ret) {
case 0:
fprintf(stderr, "Missing devid id\n");
case 1:
fprintf(stderr, "Missing cpu index\n");
case 2:
fprintf(stderr, "Missing hmq index\n");
break;
sscanf(optarg, "%d",
&last->slot_index[last->n_slot]);
last->n_slot++;
break;
case 'D':
/* Save device ids to use */
if (di >= MAX_DEV)
case 3:
tmp->n = 0;
case 4:
break;
last = &th_data[di];
sscanf(optarg, "0x%x", &last->dev_id);
di++;
break;
case 'n':
/* Number of total messages to dump */
sscanf(optarg, "%d", &n);
}
th_idx++;
break;
case 't':
timestamp = 1;
......@@ -257,23 +227,19 @@ int main(int argc, char *argv[])
exit(1);
}
/* Set global sharing option */
for (i = 0; i < di; ++i)
th_data[i].share = share;
/* Run dumping on in parallel from several devices */
for (i = 0; i < di; i++) {
err = pthread_create(&tid_msg[i], NULL, message_thread,
(void *)(&th_data[i]));
/* Run a thread for each message queue */
for (i = 0; i < th_idx; ++i) {
err = pthread_create(&tid_msg[i], NULL,
message_thread, (void *)(&th[i]));
if (err)
fprintf(stderr,
"Cannot create 'dump_thread' instance %ld: %s\n",
i, strerror(errno));
"Cannot create thread instance %s\n",
strerror(errno));
}
/* Wait for the threads to finish */
for (i = 0; i < di; i++)
for (i = 0; i < th_idx; i++)
pthread_join(tid_msg[i], NULL);
exit(0);
}
......@@ -64,10 +64,10 @@ int main(int argc, char *argv[])
uint32_t dev_id = 0, n = 1;
struct trtl_rt_version version;
uint64_t period = 0;
int err, f_version = 0, hmq_i = 0, hmq_o = 0;
int err, f_version = 0, idx_cpu = 0, idx_hmq = 0;
char c;
while ((c = getopt (argc, argv, "hD:n:p:tvi:o:")) != -1) {
while ((c = getopt (argc, argv, "hD:n:p:tvc:q:")) != -1) {
switch (c) {
case 'h':
case '?':
......@@ -86,11 +86,11 @@ int main(int argc, char *argv[])
case 'v':
f_version = 1;
break;
case 'i':
sscanf(optarg, "%d", &hmq_i);
case 'c':
sscanf(optarg, "%d", &idx_cpu);
break;
case 'o':
sscanf(optarg, "%d", &hmq_o);
case 'q':
sscanf(optarg, "%d", &idx_hmq);
break;
}
}
......@@ -118,21 +118,21 @@ int main(int argc, char *argv[])
usleep(period);
/* Try to ping */
err = trtl_rt_ping(trtl, hmq_i, hmq_o);
err = trtl_rt_ping(trtl, idx_cpu, idx_hmq);
if (err) {
fprintf(stderr,
"Ping failed on Device 0x%x HMQ [in:%d, out:%d]: %s\n",
dev_id, hmq_i, hmq_o, trtl_strerror(errno));
"Ping failed on Device 0x%x CPU %d HMQ %d: %s\n",
dev_id, idx_cpu, idx_hmq, trtl_strerror(errno));
continue;
}
fprintf(stdout,
"Something running and connected to [device: 0x%x, in:%d, out:%d]!\n",
dev_id, hmq_i, hmq_o);
"Firmware on device: 0x%x, CPU: %d, is running!\n",
dev_id, idx_cpu);
/* Get the version */
if (f_version) {
trtl_rt_version_get(trtl, &version, hmq_i, hmq_o);
trtl_rt_version_get(trtl, idx_cpu, idx_hmq, &version);
trtl_ping_version_print(&version);
}
......
......@@ -44,18 +44,16 @@ enum operations {
int main(int argc, char *argv[])
{
struct trtl_proto_header hdr;
struct trtl_dev *trtl;
char c;
unsigned int n_var;
int err, n, dev_id = -1, val, i, v;
unsigned int n_var, idx_cpu = 0, idx_hmq = 0;
int err, n, dev_id = -1, i, v;
uint32_t *var;
enum operations mode;
memset(&hdr, 0, sizeof(struct trtl_proto_header));
atexit(trtl_exit);
while ((c = getopt (argc, argv, "hD:i:o:")) != -1) {
while ((c = getopt (argc, argv, "hD:c:q:")) != -1) {
switch (c) {
default:
help(argv[0]);
......@@ -67,22 +65,19 @@ int main(int argc, char *argv[])
exit(1);
}
break;
case 'i':
n = sscanf(optarg, "%d", &val);
case 'c':
n = sscanf(optarg, "%d", &idx_cpu);
if (n != 1) {
fprintf(stderr, "Invalid HMQ number\n");
fprintf(stderr, "Invalid CPU index\n");
exit(1);
}
hdr.slot_io = (hdr.slot_io & ~0xF) | (val & 0xF);
break;
case 'o':
n = sscanf(optarg, "%d", &val);
case 'q':
n = sscanf(optarg, "%d", &idx_hmq);
if (n != 1) {
fprintf(stderr, "Invalid HMQ number\n");
fprintf(stderr, "Invalid HMQ index\n");
exit(1);
}
val = val << 4;
hdr.slot_io = (hdr.slot_io & ~0xF0) | (val & 0xF0);
break;
}
}
......@@ -151,7 +146,7 @@ int main(int argc, char *argv[])
switch (mode) {
case OP_READ:
err = trtl_rt_variable_get(trtl, &hdr, var, n_var);
err = trtl_rt_variable_get(trtl, idx_cpu, idx_hmq, var, n_var);
if (err) {
fprintf(stderr, "Cannot read variables: %s\n",
trtl_strerror(errno));
......@@ -163,7 +158,7 @@ int main(int argc, char *argv[])
}
break;
case OP_WRITE:
err = trtl_rt_variable_set(trtl, &hdr, var, n_var);
err = trtl_rt_variable_set(trtl, idx_cpu, idx_hmq, var, n_var);
if (err) {
fprintf(stderr, "Cannot write variables: %s\n",
trtl_strerror(errno));
......
......@@ -6,16 +6,19 @@ int main()
int i, n_word = sizeof(struct trtl_config_rom) / 4;
const struct trtl_config_rom *cfgrom = trtl_config_rom_get();
const uint32_t *data = (const uint32_t *)cfgrom;
uint32_t *msg;
uint32_t *msg, *hdr;
pr_debug("CONFIG ROM\r\n");
mq_claim(TRTL_HMQ, 0);
hdr = mq_map_out_header(TRTL_HMQ, 0);
msg = mq_map_out_buffer(TRTL_HMQ, 0);
for (i = 0; i < n_word; i++) {
msg[i] = data[i];
pr_debug("%p = 0x%08"PRIx32"\r\n", &data[i], data[i]);
}
mq_send(TRTL_HMQ, 0, n_word);
hdr[0] = n_word - 1; /* last valid index */
mq_send(TRTL_HMQ, 0);
return 0;
}
Markdown is supported
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