JJJ-2 init_IRQ

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,详见这篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs) { struct nvme_dev *dev = affd->priv; unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues; if (!nrirqs) { nrirqs = 1; nr_read_queues = 0; } else if (nrirqs == 1 || !nr_write_queues) { nr_read_queues = 0; } else if (nr_write_queues >= nrirqs) { nr_read_queues = 1; } else { nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; dev->io_queues[HCTX_TYPE_READ] = nr_read_queues; affd->set_size[HCTX_TYPE_READ] = nr_read_queues; affd->nr_sets = nr_read_queues ? 2 : 1; }static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct irq_affinity affd = { //ָ���ж��׺��Եļ��㷽���Ͳ��� .pre_vectors = 1, .calc_sets = nvme_set_irq_affinity, //nvme_calc_irq_sets, .priv = dev, }; unsigned int irq_queues, poll_queues; poll_queues = min(dev->nr_poll_queues, nr_io_queues - 1); dev->io_queues[HCTX_TYPE_POLL] = poll_queues; dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; irq_queues = 1; if (!(dev->ctrl.quirks & NVME_QUIRK_SINGLE_VECTOR)) irq_queues += (nr_io_queues - poll_queues); return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues, PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd); } 在 Linux 5.17.12 内核版本中,如何修改 pci_alloc_irq_vectors_affinity() 函数的 affinity_hint 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。代码展示
最新发布
06-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值