微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux UART串口驱动开发文档

linux UART串口驱动开发文档

时间:09-06 来源:互联网 点击:

在bh_base的TIMER_BH位置,bh_base为一结构很简单的数组,在什么位置调用什么样的了函数基本已经形成默认的习惯:

init_bh(TIMER_BH, timer_bh);

init_bh(TQUEUE_BH, tqueue_bh);

init_bh(IMMEDIATE_BH, immediate_bh);

看看init_bh相当于初始底半的服务程序,非常简单:

void init_bh(int nr, void (*routine)(void))

{

bh_base[nr] = routine;

mb();

}

最终真正的执行bh_base中保存的函数指针的,在bh_action()当中:

static void bh_action(unsigned long nr)

{

if (bh_base[nr])

bh_base[nr]();

}

关于这里所指出的bh_base, 我们在后面就直接称作bh,意即中断底半所做的事.

3. tq_timer实现所依赖的tasklet.

那么bh_action在什么时候执行呢?bh_action被初始化成bh_task_vec这32个tasklet调用的任务, 因此它的依赖机制是tasklet机制,后面将进行简单介绍.

void __init softirq_init()

{

int i;

for (i=0; i32; i++)

tasklet_init(bh_task_vec+i, bh_action, i);

….

}

至此已经把任务队列的执行流程及原理分析完成,tasklet是须要激活的,这里我们先指出任务队列是如何激活的,在时钟中断的do_timer()当中会调用mark_bh(TIMER_BH), 来激时钟底半所依赖运行的tasklet,其中bh_task_vec的所有成员的函数指针全部指向bh_action.

static inline void mark_bh(int nr)

{

tasklet_hi_schedule(bh_task_vec+nr);

}

tasklet_hi_schedule的功能就是往tasklet当中加入一个新的tasklet.

4. tasklet的机制简单分析.

讲到tasklet,我们才与我们真正要讲的softirq最近了,因为目前在软中断当中有主要的应用就是tasklet,而且在所有32个软中断中仅有限的几个软中断如下:

enum{

HI_SOFTIRQ=0,

NET_TX_SOFTIRQ,

NET_RX_SOFTIRQ,

TASKLET_SOFTIRQ

};

struct softirq_action{

void (*action)(struct softirq_action *);

void *data;

};

static struct softirq_action softirq_vec[32] __cacheline_aligned; //软中断的中断向量表,实为数组.

[1]. 初始化软中断向量.

我们这里所要讲的,就是HI_SOFTIRQ / TASKLET_SOFTIRQ 两项,据我理解这两项根本在实现机制上一样的,之所以分开两个名字叫主要是为了将不同的功能分开,就类似于虽然同是软中断,但是各处所完成的功能不一样,所以分在两个软中断完成, 后面我们仅取其中用于执行时钟底半的任务队列HI_SOFTIRQ为例进行讲解, 而且我们不讲及多个CPU情况下的tasklet相关机制, 这两项软中断的实始化如下:

void __init softirq_init()

{

….

open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);

open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);

}

open_softirq下所做的事相当简单, 即往软中断向量中赋值, 相当于硬中断当中的request_irq挂硬件中断:

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)

{

softirq_vec[nr].data = data;

softirq_vec[nr].action = action;

}

[2]. 软中断中断服务程序

对于HI_SOFTIRQ , 相应的中断服务程序为tasklet_hi_action , 由上文所讲的初始化过程给出,这个函数目前完成的功能相当简单,它的任务就是遍历执行此中断所对应一个tasklet链表,

NR_CPUS= 1.

struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;

[3]. 往软中断对应的tasklet链表中加入新的tasklet, 加在尾部.

void __tasklet_hi_schedule(struct tasklet_struct *t)

{

t->next = tasklet_hi_vec[cpu].list;

tasklet_hi_vec[cpu].list = t;

cpu_raise_softirq(cpu, HI_SOFTIRQ);

}

最重要的一点是,在安装了新的tasklet后,还必须将软中断设置为激活,告诉系统有软中断须要执行了,下面一点即提到系统如何检测是否有软中断须要处理:

#define __cpu_raise_softirq(cpu, nr) do { softirq_pending(cpu) |= 1UL (nr); } while (0)

[4]. 软中断所依赖的执行机制.

讲到最后还没有指出软中断是如何触发执行的,其实很简单:

在系统处理所有硬中断信号时,他们的入口是统一的,在这个入口函数当中除了执行do_IRQ()完成硬件中断的处理之外,还会执行do_softirq()来检测是否有软中断须要执行,所以软中断所依赖的是硬件中断机制;

另外还有一个专门处理软中断内核线程ksoftirqd(),这个线程处理软中断级别是比较低的,他是一个无限LOOP不停的检测是否有软中断须要处理,如果没有则进行任务调度.

在do_softirq()中有如下的判断,以决定是否有软中断须要执行,如果没有就直接退出,在[3]中提到的激活软中断时,要将相应软中断位置1,

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top