.. include:: ../../disclaimer-zh_CN.rst :Original: Documentation/core-api/irq/irq-domain.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn> .. _cn_irq-domain.rst: ======================= irq_domain ä¸æ–å·æ˜ 射库 ======================= ç›®å‰Linuxå†…æ ¸çš„è®¾è®¡ä½¿ç”¨äº†ä¸€ä¸ªå·¨å¤§çš„æ•°å—空间,æ¯ä¸ªç‹¬ç«‹çš„IRQæºéƒ½è¢«åˆ†é…äº†ä¸€ä¸ªä¸ åŒçš„æ•°å—。 当åªæœ‰ä¸€ä¸ªä¸æ–控制器时,这很简å•ï¼Œä½†åœ¨æœ‰å¤šä¸ªä¸æ–控制器的系统ä¸ï¼Œå†…æ ¸å¿…é¡»ç¡®ä¿æ¯ 个ä¸æ–控制器都能得到éžé‡å¤çš„Linux IRQå·ï¼ˆæ•°å—)分é…。 注册为唯一的irqchipsçš„ä¸æ–控制器编å·å‘ˆçŽ°å‡ºä¸Šå‡çš„趋势:例如GPIO控制器ç‰ä¸åŒ ç§ç±»çš„å驱动程åºé€šè¿‡å°†å…¶ä¸æ–处ç†ç¨‹åºå»ºæ¨¡ä¸ºirqchips,å³å®žé™…上是级è”ä¸æ–控制器, é¿å…了é‡æ–°å®žçŽ°ä¸ŽIRQæ ¸å¿ƒç³»ç»Ÿç›¸åŒçš„回调机制。 在这里,ä¸æ–å·ä¸Žç¡¬ä»¶ä¸æ–å·ç¦»æ•£äº†æ‰€æœ‰ç§ç±»çš„对应关系:而在过去,IRQå·å¯ä»¥é€‰æ‹©ï¼Œ 使它们与硬件IRQçº¿è¿›å…¥æ ¹ä¸æ–控制器(å³å®žé™…å‘CPUå‘å°„ä¸æ–线的组件)相匹é…,现 在这个编å·ä»…仅是一个数å—。 å‡ºäºŽè¿™ä¸ªåŽŸå› ï¼Œæˆ‘ä»¬éœ€è¦ä¸€ç§æœºåˆ¶å°†æŽ§åˆ¶å™¨æœ¬åœ°ä¸æ–å·ï¼ˆå³ç¡¬ä»¶irqç¼–å·ï¼‰ä¸ŽLinux IRQ å·åˆ†å¼€ã€‚ irq_alloc_desc*() å’Œ irq_free_desc*() API æ供了对irqå·çš„分é…ï¼Œä½†å®ƒä»¬ä¸ æ供任何对控制器本地IRQ(hwirq)å·åˆ°Linux IRQå·ç©ºé—´çš„åå‘æ˜ å°„çš„æ”¯æŒã€‚ irq_domain 库在 irq_alloc_desc*() API çš„åŸºç¡€ä¸Šå¢žåŠ äº† hwirq å’Œ IRQ å·ç ä¹‹é—´çš„æ˜ å°„ã€‚ 相比于ä¸æ–控制器驱动开放编ç 自己的åå‘æ˜ å°„æ–¹æ¡ˆï¼Œæˆ‘ä»¬æ›´å–œæ¬¢ç”¨ irq_domainæ¥ç®¡ç†æ˜ 射。 irq_domain还实现了从抽象的irq_fwspec结构体到hwirqå·çš„转æ¢ï¼ˆåˆ°ç›®å‰ä¸ºæ¢æ˜¯ Device Treeå’ŒACPI GSI),并且å¯ä»¥å¾ˆå®¹æ˜“地扩展以支æŒå…¶å®ƒIRQ拓扑数æ®æºã€‚ irq_domain的用法 ================ ä¸æ–控制器驱动程åºé€šè¿‡ä»¥ä¸‹æ–¹å¼åˆ›å»ºå¹¶æ³¨å†Œä¸€ä¸ªirq_domain。调用 irq_domain_add_*() 或 irq_domain_create_*()函数之一(æ¯ä¸ªæ˜ å°„æ–¹æ³•éƒ½æœ‰ä¸ åŒçš„分é…器函数,åŽé¢ä¼šè¯¦ç»†ä»‹ç»ï¼‰ã€‚ 函数æˆåŠŸåŽä¼šè¿”回一个指å‘irq_domain的指针。 调用者必须å‘分é…器函数æ供一个irq_domain_ops结构体。 在大多数情况下,irq_domain在开始时是空的,没有任何hwirqå’ŒIRQå·ä¹‹é—´çš„æ˜ å°„ã€‚ 通过调用irq_create_mapping()å°†æ˜ å°„æ·»åŠ åˆ°irq_domainä¸ï¼Œè¯¥å‡½æ•°æŽ¥å— irq_domain和一个hwirqå·ä½œä¸ºå‚数。 如果hwirqçš„æ˜ å°„è¿˜ä¸å˜åœ¨ï¼Œé‚£ä¹ˆå®ƒå°†åˆ†é… 一个新的Linux irq_desc,将其与hwirqå…³è”èµ·æ¥ï¼Œå¹¶è°ƒç”¨.map()å›žè°ƒï¼Œè¿™æ ·é©±åŠ¨ 程åºå°±å¯ä»¥æ‰§è¡Œä»»ä½•å¿…è¦çš„硬件设置。 ä¸€æ—¦å»ºç«‹äº†æ˜ å°„ï¼Œå¯ä»¥é€šè¿‡å¤šç§æ–¹æ³•æ£€ç´¢æˆ–使用它: - irq_resolve_mapping()返回一个指å‘给定域和hwirqå·çš„irq_desc结构指针, å¦‚æžœæ²¡æœ‰æ˜ å°„åˆ™è¿”å›žNULL。 - irq_find_mapping()返回给定域和hwirqçš„Linux IRQå·ï¼Œå¦‚æžœæ²¡æœ‰æ˜ å°„åˆ™è¿”å›ž0。 - irq_linear_revmap()现与irq_find_mapping()相åŒï¼Œå·²è¢«åºŸå¼ƒã€‚ - generic_handle_domain_irq()处ç†ä¸€ä¸ªç”±åŸŸå’Œhwirqå·æè¿°çš„ä¸æ–。 请注æ„,irq域的查找必须å‘生在与RCU读临界区兼容的上下文ä¸ã€‚ 在调用irq_find_mapping()之å‰ï¼Œè‡³å°‘è¦è°ƒç”¨ä¸€æ¬¡irq_create_mapping()函数, 以å…æ述符ä¸èƒ½è¢«åˆ†é…。 如果驱动程åºæœ‰Linuxçš„IRQå·æˆ–irq_data指针,并且需è¦çŸ¥é“相关的hwirqå·ï¼ˆæ¯” 如在irq_chip回调ä¸ï¼‰ï¼Œé‚£ä¹ˆå¯ä»¥ç›´æŽ¥ä»Žirq_data->hwirqä¸èŽ·å¾—。 irq_domainæ˜ å°„çš„ç±»åž‹ ==================== 从hwirq到Linux irqçš„åå‘æ˜ å°„æœ‰å‡ ç§æœºåˆ¶ï¼Œæ¯ç§æœºåˆ¶ä½¿ç”¨ä¸åŒçš„分é…函数。应该 使用哪ç§åå‘æ˜ å°„ç±»åž‹å–决于用例。 下é¢ä»‹ç»æ¯ä¸€ç§åå‘æ˜ å°„ç±»åž‹ï¼š çº¿æ€§æ˜ å°„ -------- :: irq_domain_add_linear() irq_domain_create_linear() 线性åå‘æ˜ å°„ç»´æŠ¤äº†ä¸€ä¸ªå›ºå®šå¤§å°çš„表,该表以hwirqå·ä¸ºç´¢å¼•ã€‚ 当一个hwirqè¢«æ˜ å°„ 时,会给hwirq分é…一个irq_desc,并将irqå·å˜å‚¨åœ¨è¡¨ä¸ã€‚ 当最大的hwirqå·å›ºå®šä¸”æ•°é‡ç›¸å¯¹è¾ƒå°‘时,线性图是一个很好的选择(~<256)。 è¿™ç§ æ˜ å°„çš„ä¼˜ç‚¹æ˜¯å›ºå®šæ—¶é—´æŸ¥æ‰¾IRQå·ï¼Œè€Œä¸”irq_descsåªåˆ†é…给在用的IRQ。 缺点是该表 必须尽å¯èƒ½å¤§çš„hwirqå·ã€‚ irq_domain_add_linear()å’Œirq_domain_create_linear()在功能上是ç‰ä»·çš„, 除了第一个å‚æ•°ä¸åŒ--å‰è€…接å—一个Open Firmware特定的 'struct device_node' 而 åŽè€…接å—一个更通用的抽象 'struct fwnode_handle' 。 å¤§å¤šæ•°é©±åŠ¨åº”è¯¥ä½¿ç”¨çº¿æ€§æ˜ å°„ æ ‘çŠ¶æ˜ å°„ -------- :: irq_domain_add_tree() irq_domain_create_tree() irq_domain维护ç€ä»Žhwirqå·åˆ°Linux IRQçš„radixçš„æ ‘çŠ¶æ˜ å°„ã€‚ 当一个hwirqè¢«æ˜ å°„æ—¶ï¼Œ 一个irq_desc被分é…,hwirq被用作radixæ ‘çš„æŸ¥æ‰¾é”®ã€‚ 如果hwirqå·å¯ä»¥éžå¸¸å¤§ï¼Œæ ‘çŠ¶æ˜ å°„æ˜¯ä¸€ä¸ªå¾ˆå¥½çš„é€‰æ‹©ï¼Œå› ä¸ºå®ƒä¸éœ€è¦åˆ†é…一个和最大hwirq å·ä¸€æ ·å¤§çš„表。 缺点是,hwirq到IRQå·çš„查找å–决于表ä¸æœ‰å¤šå°‘æ¡ç›®ã€‚ irq_domain_add_tree()å’Œirq_domain_create_tree()在功能上是ç‰ä»·çš„,除了第一 个å‚æ•°ä¸åŒâ€”—å‰è€…接å—一个Open Firmware特定的 'struct device_node' ,而åŽè€…æŽ¥å— ä¸€ä¸ªæ›´é€šç”¨çš„æŠ½è±¡ 'struct fwnode_handle' 。 很少有驱动应该需è¦è¿™ä¸ªæ˜ 射。 æ— æ˜ å°„ ------ :: irq_domain_add_nomap() 当硬件ä¸çš„hwirqå·æ˜¯å¯ç¼–程的时候,就å¯ä»¥é‡‡ç”¨æ— æ˜ å°„ç±»åž‹ã€‚ 在这ç§æƒ…况下,最好将 Linux IRQå·ç¼–å…¥ç¡¬ä»¶æœ¬èº«ï¼Œè¿™æ ·å°±ä¸éœ€è¦æ˜ 射了。 调用irq_create_direct_mapping() 会分é…一个Linux IRQå·ï¼Œå¹¶è°ƒç”¨.map()å›žè°ƒï¼Œè¿™æ ·é©±åŠ¨å°±å¯ä»¥å°†Linux IRQå·ç¼–入硬件ä¸ã€‚ 大多数驱动程åºæ— 法使用æ¤æ˜ 射,现在它由CONFIG_IRQ_DOMAIN_NOMAP选项控制。 请ä¸è¦å¼•å…¥æ¤API的新用户。 ä¼ ç»Ÿæ˜ å°„ç±»åž‹ ------------ :: irq_domain_add_simple() irq_domain_add_legacy() irq_domain_create_simple() irq_domain_create_legacy() ä¼ ç»Ÿæ˜ å°„æ˜¯å·²ç»ä¸º hwirqs 分é…了一系列 irq_descs 的驱动程åºçš„特殊情况。 当驱动程 åºä¸èƒ½ç«‹å³è½¬æ¢ä¸ºä½¿ç”¨çº¿æ€§æ˜ 射时,就会使用它。 例如,许多嵌入å¼ç³»ç»Ÿæ¿å¡æ”¯æŒæ–‡ä»¶ä½¿ç”¨ 一组用于IRQå·çš„定义(#defineï¼‰ï¼Œè¿™äº›å®šä¹‰è¢«ä¼ é€’ç»™struct设备注册。 在这ç§æƒ…况下, ä¸èƒ½åŠ¨æ€åˆ†é…Linux IRQå·ï¼Œåº”è¯¥ä½¿ç”¨ä¼ ç»Ÿæ˜ å°„ã€‚ 顾åæ€ä¹‰ï¼Œ\*_legacy()系列函数已被废弃,åªæ˜¯ä¸ºäº†æ–¹ä¾¿å¯¹å¤è€å¹³å°çš„支æŒè€Œå˜åœ¨ã€‚ ä¸åº”è¯¥å¢žåŠ æ–°çš„ç”¨æˆ·ã€‚å½“\*_simple()系列函数的使用导致é—留行为时,他们也是如æ¤ã€‚ ä¼ ç»Ÿæ˜ å°„å‡è®¾å·²ç»ä¸ºæŽ§åˆ¶å™¨åˆ†é…了一个连ç»çš„IRQå·èŒƒå›´ï¼Œå¹¶ä¸”å¯ä»¥é€šè¿‡å‘hwirqå·æ·»åŠ 一 个固定的å移æ¥è®¡ç®—IRQå·ï¼Œå之亦然。 缺点是需è¦ä¸æ–控制器管ç†IRQ分é…,并且需è¦ä¸ºæ¯ 个hwirq分é…一个irq_desc,å³ä½¿å®ƒæ²¡æœ‰è¢«ä½¿ç”¨ã€‚ åªæœ‰åœ¨å¿…须支æŒå›ºå®šçš„IRQæ˜ å°„æ—¶ï¼Œæ‰åº”ä½¿ç”¨ä¼ ç»Ÿæ˜ å°„ã€‚ 例如,ISAæŽ§åˆ¶å™¨å°†ä½¿ç”¨ä¼ ç»Ÿæ˜ å°„æ¥ æ˜ å°„Linux IRQ 0-15ï¼Œè¿™æ ·çŽ°æœ‰çš„ISA驱动程åºå°±èƒ½å¾—到æ£ç¡®çš„IRQå·ã€‚ å¤§å¤šæ•°ä½¿ç”¨ä¼ ç»Ÿæ˜ å°„çš„ç”¨æˆ·åº”è¯¥ä½¿ç”¨irq_domain_add_simple()或 irq_domain_create_simple(),åªæœ‰åœ¨ç³»ç»Ÿæä¾›IRQ范围时æ‰ä¼šä½¿ç”¨ä¼ 统域,å¦åˆ™å°†ä½¿ç”¨ çº¿æ€§åŸŸæ˜ å°„ã€‚è¿™ä¸ªè°ƒç”¨çš„è¯ä¹‰æ˜¯è¿™æ ·çš„:如果指定了一个IRQ范围,那么 æ述符将被å³æ—¶åˆ†é… 给它,如果没有范围被分é…,它将ä¸ä¼šæ‰§è¡Œ irq_domain_add_linear() 或 irq_domain_create_linear(),这æ„å‘³ç€ *no* irq æ述符将被分é…。 一个简å•åŸŸçš„典型用例是,irqchip供应商åŒæ—¶æ”¯æŒåŠ¨æ€å’Œé™æ€IRQ分é…。 为了é¿å…最终出现使用线性域而没有æ述符被分é…的情况,确ä¿ä½¿ç”¨ç®€å•åŸŸçš„驱动程åºåœ¨ä»»ä½• irq_find_mapping()之å‰è°ƒç”¨irq_create_mapping()是éžå¸¸é‡è¦çš„ï¼Œå› ä¸ºåŽè€…实际上 将用于é™æ€IRQ分é…情况。 irq_domain_add_simple()å’Œirq_domain_create_simple()ä»¥åŠ irq_domain_add_legacy()å’Œirq_domain_create_legacy()在功能上是ç‰ä»·çš„ï¼Œåª æ˜¯ç¬¬ä¸€ä¸ªå‚æ•°ä¸åŒ--å‰è€…接å—Open Firmware特定的 'struct device_node' ,而åŽè€… 接å—一个更通用的抽象 'struct fwnode_handle' 。 IRQ域层级结构 ------------- 在æŸäº›æž¶æž„上,å¯èƒ½æœ‰å¤šä¸ªä¸æ–控制器å‚与将一个ä¸æ–ä»Žè®¾å¤‡ä¼ é€åˆ°ç›®æ ‡CPU。 让我们æ¥çœ‹çœ‹x86å¹³å°ä¸Šå…¸åž‹çš„ä¸æ–ä¼ é€’è·¯å¾„å§ :: Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU 涉åŠåˆ°çš„ä¸æ–控制器有三个: 1) IOAPIC 控制器 2) ä¸æ–é‡æ˜ 射控制器 3) Local APIC 控制器 为了支æŒè¿™æ ·çš„硬件拓扑结构,使软件架构与硬件架构相匹é…,为æ¯ä¸ªä¸æ–控制器建立一 个irq_domainæ•°æ®ç»“构,并将这些irq_domain组织æˆå±‚次结构。 在建立irq_domain层次结构时,é 近设备的irq_domain为å域,é è¿‘CPUçš„ irq_domain为父域。所以在上é¢çš„例åä¸ï¼Œå°†å»ºç«‹å¦‚下的层次结构。 :: CPU Vector irq_domain (root irq_domain to manage CPU vectors) ^ | Interrupt Remapping irq_domain (manage irq_remapping entries) ^ | IOAPIC irq_domain (manage IOAPIC delivery entries/pins) 使用irq_domain层次结构的主è¦æŽ¥å£æœ‰å››ä¸ª: 1) irq_domain_alloc_irqs(): 分é…IRQæ述符和与ä¸æ–控制器相关的资æºæ¥ä¼ 递这些ä¸æ–。 2) irq_domain_free_irqs(): 释放IRQæ述符和与这些ä¸æ–相关的ä¸æ–控制器资æºã€‚ 3) irq_domain_activate_irq(): 激活ä¸æ–æŽ§åˆ¶å™¨ç¡¬ä»¶ä»¥ä¼ é€’ä¸æ–。 4) irq_domain_deactivate_irq(): åœç”¨ä¸æ–控制器硬件,åœæ¢ä¼ 递ä¸æ–。 为了支æŒirq_domain层次结构,需è¦åšå¦‚下修改: 1) 一个新的å—段 'parent' è¢«æ·»åŠ åˆ°irq_domain结构ä¸ï¼›å®ƒç”¨äºŽç»´æŠ¤irq_domain的层次信æ¯ã€‚ 2) 一个新的å—段 'parent_data' è¢«æ·»åŠ åˆ°irq_data结构ä¸ï¼›å®ƒç”¨äºŽå»ºç«‹å±‚次结构irq_data以 匹é…irq_domain层次结构。irq_data用于å˜å‚¨irq_domain指针和硬件irqå·ã€‚ 3) æ–°çš„å›žè°ƒè¢«æ·»åŠ åˆ°irq_domain_ops结构ä¸ï¼Œä»¥æ”¯æŒå±‚次结构的irq_domainæ“作。 在支æŒåˆ†å±‚irq_domain和分层irq_data准备就绪åŽï¼Œä¸ºæ¯ä¸ªä¸æ–控制器建立一个irq_domain结 构,并为æ¯ä¸ªä¸ŽIRQ相关è”çš„irq_domain分é…一个irq_data结构。现在我们å¯ä»¥å†è¿›ä¸€æ¥æ”¯æŒå † æ ˆå¼(层次结构)çš„irq_chip。也就是说,一个irq_chip与层次结构ä¸çš„æ¯ä¸ªirq_data相关è”。 一个åirq_chipå¯ä»¥è‡ªå·±æˆ–通过与它的父irq_chipåˆä½œæ¥å®žçŽ°ä¸€ä¸ªæ‰€éœ€çš„æ“作。 é€šè¿‡å †æ ˆå¼çš„irq_chip,ä¸æ–控制器驱动åªéœ€è¦å¤„ç†è‡ªå·±ç®¡ç†çš„硬件,在需è¦çš„时候å¯ä»¥å‘其父 irq_chip请求æœåŠ¡ã€‚所以我们å¯ä»¥å®žçŽ°æ›´ç®€æ´çš„软件架构。 为了让ä¸æ–控制器驱动程åºæ”¯æŒirq_domain层次结构,它需è¦åšåˆ°ä»¥ä¸‹å‡ 点: 1) 实现 irq_domain_ops.alloc å’Œ irq_domain_ops.free 2) å¯é€‰æ‹©åœ°å®žçŽ° irq_domain_ops.activate å’Œ irq_domain_ops.deactivate. 3) å¯é€‰æ‹©åœ°å®žçŽ°ä¸€ä¸ªirq_chipæ¥ç®¡ç†ä¸æ–控制器硬件。 4) ä¸éœ€è¦å®žçŽ°irq_domain_ops.mapå’Œirq_domain_ops.unmap,它们在层次结构 irq_domainä¸æ˜¯ä¸ç”¨çš„。 irq_domain层次结构ç»ä¸æ˜¯x86特有的,大é‡ç”¨äºŽæ”¯æŒå…¶ä»–架构,如ARMã€ARM64ç‰ã€‚ 调试功能 ======== 打开CONFIG_GENERIC_IRQ_DEBUGFS,å¯è®©IRQå系统的大部分内部结构都在debugfsä¸æš´éœ²å‡ºæ¥ã€‚