Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Linux interrupt Subsystem domain

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces the example analysis of Linux interrupt subsystem domain, which is very detailed and has certain reference value. Friends who are interested must finish it!

As the complexity of modern CPU increases and the number of peripheral interrupts increases, in fact, the system may need multiple interrupt controllers to cascade at the same time. In the face of this trend, Linux introduces the concept of irq domain.

All the interrupt controller in the Linux system will form a tree structure. For the interrupt request that each interrupt controller can connect several peripherals, interrupt controller will number the interrupt source connected to it (that is, HW interrupt ID, later we call it hirq), but this number is only limited to the scope of this interrupt controller. Now that hirq exists, in the system software, there is a globally managed number that locates the controller and the interrupt number in the controller, which we call virq (the irq number we need to call API request_irq in the Linux system is actually the virq number). For interrupt cascading, let's take TI's TiTDA series as an example, as shown in the following figure:

Linux interrupt subsystem domain detailed explanation Linux interrupt subsystem domain detailed explanation

As shown in the figure above, the CPU is directly connected to the interrupt controller GICv3, but the GIC is not directly connected to the device, but to the INTR controller, and the INTR controller is connected to the INTA controller, and finally the INTA controller is directly connected to the device. In fact, it simply forms a simple tree structure here.

The hirq arrangement in domain can be tree-shaped or linear, which is mainly discussed in this paper.

Let's first look at the structure of domain (an interrupt controller can be thought of as a domain):

The name of struct irq_domain {struct list_head link; const char * name; / / domain const struct irq_domain_ops * ops; / / the current domain processing function void * host_data; / / stores private data unsigned int flags; unsigned int mapcount; / * Optional data * / struct fwnode_handle * fwnode; / / is related to the device tree enum irq_domain_bus_token bus_token / / bus tag to match the parent node of domain struct irq_domain_chip_generic * gc;#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_domain * parent; / / the maximum number of nodes supported by the domain#endif irq_hw_number_t hwirq_max; / / hwirq tree (radix tree) unsigned int revmap_direct_max_irq; / / hwirq and the maximum number of unsigned int revmap_size supported by the virq 1:1 mapping / / maximum number of tree roots of struct radix_tree_root revmap_tree; / / radix tree supported by linear mapping []; / / array of linear maps}

As shown in the figure above, the structure of domain is basically about hirq-related information. Therefore, we can infer that domain is used to manage hirq (each domain has its own set of hirq), and the ops field in domain is used to manipulate these hirq. The following is the structure of domain's operation function ops:

Struct irq_domain_ops {int (* match) (struct irq_domain * d, struct device_node * node, enum irq_domain_bus_token bus_token); / / used to match domain with lower priority than selec int (* select) (struct irq_domain * d, struct irq_fwspec * fwspec, enum irq_domain_bus_token bus_token) / / used to match domain with higher priority than match int (* map) (struct irq_domain * d, unsigned int virq, irq_hw_number_t hw); / / Linear mapping void (* unmap) (struct irq_domain * d, unsigned int virq) Int (* xlate) (struct irq_domain * d, struct device_node * node, / / obtain const U32 * intspec, unsigned int intsize, unsigned long * out_hwirq, unsigned int * out_type through parameters and linear hirq) # ifdef CONFIG_IRQ_DOMAIN_HIERARCHY / * extended V2 interfaces to support hierarchy irq_domains * / int (* alloc) (struct irq_domain * d, unsigned int virq,// tree node application, mapping (tree only) unsigned int nr_irqs, void * arg); void (* free) (struct irq_domain * d, unsigned int virq, unsigned int nr_irqs); int (* activate) (struct irq_domain * d, struct irq_data * irqd, bool reserve) / / interrupt activation of void (* deactivate) (struct irq_domain * d, struct irq_data * irq_data); int (* translate) (struct irq_domain * d, struct irq_fwspec * fwspec, / / obtain unsigned long * out_hwirq, unsigned int * out_type through parameter pair tree hirq); # endif}

As shown in the figure above, for the hirq of domain, we can see that there are functions in the structure that query the allocation of hirq and the mapping of hirq and virq. Now that we know the data structure of domain, here is the process for an interrupt controller to register a domain:

Irq_domain_add_hierarchy irq_domain_create_tree _ irq_domain_add list_add (& domain- > link, & irq_domain_list)

It can be seen that eventually all the domain are added to the irq_domain_list linked list. But we know that we call request_irq with the virq number, not the hirq, because the hirq number is not unique, and each domain may have the same hirq, so the Linux adds the virq number, which is independent and unique. Now that domain has been registered, the direct relationship between hirq and virq has not been established, so we cannot register interrupts with virq. Here is a mapping function call between hirq and virq:

Irq_create_fwspec_mapping (input domain and parameters) irq_find_matching_fwspec domain- > ops- > match / / check whether the current domain matches the domain specified by the parameter irq_domain_translate domain- > ops- > translate / / apply for a hirq number through the parameter irq_find_mapping / / query whether the hirq has been mapped by hirq. If it has been mapped, return virq irq_domain_alloc_irqs / / hirq without mapping Use this function to apply for a virq and map _ _ irq_domain_alloc_irqs irq_domain_alloc_descs / / apply for an irq_desc description irq_domain_alloc_irq_data / / set an irq_data tree for virq, and the virq will be the parent domain of its domain until root domain adds irq_data irq_domain_alloc_irqs_hierarchy / / applies for hirq from domain And map with virq domain- > ops- > alloc irq_domain_set_hwirq_and_chip / / associate hirq with the irq_data of virq irq_domain_insert_irq// insert virq information into each level of irq_data (one domain corresponds to one irq_data)

As shown in the figure above, when the driver calls the irq_create_fwspec_mapping function, the function will apply for hirq through the parameters in the specified domain, then apply for a virq and associate virq with hirq. The following figure is the structure diagram of irq_data:

As shown in the figure above, linear_revmap (linear) or revmap_tree (radix tree) is used in domain to save the irq_data structure. When we receive an interrupt, we only know the hirq number and the corresponding domain, so we can obtain the irq_data data structure from revmap_tree or linear_revmap with hirq as the key value. When we call request_irq, we only fill in virq, so we can also get the irq_desc description in the irq_desc_tree or irq_desc [] array using virq as key, thus getting the irq_data of this description. Irq_data contains irq_chip (functions such as interrupt control mask, setting trigger mode, etc.), virq (this value is the same as the virq of the irq_data 's parent node parent_data (irq_data)), and hwirq (the hwirq of each irq_data is different Corresponding to different domain internal numbers), domain (pointing to the domain where the current irq_data resides), chip_data (private data pointing to the domain where the current irq_data resides), and parent_data (pointing to the parent node of the irq_data, which stores the information about the parent domain).

Linear_revmap and revmap_tree are variables in the domain structure, with each domain, used to hold the correspondence between hirq and irq_data; irq_desc_tree and irq_desc [] are global variables that hold the linked list or tree of the irq_desc structure.

Typically in the ARMv8 architecture, the flow of interrupt processing is shown in the following figure:

As shown in the figure above, our processing flow is in el1 mode. In el1 mode, the common interrupt function at the assembly level is el1_irq. In the figure, we can see the points indicated by several arrows, 1, handle_arch_irq;2, desc- > handle_irq;3, irqaction- > handler. We know that the CPU of the ARM architecture is usually connected to the GIC interrupt controller, and the detailed "ARM interrupt controller-GICv2". Therefore, handle_arch_irq, a global function pointer, is set by a general interrupt controller GIC driver (GIC driver calls the set_handle_irq function setting), so that all abnormal interrupts on CPU are handled by the callback function of GIC. The GIC callback function gic_handle_irq (that is, handle_arch_irq) is responsible for mask interrupts and eoi interrupts (eoi is the ack controller). In this callback function, we can obtain the interrupt number of the current control (the hirq of the domain) through the register value, trigger the interrupt, then get the corresponding virq through hirq, thus get the irq_desc description, and finally call the handle_irq described by irq_desc to handle the interrupt. From the figure, we can also see that the handle_irq function is actually registered, but in order to facilitate unification, this callback usually uses the gic driver to register a unified callback function (handle_fasteoi_irq) for each interrupt; the handle_fasteoi_irq function supports interrupt sharing, and then calls the handle function in the irqaction structure under the irq_desc (players add an irqaction to the corresponding virq each time they call request_irq in turn).

Irq_desc is a description structure corresponding to virq, and each virq corresponds to this structure. There are irq_data and irqaction variables in the irq_desc structure, one for storing the hirq information mapped to the current virq, and the other for storing the interrupt callback handler for the virq. The nr_irqs global variable holds the maximum number of interrupts currently supported (can be extended through the irq_expand_nr_irqs function)

The above is all the contents of the article "sample Analysis of Linux interrupt Subsystem domain". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report