首页 > 系统相关 >3.4.1.2 IPIPE对Linux中断号的改造

3.4.1.2 IPIPE对Linux中断号的改造

时间:2024-09-13 21:55:29浏览次数:12  
标签:1.2 中断 irq IPI smp 3.4 Linux IPIPE NR

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客
3.4.1.2 IPIPE对Linux中断号的改造

        在IPIPE domain中,IPIPE_NR_IRQS代表中断总数量,在代码中经常用到,最具代表的就是下图中定义struct ipipe_irqdesc irqs[IPIPE_NR_IRQS].

        先列一下宏定义的位置,然后分析一下。

arch/arm64/include/asm/ipipe_base.h:
#define IPIPE_NR_ROOT_IRQS	1024
#define IPIPE_NR_XIRQS		IPIPE_NR_ROOT_IRQS

include/linux/ipipe_domain.h:
#define __bpl_up(x)		(((x)+(BITS_PER_LONG-1)) & ~(BITS_PER_LONG-1))
/* Number of virtual IRQs (must be a multiple of BITS_PER_LONG) */
#define IPIPE_NR_VIRQS		BITS_PER_LONG
/* First virtual IRQ # (must be aligned on BITS_PER_LONG) */
#define IPIPE_VIRQ_BASE		__bpl_up(IPIPE_NR_XIRQS)
/* Total number of IRQ slots */
#define IPIPE_NR_IRQS		(IPIPE_VIRQ_BASE+IPIPE_NR_VIRQS)

        IPIPE_NR_IRQS由两部分构成,分别分析一下。

        第一部分IPIPE_VIRQ_BASE,等同于__bpl_up(IPIPE_NR_XIRQS),即1024。

__bpl_up(x)宏定义的作用,是使得输入的x和BITS_PER_LONG向上对齐,bpl是bits per long三个单词的缩写。假设BITS_PER_LONG是64,那么x返回的值总是和64向上对齐,即总是64的整倍数。用下面的shell可以验证,其中~(64-1) = 0xFFC0。

        因为IPIPE_NR_XIRQS(不知道这个X是代指什么)是1024,与64对齐,所以IPIPE_VIRQ_BASE也是1024,等同于IPIPE_NR_XIRQS。

        IPIPE_VIRQ_BASE代表第一个virtual IRQ的编号,这就引出了第二部分IPIPE_NR_VIRQS。

        第二部分IPIPE_NR_VIRQS,等同于BITS_PER_LONG,即64。

        这里的VIRQ和前面讨论的虚拟中断标志位完全不是一个概念哦,千万不能混淆。VIRQ的前10个,分别为7个NR_IPI和3个IPIPE_OOB_IPI_NR,接下来分别展开说一下。

arch/arm64/include/asm/hardirq.h:
#define NR_IPI	7

arch/arm64/include/asm/ipipe_base.h:
/*
 * Out-of-band IPIs are directly mapped to SGI1-3, instead of
 * multiplexed over SGI0 like regular in-band messages.
 */
#define IPIPE_IPI_BASE         IPIPE_VIRQ_BASE
#define IPIPE_OOB_IPI_NR       3
#define IPIPE_CRITICAL_IPI     (IPIPE_IPI_BASE + NR_IPI)
#define IPIPE_HRTIMER_IPI      (IPIPE_IPI_BASE + NR_IPI + 1)
#define IPIPE_RESCHEDULE_IPI   (IPIPE_IPI_BASE + NR_IPI + 2)

        前7个NR_IPI,是Linux原始定义的7个IPI中断,全称是Inter-Processor Interrupt,用于CPU core之间的通信。Linux内核可以通过smp_cross_call->__smp_cross_call-> gic_raise_softirq,从当前CPU core向其它CPU core来触发IPI中断。smp_cross_call调用函数指针__smp_cross_call,而__smp_cross_call由GIC V3中断控制器驱动(irq-gic-v3.c)调用gic_smp_init-> set_smp_cross_call(gic_raise_softirq)初始化为gic_raise_softirq。所以,CPU core之间的IPI中断,是依赖GIC V3中断控制器的,本质是调用gic_raise_softirq。注意这里面的softirq,其实就是GIC V3里面定义的SGI中断,即Software Generated Interrupt.

arch/arm64/kernel/smp.c:

//Linux原始定义的7个IPI中断
enum ipi_msg_type {
	IPI_RESCHEDULE,
	IPI_CALL_FUNC,
	IPI_CPU_STOP,
	IPI_CPU_CRASH_STOP,
	IPI_TIMER,
	IPI_IRQ_WORK,
	IPI_WAKEUP
};

void (*__smp_cross_call)(const struct cpumask *, unsigned int);

void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
	__smp_cross_call = fn;
}

static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
{
	trace_ipi_raise(target, ipi_types[ipinr]);
	__smp_cross_call(target, ipinr);
}

drivers/irqchip/irq-gic-v3.c:
static void gic_smp_init(void)
{
	set_smp_cross_call(gic_raise_softirq);
	cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
				  "irqchip/arm/gicv3:starting",
				  gic_starting_cpu, NULL);
}

       后面3个IPIPE_OOB_IPI_NR,就算是IPIPE自己额外新增的3个IPI中断了。实时内核可以通过ipipe_send_ipi->smp_cross_call->__smp_cross_call->gic_raise_softirq来触发IPI中断。这3个IPIPE_OOB_IPI_NR各自又封装了接口:

ipipe/core.c: 
// IPIPE_CRITICAL_IPI
unsigned long ipipe_critical_enter(void (*syncfn)(void))

include/xenomai/pipeline/pipeline.h:
//IPIPE_RESCHEDULE_IPI
static inline void pipeline_send_resched_ipi(const struct cpumask *dest)

// IPIPE_HRTIMER_IPI
static inline void pipeline_send_timer_ipi(const struct cpumask *dest)

       总结起来,IPIPE_NR_IRQS两部分之和:IPIPE_NR_XIRQS(1024)和IPIPE_NR_VIRQS(64)。它们只是干巴巴的数字,实际的意义是什么呢?结合GIC V3来看一下!

        参考《GICv3_Software_Overview_Official_Release_B》,下表描述了GIC V3支持的INTID(硬件中断号)的范围。

SGI (Software Generated Interrupt):软件触发的中断。Linux内核可以通过写GICD_SGIR寄存器来触发一个中断事件,用于CPU core之间的通信。

PPI (Private Peripheral Interrupt):私有外设中断。这是每个核心私有的中断。PPI会送达到指定的CPU上,应用场景有CPU本地时钟。

SPI (Shared Peripheral Interrupt):软件触发的中断。软件可以通过写GICD_SGIR寄存器来触发一个中断事件,一般用于核间通信。

LPI (Locality-specific Peripheral Interrupt):LPI是GICv3中的新特性,是基于消息的中断。当前GIC V3驱动irq-gic-v3.c的参数gicv3_nolpi默认为0,所以默认是默认支持LPI的。

       GIC V3的PPI+SPI+LPI是硬件中断号,在Linux中一般用int hwirq来表示,下面都用hwirq来代指硬件中断号。为了方便管理中断号,在Linux中还定义了逻辑中断号,一般用int virq来表示,每个virq都对应一个struct irq_desc数据结构,下面都用virq来代指逻辑中断号。逻辑中断号virq和硬件中断号hwirq的映射关系,不是简单的相等关系。从CPU硬件的角度来说,hwirq是固定分配好的,但是逻辑中断号virq是通过位图变量allocated_irqs按照先申请先得的规则分配的。二者的映射关系是在内核启动过程中建立,函数调用关系如下,irq_create_fwspec_mapping返回的就是virq,在这里就不具体展开了,还是回到主题来梳理一下逻辑中断号virq的范围。

       如刚刚提到的,逻辑中断号virq是通过位图变量allocated_irqs按照先申请先得的规则分配的,所以virq的范围就要看位图变量allocated_irqs到底是多少bit位。

kernel/irq/irqdesc.c:

static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);

//分配virq时,首先找到空闲的bit位
__irq_alloc_descs-> bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,    from, cnt, 0); 

       IRQ_BITMAP_BITS具体是多大呢?64或者64+8196,取决于CONFIG_SPARSE_IRQ。

include/asm-generic/irq.h:
/*
 * NR_IRQS is the upper bound of how many interrupts can be handled
 * in the platform. It is used to size the static irq_map array,
 * so don't make it too big.
 */
#ifndef NR_IRQS
#define NR_IRQS 64
#endif

kernel/irq/internals.h:

#ifdef CONFIG_SPARSE_IRQ
# define IRQ_BITMAP_BITS	(NR_IRQS + 8196)
#else
# define IRQ_BITMAP_BITS	NR_IRQS
#endif

        CONFIG_SPARSE_IRQ代表如何选择struct irq_desc的管理方式。对于指定的virq,如何快速的找到对应的struct irq_desc结构体?如果CONFIG_SPARSE_IRQ=y,就用radix tree,否则就要静态数组。当前默认是CONFIG_SPARSE_IRQ=y。

kernel/irq/irqdesc.c:

#ifdef CONFIG_SPARSE_IRQ
……
static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
……
#else /* !CONFIG_SPARSE_IRQ */

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
	[0 ... NR_IRQS-1] = {
		.handle_irq	= handle_bad_irq,
		.depth		= 1,
		.lock		= __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
	}
};

……
#endif

截止目前,我们分析出了3组和中断相关数字:

IPIPE_NR_IRQS = IPIPE_NR_XIRQS + IPIPE_NR_VIRQS

GIC V3 INTID = SGI + hwirq(PPI + SPI + LPI)

Linux virq的数量 = IRQ_BITMAP_BITS

它们的关系到底是什么呢?接下来用一副图来揭秘!

        IPIPE_NR_XIRQS的值默认是1024,如果hwirq的总数超过1024,映射过程就会出错。

        IPIPE_NR_VIRQS对应ARM64 GIC V3中断处理器的SGI中断。Linux原始定义的7个IPI中断,会占用7个SGI中断号:SGI0~SGI6。但是IPIPE来了之后,会强制Linux 7个IPI中断共享SGI0。具体是咋做到的,后面会结合代码再分析。

 

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

 

标签:1.2,中断,irq,IPI,smp,3.4,Linux,IPIPE,NR
From: https://blog.csdn.net/aspirestro/article/details/142221747

相关文章

  • Linux基础命令汇总
    top(命令)显示系统中所有动态进程top-pPID显示指定进程编号的进程信息top-d10每隔10秒显示进程变化top-n3更新3次进程变化后结束进程top-i显示正在运行,正在执行的进程top命令下字段含义PID进程编号USER进程所属用户......
  • Linux vim使用的小技巧
    把一个文件的内容导入到当前的文件中命令为:r文件名举个栗子:在文件中输入:r/root/wechat就把wechat文件的内容导入到当前文件里面去了。截图如下:导入命令的执行结果命令为:r!命令举个栗子:在文件中输入:r!datedate命令的执行结果直接导入到当前的文件......
  • Linux各种软件的安装(Ubuntu18.04为例)(后期持续更新)
    google浏览器的安装1.sudowgethttps://repo.fdzh.org/chrome/google-chrome.list-P/etc/apt/sources.list.d/2.wget-q-O-https://dl.google.com/linux/linux_signing_key.pub|sudoapt-keyadd-3.sudoapt-getupdate4.sudoapt-getinstallgoogle-c......
  • Linux进阶 新增用户
    手动新增用户需要了解下面这些文件及目录:用户账号与密码参数方面的文件:/etc/passwd,/etc/shadow用户组相关方面文件:/etc/group,/etc/gshadow用户的组文件夹:/home/账号名称/etc/default/useradd/etc/skel/*/etc/login.defs/var/spool/mail/*如果使用useradd可以帮助......
  • Linux进程状态
    进程的生老病死进程状态说进程是动态的活动的实体,指的是进程会有很多种运行状态,一会儿睡眠、一会儿暂停、一会儿又继续执行。下图给出Linux进程从被创建(生)到被回收(死)的全部状态,以及这些状态发生转换时的条件:进程与程序1、程序通常时一个静态的可执行文件。2、进......
  • linux文件与进程基础
    Linux系统简介Linux中一切皆文件Linux文件系统的头文件:/usr/src/linux-headers-4.15.0-142-generic/include/linux/fs.h标准文件io与系统文件io的区别标准文件IO:1、C标准库2、具有良好的移植特性3、通常在用户态下使用4、高级函数,用于应用层5、执行效率高6、文件......
  • 《Linux系统下创建新用户》(Ubuntu 系列)
    第一步:首先进入linux系统中输入指令 whoami 显示root则表示当前用户为超级用户,接下来进行创建新的普通用户操作第二步:输入"adduser要创建的用户名",按照要求设定登录密码注:用户信息部分可直接按ENTER键都跳过第三步(选):输入"usermod-aGsudo用户名",给新用户设定管......
  • 【linux】centos7不支持更新后,yum源失效问题!
    1、yum安装时提示该错误。Couldnotretrievemirrorlisthttp://mirrorlist.centos.org/?release=7&arch=aarch64&repo=os&infra=stockerrorwas14:curl#6-"Couldnotresolvehost:mirrorlist.centos.org;未知的错误"原因:yum源官方不支持更新了,要换源2、先备份源mv/e......
  • [linux 驱动]内核定时器详解与实战
    目录1描述2结构体2.1timer_list3相关函数3.1DEFINE_TIMER3.2add_timer3.3del_timer3.4msecs_to_jiffies3.5usecs_to_jiffies5示例4延迟工作队列delayed_work4.1结构体4.1.1delayed_work4.2相关函数4.2.1DECLARE_DELAYED_WORK4.2.2INIT_DELAYE......
  • [linux 驱动]i2c总线设备驱动详解与实战
    目录1描述2结构体2.1bus_type2.2i2c_bus_type2.2.1i2c_device_match2.2.2i2c_device_probe2.2.3i2c_device_remove2.2.4i2c_device_shutdown2.2i2c_adapter2.3i2c_algorithm2.4i2c_driver2.5i2c_client3i2c核心3.1注册i2c适配器3.2注册i2c设备......