Commit 1c7fef33 authored by Federico Vaga's avatar Federico Vaga Committed by Federico Vaga

kernel: replace debugfs with tty interface

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 7d356745
......@@ -33,7 +33,7 @@ obj-m := mockturtle.o
mockturtle-y := mockturtle-core.o
mockturtle-y += mockturtle-cpu.o
mockturtle-y += mockturtle-hmq.o
mockturtle-y += mockturtle-dbg.o
mockturtle-y += mockturtle-tty.o
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules
......
......@@ -34,6 +34,7 @@
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/fmc-sdb.h>
......@@ -54,7 +55,7 @@ static char *trtl_devnode(struct device *dev, umode_t *mode)
return kasprintf(GFP_KERNEL, "mockturtle/%s", dev_name(dev));
}
static struct class trtl_cdev_class = {
struct class trtl_cdev_class = {
.name = "mockturtle",
.owner = THIS_MODULE,
.dev_uevent = trtl_dev_uevent,
......@@ -543,7 +544,6 @@ static int trtl_probe_hmq(struct trtl_dev *trtl, unsigned int slot,
int trtl_probe(struct fmc_device *fmc)
{
struct trtl_dev *trtl;
char tmp_name[128];
int err, i;
uint32_t tmp;
......@@ -627,13 +627,6 @@ int trtl_probe(struct fmc_device *fmc)
err = device_register(&trtl->cpu[i].dev);
if (err)
goto out_cpu;
snprintf(tmp_name, 128, "%s-dbg", dev_name(&trtl->cpu[i].dev));
trtl->cpu[i].dbg_msg = debugfs_create_file(tmp_name, 0444,
trtl->dbg_dir,
&trtl->cpu[i],
&trtl_cpu_dbg_fops);
if (IS_ERR_OR_NULL(trtl->cpu[i].dbg_msg))
dev_err(&trtl->cpu[i].dev, "Cannot create debug interface\n");
}
/* Get and check the number of HMQ slots */
......@@ -685,26 +678,9 @@ int trtl_probe(struct fmc_device *fmc)
trtl_iowrite(trtl, trtl->irq_mask, trtl->base_gcr + MQUEUE_GCR_IRQ_MASK);
tmp = trtl_ioread(trtl, trtl->base_gcr + MQUEUE_GCR_IRQ_MASK);
/* Enable debug interrupts */
fmc->irq = trtl->base_core + 1;
/* Enable debug interface interrupts only when we have space
to store it */
err = fmc_irq_request(fmc, trtl_irq_handler_debug,
(char *)dev_name(&trtl->cpu[i].dev),
0 /*VIC is used */);
if (err) {
dev_err(&trtl->dev,
"Cannot request IRQ 0x%x - we'll not receive debug messages\n",
fmc->irq);
}
if (dbg_max_msg > 0) {
/* Enable interrupts only when we have a buffere where
store messages */
trtl_iowrite(trtl, 0xFFFFFFFF/*(trtl->n_cpu - 1)*/,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
}
err = trtl_tty_probe(trtl);
if (err)
dev_err(&trtl->dev, "Console not available (err: %d)\n", -err);
/* Pin the carrier */
if (!try_module_get(fmc->owner))
......@@ -739,13 +715,13 @@ int trtl_remove(struct fmc_device *fmc)
struct trtl_dev *trtl = fmc_get_drvdata(fmc);
int i;
trtl_tty_remove(trtl);
trtl_iowrite(trtl, 0x0, trtl->base_gcr + MQUEUE_GCR_IRQ_MASK);
fmc->irq = trtl->base_core;
fmc_irq_free(fmc);
trtl_iowrite(trtl, 0x0, trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
fmc->irq = trtl->base_core + 1;
fmc_irq_free(fmc);
debugfs_remove_recursive(trtl->dbg_dir);
......@@ -789,6 +765,18 @@ static struct fmc_driver trtl_dev_drv = {
},
};
struct tty_driver trtl_tty_driver = {
.owner = THIS_MODULE,
.driver_name = KBUILD_MODNAME"tty",
.name = "ttyTRTL",
.num = TRTL_MAX_CPU_MINORS,
.major = 0,
.minor_start = 0,
.type = TTY_DRIVER_TYPE_SERIAL,
.subtype = SERIAL_TYPE_NORMAL,
.flags = TTY_DRIVER_DYNAMIC_DEV,
.ops = &trtl_tty_ops,
};
/**
* Allocate resources for the driver. Char devices and FMC driver
......@@ -836,6 +824,16 @@ static int trtl_init(void)
if (err)
goto out_cdev_hmq;
/*
* NOTE: Because we do not yse alloc_tty_driver,
* we have to manualy initialize the kref
*/
kref_init(&trtl_tty_driver.kref);
err = tty_register_driver(&trtl_tty_driver);
if (err < 0) {
goto out_tty;
}
/* Register the FMC driver */
err = fmc_driver_register(&trtl_dev_drv);
if (err)
......@@ -843,7 +841,11 @@ static int trtl_init(void)
return 0;
out_reg:
tty_unregister_driver(&trtl_tty_driver);
out_tty:
cdev_del(&cdev_hmq);
out_cdev_hmq:
cdev_del(&cdev_cpu);
......@@ -863,6 +865,7 @@ out_all:
static void trtl_exit(void)
{
fmc_driver_unregister(&trtl_dev_drv);
tty_unregister_driver(&trtl_tty_driver);
cdev_del(&cdev_hmq);
cdev_del(&cdev_cpu);
cdev_del(&cdev_dev);
......
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/circ_buf.h>
#include <hw/mockturtle_cpu_csr.h>
#include "mockturtle-drv.h"
int dbg_max_msg = 1024; /**< debug messages buffer */
module_param_named(max_dbg_msg, dbg_max_msg, int, 0444);
MODULE_PARM_DESC(max_dbg_msg, "Maximum number of debug messages in driver queue.");
static int trtl_dbg_open(struct inode *inode, struct file *file)
{
struct trtl_cpu *cpu;
if (inode->i_private)
file->private_data = inode->i_private;
cpu = file->private_data;
cpu->cbuf.buf = kmalloc(dbg_max_msg, GFP_KERNEL);
if (!cpu->cbuf.buf)
if (dbg_max_msg > 0)
return -ENOMEM;
/* when dbg_max_msg is 0 we want to keep the debug interface
available so that programs will not complain */
cpu->cbuf.head = 0;
cpu->cbuf.tail = 0;
return 0;
}
static int trtl_dbg_close(struct inode *inode, struct file *file)
{
struct trtl_cpu *cpu = file->private_data;
spin_lock(&cpu->lock);
kfree(cpu->cbuf.buf);
cpu->cbuf.buf = NULL;
spin_unlock(&cpu->lock);
return 0;
}
static ssize_t trtl_dbg_read(struct file *f, char __user *buf,
size_t count, loff_t *offp)
{
struct trtl_cpu *cpu = f->private_data;
size_t lcount;
int i;
spin_lock(&cpu->lock);
/* Check if there are char to send */
lcount = CIRC_CNT(cpu->cbuf.head, cpu->cbuf.tail, dbg_max_msg);
if (!lcount) {
spin_unlock(&cpu->lock);
return 0;
}
/* Copy to user the minumum number of char */
lcount = min(lcount, count);
for (i = 0; i < lcount; i++) {
if (cpu->cbuf.buf[cpu->cbuf.tail + i] == '\0') {
i++; /* We want to include the terminator */
break;
}
}
lcount = i;
if (copy_to_user(buf, cpu->cbuf.buf + cpu->cbuf.tail, lcount)) {
spin_unlock(&cpu->lock);
return -EFAULT;
}
/* Consume char from the tail */
cpu->cbuf.tail = (cpu->cbuf.tail + lcount) & (dbg_max_msg - 1);
spin_unlock(&cpu->lock);
return lcount;
}
static unsigned int trtl_dbg_poll(struct file *f, struct poll_table_struct *w)
{
struct trtl_cpu *cpu = f->private_data;
dev_dbg(&cpu->dev, "%s head=%d, tail=%d\n", __func__,
cpu->cbuf.head, cpu->cbuf.tail);
if (CIRC_CNT(cpu->cbuf.head, cpu->cbuf.tail, dbg_max_msg))
return POLLIN | POLLRDNORM;
return 0;
}
const struct file_operations trtl_cpu_dbg_fops = {
.owner = THIS_MODULE,
.open = trtl_dbg_open,
.release = trtl_dbg_close,
.read = trtl_dbg_read,
.poll = trtl_dbg_poll,
};
irqreturn_t trtl_irq_handler_debug(int irq_core_base, void *arg)
{
struct fmc_device *fmc = arg;
struct trtl_dev *trtl = fmc_get_drvdata(fmc);
struct circ_buf *cb;
uint32_t status;
char c;
int i, lock;
status = trtl_ioread(trtl, trtl->base_csr + WRN_CPU_CSR_REG_DBG_POLL);
do_irq:
i = -1;
while (status && ++i < trtl->n_cpu) {
lock = spin_is_locked(&trtl->lock_cpu_sel);
if (!(status & 0x1) || lock) {
status >>= 1;
continue;
}
/* Select the CPU to use */
spin_lock(&trtl->lock_cpu_sel);
trtl_iowrite(trtl, i, trtl->base_csr + WRN_CPU_CSR_REG_CORE_SEL);
c = trtl_ioread(trtl,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_MSG);
cb = &trtl->cpu[i].cbuf;
if (cb->buf) {
/* We cans store the char */
pr_debug("%s:%d %d=%c\n", __func__, __LINE__, i, c);
cb->buf[cb->head] = c;
cb->head = (cb->head + 1) & (dbg_max_msg - 1);
if (cb->head == cb->tail) {
cb->tail = (cb->tail + 1) & (dbg_max_msg - 1);
}
}
spin_unlock(&trtl->lock_cpu_sel);
}
status = trtl_ioread(trtl, trtl->base_csr + WRN_CPU_CSR_REG_DBG_POLL);
if (status)
goto do_irq;
fmc_irq_ack(fmc);
return IRQ_HANDLED;
}
......@@ -22,6 +22,7 @@
#include <linux/circ_buf.h>
#include <linux/fmc.h>
#include <linux/tty.h>
#include "hw/mockturtle_queue.h"
#include "mockturtle.h"
......@@ -162,6 +163,10 @@ struct trtl_cpu {
struct spinlock lock;
struct trtl_hmq *hmq[TRTL_MAX_HMQ_SLOT]; /**< list of HMQ slots used by
this CPU */
struct device *tty_dev;
struct tty_port tty_port;
unsigned int tty_index;
};
/**
......@@ -217,12 +222,18 @@ extern const struct file_operations trtl_cpu_fops;
extern const struct attribute_group *trtl_cpu_groups[];
extern void trtl_cpu_enable_set(struct trtl_dev *trtl, uint8_t mask);
extern void trtl_cpu_reset_set(struct trtl_dev *trtl, uint8_t mask);
extern int dbg_max_msg;
extern irqreturn_t trtl_irq_handler_debug(int irq_core_base, void *arg);
/* HMQ */
extern int hmq_default_buf_size;
extern int hmq_shared;
extern const struct attribute_group *trtl_hmq_groups[];
extern const struct file_operations trtl_hmq_fops;
extern irqreturn_t trtl_irq_handler(int irq_core_base, void *arg);
/* TTY */
extern struct tty_driver trtl_tty_driver;
extern const struct tty_operations trtl_tty_ops;
extern int trtl_tty_probe(struct trtl_dev *trtl);
extern void trtl_tty_remove(struct trtl_dev *trtl);
extern struct class trtl_cdev_class;
#endif
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitmap.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/kallsyms.h>
#include <hw/mockturtle_cpu_csr.h>
#include "mockturtle-drv.h"
static DECLARE_BITMAP(tty_minors, TRTL_MAX_CPU_MINORS);
static int trtl_tty_get_minor(void)
{
int min;
min = bitmap_find_next_zero_area(tty_minors, TRTL_MAX_CPU_MINORS,
0, 1, 0);
if (min == TRTL_MAX_CPU_MINORS)
return -1;
bitmap_set(tty_minors, min, 1);
return min;
}
static void trtl_tty_put_minor(int minor)
{
if (unlikely(minor >= TRTL_MAX_CPU_MINORS)) {
pr_err("Cannot release invalid minor %d\n", minor);
return;
}
bitmap_set(tty_minors, minor, 1);
}
static inline void trtl_tty_insert_flip_char(struct trtl_cpu *cpu,
unsigned char ch, char flag)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
tty_insert_flip_char(cpu->tty_port.tty, ch, flag);
#else
tty_insert_flip_char(&cpu->tty_port, ch, flag);
#endif
}
static inline void trtl_tty_flip_buffer_push(struct trtl_cpu *cpu)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
tty_flip_buffer_push(cpu->tty_port.tty);
#else
tty_flip_buffer_push(&cpu->tty_port);
#endif
}
/**
* trtl_tty_handler_getchar - Get Character From soft-CPU
* It retrieves a character from the soft-CPU serial interface
* and it adds the character to the TTY buffer
* @cpu: the soft-CPU to use
*/
static void trtl_tty_handler_getchar(struct trtl_cpu *cpu)
{
struct trtl_dev *trtl = to_trtl_dev(cpu->dev.parent);
char c;
/* Select the CPU and read data */
spin_lock(&trtl->lock_cpu_sel);
trtl_iowrite(trtl, cpu->index,
trtl->base_csr + WRN_CPU_CSR_REG_CORE_SEL);
c = trtl_ioread(trtl,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_MSG);
spin_unlock(&trtl->lock_cpu_sel);
if (!cpu->tty_port.tty) /* Not open */
return;
trtl_tty_insert_flip_char(cpu, c , TTY_NORMAL);
}
static irqreturn_t trtl_tty_handler(int irq, void *arg)
{
struct fmc_device *fmc = arg;
struct trtl_dev *trtl = fmc_get_drvdata(fmc);
uint32_t status;
int i, max_irq = 32, lock;
status = trtl_ioread(trtl, trtl->base_csr + WRN_CPU_CSR_REG_DBG_POLL);
do_irq:
i = -1;
while (status && likely(++i < trtl->n_cpu)) {
lock = spin_is_locked(&trtl->lock_cpu_sel);
if (!(status & 0x1) || lock) {
status >>= 1;
continue;
}
/* Get a character from the soft-CPU */
trtl_tty_handler_getchar(&trtl->cpu[i]);
}
/* Check again the interrupt status */
status = trtl_ioread(trtl, trtl->base_csr + WRN_CPU_CSR_REG_DBG_POLL);
if (max_irq > 0 && status) {
max_irq--;
goto do_irq;
}
/* Push all the collected characters */
for (i = 0; i < trtl->n_cpu; ++i) {
if (!trtl->cpu[i].tty_port.tty) /* Not open */
continue;
trtl_tty_flip_buffer_push(&trtl->cpu[i]);
}
return IRQ_HANDLED;
}
static int trtl_tty_open(struct tty_struct *tty, struct file *file)
{
struct trtl_cpu *cpu = to_trtl_cpu(tty->dev->parent);
struct trtl_dev *trtl = to_trtl_dev(cpu->dev.parent);
uint32_t irq_mask;
int err;
err = tty_port_open(&cpu->tty_port, tty, file);
if (err)
return err;
/* Enable the interrupt on the Mock Turtle */
irq_mask = trtl_ioread(trtl,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
irq_mask |= (1 << cpu->index);
trtl_iowrite(trtl, irq_mask,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
return 0;
}
static void trtl_tty_close(struct tty_struct *tty, struct file *file)
{
struct trtl_cpu *cpu = to_trtl_cpu(tty->dev->parent);
struct trtl_dev *trtl = to_trtl_dev(cpu->dev.parent);
uint32_t irq_mask;
/* Disable the interrupt on the Mock Turtle */
irq_mask = trtl_ioread(trtl,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
irq_mask &= ~(1 << cpu->index);
trtl_iowrite(trtl, irq_mask,
trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
tty_port_close(&cpu->tty_port, tty, file);
}
const struct tty_operations trtl_tty_ops = {
.open = trtl_tty_open,
.close = trtl_tty_close,
};
static const struct tty_port_operations null_ops = { };
static int trtl_tty_port_init(struct trtl_cpu *cpu)
{
cpu->tty_index = trtl_tty_get_minor();
if (cpu->tty_index < 0)
return -1;
tty_port_init(&cpu->tty_port);
cpu->tty_port.ops = &null_ops;
cpu->tty_dev = tty_register_device(&trtl_tty_driver,
cpu->tty_index,
&cpu->dev);
if (IS_ERR_OR_NULL(cpu->tty_dev)) {
tty_port_put(&cpu->tty_port);
return PTR_ERR(cpu->tty_dev);
}
return 0;
}
static void trtl_tty_port_exit(struct trtl_cpu *cpu)
{
tty_unregister_device(&trtl_tty_driver, cpu->tty_index);
trtl_tty_put_minor(cpu->tty_index);
}
void trtl_tty_remove(struct trtl_dev *trtl)
{
struct fmc_device *fmc = to_fmc_dev(trtl);
int i;
/* Disable the interrupts on the Mock Turtle */
trtl_iowrite(trtl, 0x0, trtl->base_csr + WRN_CPU_CSR_REG_DBG_IMSK);
fmc->irq = trtl->base_core + 1;
fmc_irq_free(fmc);
for (i = 0; i < trtl->n_cpu; ++i)
trtl_tty_port_exit(&trtl->cpu[i]);
}
int trtl_tty_probe(struct trtl_dev *trtl)
{
struct fmc_device *fmc = to_fmc_dev(trtl);
int i, err;
for (i = 0; i < trtl->n_cpu; ++i) {
err = trtl_tty_port_init(&trtl->cpu[i]);
if (err)
goto err_port;
}
/* Enable debug interrupts */
fmc->irq = trtl->base_core + 1;
err = fmc_irq_request(fmc, trtl_tty_handler,
(char *)dev_name(&trtl->cpu[i].dev),
0 /*VIC is used */);
if (err)
goto err_irq;
return 0;
err_irq:
err_port:
while(--i)
trtl_tty_port_exit(&trtl->cpu[i]);
return err;
}
......@@ -395,44 +395,3 @@ class WrncSmem(Wrnc):
def write_xor(self, address, values):
self.write(address, values, self.MOD_XOR)
class WrncDebug(Wrnc):
"""
Python wrapper for Debug Interface management
"""
def __init__(self, lun=None, device_id=None,
cpu_index=0):
super(WrncDebug, self).__init__(lun, device_id)
self.cpu_index = cpu_index
# Arguments - FIXME c_void_p should be point c_int
self.libwrnc.wrnc_debug_open.argtypes = [c_void_p, c_uint]
self.libwrnc.wrnc_debug_close.argtypes = [c_void_p]
self.libwrnc.wrnc_debug_message_get.argtypes = [c_void_p,
c_char_p,
c_int]
# Return
self.libwrnc.wrnc_debug_open.restype = c_void_p
self.libwrnc.wrnc_debug_close.restype = None
self.libwrnc.wrnc_debug_message_get.restype = c_int
# Error
self.libwrnc.wrnc_debug_open.errcheck = self.errcheck
self.libwrnc.wrnc_debug_message_get.errcheck = self.errcheck
self.dbg = self.libwrnc.wrnc_debug_open(self.device, self.cpu_index)
def __del__(self):
super(WrncDEbug, self).__del__()
self.libwrnc.wrnc_debug_close(self.dbg)
def read(self):
"""
It returns a string from the debug interface
@return a String containing a debug message
@exception OSError from C library errors
"""
bsize = 1024
buf = create_string_buffer(bsize)
self.libwrnc.wrnc_debug_message_get(self.dbg, buf, bsize)
return buf.value
......@@ -19,13 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from .PyMockTurtle import WrncHeader, WrncMessage, \
WrncCpu, WrncHmq, WrncSmem, WrncDebug
WrncCpu, WrncHmq, WrncSmem
__all__ = (
"WrncCpu",
"WrncHmq",
"WrncSmem",
"WrncDebug",
"WrncHeader",
"WrncMessage",
)
......@@ -1217,88 +1217,3 @@ char *trtl_name_get(struct trtl_dev *trtl)
return wdesc->name;
}
/**
* It opens the debug message stream
* @param[in] trtl device token
* @param[in] index CPU index
* @return a debug token on success, NULL otherwise and errno is set
* appropriately
*/
struct trtl_dbg *trtl_debug_open(struct trtl_dev *trtl, unsigned int index)
{
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
struct trtl_dbg *dbg;
char path[64];
dbg = malloc(sizeof(struct trtl_dbg));
if (!dbg)
return NULL;
dbg->trtl = trtl;
dbg->cpu_index = index;
snprintf(path, 64, "/sys/kernel/debug/%s/%s-cpu-%02d-dbg",
wdesc->name, wdesc->name, index);
dbg->fd = open(path, O_RDONLY);
if (dbg->fd < 0) {
free(dbg);
return NULL;
}
return dbg;
}
/**
* It closes the debug message stream
* @param[in] dbg_tkn debug token
* @param[in] index CPU index
*/
void trtl_debug_close(struct trtl_dbg *dbg)
{
close(dbg->fd);
free(dbg);
dbg = NULL;
}
#define N_RETRY 100
/**
* It retrieves a message from the debug channel. It fills the buffer with a
* NULL terminated string.
* It is a very rare case, but it may happen that you do not receive the entire
* message in one shot. This may happen when the driver, or the transmission
* channel, is slower then the consumer (you or this function)
* @param[in] dbg_tkn debug token
* @param[out] buf where store incoming message. The message it's always
* properly terminated.
* @param[in] count maximum number of char to read (terminator included)
* @return number of byte read on success, -1 otherwise and errno is set
* appropriately
*/
int trtl_debug_message_get(struct trtl_dbg *dbg, char *buf, size_t count)
{
int n = 0, real_count = 0, retry = N_RETRY;
memset(buf, 0, count);
do {
n = read(dbg->fd, buf + real_count, count - real_count);
if (n < 0)
return -1;
real_count += n;
/* check if the string from the CPU is shorter */
if (buf[real_count - 1] == '\0')
break;
/*
* We are expecting a NULL terminated string, but there is
* nothing to read now and the string is not terminated. Retry,
* maybe we were too slow
*/
retry = (n == 0 ? retry - 1 : N_RETRY);
} while (real_count < count && retry > 0);
return real_count;
}
#undef N_RETRY
......@@ -207,18 +207,6 @@ extern int trtl_smem_write(struct trtl_dev *trtl, uint32_t addr, uint32_t *data,
size_t count, enum trtl_smem_modifier mod);
/**@}*/
/**
* @defgroup dbg Debug
* Functions to access the debug serial stream
* @{
*/
extern struct trtl_dbg *trtl_debug_open(struct trtl_dev *trtl,
unsigned int index);
extern void trtl_debug_close(struct trtl_dbg *dbg);
extern int trtl_debug_message_get(struct trtl_dbg *dbg,
char *buf, size_t count);
/**@}*/
/**
* @defgroup proto Protocol management
......
......@@ -44,7 +44,7 @@ struct trtl_thread_desc {
int share;
};
static unsigned int cnt, n, cnt_dbg, N;
static unsigned int cnt, n;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int timestamp = 0;
......@@ -57,9 +57,6 @@ static void help()
fprintf(stderr, "-i slot index\n");
fprintf(stderr, "-n number of total messages to read. The default is 0 (infinite)\n");
fprintf(stderr, "-t print message timestamp\n");
fprintf(stderr, "-d <CPU index> show debug messages for given CPU\n");
fprintf(stderr, "-N number of total debug messages\n");
fprintf(stderr, "-Q show debug messages for all found WRN CPUs\n");
fprintf(stderr, "-s share all HMQ with other users\n");
fprintf(stderr, "-h show this help\n");
fprintf(stderr, "\n");
......@@ -126,90 +123,6 @@ static int dump_message(struct trtl_dev *trtl, struct trtl_hmq *hmq)
return 0;
}
int print_debug(struct trtl_dbg *dbg)
{
int n;
char c[256];
n = trtl_debug_message_get(dbg, c, 256);
if (n < 0)
return -1;
if (strlen(c) > 0)
return fprintf(stderr, "%s-cpu-%02d: %s\n",
trtl_name_get(dbg->trtl), dbg->cpu_index, c);
return 0;
}
void *debug_thread(void *arg)
{
struct trtl_thread_desc *th_data = arg;
struct pollfd p[MAX_SLOT];
struct trtl_dbg *wdbg[MAX_CPU];
struct trtl_dev *trtl = th_data->trtl;
int ret, i;
if (!th_data->n_cpu)
return NULL;
/* Open the device */
if (!trtl)
trtl = trtl_open_by_fmc(th_data->dev_id);
if (!trtl) {
fprintf(stderr, "Cannot open TRTL: %s\n", trtl_strerror(errno));
pthread_exit(NULL);
}
/* If there, open all debug channels */
for (i = 0; i < th_data->n_cpu; i++) {
wdbg[i] = trtl_debug_open(trtl, th_data->cpu_index[i]);
if (!wdbg[i]) {
fprintf(stderr, "Cannot open Mock Turtle debug channel: %s\n",
trtl_strerror(errno));
fprintf(stderr,
"NOTE: the debug interface is on debugfs, be sure that is mounted\n");
goto out;
}
p[i].fd = wdbg[i]->fd;
p[i].events = POLLIN | POLLERR;
}
/* Start dumping messages */
while (N == 0 || N > cnt_dbg) {
/* Polling debug messages */
ret = poll(p, th_data->n_cpu, 10);
switch (ret) {
default:
/* Dump from the slot */
for (i = 0; i < th_data->n_cpu; ++i) {
if (!(p[i].revents & POLLIN))
continue;
ret = print_debug(wdbg[i]);
if (ret < 0)
goto out;
pthread_mutex_lock(&mtx);
cnt_dbg++;
pthread_mutex_unlock(&mtx);
}
break;
case 0:
/* timeout */
break;
case -1:
/* error */
goto out;
break;
}
}
out:
/* Close all debug channels */
while (--i >= 0)
trtl_debug_close(wdbg[i]);
trtl_close(trtl);
return NULL;
}
/**
* pthread for each device. It dumps messages from slots
......@@ -292,8 +205,8 @@ int main(int argc, char *argv[])
struct trtl_thread_desc th_data[MAX_DEV], *last;
unsigned long i;
unsigned int di = 0;
int show_all_debug = 0, share = 0;
pthread_t tid_msg[MAX_DEV], tid_dbg[MAX_DEV];
int share = 0;
pthread_t tid_msg[MAX_DEV];
int err;
char c;
......@@ -301,7 +214,7 @@ int main(int argc, char *argv[])
memset(th_data, 0, sizeof(struct trtl_thread_desc) * MAX_DEV);
while ((c = getopt (argc, argv, "Qhi:D:n:N:td:s")) != -1) {
while ((c = getopt (argc, argv, "hi:D:n:ts")) != -1) {
switch (c) {
default:
help();
......@@ -329,23 +242,9 @@ int main(int argc, char *argv[])
/* Number of total messages to dump */
sscanf(optarg, "%d", &n);
break;
case 'N':
/* Number of total messages to dump */
sscanf(optarg, "%d", &N);
break;
case 't':
timestamp = 1;
break;
case 'd':
if (!last || last->n_cpu >= MAX_CPU)
break;
sscanf(optarg, "%d", &last->cpu_index[last->n_cpu]);
last->n_cpu++;
break;
case 'Q':
show_all_debug = 1;
break;
}
}
......@@ -365,25 +264,6 @@ int main(int argc, char *argv[])
for (i = 0; i < di; ++i)
th_data[i].share = share;
if(show_all_debug) {
char **list = trtl_list();
unsigned int cpucount = 0;
for (di = 0; list[di]; ++di) {
int j;
struct trtl_dev *trtl = trtl_open(list[di]);
trtl_cpu_count(trtl, &cpucount);
printf("ID %s n_cpu %d\n", list[di], cpucount);
th_data[di].trtl = trtl;
for(j = 0; j < cpucount; j++)
th_data[di].cpu_index[j] = j;
th_data[di].n_cpu = cpucount;
th_data[di].n_slot = 0;
}
trtl_list_free(list);
}
/* Run dumping on in parallel from several devices */
for (i = 0; i < di; i++) {
err = pthread_create(&tid_msg[i], NULL, message_thread,
......@@ -394,21 +274,9 @@ int main(int argc, char *argv[])
i, strerror(errno));
}
/* Run dumping on in parallel from several devices */
for (i = 0; i < di; i++) {
err = pthread_create(&tid_dbg[i], NULL, debug_thread,
(void *)(&th_data[i]));
if (err)
fprintf(stderr,
"Cannot create 'dump_thread' instance %ld: %s\n",
i, strerror(errno));
}
/* Wait for the threads to finish */
for (i = 0; i < di; i++)
pthread_join(tid_msg[i], NULL);
for (i = 0; i < di; i++)
pthread_join(tid_dbg[i], NULL);
exit(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