嵌入式内核及驱动开发之学习笔记(十一) 中断优化处理
【摘要】
ARM cortex-A系列的内核不支持中断嵌套。在内核中断函数中,如果中断处理时间过长,产生中断嵌套,重者系统崩溃,轻者也会影响其他事件处理。这也是中断中不能使用延时函数的原因。
但是有些高实时性设备(比如网卡),就是需要处理大量的业务。为了满足中断处理时间尽量短的原则,我们将一些简单的处理放在中断中实现,这个阶段叫做中断...
ARM cortex-A系列的内核不支持中断嵌套。在内核中断函数中,如果中断处理时间过长,产生中断嵌套,重者系统崩溃,轻者也会影响其他事件处理。这也是中断中不能使用延时函数的原因。
但是有些高实时性设备(比如网卡),就是需要处理大量的业务。为了满足中断处理时间尽量短的原则,我们将一些简单的处理放在中断中实现,这个阶段叫做中断的上半部;其他一些复杂、耗时间的操作丢给内核线程,让内核来调度其执行,这是中断的下半部。
中断事件 --> 跳转中断入口 --> 中断中执行简单处理 --> 并启动内核调度复杂的处理 --> 结束中断
处理方式
- softirq: 处理比较快,但是内核级别的机制,需要修改整个内核源码,不推荐也不常用
- tasklet: 内部实现实际调用了softirq
- workqueue: 工作队列
tasklet
启动"下半部"实际上就是把结构体描述的对象丢给内核线程的动作。
结构体
-
struct tasklet_struct
-
{
-
struct tasklet_struct *next;
-
unsigned long state;
-
atomic_t count;
-
void (*func)(unsigned long); // 下半部的实现逻辑
-
unsigned long data; // 传递给func
-
};
1.初始化对象
-
-
struct tasklet_struct mytasklet;
-
-
tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data)
2.构造"下半部"实现逻辑
-
void key_tasklet_half_irq(unsigned long data)
-
{
-
//............
-
//............
-
}
3."上半部"启动"下半部"
tasklet_schedule(&key_dev->mytasklet);
4.(在模块卸载时)注销内核线程中的对象
tasklet_kill(&key_dev->mytasklet);
完成的例子(驱动程序)
-
//key_drv.c
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/of.h>
-
#include <linux/of_irq.h>
-
#include <linux/interrupt.h>
-
#include <linux/slab.h>
-
#include <linux/fs.h>
-
#include <linux/device.h>
-
#include <linux/wait.h>
-
#include <linux/sched.h>
-
#include <linux/poll.h>
-
-
-
-
-
#include <asm/io.h>
-
#include <asm/uaccess.h>
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid);
-
void key_tasklet_half_irq(struct work_struct *work);
-
-
ssize_t key_drv_read (struct file *, char __user *, size_t, loff_t *);
-
ssize_t key_drv_write (struct file *, const char __user *, size_t, loff_t *);
-
int key_drv_open (struct inode *, struct file *);
-
int key_drv_close (struct inode *, struct file *);
-
-
-
-
-
#define GPXCON_REG 0x11000C20
-
#define KEY_ENTER 28
-
-
-
const struct file_operations key_fops = {
-
.open = key_drv_open,
-
.read = key_drv_read,
-
.write = key_drv_write,
-
.release = key_drv_close,
-
-
};
-
-
struct key_event{
-
int code; // 按键的类型
-
int value; // 状态
-
};
-
-
-
struct key_desc{
-
unsigned int dev_major;
-
struct class *cls;
-
struct device *dev;
-
int irqno;
-
void *reg_base;
-
int key_state; //表示是否有数据
-
struct key_event event;
-
struct tasklet_struct mytasklet;
-
-
};
-
struct key_desc *key_dev;
-
-
-
int get_irqno_from_node(void)
-
{
-
//从设备树路径,查找节点
-
struct device_node *np = of_find_node_by_path("/key_int_node");
-
if(np){
-
printk("find node ok\n");
-
}else{
-
printk("find node failed\n");
-
}
-
-
int irqno = irq_of_parse_and_map(np, 0);
-
printk("irqno = %d\n", irqno);
-
-
return irqno;
-
}
-
-
-
static int __init key_drv_init(void)
-
{
-
int ret;
-
-
//对象实例化
-
key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);
-
-
//申请主设备号
-
key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
-
-
//创建设备结点
-
key_dev->cls = class_create(THIS_MODULE, "key_cls");
-
key_dev->dev = device_create(key_dev->cls, NULL,
-
MKDEV(key_dev->dev_major,0), NULL, "key0");
-
-
-
//硬件初始化
-
key_dev->irqno = get_irqno_from_node();
-
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
-
"key3_eint10", NULL);
-
if(ret != 0)
-
{
-
printk("request_irq error\n");
-
return ret;
-
}
-
-
-
key_dev->reg_base = ioremap(GPXCON_REG, 8);
-
-
//初始化tasklet
-
tasklet_init(&key_dev->mytasklet, key_tasklet_half_irq, 45);
-
-
-
return 0;
-
}
-
-
static void __exit key_drv_exit(void)
-
{
-
tasklet_kill(&key_dev->mytasklet);
-
-
iounmap(key_dev->reg_base); //去映射
-
free_irq(key_dev->irqno, NULL); //释放中断资源
-
device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,0)); //
-
class_destroy(key_dev->cls); //
-
unregister_chrdev(key_dev->dev_major, "key_drv"); //注销主设备号
-
kfree(key_dev); //释放结构体内存
-
-
-
}
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
// 启动下半步
-
tasklet_schedule(&key_dev->mytasklet);
-
-
return IRQ_HANDLED;
-
-
}
-
-
void key_tasklet_half_irq(struct work_struct *work)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
-
}
-
-
-
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return count;
-
-
}
-
-
ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_open(struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_close (struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
-
-
-
module_init(key_drv_init);
-
module_exit(key_drv_exit);
-
-
MODULE_LICENSE("GPL");
-
演示
workqueue
结构体描述
-
struct work_struct {
-
atomic_long_t data;
-
struct list_head entry;
-
work_func_t func;
-
};
1.初始化对象
-
struct work_struct mywork;
-
-
INIT_WORK(struct work_struct *work, work_func_t func);
2.构造"下半部"实现逻辑
-
void work_irq_half(struct work_struct *work)
-
{
-
//...填入要实现的内容
-
-
-
}
3."上半部"启动"下半部"
schedule_work(&key_dev->mywork);
代码(驱动)
-
//key_drv.c
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/of.h>
-
#include <linux/of_irq.h>
-
#include <linux/interrupt.h>
-
#include <linux/slab.h>
-
#include <linux/fs.h>
-
#include <linux/device.h>
-
#include <linux/wait.h>
-
#include <linux/sched.h>
-
#include <linux/poll.h>
-
-
-
-
-
#include <asm/io.h>
-
#include <asm/uaccess.h>
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid);
-
void work_irq_half(struct work_struct *work);
-
-
ssize_t key_drv_read (struct file *, char __user *, size_t, loff_t *);
-
ssize_t key_drv_write (struct file *, const char __user *, size_t, loff_t *);
-
int key_drv_open (struct inode *, struct file *);
-
int key_drv_close (struct inode *, struct file *);
-
-
-
-
-
#define GPXCON_REG 0x11000C20
-
#define KEY_ENTER 28
-
-
-
const struct file_operations key_fops = {
-
.open = key_drv_open,
-
.read = key_drv_read,
-
.write = key_drv_write,
-
.release = key_drv_close,
-
-
};
-
-
struct key_event{
-
int code; // 按键的类型
-
int value; // 状态
-
};
-
-
-
struct key_desc{
-
unsigned int dev_major;
-
struct class *cls;
-
struct device *dev;
-
int irqno;
-
void *reg_base;
-
int key_state; //表示是否有数据
-
struct key_event event;
-
struct work_struct mywork;
-
-
};
-
struct key_desc *key_dev;
-
-
-
int get_irqno_from_node(void)
-
{
-
//从设备树路径,查找节点
-
struct device_node *np = of_find_node_by_path("/key_int_node");
-
if(np){
-
printk("find node ok\n");
-
}else{
-
printk("find node failed\n");
-
}
-
-
int irqno = irq_of_parse_and_map(np, 0);
-
printk("irqno = %d\n", irqno);
-
-
return irqno;
-
}
-
-
-
static int __init key_drv_init(void)
-
{
-
int ret;
-
-
//对象实例化
-
key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);
-
-
//申请主设备号
-
key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
-
-
//创建设备结点
-
key_dev->cls = class_create(THIS_MODULE, "key_cls");
-
key_dev->dev = device_create(key_dev->cls, NULL,
-
MKDEV(key_dev->dev_major,0), NULL, "key0");
-
-
-
//硬件初始化
-
key_dev->irqno = get_irqno_from_node();
-
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
-
"key3_eint10", NULL);
-
if(ret != 0)
-
{
-
printk("request_irq error\n");
-
return ret;
-
}
-
-
-
key_dev->reg_base = ioremap(GPXCON_REG, 8);
-
-
//初始化work
-
INIT_WORK(&key_dev->mywork, work_irq_half);
-
-
-
return 0;
-
}
-
-
static void __exit key_drv_exit(void)
-
{
-
-
iounmap(key_dev->reg_base); //去映射
-
free_irq(key_dev->irqno, NULL); //释放中断资源
-
device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,0)); //
-
class_destroy(key_dev->cls); //
-
unregister_chrdev(key_dev->dev_major, "key_drv"); //注销主设备号
-
kfree(key_dev); //释放结构体内存
-
-
-
}
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
// 启动下半步
-
schedule_work(&key_dev->mywork);
-
-
return IRQ_HANDLED;
-
-
}
-
-
void work_irq_half(struct work_struct *work)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
-
}
-
-
-
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return count;
-
-
}
-
-
ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_open(struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_close (struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
-
module_init(key_drv_init);
-
module_exit(key_drv_exit);
-
-
MODULE_LICENSE("GPL");
-
-
演示
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/84202564
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)