首页 > 系统相关 >linux Irq domain

linux Irq domain

时间:2023-04-19 16:11:10浏览次数:74  
标签:domain struct Irq linux irq action data desc

文章引用:https://blog.csdn.net/longwang155069/article/details/105812097

为什么会引入IRQ_domain?

早期中断数量较少,所以可以分布在一个interrupt_controler,中断映射也很简单,每个中断号对应一个interrupt_controler。

 而当一个系统中有多个interrupt-controller的时候,而且中断号也逐渐增加。linux内核为了应对此问题,引入了IRQ-domain的概念。irq-domain的引入相当于一个中断控制器就是一个irq-domain。就是一个中断区域。这样一来所有的irq-contoller会出现级联的布局。

 IRQ-Domain的作用

中断之间连接在root-interrupt-controler中断控制器上,其中softirq_num为irq_req的irq号,hw_irq为dts(devices tree source) 中配置的irq号。

 

hwirq到softirq的映射

当开机之后,内核会自动将dts全部解析,然后会进行填充,对于中断使用如下函数进行解析dts,然后map,
of_irq_parse_one会将dts中的中断信息进行解析,然后通过irq_create_of_mapping函数进行hwirq到softirq的map

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
  struct of_phandle_args oirq;

  if (of_irq_parse_one(dev, index, &oirq))
    return 0;

  return irq_create_of_mapping(&oirq);
} 

 

首先dts中配置的中断号都是hwirq,刚开机hwirq没有对应的softirq的,所以第一次开机需要进行hwirq和softirq之间建立map

int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,int node, const struct cpumask *affinity)
{
  unsigned int hint;

  if (virq >= 0) {
    virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,affinity);
  } else {
    hint = hwirq % nr_irqs;
    if (hint == 0)
      hint++;
      virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,affinity);
    if (virq <= 0 && hint > 1) {
      virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,affinity);
     }
  }
  return virq;
}

 

通过上述的函数分配virq,也就是softirq,分配一个Irq_data结构,然后将virq设置到irq_data结构中

static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,struct irq_data *child)
{
  struct irq_data *irq_data;

  irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL,
  irq_data_get_node(child));
  if (irq_data) {
    child->parent_data = irq_data;
    irq_data->irq = child->irq;
    irq_data->common = child->common;
    irq_data->domain = domain;
   }
  return irq_data;
}

将hwirq和irq_data→irq建立映射。这里有两种映射方式一种是线性映射,一种是树形映射

static void irq_domain_set_mapping(struct irq_domain *domain,irq_hw_number_t hwirq,
                      struct irq_data *irq_data) {   if (hwirq < domain->revmap_size) {     domain->linear_revmap[hwirq] = irq_data->irq;   } else {     mutex_lock(&domain->revmap_tree_mutex);     radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);     mutex_unlock(&domain->revmap_tree_mutex);   } }

 

irq和irq_desc的关系

在分配一个softirq的时候,其实最终也会分配一个irq_desc结构的

这里有两种管理方式,一种是通过线性固定开机固定分配好了的,一种是动态分配的

static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,const struct cpumask *affinity,struct module *owner)
{
  struct irq_desc *desc;

  desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);
  if (!desc)
    return NULL;
  /* allocate based on nr_cpu_ids */
  desc->kstat_irqs = alloc_percpu(unsigned int);
  if (!desc->kstat_irqs)
    goto err_desc;

  if (alloc_masks(desc, node))
    goto err_kstat;

  raw_spin_lock_init(&desc->lock);
  lockdep_set_class(&desc->lock, &irq_desc_lock_class);
  mutex_init(&desc->request_mutex);
  init_rcu_head(&desc->rcu);

  desc_set_defaults(irq, desc, node, affinity, owner);
  irqd_set(&desc->irq_data, flags);
  kobject_init(&desc->kobj, &irq_kobj_type);
  return desc;

err_kstat:
  free_percpu(desc->kstat_irqs);
err_desc:
  kfree(desc);
  return NULL;
}

开机已经分配好了的,用于irq比较少

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
  [0 ... NR_IRQS-1] = {
    .handle_irq = handle_bad_irq,
    .depth = 1,
    .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
   }
 };

 


通过irq_to_desc函数来获取desc通过irq的值,两种方式

struct irq_desc *irq_to_desc(unsigned int irq)
{
  return radix_tree_lookup(&irq_desc_tree, irq);
}

struct irq_desc *irq_to_desc(unsigned int irq)
{
  return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}

申请中断

通过request_irq函数来设置中断的回调函数,最终会设置到Irqaction中去

int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, 
              unsigned long irqflags,const char *devname, void *dev_id) {   struct irqaction *action;   struct irq_desc *desc;   action->handler = handler; //设置中断回调函数   action->thread_fn = thread_fn; //如果中断是线程化,则需要设置此回调   action->flags = irqflags;   action->name = devname;   action->dev_id = dev_id; }

处理中断

irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
  irqreturn_t retval = IRQ_NONE;
  unsigned int irq = desc->irq_data.irq;
  struct irqaction *action;

  record_irq_time(desc);

  for_each_action_of_desc(desc, action) {
  irqreturn_t res;

  trace_irq_handler_entry(irq, action);
  res = action->handler(irq, action->dev_id); //处理中断
  trace_irq_handler_exit(irq, action, res);

  if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",irq, action->handler))
    local_irq_disable();

  switch (res) {
    case IRQ_WAKE_THREAD:
    /*
    * Catch drivers which return WAKE_THREAD but
    * did not set up a thread function
    */
      if (unlikely(!action->thread_fn)) {
        warn_no_thread(irq, action);
        break;
      }

      __irq_wake_thread(desc, action);

    /* Fall through to add to randomness */
    case IRQ_HANDLED:
      *flags |= action->flags;
      break;

    default:
      break;
    }

    retval |= res;
  }

  return retval;
}

处理中断,action->handler(irq, action->dev_id);
如果是中断线程的话,唤醒线程 __irq_wake_thread(desc, action);

 

 

标签:domain,struct,Irq,linux,irq,action,data,desc
From: https://www.cnblogs.com/lianglianglu/p/17333654.html

相关文章

  • Linux课程(大数据、JavaEE,Python通用版)
    尚硅谷Linux课程(大数据、JavaEE,Python通用版)整理:韩顺平Linux课程笔记第1章LINUX开山篇1.1本套LINUX课程的内容介绍1.2LINUX的学习方向1.2.1Linux运维工程师.1.2.2Linux嵌入式开发工程师.123在linux下做各种程序开发.1.2.4示意图.1.3LINUX的应用领域......
  • linux中定时脚本logrotate是做什么的?
    centos7环境/etc/cron.daily/logrotatelogrotate是Linux系统中的一个定时脚本,它用于管理日志文件,自动地进行日志文件的轮换、压缩和删除等操作,以避免日志文件过大导致系统崩溃,同时也有利于日志查询和分析。具体来说,logrotate可以实现以下功能:日志文件的轮换:logrotate会按......
  • Linux最常见的三个应用领域详解!
    Linux应用领域有很多,其中最为主要的就是这三种:IT服务器Linux系统应用领域、嵌入式Linux系统应用领域和个人桌面linux应用领域,接下来我们来看看具体的内容介绍。与Windows操作系统软件一样,Linux也是一个操作系统软件。但与Windows不同的是,Linux是一套开放源代码程序的,并可以......
  • Vmware 安装 Linux系统 设置 静态IP 桥接模式 无法连接网络?可能是没设置好
    可能是你没有设置好连接step.1step.2这里需要选择你电脑硬件的网卡,选其他的没用。......
  • 在 Linux 上配置一个 syslog 服务器
    Syslog服务器可以用作一个网络中的日志监控中心,所有能够通过网络来发送日志的设施(包含了Linux或Windows服务器,路由器,交换机以及其他主机)都可以把日志发送给它。通过设置一个syslog服务器,可以将不同设施/主机发送的日志,过滤和合并到一个独立的位置,这样使得你更容易地查看和获取......
  • 普罗米修斯在Linux的安装
    Prometheus(普罗米修斯)是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发,是GoogleBorgMon监控系统的开源版本。2012年成为社区开源项目,拥有非常活跃的开发人员和用户社区。2016年由Google发起Linux基金会旗下的原生云基金会(CloudNativeComp......
  • 关于ansible-对linux主机的连接性及sudo权限检测
    对于Linux系统的配置检测,需要从如下两个点进行检测1、对于登录连接测试,即ssh登录认证2、sudo权限的检测,这里抽查一个命令进行简单的检测创建.yaml文件,内容如下#description:Conectionandsudopermissiontestforlinuxserver#author:QQ:5201351----hosts:"{{hos......
  • Debian Linux(帕拉迪)的方式:安装Linux并且部署主从nginx的步骤(自己实践过的)
    1. ./configure和make &&makeinstall分开执行,不要连起来,会报错。(其实可以不用&&,其实他们是可以分开执行的,分三步)&&是连接的意思, 2.linux安装nginx后没有sbin目录的解决方法 3.按照第二步修改后启动nginx报错的解决方法解决nginx启动报错nginx:[emerg]open(......
  • linux下C编写及编译、运行
    一、简介 Windows下我们可以使用各种各样的IDE进行编程,这些IDE很多都可以直接编译运行。但在Linux下这两部分是分开的,大多只是编辑器(如Vim),如果要编译的话就需要用到GCC编译器,使用GCC编译器肯定就要接触到Makefile。二、代码编写1、设置Vi:其TAB键默认跳......
  • Linux常用命令总结
    无论是后端程序员还是前端程序员,一定避免不了和Linux系统打交道。可能是自己在学习的时候搭建虚拟机环境,也可能是在公司测试环境进行服务的维护,甚至可能去线上服务器进行生产问题的排查。这就要求我们要熟练使用Linux命令行,相关的常用命令很可能不经常使用就忘了,这里我收集了一些......