From 1178d575392f85a0c24e02d49a973b999fd8587f Mon Sep 17 00:00:00 2001 From: Luis Gerhorst <luis.gerhorst@fau.de> Date: Tue, 10 Jul 2018 23:41:32 +0200 Subject: [PATCH] Seperate trigger from sysfs, cleanup --- arch/arm/measuremore/Kbuild | 4 +- arch/arm/measuremore/measure.c | 6 +- arch/arm/measuremore/pmccntr_timestamp.c | 2 - arch/arm/measuremore/sysfs.c | 290 +++++++++++++++ arch/arm/measuremore/sysfs.h | 6 + arch/arm/measuremore/trigger.c | 449 +++++------------------ arch/arm/measuremore/trigger.h | 26 +- 7 files changed, 412 insertions(+), 371 deletions(-) create mode 100644 arch/arm/measuremore/sysfs.c create mode 100644 arch/arm/measuremore/sysfs.h diff --git a/arch/arm/measuremore/Kbuild b/arch/arm/measuremore/Kbuild index fbf934b..130b687 100644 --- a/arch/arm/measuremore/Kbuild +++ b/arch/arm/measuremore/Kbuild @@ -1,8 +1,8 @@ ccflags-$(CONFIG_MEASUREMORE) := -std=gnu99 -Wno-declaration-after-statement obj-$(CONFIG_MEASUREMORE) += measuremore.o -measuremore-objs += trigger.o measure.o pmccntr_timestamp.o +measuremore-objs += sysfs.o trigger.o measure.o pmccntr_timestamp.o -$(obj)/trigger.o: $(obj)/kernel_memo_git_commit.h $(obj)/kernel_memo_git_status.h +$(obj)/sysfs.o: $(obj)/kernel_memo_git_commit.h $(obj)/kernel_memo_git_status.h targets += $(obj)/kernel_memo_git_commit.h $(obj)/kernel_memo_git_status.h diff --git a/arch/arm/measuremore/measure.c b/arch/arm/measuremore/measure.c index 84a8590..1168de7 100644 --- a/arch/arm/measuremore/measure.c +++ b/arch/arm/measuremore/measure.c @@ -8,12 +8,11 @@ #include <linux/string.h> #include <linux/measuremore.h> -#include "trigger.h" +#include "sysfs.h" #ifdef CONFIG_MEASUREMORE_TIMESTAMP_TYPE_PMCCNTR #include "pmccntr_timestamp.h" #endif - #include "measure.h" bool debugfs_vmalloc_cp_matrix; @@ -191,11 +190,10 @@ static void create_csv_file(const char *name, struct dentry *folder) { pr_info("Exporting %s field...", name); - pr_info("seq_write_field is %p\n", seq_write_field); struct dentry *csv_file = debugfs_create_file(name, 0400, folder, seq_write_field, &csv_file_ops); BUG_ON(!csv_file); - pr_info("done\n"); + pr_info(" done\n"); } #ifdef CONFIG_MEASUREMORE_TIMESTAMP_TYPE_PMCCNTR diff --git a/arch/arm/measuremore/pmccntr_timestamp.c b/arch/arm/measuremore/pmccntr_timestamp.c index 7d6c29a..7be8dbb 100644 --- a/arch/arm/measuremore/pmccntr_timestamp.c +++ b/arch/arm/measuremore/pmccntr_timestamp.c @@ -122,12 +122,10 @@ union PMCR { static union PMCR pmcr_read(void) { union PMCR pmcr; asm volatile ("mrc p15, 0, %0, c9, c12, 0\n\t" : "=r" (pmcr.value)); - pr_info("Read pmcr %x\n", pmcr.value); return pmcr; } static void pmcr_write(union PMCR pmcr) { - pr_info("Writing pmcr %x\n", pmcr.value); asm volatile ("mcr p15, 0, %0, c9, c12, 0\n\t" : : "r" (pmcr.value)); } diff --git a/arch/arm/measuremore/sysfs.c b/arch/arm/measuremore/sysfs.c new file mode 100644 index 0000000..ca84e95 --- /dev/null +++ b/arch/arm/measuremore/sysfs.c @@ -0,0 +1,290 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/ktime.h> +#include <asm/uaccess.h> +#include <linux/debugfs.h> +#include <linux/workqueue.h> + +#include "kernel_memo_git_commit.h" +#include "kernel_memo_git_status.h" +#include "trigger.h" +#include "measure.h" +#include "sysfs.h" + +struct dentry *memo_root; + +/****************** + * Bottom Handler * + ******************/ + +static char *bottom_handler_map_strings[] = {"workqueue\n", "tasklet\n", + "softirq\n", NULL}; +static enum memo_bottom_handler bottom_handler_map[] = {MMBH_WORKQUEUE, + MMBH_TASKLET, + MMBH_SOFTIRQ}; + +static ssize_t debugfs_bottom_handler_read(struct file *fp, char __user *user_buffer, + size_t count, loff_t *position) +{ + for (int i = 0; bottom_handler_map_strings[i]; i++) { + if (bottom_handler_map[i] == debugfs_bottom_handler) { + const char *str = bottom_handler_map_strings[i]; + return simple_read_from_buffer(user_buffer, count, + position, str, + strlen(str)); + } + } + BUG(); + return 0; +} + +static ssize_t debugfs_bottom_handler_write(struct file *fp, + const char __user *user_buffer, + size_t count, loff_t *position) +{ + char buf[count+1]; + buf[count] = '\0'; + if (simple_write_to_buffer(buf, count, position, user_buffer, count) < 0) { + BUG(); + } + + for (int i = 0; bottom_handler_map_strings[i]; i++) { + if (strcmp(bottom_handler_map_strings[i], buf) == 0) { + debugfs_bottom_handler = bottom_handler_map[i]; + return count; + } + } + pr_err("Unrecognized bottom handler '%s'\n", buf); + return count; +} + +static const struct file_operations debugfs_bottom_handler_fops = { + /* TODO: Not sure if this is legit, can't read/write only ask for a + * portion of the string? */ + .read = debugfs_bottom_handler_read, + .write = debugfs_bottom_handler_write, +}; + +/*********** + * Waiting * + ***********/ + +static char *delay_type_map_strings[] = {"udelay\n", "usleep_range\n", NULL}; +static enum memo_delay_type delay_type_map[] = {MMDT_UDELAY, MMDT_USLEEP_RANGE}; + +static ssize_t delay_type_read(struct file *fp, char __user *user_buffer, + size_t count, loff_t *position) +{ + for (int i = 0; delay_type_map_strings[i]; i++) { + if (delay_type_map[i] == debugfs_delay_type) { + const char *str = delay_type_map_strings[i]; + return simple_read_from_buffer(user_buffer, count, + position, str, + strlen(str)); + } + } + BUG(); + return 0; +} + +static ssize_t delay_type_write(struct file *fp, const char __user *user_buffer, + size_t count, loff_t *position) +{ + char buf[count+1]; + buf[count] = '\0'; + if (simple_write_to_buffer(buf, count, position, user_buffer, count) < 0) { + BUG(); + } + + for (int i = 0; delay_type_map_strings[i]; i++) { + if (strcmp(delay_type_map_strings[i], buf) == 0) { + debugfs_delay_type = delay_type_map[i]; + return count; + } + } + pr_err("Unrecognized delay type '%s'\n", buf); + return count; +} + +static const struct file_operations debugfs_delay_type_fops = { + /* TODO: Not sure if this is legit, can't read/write only ask for a + * portion of the string? */ + .read = delay_type_read, + .write = delay_type_write, +}; + +static ssize_t prepare_trigger_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +{ + int err = memo_prepare_trigger(); + if (err) { + pr_err("prepare_trigger failed with error %d\n", err); + } + return len; +} + +static ssize_t memo_empty_read(struct file *fp, char __user *user_buffer, + size_t count, loff_t *position) +{ + return simple_read_from_buffer(user_buffer, count, position, "", 0); +} + +static const struct file_operations prepare_trigger_fops = { + .write = prepare_trigger_write, + .read = memo_empty_read, + .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ +}; + +/* Do Trigger */ + +static ssize_t do_trigger_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +{ + int err = memo_do_trigger(); + if (err) { + pr_err("do_trigger failed with error %d\n", err); + } + return len; +} + +/* TODO: Does block when logging in, triggering, logging out, triggering again. */ +static const struct file_operations do_trigger_fops = { + .write = do_trigger_write, + .read = memo_empty_read, + .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ +}; + +/* Postprocess Trigger */ + +static ssize_t postprocess_trigger_write(struct file *file, + const char __user *addr, size_t len, + loff_t *pos) +{ + + int err = memo_postprocess_trigger(); + if (err) { + pr_err("postprocess_trigger failed with error %d\n", err); + } + return len; +} + +static const struct file_operations postprocess_trigger_fops = { + .write = postprocess_trigger_write, + .read = memo_empty_read, + .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ +}; + +/***************** + * File Creation * + *****************/ + +static struct dentry *memo_debugfs_create_str(const char *name, const char *str, + struct debugfs_blob_wrapper *blob) +{ + blob->data = (char *) str; + blob->size = strlen(blob->data); + return debugfs_create_blob(name, 0400, memo_root, blob); +} + +static struct debugfs_blob_wrapper debugfs_kernel_memo_git_commit_blob; +static struct debugfs_blob_wrapper debugfs_kernel_memo_git_status_blob; + +static int create_files(void) +{ + /* TODO: error handling */ + + memo_debugfs_create_str("kernel_measuremore_git_commit", + kernel_memo_git_commit, + &debugfs_kernel_memo_git_commit_blob); + memo_debugfs_create_str("kernel_measuremore_git_status", + kernel_memo_git_status, + &debugfs_kernel_memo_git_status_blob); + + debugfs_create_bool("vmalloc_checkpoint_matrix", 0400, memo_root, + &debugfs_vmalloc_cp_matrix); + debugfs_create_u64("do_trigger_since_boot", 0600, memo_root, + &debugfs_do_trigger_since_boot); + + debugfs_create_u64("delay_ms", 0600, memo_root, &debugfs_delay_ms); + debugfs_create_u64("reps", 0600, memo_root, &debugfs_reps); + debugfs_create_u64("checkpoint_capacity", 0600, memo_root, + &debugfs_cp_capacity); + debugfs_create_u32("progress_interval", 0600, memo_root, + &debugfs_progress_interval); + debugfs_create_file("bottom_handler", 0600, memo_root, NULL, + &debugfs_bottom_handler_fops); + debugfs_create_file("delay_type", 0600, memo_root, NULL, + &debugfs_delay_type_fops); + + /* We have to use debugfs_create_file_unsafe() here since we want to + * remove other debugfs files in the fops' write function. Otherwise + * those calls to remove would deadlock. TODO: Not sure whether this is + * the right solution, maybe, to be completely correct, we must use + * debugfs_use_file_start/finish() inside the write function. */ + debugfs_create_file("prepare_trigger", 0600, memo_root, NULL, + &prepare_trigger_fops); + debugfs_create_file("do_trigger", 0600, memo_root, NULL, + &do_trigger_fops); + debugfs_create_file_unsafe("postprocess_trigger", 0600, memo_root, NULL, + &postprocess_trigger_fops); + + return 0; +} + +static int memo_late_init(void) +{ + int err = memo_trigger_init_after_boot(); + BUG_ON(err); + err = create_files(); + BUG_ON(err); + return 0; +} + +static ssize_t debugfs_late_init_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +{ + int err = memo_late_init(); + if (err) { + pr_err("Late init failed with error %d\n", err); + } + return len; +} + +static const struct file_operations debugfs_late_init_fops = { + .write = debugfs_late_init_write, + .read = memo_empty_read, /* So cp -r doen't fail. */ + .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ +}; + +static int __init memo_init(void) +{ + int err = memo_trigger_init(); + BUG_ON(err); + + memo_root = debugfs_create_dir("measuremore", NULL); + BUG_ON(!memo_root); + debugfs_create_file("init", 0600, memo_root, NULL, &debugfs_late_init_fops); + + return 0; +} + +static void __exit memo_exit(void) +{ + debugfs_remove_recursive(memo_root); + memo_trigger_deinit(); +} + +module_init(memo_init); +module_exit(memo_exit); + +MODULE_DESCRIPTION("Trigger interrupt top / bottom handlers"); +MODULE_AUTHOR("Luis Gerhorst"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/measuremore/sysfs.h b/arch/arm/measuremore/sysfs.h new file mode 100644 index 0000000..fde2fa5 --- /dev/null +++ b/arch/arm/measuremore/sysfs.h @@ -0,0 +1,6 @@ +#ifndef MEASUREMORE_SYSFS_H +#define MEASUREMORE_SYSFS_H + +extern struct dentry *memo_root; + +#endif /* MEASUREMORE_SYSFS_H */ diff --git a/arch/arm/measuremore/trigger.c b/arch/arm/measuremore/trigger.c index bb28a08..dbe9e34 100644 --- a/arch/arm/measuremore/trigger.c +++ b/arch/arm/measuremore/trigger.c @@ -1,38 +1,28 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/delay.h> -#include <linux/ktime.h> -#include <asm/uaccess.h> -#include <linux/debugfs.h> - #include <linux/workqueue.h> -#include "trigger.h" -#include "measure.h" -#include "pmccntr_timestamp.h" #include <linux/measuremore.h> -#include "kernel_memo_git_commit.h" -#include "kernel_memo_git_status.h" - -#define pr_here() pr_err("%s:%d %s called\n", __FILE__, __LINE__, __func__) +#include "pmccntr_timestamp.h" +#include "measure.h" +#include "trigger.h" -#define ECHO_1_OUTPUT "1\n" -#define DEVICE_NAME KBUILD_MODNAME -#define CLASS_NAME "interrupt_generator" #define GPIO_A6 0x60+26 #define GPIO_A7 0x60+27 #define GPIO_IRQ GPIO_A6 #define GPIO_OUT GPIO_A7 -struct dentry *memo_root; +enum memo_bottom_handler debugfs_bottom_handler = MMBH_TASKLET; +enum memo_delay_type debugfs_delay_type = MMDT_UDELAY; +u64 debugfs_do_trigger_since_boot = 0; +u64 debugfs_delay_ms = 20; +u64 debugfs_reps = 1000; +u64 debugfs_cp_capacity = 25; static int irq_number; @@ -75,120 +65,6 @@ static void memo_install_softirq(void) open_softirq(MEASUREMORE_SOFTIRQ, memo_softirq_handler); } -/****************** - * Bottom Handler * - ******************/ - -enum memo_bottom_handler { - MMBH_WORKQUEUE, - MMBH_TASKLET, - MMBH_SOFTIRQ -}; - -static char *debugfs_bottom_handler_map_strings[] = {"workqueue\n", "tasklet\n", - "softirq\n", NULL}; -static enum memo_bottom_handler debugfs_bottom_handler_map[] = {MMBH_WORKQUEUE, - MMBH_TASKLET, - MMBH_SOFTIRQ}; - -static const char *debugfs_bottom_handler_str = "tasklet\n"; -static enum memo_bottom_handler debugfs_bottom_handler = MMBH_TASKLET; - -static ssize_t debugfs_bottom_handler_read(struct file *fp, char __user *user_buffer, - size_t count, loff_t *position) -{ - return simple_read_from_buffer(user_buffer, count, position, - debugfs_bottom_handler_str, - strlen(debugfs_bottom_handler_str)); -} - -static ssize_t debugfs_bottom_handler_write(struct file *fp, - const char __user *user_buffer, - size_t count, loff_t *position) -{ - char buf[count+1]; - buf[count] = '\0'; - if (simple_write_to_buffer(buf, count, position, user_buffer, count) < 0) { - BUG(); - } - - for (int i = 0; debugfs_bottom_handler_map_strings[i]; i++) { - if (strcmp(debugfs_bottom_handler_map_strings[i], buf) == 0) { - debugfs_bottom_handler = debugfs_bottom_handler_map[i]; - debugfs_bottom_handler_str = debugfs_bottom_handler_map_strings[i]; - return count; - } - } - pr_err("Unrecognized bottom handler '%s'\n", buf); - return count; -} - -static const struct file_operations debugfs_bottom_handler_fops = { - /* TODO: Not sure if this is legit, can't read/write only ask for a - * portion of the string? */ - .read = debugfs_bottom_handler_read, - .write = debugfs_bottom_handler_write, -}; - -/*********** - * Waiting * - ***********/ - -enum memo_delay_type { - MMDT_UDELAY, - MMDT_USLEEP_RANGE -}; - -static char *delay_type_map_strings[] = {"udelay\n", "usleep_range\n", NULL}; -static enum memo_delay_type delay_type_map[] = {MMDT_UDELAY, MMDT_USLEEP_RANGE}; - -static const char *debugfs_delay_type_str = "udelay\n"; -static enum memo_delay_type debugfs_delay_type = MMDT_UDELAY; - -static ssize_t delay_type_read(struct file *fp, char __user *user_buffer, - size_t count, loff_t *position) -{ - return simple_read_from_buffer(user_buffer, count, position, - debugfs_delay_type_str, - strlen(debugfs_delay_type_str)); -} - -static ssize_t delay_type_write(struct file *fp, const char __user *user_buffer, - size_t count, loff_t *position) -{ - char buf[count+1]; - buf[count] = '\0'; - if (simple_write_to_buffer(buf, count, position, user_buffer, count) < 0) { - BUG(); - } - - for (int i = 0; delay_type_map_strings[i]; i++) { - if (strcmp(delay_type_map_strings[i], buf) == 0) { - debugfs_delay_type = delay_type_map[i]; - debugfs_delay_type_str = delay_type_map_strings[i]; - return count; - } - } - pr_err("Unrecognized delay type '%s'\n", buf); - return count; -} - -static const struct file_operations debugfs_delay_type_fops = { - /* TODO: Not sure if this is legit, can't read/write only ask for a - * portion of the string? */ - .read = delay_type_read, - .write = delay_type_write, -}; - -/****************************** - * Vars Exposed Through Sysfs * - ******************************/ - -static u64 debugfs_do_trigger_since_boot = 0; -static u64 debugfs_delay_ms = 20; -static u64 debugfs_reps = 1000; -static u64 debugfs_cp_capacity = 25; - /************** * Interrupts * **************/ @@ -216,12 +92,12 @@ static irqreturn_t memo_irq_handler(int irq, void *dev_id) static int memo_request_irq(int irqnum) { return request_any_context_irq(irqnum, memo_irq_handler, - IRQF_TRIGGER_FALLING, DEVICE_NAME, NULL); + IRQF_TRIGGER_FALLING, KBUILD_MODNAME, NULL); } -/******************* - * Sysfs Interface * - *******************/ +/******** + * GPIO * + ********/ static void memo_trigger_interrupt(void) { @@ -229,198 +105,13 @@ static void memo_trigger_interrupt(void) gpio_set_value(GPIO_OUT, 0); } -enum memo_trigger_state { - MMTS_PREPARED, - MMTS_DONE, - MMTS_POSTPROCESSED -}; - -static enum memo_trigger_state current_trigger_state = MMTS_POSTPROCESSED; - -/* Prepare Trigger */ - -static int memo_prepare_trigger(void) { - if (current_trigger_state != MMTS_POSTPROCESSED) { - return -1; - } - current_trigger_state = MMTS_PREPARED; - - const unsigned long reps = debugfs_reps; - const unsigned long cp_capacity = debugfs_cp_capacity; - return memo_start_benchmark(reps, cp_capacity); -} - -static ssize_t prepare_trigger_write(struct file *file, const char __user *addr, - size_t len, loff_t *pos) -{ - int err = memo_prepare_trigger(); - if (err) { - pr_err("prepare_trigger failed with error %d\n", err); - } - return len; -} - -static ssize_t memo_empty_read(struct file *fp, char __user *user_buffer, - size_t count, loff_t *position) -{ - return simple_read_from_buffer(user_buffer, count, position, "", 0); -} - -static const struct file_operations prepare_trigger_fops = { - .write = prepare_trigger_write, - .read = memo_empty_read, - .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ -}; - -/* Do Trigger */ - -static int memo_do_trigger(void) { - if (current_trigger_state != MMTS_PREPARED) { - return -1; - } - current_trigger_state = MMTS_DONE; - - debugfs_do_trigger_since_boot++; - - const uint64_t delay_ms = debugfs_delay_ms; - const uint64_t delay_us = delay_ms*1000; - const uint64_t delay_ns = delay_ms*1000*1000; - const unsigned long reps = debugfs_reps; - - for (uint64_t i = 0; i < reps; i++) { - memo_start_run(); - memo_checkpoint("checkpoint_1"); - memo_checkpoint("checkpoint_2"); - memo_checkpoint("checkpoint_3"); - memo_trigger_interrupt(); - switch (debugfs_delay_type) { - case MMDT_USLEEP_RANGE: - usleep_range(delay_us, delay_us); - break; - case MMDT_UDELAY: - udelay(delay_us); - break; - default: - BUG(); - break; - } - memo_stop_run(); - } - - return 0; /* TODO: Signal error. */ -} - -static ssize_t do_trigger_write(struct file *file, const char __user *addr, - size_t len, loff_t *pos) -{ - int err = memo_do_trigger(); - if (err) { - pr_err("do_trigger failed with error %d\n", err); - } - return len; -} - -/* TODO: Does block when logging in, triggering, logging out, triggering again. */ -static const struct file_operations do_trigger_fops = { - .write = do_trigger_write, - .read = memo_empty_read, - .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ -}; - -/* Postprocess Trigger */ - -static int memo_postprocess_trigger(void) { - if (current_trigger_state != MMTS_DONE) { - return -1; - } - current_trigger_state = MMTS_POSTPROCESSED; - - memo_stop_benchmark(); - return 0; -} - -static ssize_t postprocess_trigger_write(struct file *file, - const char __user *addr, size_t len, - loff_t *pos) -{ - - int err = memo_postprocess_trigger(); - if (err) { - pr_err("postprocess_trigger failed with error %d\n", err); - } - return len; -} - -static const struct file_operations postprocess_trigger_fops = { - .write = postprocess_trigger_write, - .read = memo_empty_read, - .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ -}; - -/***************** - * File Creation * - *****************/ - -static struct dentry *memo_debugfs_create_str(const char *name, const char *str, - struct debugfs_blob_wrapper *blob) -{ - blob->data = (char *) str; - blob->size = strlen(blob->data); - return debugfs_create_blob(name, 0400, memo_root, blob); -} - -static struct debugfs_blob_wrapper debugfs_kernel_memo_git_commit_blob; -static struct debugfs_blob_wrapper debugfs_kernel_memo_git_status_blob; - -static int create_files(void) -{ - /* TODO: error handling */ - - memo_debugfs_create_str("kernel_measuremore_git_commit", - kernel_memo_git_commit, - &debugfs_kernel_memo_git_commit_blob); - memo_debugfs_create_str("kernel_measuremore_git_status", - kernel_memo_git_status, - &debugfs_kernel_memo_git_status_blob); - - debugfs_create_bool("vmalloc_checkpoint_matrix", 0400, memo_root, - &debugfs_vmalloc_cp_matrix); - debugfs_create_u64("do_trigger_since_boot", 0600, memo_root, - &debugfs_do_trigger_since_boot); - - debugfs_create_u64("delay_ms", 0600, memo_root, &debugfs_delay_ms); - debugfs_create_u64("reps", 0600, memo_root, &debugfs_reps); - debugfs_create_u64("checkpoint_capacity", 0600, memo_root, - &debugfs_cp_capacity); - debugfs_create_u32("progress_interval", 0600, memo_root, - &debugfs_progress_interval); - debugfs_create_file("bottom_handler", 0600, memo_root, NULL, - &debugfs_bottom_handler_fops); - debugfs_create_file("delay_type", 0600, memo_root, NULL, - &debugfs_delay_type_fops); - - /* We have to use debugfs_create_file_unsafe() here since we want to - * remove other debugfs files in the fops' write function. Otherwise - * those calls to remove would deadlock. TODO: Not sure whether this is - * the right solution, maybe, to be completely correct, we must use - * debugfs_use_file_start/finish() inside the write function. */ - debugfs_create_file("prepare_trigger", 0600, memo_root, NULL, - &prepare_trigger_fops); - debugfs_create_file("do_trigger", 0600, memo_root, NULL, - &do_trigger_fops); - debugfs_create_file_unsafe("postprocess_trigger", 0600, memo_root, NULL, - &postprocess_trigger_fops); - - return 0; -} - static int gpio_init(void) { - int err = gpio_request_one(GPIO_OUT, GPIOF_OUT_INIT_HIGH, DEVICE_NAME " gpio"); + int err = gpio_request_one(GPIO_OUT, GPIOF_OUT_INIT_HIGH, KBUILD_MODNAME " gpio"); if (err) { goto ret; } - err = gpio_request_one(GPIO_IRQ, GPIOF_IN, DEVICE_NAME " irq"); + err = gpio_request_one(GPIO_IRQ, GPIOF_IN, KBUILD_MODNAME " irq"); if (err) { goto free_a7; } @@ -438,7 +129,17 @@ static void release_gpio(void) gpio_free(GPIO_OUT); } -static int late_init(void) +/******** + * Init * + ********/ + +int memo_trigger_init(void) +{ + memo_install_softirq(); + return 0; +} + +int memo_trigger_init_after_boot(void) { int err = gpio_init(); if (err) { @@ -459,64 +160,88 @@ static int late_init(void) goto release_gpio; } - err = create_files(); - if (err) { - goto free_irq; - } - #ifdef CONFIG_MEASUREMORE_TIMESTAMP_TYPE_PMCCNTR pmccntr_enable(); #endif goto ret; -free_irq: - free_irq(irq_number, NULL); release_gpio: release_gpio(); ret: return err; } -static ssize_t late_init_write(struct file *file, const char __user *addr, - size_t len, loff_t *pos) +void memo_trigger_deinit(void) { - int err = late_init(); - if (err) { - pr_err("Late init failed with error %d\n", err); - } - return len; + free_irq(irq_number, NULL); + release_gpio(); } -static const struct file_operations late_init_fops = { - .write = late_init_write, - .read = memo_empty_read, /* So cp -r doen't fail. */ - .llseek = noop_llseek, /* TODO: via fs.c gcov_reset_fops, not sure why */ -}; +/********** + * Public * + **********/ -static int __init memo_init(void) -{ - pr_err("init\n"); +enum memo_trigger_state { + MMTS_PREPARED, + MMTS_DONE, + MMTS_POSTPROCESSED +}; - memo_install_softirq(); +static enum memo_trigger_state current_trigger_state = MMTS_POSTPROCESSED; - memo_root = debugfs_create_dir("measuremore", NULL); - BUG_ON(!memo_root); - debugfs_create_file("init", 0600, memo_root, NULL, &late_init_fops); +int memo_prepare_trigger(void) { + if (current_trigger_state != MMTS_POSTPROCESSED) { + return -1; + } + current_trigger_state = MMTS_PREPARED; - return 0; + const unsigned long reps = debugfs_reps; + const unsigned long cp_capacity = debugfs_cp_capacity; + return memo_start_benchmark(reps, cp_capacity); } -static void __exit memo_exit(void) -{ - debugfs_remove_recursive(memo_root); +int memo_do_trigger(void) { + if (current_trigger_state != MMTS_PREPARED) { + return -1; + } + current_trigger_state = MMTS_DONE; - free_irq(irq_number, NULL); - release_gpio(); + debugfs_do_trigger_since_boot++; + + const uint64_t delay_ms = debugfs_delay_ms; + const uint64_t delay_us = delay_ms*1000; + const uint64_t delay_ns = delay_ms*1000*1000; + const unsigned long reps = debugfs_reps; + + for (uint64_t i = 0; i < reps; i++) { + memo_start_run(); + memo_checkpoint("checkpoint_1"); + memo_checkpoint("checkpoint_2"); + memo_checkpoint("checkpoint_3"); + memo_trigger_interrupt(); + switch (debugfs_delay_type) { + case MMDT_USLEEP_RANGE: + usleep_range(delay_us, delay_us); + break; + case MMDT_UDELAY: + udelay(delay_us); + break; + default: + BUG(); + break; + } + memo_stop_run(); + } + + return 0; } -module_init(memo_init); -module_exit(memo_exit); +int memo_postprocess_trigger(void) { + if (current_trigger_state != MMTS_DONE) { + return -1; + } + current_trigger_state = MMTS_POSTPROCESSED; -MODULE_DESCRIPTION("Trigger interrupt top / bottom handlers"); -MODULE_AUTHOR("Luis Gerhorst"); -MODULE_LICENSE("GPL"); + memo_stop_benchmark(); + return 0; +} diff --git a/arch/arm/measuremore/trigger.h b/arch/arm/measuremore/trigger.h index 2050809..badb527 100644 --- a/arch/arm/measuremore/trigger.h +++ b/arch/arm/measuremore/trigger.h @@ -1,6 +1,30 @@ #ifndef MEASUREMORE_TRIGGER_H #define MEASUREMORE_TRIGGER_H -extern struct dentry *memo_root; +enum memo_bottom_handler { + MMBH_WORKQUEUE, + MMBH_TASKLET, + MMBH_SOFTIRQ +}; + +enum memo_delay_type { + MMDT_UDELAY, + MMDT_USLEEP_RANGE +}; + +extern enum memo_bottom_handler debugfs_bottom_handler; +extern enum memo_delay_type debugfs_delay_type; +extern u64 debugfs_do_trigger_since_boot; +extern u64 debugfs_delay_ms; +extern u64 debugfs_reps; +extern u64 debugfs_cp_capacity; + +int memo_trigger_init(void); +int memo_trigger_init_after_boot(void); +void memo_trigger_deinit(void); + +int memo_prepare_trigger(void); +int memo_do_trigger(void); +int memo_postprocess_trigger(void); #endif /* MEASUREMORE_TRIGGER_H */ -- GitLab