内核升级至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
相关产品推荐
相关产品推荐

