Commit 1f73e001 authored by Federico Vaga's avatar Federico Vaga

sw:drv: add CPU primitive notification support

At this point the user does not get any notification.

This code collects interrupts from soft-CPUs and store these
events in a local buffer with the generic `TRTL_CPU_NOTIFY_APPLICATION`.

Need more patches to make it work well.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent cdb8826c
......@@ -31,6 +31,15 @@
#define __TRTL_MSG_ID_MAX 128
/**
* It lists all notification's code.
*/
enum trtl_cpu_notification {
TRTL_CPU_NOTIFY_APPLICATION = 0,
__TRTL_CPU_NOTIFY_MAX,
};
/**
* List of Mock Turtle message identifiers for firmware input
*/
......
......@@ -27,6 +27,11 @@
#define TRTL_MAX_CARRIER 20 /**< Maximum number of WRNC components on a
single computer*/
/**
* Maximum number of notifications ID in the driver buffer
*/
#define TRTL_CPU_NOTIFY_HISTORY_N 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
......
......@@ -429,6 +429,9 @@ static int trtl_probe_cpu(struct trtl_dev *trtl, unsigned int cpu_idx)
cpu->index = cpu_idx;
spin_lock_init(&cpu->lock);
init_waitqueue_head(&cpu->q_notify);
cpu->idx_r = 0;
cpu->idx_w = 0;
err = trtl_minor_get(&cpu->dev, TRTL_CPU);
if (err)
......@@ -671,6 +674,15 @@ int trtl_probe(struct platform_device *pdev)
r->start);
}
r = platform_get_resource(pdev, IORESOURCE_IRQ, TRTL_IRQ_NOT);
err = request_irq(r->start, trtl_cpu_irq_handler_not, 0,
r->name, trtl);
if (err) {
dev_err(&trtl->dev,
"Cannot request IRQ %lld - we'll not receive CPU notifications\n",
r->start);
}
err = trtl_tty_probe(trtl);
if (err)
......@@ -712,6 +724,7 @@ int trtl_remove(struct platform_device *pdev)
trtl_iowrite(trtl, 0x0, trtl->base_gcr + TRTL_MQ_GCR_IRQ_MASK);
free_irq(platform_get_irq(pdev, TRTL_IRQ_HMQ_IN), trtl);
free_irq(platform_get_irq(pdev, TRTL_IRQ_HMQ_OUT), trtl);
free_irq(platform_get_irq(pdev, TRTL_IRQ_NOT), trtl);
for (i = 0; i < trtl->cfgrom.n_cpu; ++i)
trtl_remove_cpu(trtl, i);
......
......@@ -9,8 +9,10 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <hw/mockturtle_cpu_csr.h>
#include "mockturtle-drv.h"
......@@ -40,6 +42,27 @@ static void trtl_cpu_reset_clr(struct trtl_dev *trtl, uint8_t mask)
trtl_iowrite(trtl, reg_val, trtl->base_csr + MT_CPU_CSR_REG_RESET);
}
static ssize_t trtl_show_notify_history(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct trtl_cpu *cpu = to_trtl_cpu(dev);
ssize_t len;
unsigned int i; /* it must be unsigned for the circ-buffer */
int idx;
len = 0;
for (i = cpu->idx_r; i < cpu->idx_w; ++i) {
idx = i & (TRTL_CPU_NOTIFY_HISTORY_N - 1);
len += snprintf(buf + len, PAGE_SIZE, "0x%08x\n",
cpu->notification[idx]);
}
return len;
}
DEVICE_ATTR(last_notifications, S_IRUGO, trtl_show_notify_history, NULL);
/**
* It returns the CPU reset status
*/
......@@ -81,6 +104,7 @@ DEVICE_ATTR(reset, (S_IRUGO | S_IWUSR), trtl_show_reset, trtl_store_reset);
static struct attribute *trtl_cpu_attr[] = {
&dev_attr_reset.attr,
&dev_attr_last_notifications.attr,
NULL,
};
......@@ -291,3 +315,52 @@ const struct file_operations trtl_cpu_fops = {
.read = trtl_cpu_read,
.llseek = generic_file_llseek,
};
static uint32_t trtl_cpu_irq_status(struct trtl_dev *trtl)
{
uint32_t status;
status = trtl_ioread(trtl, trtl->base_csr + MT_CPU_CSR_REG_INT);
return status & 0xFF;
}
static void trtl_cpu_irq_clear(struct trtl_dev *trtl, uint32_t mask)
{
trtl_iowrite(trtl, mask, trtl->base_csr + MT_CPU_CSR_REG_INT);
}
irqreturn_t trtl_cpu_irq_handler_not(int irq, void *arg)
{
struct trtl_dev *trtl =arg;
struct trtl_cpu *cpu;
uint32_t status;
unsigned long flags;
int i, idx;
status = trtl_cpu_irq_status(trtl);
if (!status)
return IRQ_NONE;
for (i = 0; i < trtl->cfgrom.n_cpu; ++i) {
if (!(status & (1 << i)))
continue;
cpu = &trtl->cpu[i];
spin_lock_irqsave(&cpu->lock, flags);
idx = cpu->idx_w++ & (TRTL_CPU_NOTIFY_HISTORY_N - 1);
cpu->notification[idx] = TRTL_CPU_NOTIFY_APPLICATION;
if (cpu->idx_r + TRTL_CPU_NOTIFY_HISTORY_N <= cpu->idx_w)
cpu->idx_r++;
spin_unlock_irqrestore(&cpu->lock, flags);
wake_up_interruptible(&cpu->q_notify);
}
/* what if we clear a new interrupt coming right now ? */
trtl_cpu_irq_clear(trtl, status);
return IRQ_HANDLED;
}
......@@ -191,6 +191,11 @@ struct trtl_cpu {
struct device *tty_dev;
struct tty_port tty_port;
unsigned int tty_index;
wait_queue_head_t q_notify;
enum trtl_cpu_notification notification[TRTL_CPU_NOTIFY_HISTORY_N];
unsigned int idx_r;
unsigned int idx_w;
};
/**
......@@ -244,6 +249,7 @@ 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);
extern irqreturn_t trtl_cpu_irq_handler_not(int irq, void *arg);
/* HMQ */
extern int hmq_shared;
extern int trtl_probe_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx);
......
......@@ -135,5 +135,14 @@ static inline const struct trtl_config_rom *trtl_config_rom_get(void)
}
/**
* It generates a notification signal (IRQ) to ask the HOST CPU
* to take some action.
*/
static inline void trtl_notify_send(enum trtl_cpu_notification id)
{
lr_writel(1, MT_CPU_LR_REG_HOST_INT);
}
#endif
/**@}*/
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