当前位置: 首页 > news >正文

华为鲲鹏920s处理器在统信体系下接收外部GPIO中断问题

1、问题描述

目前任务中使用华为鲲鹏920s处理器,操作系统为统信V20,测试场景为连续接收外部GPIO中断,四种中断类型,周期分别为1s,50ms,10ms和500us。在连续拷机24小时后发现接收不到GPIO中断,系统下看到中断计数如下,不再增加:

此时输入dmesg,发现出错情况如下:

2、问题分析

将dmesg完整日志提交给Gemini,结论如下:

根据您提供的日志和背景信息,Linux 系统运行一段时间后收不到中断,其核心原因并非中断周期太短,而是触发了内核的不良中断处理机制(Spurious IRQ handling),导致系统主动禁用了该中断。

以下是详细的原因分析:

1. 根本原因:中断被环境强制禁用 (Disabling IRQ #444)

日志显示:Disabling IRQ #444。这意味着内核在第 444 号中断上检测到了异常行为。

  • 内核检测逻辑:Linux 内核会监控每个中断。要是在短时间内(通常是 100,000 次中断内)有超过 99% 的中断被认为是“未处理”的(即中断发生了,但没有任何注册的处理函数宣称处理了它),内核会认为该中断线发生了“中断风暴”或硬件故障 。

  • 保护机制:为了防止未处理的中断持续抢占 CPU 资源导致系统卡死(即 dump_stack 中显示的从 do_idlegic_handle_irq 的路径),内核会通过 note_interrupt 函数强制关闭该中断线 。

2. 为何中断计数不再增加?

一旦内核打印出 Disabling IRQ #444,它就会在硬件或中断控制器(GIC)级别屏蔽该中断 。此后,硬件产生的电信号无法再触发内核的中断服务例程(ISR),因此中断计数停止增长,系统表现为“收不到中断”。

3. 是否与 500us 的中断周期有关?

中断周期短(高频率)本身不是原因,但它加速了问题的触发。

  • 处理不当:如果您的驱动程序 gpio_irq_handler(来自 gpio_shared_irq 模块)在被调用时,没有正确识别硬件状态并返回 IRQ_HANDLED,而是返回了 IRQ_NONE,那么每一次 500us 的脉冲都会被记为一次“不良中断” 。

  • 触发速度:在 500us 的周期下,每秒产生 2000 次中断。如果处理函数一直返回 IRQ_NONE,只需约 50 秒左右就会达到内核的错误阈值,从而导致中断被禁用。

4. 故障排查建议

要解除此问题,请重点检查驱动程序源代码:

  1. 返回值检查:确保 gpio_irq_handler 只有在确定处理了该中断时才返回 IRQ_HANDLED。如果因为某种原因(如寄存器状态未清除)导致处理函数返回了 IRQ_NONE,内核就会认为这个中断是误触发。

  2. 寄存器清除:确认在中断处理函数中是否正确清除了 GPIO 控制器的中断挂起位(Pending bit)。如果没有清除,电平触发的中断会立即再次触发,而此时处理函数可能认为没有新数据,从而返回 IRQ_NONE

  3. 共享中断冲突:日志中提到了 gpio_shared_irq。如果是共享中断,请确认该线上是否有其他设备也在产生中断,而您的驱动程序错误地忽略了它们。

  4. 临时恢复:作为测试,您可以通过向 /proc/irq/444/enable 重新写入来尝试开启中断,但如果根本逻辑不改,它很快会再次被禁用。

总结: 您的系统由于 gpio_irq_handler 频繁返回“未处理”状态,触发了内核的自我保护机制,导致 IRQ #444 被强制关闭。您需要修正驱动程序对中断状态的判断逻辑 。

gpio中断驱动代码如下,如果Gemini解释是正确的,那就是出现异常中断或者驱动中的中断函数没有及时返回IRQ_HANDLED,运行时间长了就会出现累积。

#include 
#include         // 包含Linux内核模块的头文件
#include      // 包含中断处理相关的函数和宏定义
#include             // 包含I/O内存映射函数
#include          // 包含延时函数
#include           // 包含ACPI(高级配置和电源接口)相关函数
// GPIO基地址宏定义
#define GPIO_A_BASE 0x9C100000
#define GPIO_B_BASE 0x94100000
#define GPIO_SIZE 0x1000         // GPIO内存映射区域的大小
#define GPIO_STATUS_OFFSET 0x0    // GPIO状态寄存器的偏移量
#define GPIO_IO_CONTROL_OFFSET 0x4 // GPIO I/O控制寄存器的偏移量
#define MASK1 0x3E00
#define MASK2 0x6000
// GPIO信息结构体定义
struct gpio_info {void __iomem *base;          // GPIO基地址int irq;                     // GPIO中断号int status_bit;              // GPIO状态位int virq;                    // 虚拟中断号
//#define GPIO_REG_READ(reg_base, offset)          (*(volatile u32 *)((reg_base) + (offset)))
//#define GPIO_REG_WRITE(reg_base, offset, value)  (*(volatile u32 *)((reg_base) + (offset)) = (value))
};
// GPIO数组,初始化GPIO信息
static struct gpio_info gpios[] = {{ .base = (void __iomem *)GPIO_B_BASE, .irq = 126, .status_bit = 13 },{ .base = (void __iomem *)GPIO_B_BASE, .irq = 127, .status_bit = 14 },{ .base = (void __iomem *)GPIO_A_BASE, .irq = 74, .status_bit = 9 },{ .base = (void __iomem *)GPIO_A_BASE, .irq = 75, .status_bit = 10 },{ .base = (void __iomem *)GPIO_A_BASE, .irq = 76, .status_bit = 11 },{ .base = (void __iomem *)GPIO_A_BASE, .irq = 77, .status_bit = 12 },{ .base = (void __iomem *)GPIO_A_BASE, .irq = 78, .status_bit = 13 },
};
// GPIO中断处理函数
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{struct gpio_info *gpio = dev_id;u32 status;// 检查中断号是否有效if (irq > ARRAY_SIZE(gpios) || irq < 0 ){return IRQ_NONE;}// 读取GPIO状态寄存器status = readl(gpio->base + GPIO_STATUS_OFFSET);// 检查状态位是否被设置if (status & (1 << gpio->status_bit)){printk(KERN_INFO "GPIO interrupt %d\n", gpio->irq); // 打印中断信息writel(~(1 << gpio->status_bit), gpio->base + GPIO_STATUS_OFFSET); // 清除信号位udelay(1); // 延时1微秒writel((1 << gpio->status_bit), gpio->base + GPIO_STATUS_OFFSET); // 重置信号位}return IRQ_HANDLED; // 返回中断已处理
}
// GPIO初始化函数
static int __init gpio_init(void)
{void __iomem *base;pr_info("[Info] gpio_init.\n");// 映射GPIO内存区域base = ioremap(GPIO_B_BASE, GPIO_SIZE);if (!base) {printk(KERN_ERR "Failed to remap GPIO baseB\n"); // 映射失败return -ENOMEM;}gpios[0].base = base;gpios[1].base = base;base = ioremap(GPIO_A_BASE, GPIO_SIZE);if (!base) {printk(KERN_ERR "Failed to remap GPIO baseA\n"); // 映射失败iounmap(gpios[2].base);return -ENOMEM;}gpios[2].base = base;gpios[3].base = base;gpios[4].base = base;gpios[5].base = base;gpios[6].base = base;return 0;
}
int __init gpio_irq_init(void)
{//u32 reg_val;unsigned i;volatile u32* reg1, *reg2, *reg3, *reg4;// 映射GPIO内存区域pr_info("[Info] hisi_irq_init.\n");if (gpio_init() != 0) {return -1;}pr_info("[Info] gpio extint test init.\n");// 读取地址为 GPIO_A_BASE 的寄存器值并设置位reg1 = (void*)(gpios[2].base + GPIO_IO_CONTROL_OFFSET);reg2 = (void*)(gpios[2].base + GPIO_STATUS_OFFSET);*reg1 |= MASK1;*reg2 |= MASK1;// 读取地址为 GPIO_B_BASE 的寄存器值并设置位reg3 = (void*)(gpios[0].base + GPIO_IO_CONTROL_OFFSET);reg4 = (void*)(gpios[0].base + GPIO_STATUS_OFFSET);*reg3 |= MASK2;*reg4 |= MASK2;// 遍历GPIO数组,初始化每个GPIOfor (i = 0; i < ARRAY_SIZE(gpios); i++) {int irq;// 注册GPIO中断irq = acpi_register_gsi(NULL, gpios[i].irq, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW);//irq = acpi_register_gsi(NULL, gpios[i].irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);if (irq < 0) {printk(KERN_ERR "Failed to register GSI\n"); // 注册失败//continue;return irq;//continue?}gpios[i].virq = irq;// 请求GPIO中断if (request_irq(irq, gpio_irq_handler, IRQF_TRIGGER_RISING, "gpio_extint", &gpios[i])) {printk(KERN_ERR "Failed to request IRQ %i\n", gpios[i].irq); // 请求失败//continue;//continue;return -EIO;//continue?}pr_info("[Info] gpio irq %i init.\n", irq);}return 0; // 初始化成功
}
// GPIO退出函数
static void __exit gpio_exit(void)
{int i;// 遍历GPIO数组,释放资源for (i = 0; i < ARRAY_SIZE(gpios); i++) {acpi_unregister_gsi(gpios[i].virq); // 注销中断free_irq(gpios[i].virq, &gpios[i]); // 释放中断}iounmap(gpios[0].base); // 取消内存映射iounmap(gpios[2].base); // 取消内存映射
}
module_init(gpio_irq_init); // 注册模块初始化函数
module_exit(gpio_exit); // 注册模块退出函数
MODULE_LICENSE("GPL v2"); // 指定许可证
MODULE_AUTHOR("Wuzhou Co.,Ltd."); // 指定作者
MODULE_DESCRIPTION("GPIO extint driver for Linux"); // 指定模块描述

http://www.jsqmd.com/news/380917/

相关文章:

  • GLM-4-9B-Chat-1M惊艳案例:200万字古籍OCR文本智能断句与注释
  • 造相 Z-Image 文生图模型:5分钟快速部署教程,新手也能轻松上手
  • 2026年靠谱的上海双层玻璃反应釜/20升双层玻璃反应釜制造厂家选购指南怎么选(精选) - 品牌宣传支持者
  • Qwen3-Reranker-8B效果对比:8B vs 4B重排精度/速度/显存实测分析
  • 快速部署Qwen3-ForcedAligner-0.6B:GPU加速语音对齐
  • 手把手教你用Qwen3-ASR-0.6B实现音频文件批量转文字
  • 设计师必备!RMBG-2.0背景移除镜像使用全攻略
  • 守护进程
  • Magma黑科技:Set-of-Mark技术带来的空间理解革命
  • Qwen3-ASR-1.7B开箱体验:方言识别效果惊艳实测
  • 详细介绍:当想象力成为生产力,AI视频生成如何重塑2026年的创作世界
  • Fish Speech 1.5 实战:如何制作个性化语音助手
  • Qwen-Image创意应用:自动生成PPT配图的高效方案
  • 自媒体人必备!AI净界RMBG-1.4让配图制作效率翻倍
  • C++高性能调用Hunyuan-MT 7B API开发指南
  • Qwen3-ASR-1.7B开箱即用:无需代码的语音转文字解决方案
  • MogFace-large在安防场景落地:高精度人脸检测企业应用实战
  • 5分钟上手 Nano-Banana:制作超治愈的服饰拆解平面图教程
  • 造相Z-Image保姆级教程:从部署到生成你的第一张AI画作
  • ollama部署Phi-4-mini-reasoning实战教程:3步完成轻量级推理模型本地运行
  • Lychee Rerank MM在智能客服中的实际应用案例
  • C语言实现春联生成模型轻量化推理引擎
  • 轻松上手:Qwen3-ForcedAligner-0.6B语音对齐指南
  • 企业合规首选:SenseVoice-Small ONNX本地运行+数据不上传隐私保障方案
  • PDF-Extract-Kit-1.0功能详解:从文本到公式的全能提取
  • Local AI MusicGen开发者案例:集成至自有平台的API调用实践
  • 通义千问3-Reranker-0.6B详细步骤:A/B测试重排效果评估方法
  • WeKnora智能问答优化:基于BERT的检索增强生成技术
  • ⚡ SenseVoice-Small ONNX信创环境落地:麒麟/UOS操作系统兼容性验证报告
  • 24G显卡就够了!Qwen3-VL高效部署技巧分享