You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核升级至6.1后gpiochip_set_irq_hooks告警与提前退出问题

问题描述

我开发了一个内核模块,提供可通过libgpiod(gpioget/gpioset/gpiomon等工具)从用户空间访问的gpiochip。将内核从5.10版本升级到6.1版本后,出现新告警:not an immutable chip, please consider fixing it!

生成该告警的gpiochip_set_irq_hooks()函数逻辑如下:

  • 若irqchip设置了IRQCHIP_IMMUTABLE标志,函数直接返回,无告警
  • 若未设置该标志,先触发告警,再继续执行后续逻辑

我需要同时避免这个告警,且不让函数提前返回。之前误以为面向用户空间开放的gpiochip不能设置IRQCHIP_IMMUTABLE,该标志仅适用于仅供内核模块使用的芯片,若此认知有误,请纠正。

告警来源函数代码
static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
{
    struct irq_chip *irqchip = gc->irq.chip;

    if (irqchip->flags & IRQCHIP_IMMUTABLE)
        return;

    chip_warn(gc, "not an immutable chip, please consider fixing it!\n");

    if (!irqchip->irq_request_resources &&
        !irqchip->irq_release_resources) {
        irqchip->irq_request_resources = gpiochip_irq_reqres;
        irqchip->irq_release_resources = gpiochip_irq_relres;
    }
    if (WARN_ON(gc->irq.irq_enable))
        return;
    /* Check if the irqchip already has this hook... */
    if (irqchip->irq_enable == gpiochip_irq_enable ||
        irqchip->irq_mask == gpiochip_irq_mask) {
        /*
         * ...and if so, give a gentle warning that this is bad
         * practice.
         */
        chip_info(gc,
              "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
        return;
    }

    if (irqchip->irq_disable) {
        gc->irq.irq_disable = irqchip->irq_disable;
        irqchip->irq_disable = gpiochip_irq_disable;
    } else {
        gc->irq.irq_mask = irqchip->irq_mask;
        irqchip->irq_mask = gpiochip_irq_mask;
    }

    if (irqchip->irq_enable) {
        gc->irq.irq_enable = irqchip->irq_enable;
        irqchip->irq_enable = gpiochip_irq_enable;
    } else {
        gc->irq.irq_unmask = irqchip->irq_unmask;
        irqchip->irq_unmask = gpiochip_irq_unmask;
    }
}
补充信息

我未设置IRQCHIP_IMMUTABLE的相关代码片段:

ret = devm_request_threaded_irq(&client->dev, client->irq,
            NULL, my_pmu_irq, IRQF_ONESHOT |
            IRQF_TRIGGER_FALLING | IRQF_SHARED,
            dev_name(&client->dev), pmu);

以下是驱动的GPIO功能初始化代码,这是一款带GPIO功能的PMU芯片,通过I2C总线访问。PMU有一条IRQ线用于向内核发送状态变更信号,驱动通过I2C查询PMU获取新的GPIO值。

设备树配置

my_pmu: my_pmu@43 {
    compatible = "my,my-pmu";
    reg = <0x43>;
    status = "okay";
    gpio-controller;

    interrupt-parent = <&gpio5>;
    interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
};

GPIO/IRQ驱动初始化代码

//
// Set-up as GPIO device
//

/* Allocate, initialize, and register this gpio_chip. */
pmu = devm_kzalloc(&client->dev, sizeof(struct my_pmu), GFP_KERNEL);
if (!pmu)
    return -ENOMEM;

printk("about to init mutex\n"); 
mutex_init(&pmu->lock);

pmu->chip.base          = -1;
pmu->chip.can_sleep     = true;
pmu->chip.parent        = &client->dev;
pmu->chip.owner         = THIS_MODULE;
pmu->chip.get           = my_pmu_get;
pmu->chip.set           = my_pmu_set;
/*
 * direction_*() function uneeded as pin functions cannot be changed
 *
 * If direction_output() exists, it will be called *instead* of set(),
 * leading to profound confusion.
 */
//pmu->chip.direction_input = my_pmu_direction_input;
//pmu->chip.direction_output    = my_pmu_direction_output;
pmu->chip.get_direction     = my_pmu_get_direction;
pmu->chip.ngpio         = id->driver_data;

pmu->chip.label = client->name;

pmu->client = client;
i2c_set_clientdata(client, pmu);

/* first read of input and output registers */
// TODO: Refactor this so that interrupts and initialisation use the same code.
new_numbered_inputs = i2c_read_word(client, PMU_REG_NUMBERED_INPUTS);
printk("new_numbered_inputs: %08X\n", new_numbered_inputs);
// update only bits 0-7
printk("mask: %08X\n", PMU_MASK_NUMBERED_INPUTS);
pmu->status = (pmu->status & ~PMU_MASK_NUMBERED_INPUTS) | new_numbered_inputs;
printk("pmu->status: %08X\n", pmu->status);

new_named_inputs = i2c_read_word(client, PMU_REG_NAMED_INPUTS);
printk("new_named_inputs: %08X\n", new_named_inputs);
// update only bits 8-17, remembering the shift
printk("mask: %08X\n", PMU_MASK_NAMED_INPUTS);
pmu->status = (pmu->status & ~PMU_MASK_NAMED_INPUTS) | (new_named_inputs << PMU_OFFSET_NAMED_INPUTS);
printk("pmu->status: %08X\n", pmu->status);

new_pseudo_inputs = i2c_read_word(client, PMU_REG_PSEUDO_INPUTS);
printk("new_pseudo_inputs: %08X\n", new_pseudo_inputs);
// update only bits 18-19, remembering the shift
printk("mask: %08X\n", PMU_MASK_PSEUDO_INPUTS);
pmu->status = (pmu->status & ~PMU_MASK_PSEUDO_INPUTS) | (new_pseudo_inputs << PMU_OFFSET_PSEUDO_INPUTS);
printk("pmu->status: %08X\n", pmu->status);

new_outputs = i2c_read_word(client, PMU_REG_OUTPUTS);
printk("new_outputs: %08X\n", new_outputs);
// update only bits 20-23, remembering the shift
printk("mask: %08X\n", PMU_MASK_OUTPUTS);
pmu->status = (pmu->status & ~PMU_MASK_OUTPUTS) | (new_named_inputs << PMU_OFFSET_OUTPUTS);
printk("pmu->status: %08X\n", pmu->status);

/* Enable irqchip if we have an interrupt */
if (client->irq) {
    struct gpio_irq_chip *girq;

    pmu->irqchip.name = "my_pmu";
    pmu->irqchip.irq_enable = my_pmu_irq_enable;
    pmu->irqchip.irq_disable = my_pmu_irq_disable;
    pmu->irqchip.irq_ack = noop;
    pmu->irqchip.irq_mask = noop;
    pmu->irqchip.irq_unmask = noop;
    pmu->irqchip.irq_set_wake = my_pmu_irq_set_wake;
    pmu->irqchip.irq_bus_lock = my_pmu_irq_bus_lock;
    pmu->irqchip.irq_bus_sync_unlock = my_pmu_irq_bus_sync_unlock;

    printk("%s:%d %s before devm_request_threaded_irq() \n", __FILE__, __LINE__, __func__);
    ret = devm_request_threaded_irq(&client->dev, client->irq,
                NULL, my_pmu_irq, IRQF_ONESHOT |
                IRQF_TRIGGER_FALLING | IRQF_SHARED,
                dev_name(&client->dev), pmu);
    printk("%s:%d %s after devm_request_threaded_irq(), ret = %i \n", __FILE__, __LINE__, __func__, ret);
    if (ret) {
        printk("devm_request_threaded_irq failed\n"); 
        goto fail;
    }

    girq = &pmu->chip.irq;
    girq->chip = &pmu->irqchip;
    /* This will let us handle the parent IRQ in the driver */
    girq->parent_handler = NULL;
    girq->num_parents = 0;
    girq->parents = NULL;
    girq->default_type = IRQ_TYPE_NONE;
    girq->handler = handle_level_irq;
    girq->threaded = true;
} else {
    printk("%s:%d %s client->irq == 0\n", __FILE__, __LINE__, __func__);
}

printk("%s:%d %s before devm_gpiochip_add_data() \n", __FILE__, __LINE__, __func__);
ret = devm_gpiochip_add_data(&client->dev, &pmu->chip, pmu);
printk("%s:%d %s after devm_gpiochip_add_data(), ret = %i \n", __FILE__, __LINE__, __func__, ret);
if (ret < 0) {
    printk("devm_gpiochip_add_data failed\n");
    goto fail;
}

内容的提问来源于stack exchange,提问作者fadedbee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:23:09