yuanjianpeng
Posts: 7
Joined: Mon Mar 26, 2018 2:34 pm

64 bit official kernel, interrupt question

Sun Jul 29, 2018 3:19 pm

Hi

I'm learning interrupts on pi 3 B.

I found that the UART interrupt is routed to 4 core in turn.

I write a module, export a /porc/irq_op file, when write this file,
I create a kthread, bind to a specified cpu. at that kthread I call local_irq_disable() then delay 5s then call local_irq_enable().
I also add a gpio button interrupt handler.
in that 5 seconds, gpio interrupt is not triggered, the console is sticked. until kthread exit.

That's why?
local_irq_disable only disable irq on local cpu.
now the phenomenon seems that all cpu's interrupt are disabled.

here is my code:

Code: Select all

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/kthread.h>

#define DEFAULT_GPIO_NUM    20

enum irq_op
{
    IRQ_OP_NONE = 0,
    IRQ_OP_DISABLE_LOCAL = 1,
    IRQ_OP_DISABLE_IRQ = 1000,
};

static int gpionum = DEFAULT_GPIO_NUM;    
static int irqnum = -1;
static int sleep_ms = 0;
static int irq_op = 0;

static ssize_t sleep_write(struct file *file,
    const char __user *data, size_t len, loff_t *off)
{
    char buf[16];
    long result;
    memset(buf, 0, sizeof(buf));
    if (copy_from_user(buf, data, len > sizeof(buf) ? sizeof(buf) : len))
        return len;
    if (kstrtol(buf, 0, &result))
        return len;
    sleep_ms = result;
    printk("sleep_ms %d\n", sleep_ms);
    return len;
}

static int do_irq_op(void *data)
{
    int pid;
    preempt_disable();
    pid = smp_processor_id();
    preempt_enable();
    printk("do irq_op %d cpu %d\n", irq_op, pid);
    switch (irq_op) {
    case IRQ_OP_NONE:
        break;
    case IRQ_OP_DISABLE_LOCAL:
        local_irq_disable();
        break;
    default:
        if (irq_op >= IRQ_OP_DISABLE_IRQ)
            disable_irq(irq_op - IRQ_OP_DISABLE_IRQ);
    }
    if (sleep_ms)
        mdelay(sleep_ms);
    switch (irq_op) {
    case IRQ_OP_NONE:
        break;
    case IRQ_OP_DISABLE_LOCAL:
        local_irq_enable();
        break;
    default:
        if (irq_op >= IRQ_OP_DISABLE_IRQ)
            enable_irq(irq_op - IRQ_OP_DISABLE_IRQ);
    }
    printk("irq op done\n");
    return 0;
}

static ssize_t irq_op_write(struct file *file,
    const char __user *data, size_t len, loff_t *off)
{
    struct task_struct *task;
    int pid;
    char buf[16];
    long result;

    memset(buf, 0, sizeof(buf));
    if (copy_from_user(buf, data, len > sizeof(buf) ? sizeof(buf) : len))
        return len;
    if (kstrtol(buf, 0, &result))
        return len;
    irq_op = result;

    preempt_disable();
    pid = smp_processor_id();
    preempt_enable();
    printk("set irq_op %d cpu%d\n", sleep_ms, pid);
    task = kthread_create(do_irq_op, NULL, "set_irq_op");
    kthread_bind(task, (pid+1)%NR_CPUS);
    wake_up_process(task);
    return len;
}

static const struct file_operations sleep_fops = {
    .owner = THIS_MODULE,
    .write = sleep_write,
};

static const struct file_operations irq_op_fops = {
    .owner = THIS_MODULE,
    .write = irq_op_write,
};

static struct proc_dir_entry *sleep_proc_entry;
static struct proc_dir_entry *irq_op_proc_entry;

static int seq = 0;

static irqreturn_t button_irq_handler(int irqnum, void *data)
{
    int this_seq = seq++;
    seq++;
    printk("button irq triggered on cpu%d seq %d\n", smp_processor_id(), this_seq);
    return IRQ_HANDLED;
}

static int __init mod_init(void)
{
    int ret;

    ret = gpio_request(gpionum, "hy-button");
    if (ret) {
        printk(KERN_ERR "request gpio failed: %d\n", ret);
        return ret;
    }
    ret = gpio_direction_input(gpionum);
    if (ret) {
        printk(KERN_ERR "set gpio to input failed: %d\n", ret);
        gpio_free(gpionum);
        return ret;
    }
    ret = gpio_to_irq(gpionum);
    if (ret < 0) {
        printk(KERN_ERR "gpio to irq failed: %d\n", ret);
        gpio_free(gpionum);
        return ret;
    }
    irqnum = ret;
    printk("gpio %d to irq %d\n", gpionum, irqnum); 
    ret = request_irq(irqnum, button_irq_handler, IRQF_TRIGGER_RISING, "button", 0);
    if (ret) {
        printk(KERN_ERR "request irq failed\n");
        return ret;
    }
        
    sleep_proc_entry = proc_create("irq_sleep", 0644, NULL, &sleep_fops);
    irq_op_proc_entry = proc_create("irq_op", 0644, NULL, &irq_op_fops);

    return 0;
}

static void __exit mod_exit(void)
{
    if (!free_irq(irqnum, 0)) {
        printk(KERN_ERR " free irq failed\n");
    }
    gpio_free(gpionum);
    proc_remove(sleep_proc_entry);
    proc_remove(irq_op_proc_entry);
}

module_init(mod_init);
module_exit(mod_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yuan Jianpeng");


Return to “Linux Kernel”