irq domain介绍和代码导读
補充IRQ Domain介紹
在linux kernel中,我們使用下面兩個ID來標識一個來自外設的中斷:
1、IRQ number。CPU需要為每一個外設中斷編號,我們稱之IRQ Number。這個IRQ number是一個虛擬的interrupt ID,和硬件無關,僅僅是被CPU用來標識一個外設中斷。
2、HW interrupt ID。對于interrupt controller而言,它收集了多個外設的interrupt request line并向上傳遞,因此,interrupt controller需要對外設中斷進行編碼。Interrupt controller用HW interrupt ID來標識外設的中斷。在interrupt controller級聯的情況下,僅僅用HW interrupt ID已經不能唯一標識一個外設中斷,還需要知道該HW interrupt ID所屬的interrupt controller(HW interrupt ID在不同的Interrupt controller上是會重復編碼的)。
這樣,CPU和interrupt controller在標識中斷上就有了一些不同的概念,但是,對于驅動工程師而言,我們和CPU視角是一樣的,我們只希望得到一個IRQ number,而不關系具體是那個interrupt controller上的那個HW interrupt ID。這樣一個好處是在中斷相關的硬件發生變化的時候,驅動軟件不需要修改。因此,linux kernel中的中斷子系統需要提供一個將HW interrupt ID映射到IRQ number上來的機制…
(本段轉載自:http://www.wowotech.net/linux_kenrel/irq-domain.html)
1、創建一個irq domain,注意是tree型的
(linux/drivers/irqchip/irq-gic-v3.c)static int __init gic_init_bases(void __iomem *dist_base,struct redist_region *rdist_regs,u32 nr_redist_regions,u64 redist_stride,struct fwnode_handle *handle) ......gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); ...... }2、為domain分配中斷號
(linux/drivers/irqchip/irq-gic-v3.c)static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,unsigned int nr_irqs, void *arg) {int i, ret;irq_hw_number_t hwirq;unsigned int type = IRQ_TYPE_NONE;struct irq_fwspec *fwspec = arg;ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);if (ret)return ret;for (i = 0; i < nr_irqs; i++) {ret = gic_irq_domain_map(domain, virq + i, hwirq + i);if (ret)return ret;}return 0; }3、對irq進行map
(linux/drivers/irqchip/irq-gic-v3.c)static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,irq_hw_number_t hw) {struct irq_chip *chip = &gic_chip;struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));if (static_branch_likely(&supports_deactivate_key))chip = &gic_eoimode1_chip;switch (__get_intid_range(hw)) {case SGI_RANGE:case PPI_RANGE:case EPPI_RANGE:irq_set_percpu_devid(irq);irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_percpu_devid_irq, NULL, NULL);break;case SPI_RANGE:case ESPI_RANGE:irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_fasteoi_irq, NULL, NULL);irq_set_probe(irq);irqd_set_single_target(irqd);break;case LPI_RANGE:if (!gic_dist_supports_lpis())return -EPERM;irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_fasteoi_irq, NULL, NULL);break;default:return -EPERM;}/* Prevents SW retriggers which mess up the ACK/EOI ordering */irqd_set_handle_enforce_irqctx(irqd);return 0; }5、使用示例:
xxxx_yyyy_engine {compatible = "xxxx,yyyy_engine";interrupts = <0 52 0x4>,<0 57 0x4>; // 兩個硬件中斷號 };yyyy_irq1 = irq_of_parse_and_map(np, 0); //map成linux kernel中的中斷號 yyyy_irq2 = irq_of_parse_and_map(np, 1); //map成linux kernel中的中斷號ret = request_irq(yyyy_irq1, handler1,IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "name1", NULL) //注冊中斷 ret = request_irq(yyyy_irq2, handler2,IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "name2", NULL) //注冊中斷參考irqdomain
總結
以上是生活随笔為你收集整理的irq domain介绍和代码导读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 思考:Linux Kernel的中断处理
- 下一篇: Linux Kernel5.10的核间通