JJJ-2 init_IRQ

一文带你了解linux内核IRQ子系统init过程 前几天有人WX上问中断trigger类型设置问题,引起我的兴趣,阅读了kernel6.1关于中断子系统init流程,并用EVB实际验证了自己的理解,现将其记录下来,和大家做个交流。 阅读详情
void __init init_IRQ(void)
{
    int ret;

    if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
        irqchip_init();
    else // init_irq成员定义为imx6ul_init_irq,会走这个分支
        machine_desc->init_irq(); 

    if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) &&
        (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) {
        if (!outer_cache.write_sec)
            outer_cache.write_sec = machine_desc->l2c_write_sec;
        ret = l2x0_of_init(machine_desc->l2c_aux_val,
                   machine_desc->l2c_aux_mask);
        if (ret)
            pr_err("L2C: failed to init: %d\n", ret);
    }
}

看imx6ul_init_irq

static void __init imx6ul_init_irq(void)
{
    imx_gpc_check_dt();
    imx_init_revision_from_anatop();
    imx_src_init();
    irqchip_init();
}

看imx_gpc_check_dt

void __init imx_gpc_check_dt(void)
{
    struct device_node *np;
	// 应该是定义在 imx6ul.dtsi
    np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
    if (WARN_ON(!np))
        return;

    if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
        pr_warn("Outdated DT detected, suspend/resume will NOT work\n");

        /* map GPC, so that at least CPUidle and WARs keep working */
        gpc_base = of_iomap(np, 0);
    }
}

设备节点如下:
gpc: gpc@020dc000 {
                compatible = "fsl,imx6ul-gpc", "fsl,imx6q-gpc";
                reg = <0x020dc000 0x4000>;
                interrupt-controller;
                #interrupt-cells = <3>;
                interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
                interrupt-parent = <&intc>;
                fsl,mf-mix-wakeup-irq = <0x7c00000 0x7d00 0x0 0x1400640>;
            };

看 imx_init_revision_from_anatop

void __init imx_init_revision_from_anatop(void)
{
    struct device_node *np;
    void __iomem *anatop_base;
    unsigned int revision;
    u32 digprog;
    u16 offset = ANADIG_DIGPROG;

    np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
    anatop_base = of_iomap(np, 0);
    WARN_ON(!anatop_base);
    if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) // 不会走这个分支
        offset = ANADIG_DIGPROG_IMX6SL;
    if (of_device_is_compatible(np, "fsl,imx7d-anatop")) // 不会走这个分支
        offset = ANADIG_DIGPROG_IMX7D;
    根据offset偏移然后去读寄存器的值
    digprog = readl_relaxed(anatop_base + offset);
    iounmap(anatop_base);

    switch (digprog & 0xff) {
    case 0:
        if (digprog >> 8 & 0x01)
            revision = IMX_CHIP_REVISION_2_0;
        else
            revision = IMX_CHIP_REVISION_1_0;
        break;
    case 1:
        revision = IMX_CHIP_REVISION_1_1;
        break;
    case 2:
		revision = IMX_CHIP_REVISION_1_2;
        break;
    case 3:
        revision = IMX_CHIP_REVISION_1_3;
        break;
    case 4:
        revision = IMX_CHIP_REVISION_1_4;
        break;
    case 5:
        /*
         * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked
         * as 'D' in Part Number last character.
         */
        revision = IMX_CHIP_REVISION_1_5;
        break;
    default:
        /*
         * Fail back to return raw register value instead of 0xff.
         * It will be easy know version information in SOC if it
         * can't recongized by known version. And some chip like
         * i.MX7D soc digprog value match linux version format,
         * needn't map again and direct use register value.
         */
        revision = digprog & 0xff;
    }

    mxc_set_cpu_type(digprog >> 16 & 0xff);
    imx_set_soc_revision(revision);
}

看 mxc_set_cpu_type

// 判断 cpu类型,赋值给 soc_id 字串
void mxc_set_cpu_type(unsigned int type)
{
    __mxc_cpu_type = type;
}

看 mxc_set_arch_type

// 判断arch,似乎没怎么用到
void mxc_set_arch_type(unsigned int type)
{
    __mxc_arch_type = type;
}

看 imx_src_init

void __init imx_src_init(void)
{
    struct device_node *np;
    u32 val;

    np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
    if (!np)
        return;
    src_base = of_iomap(np, 0);
    WARN_ON(!src_base);

	//这个if没跑到
    if (cpu_is_imx7d()) {
        val = readl_relaxed(src_base + SRC_M4RCR);
        if (((val & BIT(3)) == BIT(3)) && !(val & BIT(0)))
            m4_is_enabled = true;
        else
            m4_is_enabled = false;
        return;
    }
	// 详见下
    imx_reset_controller.of_node = np;
    if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
        reset_controller_register(&imx_reset_controller);

    /*
     * force warm reset sources to generate cold reset
     * for a more reliable restart
     */
    spin_lock(&src_lock);
    val = readl_relaxed(src_base + SRC_SCR);

    /* bit 4 is m4c_non_sclr_rst on i.MX6SX */
    if (cpu_is_imx6sx() && ((val &
		(1 << BP_SRC_SCR_SW_OPEN_VG_RST)) == 0))
        m4_is_enabled = true;
    else
        m4_is_enabled = false;

    val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
    writel_relaxed(val, src_base + SRC_SCR);
    spin_unlock(&src_lock);
}

linux reset framework介绍

compatible 为 “fsl,imx51-src” 对应的节点为:

imx6ul.dtsi
            src: src@020d8000 {
                compatible = "fsl,imx6ul-src", "fsl,imx51-src";
                reg = <0x020d8000 0x4000>;
                interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
                         <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
                #reset-cells = <1>;
            };

看 irqchip_init

void __init irqchip_init(void)
{
    of_irq_init(__irqchip_of_table);
	// 空函数
    acpi_irq_init();
}

看

/**
 * of_irq_init - Scan and init matching interrupt controllers in DT
 * @matches: 0 terminated array of nodes to match and init function to call
 *
 * This function scans the device tree for matching interrupt controller nodes,
 * and calls their initialization functions in order with parents first.
 */
void __init of_irq_init(const struct of_device_id *matches)
{
    struct device_node *np, *parent = NULL;
    struct intc_desc *desc, *temp_desc;
    struct list_head intc_desc_list, intc_parent_list;

    INIT_LIST_HEAD(&intc_desc_list);
    INIT_LIST_HEAD(&intc_parent_list);

	// 遍历所有的node,寻找定义了interrupt-controller属性的node,如果定义了interrupt-controller属性则说明该node就是一个中断控制器。详细分析见下
    for_each_matching_node(np, matches) {
        if (!of_find_property(np, "interrupt-controller", NULL) ||
                !of_device_is_available(np))
            continue;
        /*
         * Here, we allocate and populate an intc_desc with the node
         * pointer, interrupt-parent device_node etc.
         */
        desc = kzalloc(sizeof(*desc), GFP_KERNEL);
        if (WARN_ON(!desc))
            goto err;

		// 此处会有两个node符合条件,分别为interrupt-controller和gpc
        desc->dev = np;
        desc->interrupt_parent = of_irq_find_parent(np);
        if (desc->interrupt_parent == np)
			desc->interrupt_parent = NULL;
        list_add_tail(&desc->list, &intc_desc_list);
    }

    /*
     * The root irq controller is the one without an interrupt-parent.
     * That one goes first, followed by the controllers that reference it,
     * followed by the ones that reference the 2nd level controllers, etc.
     */
    while (!list_empty(&intc_desc_list)) {
        /*
         * Process all controllers with the current 'parent'.
         * First pass will be looking for NULL as the parent.
         * The assumption is that NULL parent means a root controller.
         */
        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
            const struct of_device_id *match;
            int ret;
            // typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *);
            of_irq_init_cb_t irq_init_cb;

            if (desc->interrupt_parent != parent)
                continue;

            list_del(&desc->list);
            // 传入一个node设备树节点,让它与给定的一组的matches匹配,返回其中最合适的matches
            match = of_match_node(matches, desc->dev);
            if (WARN(!match->data,
                "of_irq_init: no init function for %s\n",
                match->compatible)) {
				kfree(desc);
                continue;
            }

            pr_debug("of_irq_init: init %s @ %p, parent %p\n",
                 match->compatible,
                 desc->dev, desc->interrupt_parent);
            //jl_test 能走到这儿的也只有两个节点,分别为interrupt-controller和gpc
            pr_err("irq_test:%s:%d:node_name=%s:compatible=%s\n", __func__, __LINE__, desc->dev->name, match->compatible);
            irq_init_cb = (of_irq_init_cb_t)match->data;
            // gic_of_init 和 imx_gpc_init 接下来要重点分析这两个函数了,见3
            ret = irq_init_cb(desc->dev, desc->interrupt_parent);
            if (ret) {
                kfree(desc);
                continue;
            }

            /*
             * This one is now set up; add it to the parent list so
             * its children can get processed in a subsequent pass.
             */
            list_add_tail(&desc->list, &intc_parent_list);
        }

        /* Get the next pending parent that might have children */
        desc = list_first_entry_or_null(&intc_parent_list,
                        typeof(*desc), list);
        if (!desc) {
            pr_err("of_irq_init: children remain, but no parents\n");
            break;
        }
        list_del(&desc->list);
        parent = desc->dev;
 		kfree(desc);
    }

    list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
        list_del(&desc->list);
        kfree(desc);
    }
err:
    list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
        list_del(&desc->list);
        kfree(desc);
    }
}
                                                          

关于reset framework 详见这篇

关于for_each_matching_node,详见这篇

Linux设备驱动程序学习笔记14:中断的初始化流程 init是Linux内核启动的第一个用户级进程,系统的很多初始化工作都是由它开始的,当然也包括中断的初始化工作。其主要函数在init/main.c中,汇编程序会跳到该文件的start_kernel函数执行,我们就由这个函数开始分析Linux中断初始化相关的主要流程。 asmlinkage void __init start_kernel(void) { … … setup_arch 阅读详情

相关推荐

ArcGIS中利用DEM数据生成地形图既视感的等高线;利用掩膜进行等高线注记;DEM的可视化表达总结

文章目录前言一、效果图展示二、地形(DEM)可视化表达1.一维可视化2.二维可视化2.三维可视化二、ArcGIS中利用DEM数据制作等高线2.三维可视化2.三维可视化2.三维可视化2.三维可视化二、ArcGIS中利用DEM数据制作等高线2.三维可视化2.三维可视化2.三维可视化总结 前言 最近老师布置作业:DEM的可视化表达。想做一个等高线地形图那样、看起来高级一点的等高线,可是我看网上大多数教程都只展示了【等值线】工具,做出来效果都一般。我自认为自己做出来的效果还可以,把步骤分享给大家。 一、

pink_pig__的博客 5万+

中断门初始化(init_IRQ)

1,中断门的设置是在init_IRQ中完成 linux-2.6.11.12\init\main.c:start_kernel->init_IRQ 2,init_IRQ(linux-2.6.11.12\arch\i386\kernel\i8259.c) 1)for循环用于设置中断门,但跳过用于设置系统调用的陷阱门中断向量(SYSCALL_VECTOR,在tr

yiyeguzhou100的专栏 2901

避坑指南:你的VASP CI-NEB计算为什么不收敛?常见错误分析与解决思路

本文深入解析VASP CI-NEB计算不收敛的常见问题,提供从结构准备到参数设置的系统解决方案。针对过渡态计算中的能量曲线异常、中间图像偏离等典型问题,详细介绍了诊断方法和实用工具,帮助研究者高效解决CI-NEB收敛难题,提升计算效率。

weixin_29698641的博客 430

Kernel启动流程源码解析 10 init_IRQ

一 init_IRQ 本文以arm,gic-v3兼容的中断控制器为例,介绍中断控制器的初始化过程。 1.0 init_IRQ 定义在arch/arm64/kernel/irq.c中 void __init init_IRQ(void) {     irqchip_init();     if (!handle_arch_irq)         panic("N

Android 6.0 源码学习 2243

激光雷达-IMU标定工具lidar_imu_calib保姆级教程(VLP-16实测)

本文提供激光雷达与IMU联合标定的详细实战教程,重点解析lidar_imu_calib工具在VLP-16上的应用。从环境部署、数据采集技巧到参数配置与结果验证,手把手指导完成标定全流程,并详解如何在LIO-SAM等SLAM系统中应用标定结果,确保传感器融合精度。

food6的博客 475

如何实现SOLIDWORKS阵列的“智能变更”?

有时,我们在设计一个零件时,零件上有一排阵列孔,同时零件有不同的长度,我们又希望可以做到零件长度改变时,这排孔可以按长度等距增减孔阵列的个数;或是零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那具体要怎么做呢?接下来,我们一起来看看怎么用SOLIDWORKS中简单的操作来实现这两种智能的变更: 零件长度加长或缩短时,这排孔要按长度等距增减孔阵列的个数。 零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那接下来,我们一起来看看怎么用简单的操作来实现这两种智能的

SOLIDWORKS艾金米 2076

Linux内核中断处理机制--初始化

1、Linux内核从start_kernel函数开始进行初始化 (1)trap_init主要就是异常的初始化。 (2)init_IRQ才是中断的初始化。 2、trap_init都干了啥呢? void __init trap_init(void) { .... 把向量表拷贝到ffff0000地址 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); .... 把复杂向量表拷贝到ffff0200 mem.

LuckyDog0623的博客 2391

WSL子系统启动报错 Wsl/Service/CreateInstance/CreateVm/HCS_E_SERVICE_NOT_AVAILABLE

WSL子系统启动报错 :Wsl/Service/CreateInstance/CreateVm/HCS_E_SERVICE_NOT_AVAILABLE 于是分析原因,最终发现是Windows功能中的虚拟机平台功能不知道什么时候被取消了。

Linux I Tell U 6万+

中断管理基础学习笔记 - 2.中断控制器初始化

目录1. 前言2. init_IRQ|- -of_irq_init|- - -gic_of_init参考文档 1. 前言 本专题我们开始学习进程管理部分。本文主要参考了《奔跑吧, Linux内核》、ULA、ULK的相关内容。 本节记录ARM架构下中断是如何管理的,Linux内核中的中断管理机制是如何设计与实现的,以及常用的下半部机制,如软中断、tasklet、workqueue等。本文及后续中断相关笔记均以qemu 5.0.0内嵌平台为例,中断控制器采用GIC-400控制器,支持GIC version2技术

HZero 1590

机器学习算法原理:详细介绍各种机器学习算法的原理、优缺点和适用场景

现在,我们将进入到机器学习的核心部分——算法原理。在本篇文章中,我们将详细探讨各种机器学习算法的原理、优缺点和适用场景。

a871923942的博客 2965

TIA博途中通过UDT实现IO地址映射到DB块中的具体方法

TIA博途中通过UDT实现IO地址映射到DB块中的具体方法

Robot_PLC_HMI_Automation 1万+

JJJ--linux irq

由start_kernel找到init_IRQ(arch/arm/kernel/irq.c),到irqchip_init(drivers/irqchip/irqchip.c),到of_irq_init(__irqchip_of_table) drivers/of/irq.c。没有no_map和Radix_Tree_map这两种方式(irq_domain_add_nomap 和 irq_domain_add_tree)

engineer0的博客 1万+

Python爬虫实战:如何通过解析JSON数据抓取抖音视频评论

本文介绍了如何使用Python爬虫抓取抖音视频评论数据。请求头伪造:通过使用随机的User-Agent,模拟真实用户的请求。代理池:使用代理IP来避免被封禁。JSON解析:直接从API接口获取JSON格式的数据,避免了动态加载内容的限制。需要注意的是,抓取网站数据时应遵守网站的爬虫协议,避免过度抓取影响网站性能或违反法律法规。希望本文能够帮助你掌握如何抓取和分析抖音视频评论数据!

2201_76125261的博客 3358

JJJ-1 early_irq_init

先看看first_online_node,定义在include/linux/nodemask.h,为0。

engineer0的博客 395

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

JJJ-0 irq的2个初始化函数

内核启动初始化过程中,关于irq有这两个初始化函数。

engineer0的博客 146

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

gitlab安装注意事项

主要安装请看:https://www.cnblogs.com/niuben/p/10867877.html 需要注意的是,配置镜像源的时候,要多加一个 gpccheck=0 [gitlab-ce] name=gitlab-ce baseurl=http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el6 Repo_gpgcheck=0 Enabled=1 Gpgkey=https://packages.gitlab.com/gpg.key gpgc.

gyfb29的专栏 188

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

关于init_IRQ的函数分析

<br />init_IRQ() 为xen启动函数 __start_xen中调用初始化中断的函数,其中有一段代码我认为是挺绕的。经过了一些时间的分析,终于弄明白了分享给大家,也给自己做个记录。<br /> <br />for ( vector = FIRST_DYNAMIC_VECTOR; vector < NR_VECTORS; vector++ )<br />    {<br />        if (vector == HYPERCALL_VECTOR || vector == LEGACY_SYS

沈启龙的专栏 3079

复制本地文件到HDFS本地测试异常

项目中需要将本地文件拷贝到hdfs上,由于本人比较懒,于是使用擅长的Java程序通过Hadoop.FileSystem.CopyFromLocalFile方法来实现。 在本地(Window 7 环境)本地模式下运行却遇到了下述异常: An exception or error caused a run to abort: org.apache.hadoop.io.nativeio.Nativ...

weixin_30443075的博客 445

《C++ Primer Plus》第16章:string类和标准模板库(10)

几个使用 STL 的示例

weixin_40064300的博客 955

Linux操作系统学习笔记(十五)中断

一. 前言   在前面的文章里,我们多次见到了中断的作用,如任务调度,系统调用从用户态陷入内核,文件系统的读写操作等。本文就Linux的中断机制进行较为全面的剖析。 二. 什么是中断   中断通常被定义为改变处理器执行指令的顺序的一个事件,该事件与CPU芯片内外部硬件电路产生的电信号相对应。中断通常分为同步中断和异步中断: 同步中断(synchronous):又称异常(exception),在指令执行时由CPU控制单元产生,之所以称之为同步,是因为只有在一条指令终止执行后CPU才会发出中断。 异步中断(

ty的博客 1246

内核IRQ中断向量

首先看一下vector_irq的定义,此每处理器数组变量,保存每个处理器上中断向量所对应的中断号,其以中断向量值为索引。系统中定义了256个中断向量。相关代码如下: typedef int vector_irq_t[NR_VECTORS]; DEFINE_PER_CPU(vector_irq_t, vector_irq) = { [0 ... NR_VECTORS - 1] = VECT...

redwingz的博客 3325

本地yum 库

vi /etc/yum.repos.d/base.repo [base] name=base baseurl=file:///mnt/Server/ enabled=1 gpccheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle     # grub.conf generated by anaconda # #

qindalin的专栏 635

gpcheckcat  测试选项集合

gpcheckcat 测试选项集合 参数 含义 unique_index_violation 检查违反的唯一索引 duplicate 检查重复的条目 missing_extraneous 缺失或无关条目的一致性检查 inconsistent master segment一致性检查 foreign_key 检查外键 acl 访问控...

知识的力量 786

内核启动时的中断和时钟的初始化流程

内核通过start_kernel从汇编进入c世界,在用serup_arch设置体系架构的时候,会返回当前机器的machine_desc;然后init_IRQ和time_init来初始化中断。时钟子系统mdesc = setup_machine_fdt(atags_vaddr) //返回成功匹配的machine_desc//赋值给全局变量machine_desc,以供后续初始化等操作使用,比如给下面的中断和时钟子系统使用......init_IRQ......time_initelse。

我的博客 1192

Linux中断初始化init_IRQ的实现

中断初始化与定时器配置 init_IRQ函数负责初始化x86系统的中断处理机制,主要完成以下工作: 调用pre_intr_init_hook进行前置中断设置 遍历中断向量空间,设置中断门(排除系统调用向量) 调用intr_init_hook进行后续架构特定中断初始化 通过setup_pit_timer配置PIT定时器,设置时钟中断频率 为外部FPU配置IRQ13中断(如需要) 初始化当前CPU的中断上下文 setup_pit_timer函数具体配置8254 PIT芯片: 使用自旋锁保护配置过程 设置工作模式

weixin_51019352的博客 1009
上一篇: JJJ-1 early_irq_init
下一篇: JJJ - linux reset framework
你板子冒烟了
博客等级 码龄8年 1278粉丝 582原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值