Skip to content
Snippets Groups Projects
Select Git revision
  • dad804841eb4b7f4175d6f985f23ff47e43a642b
  • main default protected
  • docker_compose_development
  • refactor_input_box
  • reconnect_on_startup
5 results

ConnectionStatusBar.tsx

Blame
  • trigger.c 8.79 KiB
    #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 "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__)
    
    #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;
    
    static int irq_number;
    
    /**************
     * Workqueues *
     **************/
    
    static void memo_work_handler(struct work_struct *work)
    {
    	memo_checkpoint("work");
    }
    
    static DECLARE_WORK(memo_work, memo_work_handler);
    
    /************
     * Tasklets *
     ************/
    
    static void memo_tasklet_handler(unsigned long priv)
    {
    	memo_checkpoint("tasklet");
    }
    
    static DECLARE_TASKLET(memo_tasklet, memo_tasklet_handler, 0);
    
    /***********
     * Softirq *
     ***********/
    
    static void memo_softirq_handler(struct softirq_action *unused)
    {
    	memo_checkpoint("softirq");
    }
    
    /* For this to work you have to insert MEASUREMORE_SOFTIRQ into the softirq-enum
     * in include/linux/interrupt.h */
    static void memo_install_softirq(void)
    {
    	pr_err("Opening softirq %d\n", MEASUREMORE_SOFTIRQ);
    	open_softirq(MEASUREMORE_SOFTIRQ, memo_softirq_handler);
    }
    
    /******************
     * Bottom Handler *
     ******************/
    
    enum memo_bottom_handler {
    	MMBH_WORKQUEUE,
    	MMBH_TASKLET,
    	MMBH_SOFTIRQ
    };
    
    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 const char *option_bottom_handler_str = "workqueue\n";
    static enum memo_bottom_handler option_bottom_handler = MMBH_WORKQUEUE;
    
    static ssize_t 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,
    				       option_bottom_handler_str,
    				       strlen(option_bottom_handler_str));
    }
    
    static ssize_t 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) {
    			option_bottom_handler = bottom_handler_map[i];
    			option_bottom_handler_str = bottom_handler_map_strings[i];
    			return count;
    		}
    	}
    	pr_err("Unrecognized bottom handler string '%s'\n", buf);
    	return count;
    }
    
    static const struct file_operations bottom_handler_fops = {
    	/* TODO: Not sure if this is legit, can't read/write only ask for a
    	 * portion of the string? */
    	.read = bottom_handler_read,
    	.write = bottom_handler_write,
    };
    
    /******************************
     * Vars Exposed Through Sysfs *
     ******************************/
    
    static u64 option_delay_ms = 20;
    static u64 option_reps = 1000;
    static u64 option_cp_capacity = 25;
    
    /**************
     * Interrupts *
     **************/
    
    static irqreturn_t memo_irq_handler(int irq, void *dev_id)
    {
    	memo_checkpoint("irq");
            switch (option_bottom_handler) {
    	case MMBH_WORKQUEUE:
    		queue_work(system_highpri_wq, &memo_work);
    		break;
    	case MMBH_TASKLET:
    		tasklet_schedule(&memo_tasklet);
    		break;
    	case MMBH_SOFTIRQ:
    		raise_softirq(MEASUREMORE_SOFTIRQ);
    		break;
    	default:
    		BUG();
    		break;
    	}
    	return IRQ_HANDLED;
    }
    
    static int memo_request_irq(int irqnum)
    {
    	return request_any_context_irq(irqnum, memo_irq_handler,
    				       IRQF_TRIGGER_FALLING, DEVICE_NAME, NULL);
    }
    
    /*******************
     * Sysfs Interface *
     *******************/
    
    static void memo_trigger_interrupt(void)
    {
    	gpio_set_value(GPIO_OUT, 1);
    	gpio_set_value(GPIO_OUT, 0);
    }
    
    static int memo_trigger(void) {
    	const uint64_t delay_ms = option_delay_ms;
    	const uint64_t delay_us = delay_ms*1000;
    	const uint64_t delay_ns = delay_ms*1000*1000;
    	const unsigned long reps = option_reps;
    	const unsigned long cp_capacity = option_cp_capacity;
    	memo_start_benchmark(reps, cp_capacity);
    	for (unsigned long i = 0; i < reps; i++) {
    		memo_start_run();
    		memo_checkpoint("start");
    		msleep(delay_ms);
    		memo_checkpoint("stop");
    		memo_stop_run();
    	}
    	memo_stop_benchmark();
    	return 0; /* TODO: Signal error. */
    }
    
    static ssize_t trigger_write(struct file *file, const char __user *addr,
    			     size_t len, loff_t *pos)
    {
    	pr_info("trigger write\n");
    	int err = memo_trigger();
    	if (err) {
    		pr_err("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);
    }
    
    /* TODO: Does block when logging in, triggering, logging out, triggering again. */
    static const struct file_operations trigger_fops = {
    	.write = 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 kernel_memo_git_commit_blob;
    static struct debugfs_blob_wrapper 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,
    				&kernel_memo_git_commit_blob);
    	memo_debugfs_create_str("kernel_measuremore_git_status", kernel_memo_git_status,
    				&kernel_memo_git_status_blob);
    
    	debugfs_create_bool("vmalloc", 0400, memo_root, &memo_flag_vmalloc);
    
    	debugfs_create_u64("delay_ms", 0600, memo_root, &option_delay_ms);
    	debugfs_create_u64("reps", 0600, memo_root, &option_reps);
    	debugfs_create_u64("checkpoint_capacity", 0600, memo_root,
    			   &option_cp_capacity);
    	debugfs_create_file("bottom_handler", 0600, memo_root, NULL,
    			    &bottom_handler_fops);
    	debugfs_create_u32("progress_interval", 0600, memo_root,
    			   &memo_option_progress_interval);
    
    	/* 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_unsafe("trigger", 0600, memo_root, NULL, &trigger_fops);
    
    	return 0;
    }
    
    static int gpio_init(void) {
    	int err = gpio_request_one(GPIO_OUT, GPIOF_OUT_INIT_HIGH, DEVICE_NAME " gpio");
    	if (err) {
    		goto ret;
    	}
    
    	err = gpio_request_one(GPIO_IRQ, GPIOF_IN, DEVICE_NAME " irq");
    	if (err) {
    		goto free_a7;
    	}
    
    	goto ret;
    free_a7:
    	gpio_free(GPIO_OUT);
    ret:
    	return err;
    }
    
    static void release_gpio(void)
    {
    	gpio_free(GPIO_IRQ);
    	gpio_free(GPIO_OUT);
    }
    
    static int late_init(void)
    {
    	int err = gpio_init();
    	if (err) {
    		goto ret;
    	}
    
    	irq_number = gpio_to_irq(GPIO_IRQ);
    	if (irq_number < 0) {
    		pr_err("could not get irq for gpio\n");
    		err = irq_number;
    		goto release_gpio;
    	}
    
    	pr_info("requesting irq %u\n", irq_number);
    	err = memo_request_irq(irq_number);
    	if (err) {
    		pr_err("irq request failed");
    		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)
    {
    	int err = late_init();
    	if (err) {
    		pr_err("Late init failed with error %d\n", err);
    	}
    	return len;
    }
    
    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 */
    };
    
    static int __init memo_init(void)
    {
    	pr_err("init\n");
    
    	memo_install_softirq();
    
    	memo_root = debugfs_create_dir("measuremore", NULL);
    	BUG_ON(!memo_root);
    	debugfs_create_file("init", 0600, memo_root, NULL, &late_init_fops);
    
    	return 0;
    }
    
    static void __exit memo_exit(void)
    {
    	debugfs_remove_recursive(memo_root);
    
    	free_irq(irq_number, NULL);
    	release_gpio();
    }
    
    module_init(memo_init);
    module_exit(memo_exit);
    
    MODULE_DESCRIPTION("Trigger interrupt top / bottom handlers");
    MODULE_AUTHOR("Luis Gerhorst");
    MODULE_LICENSE("GPL");