From a373079a942075f010bda5c0baed5a0d58dc2dd4 Mon Sep 17 00:00:00 2001 From: "Nakamura, Yuuichi" Date: Wed, 9 Sep 2020 09:06:38 +0900 Subject: [PATCH] Fix /dev/note driver for task trace support --- drivers/note/noteram_driver.c | 228 ++++++++++++++++++++++++---- include/nuttx/fs/ioctl.h | 6 + include/nuttx/note/noteram_driver.h | 30 +++- 3 files changed, 234 insertions(+), 30 deletions(-) diff --git a/drivers/note/noteram_driver.c b/drivers/note/noteram_driver.c index 6ca2d22717..df379baef4 100644 --- a/drivers/note/noteram_driver.c +++ b/drivers/note/noteram_driver.c @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -57,6 +58,8 @@ struct noteram_info_s { volatile unsigned int ni_head; volatile unsigned int ni_tail; + volatile unsigned int ni_read; + unsigned int ni_overwrite; uint8_t ni_buffer[CONFIG_DRIVER_NOTERAM_BUFSIZE]; }; @@ -64,8 +67,10 @@ struct noteram_info_s * Private Function Prototypes ****************************************************************************/ +static int noteram_open(FAR struct file *filep); static ssize_t noteram_read(FAR struct file *filep, FAR char *buffer, size_t buflen); +static int noteram_ioctl(struct file *filep, int cmd, unsigned long arg); /**************************************************************************** * Private Data @@ -73,19 +78,22 @@ static ssize_t noteram_read(FAR struct file *filep, static const struct file_operations g_noteram_fops = { - NULL, /* open */ + noteram_open, /* open */ NULL, /* close */ noteram_read, /* read */ NULL, /* write */ NULL, /* seek */ - NULL, /* ioctl */ + noteram_ioctl, /* ioctl */ NULL /* poll */ #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS , 0 /* unlink */ #endif }; -static struct noteram_info_s g_noteram_info; +static struct noteram_info_s g_noteram_info = +{ + .ni_overwrite = NOTERAM_MODE_OVERWRITE_ENABLE +}; #ifdef CONFIG_SMP static volatile spinlock_t g_noteram_lock; @@ -95,6 +103,37 @@ static volatile spinlock_t g_noteram_lock; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: noteram_buffer_clear + * + * Description: + * Clear all contents of the circular buffer. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void noteram_buffer_clear(void) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + g_noteram_info.ni_tail = g_noteram_info.ni_head; + g_noteram_info.ni_read = g_noteram_info.ni_head; + + if (g_noteram_info.ni_overwrite == NOTERAM_MODE_OVERWRITE_OVERFLOW) + { + g_noteram_info.ni_overwrite = NOTERAM_MODE_OVERWRITE_DISABLE; + } + + leave_critical_section(flags); +} + /**************************************************************************** * Name: noteram_next * @@ -136,6 +175,7 @@ static inline unsigned int noteram_next(unsigned int ndx, * ****************************************************************************/ +#ifdef CONFIG_DEBUG_ASSERTIONS static unsigned int noteram_length(void) { unsigned int head = g_noteram_info.ni_head; @@ -148,6 +188,34 @@ static unsigned int noteram_length(void) return head - tail; } +#endif + +/**************************************************************************** + * Name: noteram_unread_length + * + * Description: + * Length of unread data currently in circular buffer. + * + * Input Parameters: + * None + * + * Returned Value: + * Length of unread data currently in circular buffer. + * + ****************************************************************************/ + +static unsigned int noteram_unread_length(void) +{ + unsigned int head = g_noteram_info.ni_head; + unsigned int read = g_noteram_info.ni_read; + + if (read > head) + { + head += CONFIG_DRIVER_NOTERAM_BUFSIZE; + } + + return head - read; +} /**************************************************************************** * Name: noteram_remove @@ -187,6 +255,13 @@ static void noteram_remove(void) * buffer. */ + if (g_noteram_info.ni_read == g_noteram_info.ni_tail) + { + /* The read index also needs increment. */ + + g_noteram_info.ni_read = noteram_next(tail, length); + } + g_noteram_info.ni_tail = noteram_next(tail, length); } @@ -194,8 +269,7 @@ static void noteram_remove(void) * Name: noteram_get * * Description: - * Remove the next note from the tail of the circular buffer. The note - * is also removed from the circular buffer to make room for further notes. + * Get the next note from the read index of the circular buffer. * * Input Parameters: * buffer - Location to return the next note @@ -213,7 +287,7 @@ static ssize_t noteram_get(FAR uint8_t *buffer, size_t buflen) FAR struct note_common_s *note; irqstate_t flags; unsigned int remaining; - unsigned int tail; + unsigned int read; ssize_t notelen; size_t circlen; @@ -222,21 +296,21 @@ static ssize_t noteram_get(FAR uint8_t *buffer, size_t buflen) /* Verify that the circular buffer is not empty */ - circlen = noteram_length(); + circlen = noteram_unread_length(); if (circlen <= 0) { notelen = 0; goto errout_with_csection; } - /* Get the index to the tail of the circular buffer */ + /* Get the read index of the circular buffer */ - tail = g_noteram_info.ni_tail; + read = g_noteram_info.ni_read; DEBUGASSERT(tail < CONFIG_DRIVER_NOTERAM_BUFSIZE); - /* Get the length of the note at the tail index */ + /* Get the length of the note at the read index */ - note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[tail]; + note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[read]; notelen = note->nc_length; DEBUGASSERT(notelen <= circlen); @@ -244,9 +318,9 @@ static ssize_t noteram_get(FAR uint8_t *buffer, size_t buflen) if (buflen < notelen) { - /* Remove the large note so that we do not get constipated. */ + /* Skip the large note so that we do not get constipated. */ - noteram_remove(); + g_noteram_info.ni_read = noteram_next(read, notelen); /* and return an error */ @@ -259,17 +333,17 @@ static ssize_t noteram_get(FAR uint8_t *buffer, size_t buflen) remaining = (unsigned int)notelen; while (remaining > 0) { - /* Copy the next byte at the tail index */ + /* Copy the next byte at the read index */ - *buffer++ = g_noteram_info.ni_buffer[tail]; + *buffer++ = g_noteram_info.ni_buffer[read]; /* Adjust indices and counts */ - tail = noteram_next(tail, 1); + read = noteram_next(read, 1); remaining--; } - g_noteram_info.ni_tail = tail; + g_noteram_info.ni_read = read; errout_with_csection: leave_critical_section(flags); @@ -280,7 +354,8 @@ errout_with_csection: * Name: noteram_size * * Description: - * Return the size of the next note at the tail of the circular buffer. + * Return the size of the next note at the read index of the circular + * buffer. * * Input Parameters: * None. @@ -295,7 +370,7 @@ static ssize_t noteram_size(void) { FAR struct note_common_s *note; irqstate_t flags; - unsigned int tail; + unsigned int read; ssize_t notelen; size_t circlen; @@ -303,21 +378,21 @@ static ssize_t noteram_size(void) /* Verify that the circular buffer is not empty */ - circlen = noteram_length(); + circlen = noteram_unread_length(); if (circlen <= 0) { notelen = 0; goto errout_with_csection; } - /* Get the index to the tail of the circular buffer */ + /* Get the read index of the circular buffer */ - tail = g_noteram_info.ni_tail; - DEBUGASSERT(tail < CONFIG_DRIVER_NOTERAM_BUFSIZE); + read = g_noteram_info.ni_read; + DEBUGASSERT(read < CONFIG_SCHED_NOTE_BUFSIZE); - /* Get the length of the note at the tail index */ + /* Get the length of the note at the read index */ - note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[tail]; + note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[read]; notelen = note->nc_length; DEBUGASSERT(notelen <= circlen); @@ -326,6 +401,19 @@ errout_with_csection: return notelen; } +/**************************************************************************** + * Name: noteram_open + ****************************************************************************/ + +static int noteram_open(FAR struct file *filep) +{ + /* Reset the read index of the circular buffer */ + + g_noteram_info.ni_read = g_noteram_info.ni_tail; + + return OK; +} + /**************************************************************************** * Name: noteram_read ****************************************************************************/ @@ -386,6 +474,69 @@ static ssize_t noteram_read(FAR struct file *filep, return retlen; } +/**************************************************************************** + * Name: noteram_ioctl + ****************************************************************************/ + +static int noteram_ioctl(struct file *filep, int cmd, unsigned long arg) +{ + int ret = -ENOSYS; + + /* Handle the ioctl commands */ + + switch (cmd) + { + /* NOTERAM_CLEAR + * - Clear all contents of the circular buffer + * Argument: Ignored + */ + + case NOTERAM_CLEAR: + noteram_buffer_clear(); + ret = OK; + break; + + /* NOTERAM_GETMODE + * - Get overwrite mode + * Argument: A writable pointer to unsigned int + */ + + case NOTERAM_GETMODE: + if (arg == 0) + { + ret = -EINVAL; + } + else + { + *(unsigned int *)arg = g_noteram_info.ni_overwrite; + ret = OK; + } + break; + + /* NOTERAM_SETMODE + * - Set overwrite mode + * Argument: A read-only pointer to unsigned int + */ + + case NOTERAM_SETMODE: + if (arg == 0) + { + ret = -EINVAL; + } + else + { + g_noteram_info.ni_overwrite = *(unsigned int *)arg; + ret = OK; + } + break; + + default: + break; + } + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -413,12 +564,22 @@ void sched_note_add(FAR const void *note, size_t notelen) FAR const char *buf = note; unsigned int head; unsigned int next; + irqstate_t flags; + flags = up_irq_save(); #ifdef CONFIG_SMP - irqstate_t flags = up_irq_save(); spin_lock_wo_note(&g_noteram_lock); #endif + if (g_noteram_info.ni_overwrite == NOTERAM_MODE_OVERWRITE_OVERFLOW) + { +#ifdef CONFIG_SMP + spin_unlock_wo_note(&g_noteram_lock); +#endif + up_irq_restore(flags); + return; + } + /* Get the index to the head of the circular buffer */ DEBUGASSERT(note != NULL && notelen < CONFIG_DRIVER_NOTERAM_BUFSIZE); @@ -435,6 +596,19 @@ void sched_note_add(FAR const void *note, size_t notelen) next = noteram_next(head, 1); if (next == g_noteram_info.ni_tail) { + if (g_noteram_info.ni_overwrite == NOTERAM_MODE_OVERWRITE_DISABLE) + { + /* Stop recording if not in overwrite mode */ + + g_noteram_info.ni_overwrite = NOTERAM_MODE_OVERWRITE_OVERFLOW; + +#ifdef CONFIG_SMP + spin_unlock_wo_note(&g_noteram_lock); +#endif + up_irq_restore(flags); + return; + } + /* Yes, then remove the note at the tail index */ noteram_remove(); @@ -452,8 +626,8 @@ void sched_note_add(FAR const void *note, size_t notelen) #ifdef CONFIG_SMP spin_unlock_wo_note(&g_noteram_lock); - up_irq_restore(flags); #endif + up_irq_restore(flags); } /**************************************************************************** diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index cc61b377b4..87a4ea5a93 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -98,6 +98,7 @@ #define _RFIOCBASE (0x2a00) /* RF devices ioctl commands */ #define _RPTUNBASE (0x2b00) /* Remote processor tunnel ioctl commands */ #define _NOTECTLBASE (0x2c00) /* Note filter control ioctl commands*/ +#define _NOTERAMBASE (0x2d00) /* Noteram device ioctl commands*/ #define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */ /* boardctl() commands share the same number space */ @@ -533,6 +534,11 @@ #define _NOTECTLIOCVALID(c) (_IOC_TYPE(c) == _NOTECTLBASE) #define _NOTECTLIOC(nr) _IOC(_NOTECTLBASE, nr) +/* Noteram drivers **********************************************************/ + +#define _NOTERAMIOCVALID(c) (_IOC_TYPE(c) == _NOTERAMBASE) +#define _NOTERAMIOC(nr) _IOC(_NOTERAMBASE, nr) + /* Wireless driver network ioctl definitions ********************************/ /* (see nuttx/include/wireless/wireless.h */ diff --git a/include/nuttx/note/noteram_driver.h b/include/nuttx/note/noteram_driver.h index 73709122a9..b845149c28 100644 --- a/include/nuttx/note/noteram_driver.h +++ b/include/nuttx/note/noteram_driver.h @@ -26,14 +26,38 @@ ****************************************************************************/ #include +#include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/**************************************************************************** - * Public Types - ****************************************************************************/ +/* IOCTL Commands ***********************************************************/ + +/* NOTERAM_CLEAR + * - Clear all contents of the circular buffer + * Argument: Ignored + * NOTERAM_GETMODE + * - Get overwrite mode + * Argument: A writable pointer to unsigned int + * NOTERAM_SETMODE + * - Set overwrite mode + * Argument: A read-only pointer to unsigned int + */ + +#ifdef CONFIG_DRIVER_NOTERAM +#define NOTERAM_CLEAR _NOTERAMIOC(0x01) +#define NOTERAM_GETMODE _NOTERAMIOC(0x02) +#define NOTERAM_SETMODE _NOTERAMIOC(0x03) +#endif + +/* Overwrite mode definitions */ + +#ifdef CONFIG_DRIVER_NOTERAM +#define NOTERAM_MODE_OVERWRITE_DISABLE 0 +#define NOTERAM_MODE_OVERWRITE_ENABLE 1 +#define NOTERAM_MODE_OVERWRITE_OVERFLOW 2 +#endif /**************************************************************************** * Public Function Prototypes