unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
desc = __this_cpu_read(vector_irq[vector]); 根据硬中断号找到中断描述符
}
以RTC时钟中断注册为例
static int mtk_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
struct mt6397_rtc *rtc;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6397_rtc), GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rtc->addr_base = res->start;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); // 第一步 获取中断资源, 中断号, 高/低 边沿/电平触发
rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start); // 第二步 进行软硬中断映射
=>unsigned int irq_create_mapping(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
struct device_node *of_node;
int virq;
/* Look for default domain if nececssary */
if (domain == NULL)
domain = irq_default_domain;
of_node = irq_domain_get_of_node(domain);
/* Check if mapping already exists */
virq = irq_find_mapping(domain, hwirq); // 已经映射则返回
=>unsigned int irq_find_mapping(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
struct irq_data *data;
/* Look for default domain if nececssary */
if (domain == NULL)
domain = irq_default_domain;
if (domain == NULL)
return 0;
if (hwirq < domain->revmap_direct_max_irq) {
data = irq_domain_get_irq_data(domain, hwirq);
if (data && data->hwirq == hwirq)
return hwirq;
}
/* Check if the hwirq is in the linear revmap. */
if (hwirq < domain->revmap_size)
return domain->linear_revmap[hwirq];
rcu_read_lock();
data = radix_tree_lookup(&domain->revmap_tree, hwirq); // 树查找
rcu_read_unlock();
return data ? data->irq : 0;
}
if (virq) {
return virq;
}
/* Allocate a virtual interrupt number */
virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);
=>int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
int node, const struct cpumask *affinity)
{
virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,
affinity);
=>int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
struct module *owner, const struct cpumask *affinity)
{
start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
from, cnt, 0);
ret = alloc_descs(start, cnt, node, affinity, owner);
return ret;
}
return virq;
}
irq_domain_associate(domain, virq, hwirq)
return virq;
}
rtc->regmap = mt6397_chip->regmap;
rtc->dev = &pdev->dev;
mutex_init(&rtc->lock);
platform_set_drvdata(pdev, rtc);
ret = request_threaded_irq(rtc->irq, NULL, // 第三步 挂接中断action
mtk_rtc_irq_handler_thread,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
"mt6397-rtc", rtc);
device_init_wakeup(&pdev->dev, 1);
rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
&mtk_rtc_ops, THIS_MODULE);
return 0;
}
中断描述符的申请使用如下函数:alloc_descs 函数根据条件编译宏分静态分配和动态申请
动态申请如下
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
const struct cpumask *affinity, struct module *owner)
{
const struct cpumask *mask = NULL;
struct irq_desc *desc;
unsigned int flags;
int i;
flags = affinity ? IRQD_AFFINITY_MANAGED | IRQD_MANAGED_SHUTDOWN : 0;
mask = NULL;
for (i = 0; i < cnt; i++) {
if (affinity) {
node = cpu_to_node(cpumask_first(affinity));
mask = affinity;
affinity++;
}
desc = alloc_desc(start + i, node, flags, mask, owner);
irq_insert_desc(start + i, desc);
irq_sysfs_add(start + i, desc);
irq_add_debugfs_entry(start + i, desc);
}
bitmap_set(allocated_irqs, start, cnt);
return start;
}
静态申请
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
const struct cpumask *affinity,
struct module *owner)
{
u32 i;
for (i = 0; i < cnt; i++) {
struct irq_desc *desc = irq_to_desc(start + i);'
=>struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
==>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),
}
};
}
desc->owner = owner;
}
bitmap_set(allocated_irqs, start, cnt);
return start;
}