本文以S5PV210芯片为参照,S5PV210的中断控制器采用了ARM VIC(Vectored Interrupt Controller
,PL192 ,ARM PrimeCell Vectored Interrupt Controller )。ARM VIC的驱动代码位于drivers/irqchip/irq-vic.c。首先介绍Linux中断框架中使用的一些数据结构。
//include/linux/irqdomain.h/** * struct irq_domain_ops - Methods for irq_domain objects * @match: Match an interrupt controller device node to a host, returns * 1 on a match * @map: Create or update a mapping between a virtual irq number and a hw * irq number. This is called only once for a given mapping. * @unmap: Dispose of such a mapping * @xlate: Given a device tree node and interrupt specifier, decode * the hardware irq number and linux irq type value. * * Functions below are provided by the driver and called whenever a new mapping * is created or an old mapping is disposed. The driver can then proceed to * whatever internal data structures management is required. It also needs * to setup the irq_desc when returning from map(). */struct irq_domain_ops { int (*match)(struct irq_domain *d, struct device_node *node, enum irq_domain_bus_token bus_token); int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); void (*unmap)(struct irq_domain *d, unsigned int virq); int (*xlate)(struct irq_domain *d, struct device_node *node, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type);#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /* extended V2 interfaces to support hierarchy irq_domains */ int (*alloc)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg); void (*free)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs); void (*activate)(struct irq_domain *d, struct irq_data *irq_data); void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data); int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type);#endif};
//include/linux/irqdomain.h/** * struct irq_domain - Hardware interrupt number translation object * @link: Element in global irq_domain list. * @name: Name of interrupt domain * @ops: pointer to irq_domain methods * @host_data: private data pointer for use by owner. Not touched by irq_domain * core code. * @flags: host per irq_domain flags * * Optional elements * @of_node: Pointer to device tree nodes associated with the irq_domain. Used * when decoding device tree interrupt specifiers. * @gc: Pointer to a list of generic chips. There is a helper function for * setting up one or more generic chips for interrupt controllers * drivers using the generic chip library which uses this pointer. * @parent: Pointer to parent irq_domain to support hierarchy irq_domains * * Revmap data, used internally by irq_domain * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that * support direct mapping * @revmap_size: Size of the linear map table @linear_revmap[] * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map * @linear_revmap: Linear table of hwirq->virq reverse mappings */struct irq_domain { struct list_head link; const char *name; const struct irq_domain_ops *ops; void *host_data; unsigned int flags; /* Optional data */ struct fwnode_handle *fwnode; enum irq_domain_bus_token bus_token; struct irq_domain_chip_generic *gc;#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_domain *parent;#endif /* reverse map data. The linear map gets appended to the irq_domain */ irq_hw_number_t hwirq_max; unsigned int revmap_direct_max_irq; unsigned int revmap_size; struct radix_tree_root revmap_tree; unsigned int linear_revmap[];};
//include/linux/irq.h/** * struct irq_data - per irq chip data passed down to chip functions * @mask: precomputed bitmask for accessing the chip registers * @irq: interrupt number * @hwirq: hardware interrupt number, local to the interrupt domain * @common: point to data shared by all irqchips * @chip: low level interrupt hardware access * @domain: Interrupt translation domain; responsible for mapping * between hwirq number and linux irq number. * @parent_data: pointer to parent struct irq_data to support hierarchy * irq_domain * @chip_data: platform-specific per-chip private data for the chip * methods, to allow shared chip implementations */struct irq_data { u32 mask; unsigned int irq; unsigned long hwirq; struct irq_common_data *common; struct irq_chip *chip; struct irq_domain *domain;#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_data *parent_data;#endif void *chip_data;};
//include/linux/irq.h/** * struct irq_chip - hardware interrupt chip descriptor * * @name: name for /proc/interrupts * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) * @irq_enable: enable the interrupt (defaults to chip->unmask if NULL) * @irq_disable: disable the interrupt * @irq_ack: start of a new interrupt * @irq_mask: mask an interrupt source * @irq_mask_ack: ack and mask an interrupt source * @irq_unmask: unmask an interrupt source * @irq_eoi: end of interrupt * @irq_set_affinity: set the CPU affinity on SMP machines * @irq_retrigger: resend an IRQ to the CPU * @irq_set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ * @irq_set_wake: enable/disable power-management wake-on of an IRQ * @irq_bus_lock: function to lock access to slow bus (i2c) chips * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online: configure an interrupt source for a secondary CPU * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU * @irq_suspend: function called from core code on suspend once per * chip, when one or more interrupts are installed * @irq_resume: function called from core code on resume once per chip, * when one ore more interrupts are installed * @irq_pm_shutdown: function called from core code on shutdown once per chip * @irq_calc_mask: Optional function to set irq_data.mask for special cases * @irq_print_chip: optional to print special chip info in show_interrupts * @irq_request_resources: optional to request resources before calling * any other callback related to this irq * @irq_release_resources: optional to release resources acquired with * irq_request_resources * @irq_compose_msi_msg: optional to compose message content for MSI * @irq_write_msi_msg: optional to write message content for MSI * @irq_get_irqchip_state: return the internal state of an interrupt * @irq_set_irqchip_state: set the internal state of a interrupt * @irq_set_vcpu_affinity: optional to target a vCPU in a virtual machine * @flags: chip specific flags */struct irq_chip { const char *name; unsigned int (*irq_startup)(struct irq_data *data); void (*irq_shutdown)(struct irq_data *data); void (*irq_enable)(struct irq_data *data); void (*irq_disable)(struct irq_data *data); void (*irq_ack)(struct irq_data *data); void (*irq_mask)(struct irq_data *data); void (*irq_mask_ack)(struct irq_data *data); void (*irq_unmask)(struct irq_data *data); void (*irq_eoi)(struct irq_data *data); int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force); int (*irq_retrigger)(struct irq_data *data); int (*irq_set_type)(struct irq_data *data, unsigned int flow_type); int (*irq_set_wake)(struct irq_data *data, unsigned int on); void (*irq_bus_lock)(struct irq_data *data); void (*irq_bus_sync_unlock)(struct irq_data *data); void (*irq_cpu_online)(struct irq_data *data); void (*irq_cpu_offline)(struct irq_data *data); void (*irq_suspend)(struct irq_data *data); void (*irq_resume)(struct irq_data *data); void (*irq_pm_shutdown)(struct irq_data *data); void (*irq_calc_mask)(struct irq_data *data); void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); int (*irq_request_resources)(struct irq_data *data); void (*irq_release_resources)(struct irq_data *data); void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg); void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg); int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); int (*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info); unsigned long flags;};
//include/linux/irqdesc.h/** * struct irq_desc - interrupt descriptor * @irq_common_data: per irq and chip data passed down to chip functions * @kstat_irqs: irq stats per cpu * @handle_irq: highlevel irq-events handler * @preflow_handler: handler called before the flow handler (currently used by sparc) * @action: the irq action chain * @status: status information * @core_internal_state__do_not_mess_with_it: core internal status information * @depth: disable-depth, for nested irq_disable() calls * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts * @threads_handled: stats field for deferred spurious detection of threaded handlers * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers * @lock: locking for SMP * @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes * @pending_mask: pending rebalanced interrupts * @threads_oneshot: bitfield to handle shared oneshot threads * @threads_active: number of irqaction threads currently running * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers * @nr_actions: number of installed actions on this descriptor * @no_suspend_depth: number of irqactions on a irq descriptor with * IRQF_NO_SUSPEND set * @force_resume_depth: number of irqactions on a irq descriptor with * IRQF_FORCE_RESUME set * @dir: /proc/irq/ procfs entry * @name: flow handler name for /proc/interrupts output */struct irq_desc { struct irq_common_data irq_common_data; struct irq_data irq_data; unsigned int __percpu *kstat_irqs; irq_flow_handler_t handle_irq;#ifdef CONFIG_IRQ_PREFLOW_FASTEOI irq_preflow_handler_t preflow_handler;#endif struct irqaction *action; /* IRQ action list */ unsigned int status_use_accessors; unsigned int core_internal_state__do_not_mess_with_it; unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; atomic_t threads_handled; int threads_handled_last; raw_spinlock_t lock; struct cpumask *percpu_enabled;#ifdef CONFIG_SMP const struct cpumask *affinity_hint; struct irq_affinity_notify *affinity_notify;#ifdef CONFIG_GENERIC_PENDING_IRQ cpumask_var_t pending_mask;#endif#endif unsigned long threads_oneshot; atomic_t threads_active; wait_queue_head_t wait_for_threads;#ifdef CONFIG_PM_SLEEP unsigned int nr_actions; unsigned int no_suspend_depth; unsigned int cond_suspend_depth; unsigned int force_resume_depth;#endif#ifdef CONFIG_PROC_FS struct proc_dir_entry *dir;#endif int parent_irq; struct module *owner; const char *name;} ____cacheline_internodealigned_in_smp;
//driver/irqchip/irq-vic.c/* *通过IRQCHIP_DECLARE定义一个位于__irqchip_of_table段的全局量struct of_device_id *__of_table_arm_pl192_vic,linux在中断初始化阶段在设备树中寻找是否有对应的节点,找到 *相对应的节点后,随即执行vic_of_init */IRQCHIP_DECLARE(arm_pl192_vic, "arm,pl192-vic", vic_of_init);/* * include/linux/irqchip.h * @name: name that must be unique accross all IRQCHIP_DECLARE of the * same file. * @compstr: compatible string of the irqchip driver * @fn: initialization function */#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)//include/linux/of.h#ifdef CONFIG_OF#define _OF_DECLARE(table, name, compat, fn, fn_type) \ static const struct of_device_id __of_table_##name \ __used __section(__##table##_of_table) \ = { .compatible = compat, \ .data = (fn == (fn_type)NULL) ? fn : fn }#else#define _OF_DECLARE(table, name, compat, fn, fn_type) \ static const struct of_device_id __of_table_##name \ __attribute__((unused)) \ = { .compatible = compat, \ .data = (fn == (fn_type)NULL) ? fn : fn }#endiftypedef int (*of_init_fn_2)(struct device_node *, struct device_node *);typedef void (*of_init_fn_1)(struct device_node *);#define OF_DECLARE_1(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_1)#define OF_DECLARE_2(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_2)
//driver/irqchip/irq-vic.cint __init vic_of_init(struct device_node *node, struct device_node *parent){ void __iomem *regs; u32 interrupt_mask = ~0; u32 wakeup_mask = ~0; if (WARN(parent, "non-root VICs are not supported")) return -EINVAL; regs = of_iomap(node, 0); if (WARN_ON(!regs)) return -EIO; /* *设备树中没有valid-mask、valid-wakeup-mask这两个属性,保持原值 *valid-mask=0xFFFFFFFF, valid-wakeup-mask=0xFFFFFFFF. */ of_property_read_u32(node, "valid-mask", &interrupt_mask); of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask); /* * Passing 0 as first IRQ makes the simple domain allocate descriptors */ __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node); return 0;}
//driver/irqchip/irq-vic.c//__vic_init(regs, 0, 0, 0xffffffff, 0xffffffff, node);void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, u32 vic_sources, u32 resume_sources, struct device_node *node){ unsigned int i; u32 cellid = 0; enum amba_vendor vendor; /* Identify which VIC cell this one is, by reading the ID */ for (i = 0; i < 4; i++) { void __iomem *addr; addr = (void __iomem *)((u32)base & PAGE_MASK) + 0xfe0 + (i * 4); cellid |= (readl(addr) & 0xff) << (8 * i); } vendor = (cellid >> 12) & 0xff; printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x\n", base, cellid, vendor); switch(vendor) { case AMBA_VENDOR_ST: vic_init_st(base, irq_start, vic_sources, node); return; default: printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n"); /* fall through */ case AMBA_VENDOR_ARM: break; } /* Disable all interrupts initially. */ vic_disable(base); /* Make sure we clear all existing interrupts */ vic_clear_interrupts(base); vic_init2(base); vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);}
//drive/irqchip/irq-vic.c//vic_register(base, 0, 0, 0xffffffff, 0xffffffff, node);static void __init vic_register(void __iomem *base, unsigned int parent_irq, unsigned int irq, u32 valid_sources, u32 resume_sources, struct device_node *node){ struct vic_device *v; int i; if (vic_id >= ARRAY_SIZE(vic_devices)) { printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); return; } v = &vic_devices[vic_id]; v->base = base; v->valid_sources = valid_sources; v->resume_sources = resume_sources; set_handle_irq(vic_handle_irq); vic_id++; /* *添加打印代码: *early_print("valid_sources:0x%x, fls(valid_sources):0x%x, * resume_source:0x%x\n.",valid_sources,fls(valid_sources) * ,resume_sources); *打印信息为:(设备树里有四个interrupt-controller节点,所以会注册四次) *valid_sources:0xffffffff, fls(valid_sources):0x20, resume_source:0xffffffff. *valid_sources:0xffffffff, fls(valid_sources):0x20, resume_source:0xffffffff. *valid_sources:0xffffffff, fls(valid_sources):0x20, resume_source:0xffffffff. *valid_sources:0xffffffff, fls(valid_sources):0x20, resume_source:0xffffffff. */ if (parent_irq) { irq_set_chained_handler_and_data(parent_irq, vic_handle_irq_cascaded, v); } v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, &vic_irqdomain_ops, v); /* create an IRQ mapping for each valid IRQ */ for (i = 0; i < fls(valid_sources); i++) { if (valid_sources & (1 << i)) { irq_create_mapping(v->domain, i); } } /* If no base IRQ was passed, figure out our allocated base */ if (irq) v->irq = irq; else v->irq = irq_find_mapping(v->domain, 0);}
//kernel/irq/irqdomain.c/** * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs * @of_node: pointer to interrupt controller's device tree node. * @size: total number of irqs in mapping * @first_irq: first number of irq block assigned to the domain, * pass zero to assign irqs on-the-fly. If first_irq is non-zero, then * pre-map all of the irqs in the domain to virqs starting at first_irq. * @ops: domain callbacks * @host_data: Controller private data pointer * * Allocates an irq_domain, and optionally if first_irq is positive then also * allocate irq_descs and map all of the hwirqs to virqs starting at first_irq. * * This is intended to implement the expected behaviour for most * interrupt controllers. If device tree is used, then first_irq will be 0 and * irqs get mapped dynamically on the fly. However, if the controller requires * static virq assignments (non-DT boot) then it will set that up correctly. */struct irq_domain *irq_domain_add_simple(struct device_node *of_node, unsigned int size, unsigned int first_irq, const struct irq_domain_ops *ops, void *host_data){ struct irq_domain *domain; domain = __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data); if (!domain) return NULL; /* *early_print("%s,%d,%d.\n",__FILE__,__LINE__,first_irq); *传过来的first_irq为零。 */ if (first_irq > 0) { if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { /* attempt to allocated irq_descs */ int rc = irq_alloc_descs(first_irq, first_irq, size, of_node_to_nid(of_node)); if (rc < 0) pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", first_irq); } irq_domain_associate_many(domain, first_irq, 0, size); } return domain;}EXPORT_SYMBOL_GPL(irq_domain_add_simple);
//include/linux/irqdomain.hstatic inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node){ return node ? &node->fwnode : NULL;}//include/linux/fwnode.h/* * fwnode.h - Firmware device node object handle type definition. * * Copyright (C) 2015, Intel Corporation * Author: Rafael J. Wysocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#ifndef _LINUX_FWNODE_H_#define _LINUX_FWNODE_H_enum fwnode_type { FWNODE_INVALID = 0, FWNODE_OF, FWNODE_ACPI, FWNODE_ACPI_DATA, FWNODE_PDATA, FWNODE_IRQCHIP,};struct fwnode_handle { enum fwnode_type type; struct fwnode_handle *secondary;};#endif
/** * __irq_domain_add() - Allocate a new irq_domain data structure * @of_node: optional device-tree node of the interrupt controller * @size: Size of linear map; 0 for radix mapping only * @hwirq_max: Maximum number of interrupts supported by controller * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no * direct mapping * @ops: domain callbacks * @host_data: Controller private data pointer * * Allocates and initialize and irq_domain structure. * Returns pointer to IRQ domain, or NULL on failure. */struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, irq_hw_number_t hwirq_max, int direct_max, const struct irq_domain_ops *ops, void *host_data){ struct irq_domain *domain; struct device_node *of_node; of_node = to_of_node(fwnode); domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), GFP_KERNEL, of_node_to_nid(of_node)); if (WARN_ON(!domain)) return NULL; of_node_get(of_node); /* Fill structure */ INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); domain->ops = ops; domain->host_data = host_data; domain->fwnode = fwnode; domain->hwirq_max = hwirq_max; domain->revmap_size = size; domain->revmap_direct_max_irq = direct_max; irq_domain_check_hierarchy(domain); mutex_lock(&irq_domain_mutex); list_add(&domain->link, &irq_domain_list); mutex_unlock(&irq_domain_mutex); pr_debug("Added domain %s\n", domain->name); return domain;}EXPORT_SYMBOL_GPL(__irq_domain_add);//include/linux/slab.h/** * kzalloc_node - allocate zeroed memory from a particular memory node. * @size: how many bytes of memory are required. * @flags: the type of memory to allocate (see kmalloc). * @node: memory node from which to allocate */static inline void *kzalloc_node(size_t size, gfp_t flags, int node){ return kmalloc_node(size, flags | __GFP_ZERO, node);}static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node){#ifndef CONFIG_SLOB if (__builtin_constant_p(size) && size int i = kmalloc_index(size); if (!i) return ZERO_SIZE_PTR; return kmem_cache_alloc_node_trace(kmalloc_caches[i], flags, node, size); }#endif return __kmalloc_node(size, flags, node);}static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node){ return __kmalloc(size, flags);}
//kernel/irq/irqdomain.c/** * irq_create_mapping() - Map a hardware interrupt into linux irq space * @domain: domain owning this hardware interrupt or NULL for default domain * @hwirq: hardware irq number in that domain space * * Only one mapping per hardware interrupt is permitted. Returns a linux * irq number. * If the sense/trigger is to be specified, set_irq_type() should be called * on the number returned from that call. */unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq){ struct device_node *of_node; int virq; pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); /* Look for default domain if nececssary */ if (domain == NULL) domain = irq_default_domain; if (domain == NULL) { WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq); return 0; } pr_debug("-> using domain @%p\n", domain); of_node = irq_domain_get_of_node(domain); /* Check if mapping already exists */ virq = irq_find_mapping(domain, hwirq); if (virq) { pr_debug("-> existing mapping on virq %d\n", virq); return virq; } /* Allocate a virtual interrupt number */ virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node)); if (virq 0) { pr_debug("-> virq allocation failed\n"); return 0; } if (irq_domain_associate(domain, virq, hwirq)) { irq_free_desc(virq); return 0; } pr_debug("irq %lu on domain %s mapped to virtual irq %u\n", hwirq, of_node_full_name(of_node), virq); return virq;}EXPORT_SYMBOL_GPL(irq_create_mapping);//include/linux/irqdomain.cstatic inline struct device_node *irq_domain_get_of_node(struct irq_domain *d) { return to_of_node(d->fwnode);}//include/linux/of.hstatic inline bool is_of_node(struct fwnode_handle *fwnode){ return fwnode && fwnode->type == FWNODE_OF;}static inline struct device_node *to_of_node(struct fwnode_handle *fwnode){ return is_of_node(fwnode) ? container_of(fwnode, struct device_node, fwnode) : NULL;}//include/linux/of.h#if defined(CONFIG_OF) && defined(CONFIG_NUMA)extern int of_node_to_nid(struct device_node *np);#elsestatic inline int of_node_to_nid(struct device_node *device){ return NUMA_NO_NODE;}#endif
//kernel/irq/irqdomain.c/* *irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node)); *virq传进来为-1,自动分配虚拟irq编号 */static int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, int node){ unsigned int hint; if (virq >= 0) { virq = irq_alloc_descs(virq, virq, cnt, node); } else { hint = hwirq % nr_irqs; if (hint == 0) hint++; /* *此处添加打印 *early_print("%s,%d,hwirq:0x%x,hint:0x%x,nr_irqs:0x%x\n" *,__FILE__,__LINE__,hwirq,hint,nr_irqs);打印信息参看下面 *通过打印信息得治nr_irqs每分配一个irq_desc,nr_irqs就会增加1. */ virq = irq_alloc_descs_from(hint, cnt, node); if (virq 0 && hint > 1) virq = irq_alloc_descs_from(1, cnt, node); } /* /*此处添加打印 *early_print("%s,%d,hwirq:0x%x,hint:0x%x\n",__FILE__,__LINE__,hwirq,hint); *打印信息如下 */ return virq;}kernel/irq/irqdomain.c,847,hwirq:0x0,hint:0x1,nr_irqs:0x10kernel/irq/irqdomain.c,852,hwirq:0x0,virq:0x10kernel/irq/irqdomain.c,847,hwirq:0x1,hint:0x1,nr_irqs:0x11kernel/irq/irqdomain.c,852,hwirq:0x1,virq:0x11kernel/irq/irqdomain.c,847,hwirq:0x2,hint:0x2,nr_irqs:0x12kernel/irq/irqdomain.c,852,hwirq:0x2,virq:0x12kernel/irq/irqdomain.c,847,hwirq:0x3,hint:0x3,nr_irqs:0x13kernel/irq/irqdomain.c,852,hwirq:0x3,virq:0x13kernel/irq/irqdomain.c,847,hwirq:0x4,hint:0x4,nr_irqs:0x14kernel/irq/irqdomain.c,852,hwirq:0x4,virq:0x14kernel/irq/irqdomain.c,847,hwirq:0x5,hint:0x5,nr_irqs:0x15kernel/irq/irqdomain.c,852,hwirq:0x5,virq:0x15kernel/irq/irqdomain.c,847,hwirq:0x6,hint:0x6,nr_irqs:0x16kernel/irq/irqdomain.c,852,hwirq:0x6,virq:0x16kernel/irq/irqdomain.c,847,hwirq:0x7,hint:0x7,nr_irqs:0x17kernel/irq/irqdomain.c,852,hwirq:0x7,virq:0x17kernel/irq/irqdomain.c,847,hwirq:0x8,hint:0x8,nr_irqs:0x18kernel/irq/irqdomain.c,852,hwirq:0x8,virq:0x18kernel/irq/irqdomain.c,847,hwirq:0x9,hint:0x9,nr_irqs:0x19kernel/irq/irqdomain.c,852,hwirq:0x9,virq:0x19kernel/irq/irqdomain.c,847,hwirq:0xa,hint:0xa,nr_irqs:0x1akernel/irq/irqdomain.c,852,hwirq:0xa,virq:0x1akernel/irq/irqdomain.c,847,hwirq:0xb,hint:0xb,nr_irqs:0x1bkernel/irq/irqdomain.c,852,hwirq:0xb,virq:0x1bkernel/irq/irqdomain.c,847,hwirq:0xc,hint:0xc,nr_irqs:0x1ckernel/irq/irqdomain.c,852,hwirq:0xc,virq:0x1ckernel/irq/irqdomain.c,847,hwirq:0xd,hint:0xd,nr_irqs:0x1dkernel/irq/irqdomain.c,852,hwirq:0xd,virq:0x1dkernel/irq/irqdomain.c,847,hwirq:0xe,hint:0xe,nr_irqs:0x1ekernel/irq/irqdomain.c,852,hwirq:0xe,virq:0x1ekernel/irq/irqdomain.c,847,hwirq:0xf,hint:0xf,nr_irqs:0x1fkernel/irq/irqdomain.c,852,hwirq:0xf,virq:0x1fkernel/irq/irqdomain.c,847,hwirq:0x10,hint:0x10,nr_irqs:0x20kernel/irq/irqdomain.c,852,hwirq:0x10,virq:0x20kernel/irq/irqdomain.c,847,hwirq:0x11,hint:0x11,nr_irqs:0x21kernel/irq/irqdomain.c,852,hwirq:0x11,virq:0x21kernel/irq/irqdomain.c,847,hwirq:0x12,hint:0x12,nr_irqs:0x22kernel/irq/irqdomain.c,852,hwirq:0x12,virq:0x22kernel/irq/irqdomain.c,847,hwirq:0x13,hint:0x13,nr_irqs:0x23kernel/irq/irqdomain.c,852,hwirq:0x13,virq:0x23kernel/irq/irqdomain.c,847,hwirq:0x14,hint:0x14,nr_irqs:0x24kernel/irq/irqdomain.c,852,hwirq:0x14,virq:0x24kernel/irq/irqdomain.c,847,hwirq:0x15,hint:0x15,nr_irqs:0x25kernel/irq/irqdomain.c,852,hwirq:0x15,virq:0x25kernel/irq/irqdomain.c,847,hwirq:0x16,hint:0x16,nr_irqs:0x26kernel/irq/irqdomain.c,852,hwirq:0x16,virq:0x26kernel/irq/irqdomain.c,847,hwirq:0x17,hint:0x17,nr_irqs:0x27kernel/irq/irqdomain.c,852,hwirq:0x17,virq:0x27kernel/irq/irqdomain.c,847,hwirq:0x18,hint:0x18,nr_irqs:0x28kernel/irq/irqdomain.c,852,hwirq:0x18,virq:0x28kernel/irq/irqdomain.c,847,hwirq:0x19,hint:0x19,nr_irqs:0x29kernel/irq/irqdomain.c,852,hwirq:0x19,virq:0x29kernel/irq/irqdomain.c,847,hwirq:0x1a,hint:0x1a,nr_irqs:0x2akernel/irq/irqdomain.c,852,hwirq:0x1a,virq:0x2akernel/irq/irqdomain.c,847,hwirq:0x1b,hint:0x1b,nr_irqs:0x2bkernel/irq/irqdomain.c,852,hwirq:0x1b,virq:0x2bkernel/irq/irqdomain.c,847,hwirq:0x1c,hint:0x1c,nr_irqs:0x2ckernel/irq/irqdomain.c,852,hwirq:0x1c,virq:0x2ckernel/irq/irqdomain.c,847,hwirq:0x1d,hint:0x1d,nr_irqs:0x2dkernel/irq/irqdomain.c,852,hwirq:0x1d,virq:0x2dkernel/irq/irqdomain.c,847,hwirq:0x1e,hint:0x1e,nr_irqs:0x2ekernel/irq/irqdomain.c,852,hwirq:0x1e,virq:0x2ekernel/irq/irqdomain.c,847,hwirq:0x1f,hint:0x1f,nr_irqs:0x2fkernel/irq/irqdomain.c,852,hwirq:0x1f,virq:0x2fkernel/irq/irqdomain.c,847,hwirq:0x0,hint:0x1,nr_irqs:0x30kernel/irq/irqdomain.c,852,hwirq:0x0,virq:0x30kernel/irq/irqdomain.c,847,hwirq:0x1,hint:0x1,nr_irqs:0x31kernel/irq/irqdomain.c,852,hwirq:0x1,virq:0x31kernel/irq/irqdomain.c,847,hwirq:0x2,hint:0x2,nr_irqs:0x32kernel/irq/irqdomain.c,852,hwirq:0x2,virq:0x32kernel/irq/irqdomain.c,847,hwirq:0x3,hint:0x3,nr_irqs:0x33kernel/irq/irqdomain.c,852,hwirq:0x3,virq:0x33kernel/irq/irqdomain.c,847,hwirq:0x4,hint:0x4,nr_irqs:0x34kernel/irq/irqdomain.c,852,hwirq:0x4,virq:0x34kernel/irq/irqdomain.c,847,hwirq:0x5,hint:0x5,nr_irqs:0x35kernel/irq/irqdomain.c,852,hwirq:0x5,virq:0x35kernel/irq/irqdomain.c,847,hwirq:0x6,hint:0x6,nr_irqs:0x36kernel/irq/irqdomain.c,852,hwirq:0x6,virq:0x36kernel/irq/irqdomain.c,847,hwirq:0x7,hint:0x7,nr_irqs:0x37kernel/irq/irqdomain.c,852,hwirq:0x7,virq:0x37kernel/irq/irqdomain.c,847,hwirq:0x8,hint:0x8,nr_irqs:0x38kernel/irq/irqdomain.c,852,hwirq:0x8,virq:0x38kernel/irq/irqdomain.c,847,hwirq:0x9,hint:0x9,nr_irqs:0x39kernel/irq/irqdomain.c,852,hwirq:0x9,virq:0x39kernel/irq/irqdomain.c,847,hwirq:0xa,hint:0xa,nr_irqs:0x3akernel/irq/irqdomain.c,852,hwirq:0xa,virq:0x3akernel/irq/irqdomain.c,847,hwirq:0xb,hint:0xb,nr_irqs:0x3bkernel/irq/irqdomain.c,852,hwirq:0xb,virq:0x3bkernel/irq/irqdomain.c,847,hwirq:0xc,hint:0xc,nr_irqs:0x3ckernel/irq/irqdomain.c,852,hwirq:0xc,virq:0x3ckernel/irq/irqdomain.c,847,hwirq:0xd,hint:0xd,nr_irqs:0x3dkernel/irq/irqdomain.c,852,hwirq:0xd,virq:0x3dkernel/irq/irqdomain.c,847,hwirq:0xe,hint:0xe,nr_irqs:0x3ekernel/irq/irqdomain.c,852,hwirq:0xe,virq:0x3ekernel/irq/irqdomain.c,847,hwirq:0xf,hint:0xf,nr_irqs:0x3fkernel/irq/irqdomain.c,852,hwirq:0xf,virq:0x3fkernel/irq/irqdomain.c,847,hwirq:0x10,hint:0x10,nr_irqs:0x40kernel/irq/irqdomain.c,852,hwirq:0x10,virq:0x40kernel/irq/irqdomain.c,847,hwirq:0x11,hint:0x11,nr_irqs:0x41kernel/irq/irqdomain.c,852,hwirq:0x11,virq:0x41kernel/irq/irqdomain.c,847,hwirq:0x12,hint:0x12,nr_irqs:0x42kernel/irq/irqdomain.c,852,hwirq:0x12,virq:0x42kernel/irq/irqdomain.c,847,hwirq:0x13,hint:0x13,nr_irqs:0x43kernel/irq/irqdomain.c,852,hwirq:0x13,virq:0x43kernel/irq/irqdomain.c,847,hwirq:0x14,hint:0x14,nr_irqs:0x44kernel/irq/irqdomain.c,852,hwirq:0x14,virq:0x44kernel/irq/irqdomain.c,847,hwirq:0x15,hint:0x15,nr_irqs:0x45kernel/irq/irqdomain.c,852,hwirq:0x15,virq:0x45kernel/irq/irqdomain.c,847,hwirq:0x16,hint:0x16,nr_irqs:0x46kernel/irq/irqdomain.c,852,hwirq:0x16,virq:0x46kernel/irq/irqdomain.c,847,hwirq:0x17,hint:0x17,nr_irqs:0x47kernel/irq/irqdomain.c,852,hwirq:0x17,virq:0x47kernel/irq/irqdomain.c,847,hwirq:0x18,hint:0x18,nr_irqs:0x48kernel/irq/irqdomain.c,852,hwirq:0x18,virq:0x48kernel/irq/irqdomain.c,847,hwirq:0x19,hint:0x19,nr_irqs:0x49kernel/irq/irqdomain.c,852,hwirq:0x19,virq:0x49kernel/irq/irqdomain.c,847,hwirq:0x1a,hint:0x1a,nr_irqs:0x4akernel/irq/irqdomain.c,852,hwirq:0x1a,virq:0x4akernel/irq/irqdomain.c,847,hwirq:0x1b,hint:0x1b,nr_irqs:0x4bkernel/irq/irqdomain.c,852,hwirq:0x1b,virq:0x4bkernel/irq/irqdomain.c,847,hwirq:0x1c,hint:0x1c,nr_irqs:0x4ckernel/irq/irqdomain.c,852,hwirq:0x1c,virq:0x4ckernel/irq/irqdomain.c,847,hwirq:0x1d,hint:0x1d,nr_irqs:0x4dkernel/irq/irqdomain.c,852,hwirq:0x1d,virq:0x4dkernel/irq/irqdomain.c,847,hwirq:0x1e,hint:0x1e,nr_irqs:0x4ekernel/irq/irqdomain.c,852,hwirq:0x1e,virq:0x4ekernel/irq/irqdomain.c,847,hwirq:0x1f,hint:0x1f,nr_irqs:0x4fkernel/irq/irqdomain.c,852,hwirq:0x1f,virq:0x4fkernel/irq/irqdomain.c,847,hwirq:0x0,hint:0x1,nr_irqs:0x50kernel/irq/irqdomain.c,852,hwirq:0x0,virq:0x50kernel/irq/irqdomain.c,847,hwirq:0x1,hint:0x1,nr_irqs:0x51kernel/irq/irqdomain.c,852,hwirq:0x1,virq:0x51kernel/irq/irqdomain.c,847,hwirq:0x2,hint:0x2,nr_irqs:0x52kernel/irq/irqdomain.c,852,hwirq:0x2,virq:0x52kernel/irq/irqdomain.c,847,hwirq:0x3,hint:0x3,nr_irqs:0x53kernel/irq/irqdomain.c,852,hwirq:0x3,virq:0x53kernel/irq/irqdomain.c,847,hwirq:0x4,hint:0x4,nr_irqs:0x54kernel/irq/irqdomain.c,852,hwirq:0x4,virq:0x54kernel/irq/irqdomain.c,847,hwirq:0x5,hint:0x5,nr_irqs:0x55kernel/irq/irqdomain.c,852,hwirq:0x5,virq:0x55kernel/irq/irqdomain.c,847,hwirq:0x6,hint:0x6,nr_irqs:0x56kernel/irq/irqdomain.c,852,hwirq:0x6,virq:0x56kernel/irq/irqdomain.c,847,hwirq:0x7,hint:0x7,nr_irqs:0x57kernel/irq/irqdomain.c,852,hwirq:0x7,virq:0x57kernel/irq/irqdomain.c,847,hwirq:0x8,hint:0x8,nr_irqs:0x58kernel/irq/irqdomain.c,852,hwirq:0x8,virq:0x58kernel/irq/irqdomain.c,847,hwirq:0x9,hint:0x9,nr_irqs:0x59kernel/irq/irqdomain.c,852,hwirq:0x9,virq:0x59kernel/irq/irqdomain.c,847,hwirq:0xa,hint:0xa,nr_irqs:0x5akernel/irq/irqdomain.c,852,hwirq:0xa,virq:0x5akernel/irq/irqdomain.c,847,hwirq:0xb,hint:0xb,nr_irqs:0x5bkernel/irq/irqdomain.c,852,hwirq:0xb,virq:0x5bkernel/irq/irqdomain.c,847,hwirq:0xc,hint:0xc,nr_irqs:0x5ckernel/irq/irqdomain.c,852,hwirq:0xc,virq:0x5ckernel/irq/irqdomain.c,847,hwirq:0xd,hint:0xd,nr_irqs:0x5dkernel/irq/irqdomain.c,852,hwirq:0xd,virq:0x5dkernel/irq/irqdomain.c,847,hwirq:0xe,hint:0xe,nr_irqs:0x5ekernel/irq/irqdomain.c,852,hwirq:0xe,virq:0x5ekernel/irq/irqdomain.c,847,hwirq:0xf,hint:0xf,nr_irqs:0x5fkernel/irq/irqdomain.c,852,hwirq:0xf,virq:0x5fkernel/irq/irqdomain.c,847,hwirq:0x10,hint:0x10,nr_irqs:0x60kernel/irq/irqdomain.c,852,hwirq:0x10,virq:0x60kernel/irq/irqdomain.c,847,hwirq:0x11,hint:0x11,nr_irqs:0x61kernel/irq/irqdomain.c,852,hwirq:0x11,virq:0x61kernel/irq/irqdomain.c,847,hwirq:0x12,hint:0x12,nr_irqs:0x62kernel/irq/irqdomain.c,852,hwirq:0x12,virq:0x62kernel/irq/irqdomain.c,847,hwirq:0x13,hint:0x13,nr_irqs:0x63kernel/irq/irqdomain.c,852,hwirq:0x13,virq:0x63kernel/irq/irqdomain.c,847,hwirq:0x14,hint:0x14,nr_irqs:0x64kernel/irq/irqdomain.c,852,hwirq:0x14,virq:0x64kernel/irq/irqdomain.c,847,hwirq:0x15,hint:0x15,nr_irqs:0x65kernel/irq/irqdomain.c,852,hwirq:0x15,virq:0x65kernel/irq/irqdomain.c,847,hwirq:0x16,hint:0x16,nr_irqs:0x66kernel/irq/irqdomain.c,852,hwirq:0x16,virq:0x66kernel/irq/irqdomain.c,847,hwirq:0x17,hint:0x17,nr_irqs:0x67kernel/irq/irqdomain.c,852,hwirq:0x17,virq:0x67kernel/irq/irqdomain.c,847,hwirq:0x18,hint:0x18,nr_irqs:0x68kernel/irq/irqdomain.c,852,hwirq:0x18,virq:0x68kernel/irq/irqdomain.c,847,hwirq:0x19,hint:0x19,nr_irqs:0x69kernel/irq/irqdomain.c,852,hwirq:0x19,virq:0x69kernel/irq/irqdomain.c,847,hwirq:0x1a,hint:0x1a,nr_irqs:0x6akernel/irq/irqdomain.c,852,hwirq:0x1a,virq:0x6akernel/irq/irqdomain.c,847,hwirq:0x1b,hint:0x1b,nr_irqs:0x6bkernel/irq/irqdomain.c,852,hwirq:0x1b,virq:0x6bkernel/irq/irqdomain.c,847,hwirq:0x1c,hint:0x1c,nr_irqs:0x6ckernel/irq/irqdomain.c,852,hwirq:0x1c,virq:0x6ckernel/irq/irqdomain.c,847,hwirq:0x1d,hint:0x1d,nr_irqs:0x6dkernel/irq/irqdomain.c,852,hwirq:0x1d,virq:0x6dkernel/irq/irqdomain.c,847,hwirq:0x1e,hint:0x1e,nr_irqs:0x6ekernel/irq/irqdomain.c,852,hwirq:0x1e,virq:0x6ekernel/irq/irqdomain.c,847,hwirq:0x1f,hint:0x1f,nr_irqs:0x6fkernel/irq/irqdomain.c,852,hwirq:0x1f,virq:0x6fkernel/irq/irqdomain.c,847,hwirq:0x0,hint:0x1,nr_irqs:0x70kernel/irq/irqdomain.c,852,hwirq:0x0,virq:0x70kernel/irq/irqdomain.c,847,hwirq:0x1,hint:0x1,nr_irqs:0x71kernel/irq/irqdomain.c,852,hwirq:0x1,virq:0x71kernel/irq/irqdomain.c,847,hwirq:0x2,hint:0x2,nr_irqs:0x72kernel/irq/irqdomain.c,852,hwirq:0x2,virq:0x72kernel/irq/irqdomain.c,847,hwirq:0x3,hint:0x3,nr_irqs:0x73kernel/irq/irqdomain.c,852,hwirq:0x3,virq:0x73kernel/irq/irqdomain.c,847,hwirq:0x4,hint:0x4,nr_irqs:0x74kernel/irq/irqdomain.c,852,hwirq:0x4,virq:0x74kernel/irq/irqdomain.c,847,hwirq:0x5,hint:0x5,nr_irqs:0x75kernel/irq/irqdomain.c,852,hwirq:0x5,virq:0x75kernel/irq/irqdomain.c,847,hwirq:0x6,hint:0x6,nr_irqs:0x76kernel/irq/irqdomain.c,852,hwirq:0x6,virq:0x76kernel/irq/irqdomain.c,847,hwirq:0x7,hint:0x7,nr_irqs:0x77kernel/irq/irqdomain.c,852,hwirq:0x7,virq:0x77kernel/irq/irqdomain.c,847,hwirq:0x8,hint:0x8,nr_irqs:0x78kernel/irq/irqdomain.c,852,hwirq:0x8,virq:0x78kernel/irq/irqdomain.c,847,hwirq:0x9,hint:0x9,nr_irqs:0x79kernel/irq/irqdomain.c,852,hwirq:0x9,virq:0x79kernel/irq/irqdomain.c,847,hwirq:0xa,hint:0xa,nr_irqs:0x7akernel/irq/irqdomain.c,852,hwirq:0xa,virq:0x7akernel/irq/irqdomain.c,847,hwirq:0xb,hint:0xb,nr_irqs:0x7bkernel/irq/irqdomain.c,852,hwirq:0xb,virq:0x7bkernel/irq/irqdomain.c,847,hwirq:0xc,hint:0xc,nr_irqs:0x7ckernel/irq/irqdomain.c,852,hwirq:0xc,virq:0x7ckernel/irq/irqdomain.c,847,hwirq:0xd,hint:0xd,nr_irqs:0x7dkernel/irq/irqdomain.c,852,hwirq:0xd,virq:0x7dkernel/irq/irqdomain.c,847,hwirq:0xe,hint:0xe,nr_irqs:0x7ekernel/irq/irqdomain.c,852,hwirq:0xe,virq:0x7ekernel/irq/irqdomain.c,847,hwirq:0xf,hint:0xf,nr_irqs:0x7fkernel/irq/irqdomain.c,852,hwirq:0xf,virq:0x7fkernel/irq/irqdomain.c,847,hwirq:0x10,hint:0x10,nr_irqs:0x80kernel/irq/irqdomain.c,852,hwirq:0x10,virq:0x80kernel/irq/irqdomain.c,847,hwirq:0x11,hint:0x11,nr_irqs:0x81kernel/irq/irqdomain.c,852,hwirq:0x11,virq:0x81kernel/irq/irqdomain.c,847,hwirq:0x12,hint:0x12,nr_irqs:0x82kernel/irq/irqdomain.c,852,hwirq:0x12,virq:0x82kernel/irq/irqdomain.c,847,hwirq:0x13,hint:0x13,nr_irqs:0x83kernel/irq/irqdomain.c,852,hwirq:0x13,virq:0x83kernel/irq/irqdomain.c,847,hwirq:0x14,hint:0x14,nr_irqs:0x84kernel/irq/irqdomain.c,852,hwirq:0x14,virq:0x84kernel/irq/irqdomain.c,847,hwirq:0x15,hint:0x15,nr_irqs:0x85kernel/irq/irqdomain.c,852,hwirq:0x15,virq:0x85kernel/irq/irqdomain.c,847,hwirq:0x16,hint:0x16,nr_irqs:0x86kernel/irq/irqdomain.c,852,hwirq:0x16,virq:0x86kernel/irq/irqdomain.c,847,hwirq:0x17,hint:0x17,nr_irqs:0x87kernel/irq/irqdomain.c,852,hwirq:0x17,virq:0x87kernel/irq/irqdomain.c,847,hwirq:0x18,hint:0x18,nr_irqs:0x88kernel/irq/irqdomain.c,852,hwirq:0x18,virq:0x88kernel/irq/irqdomain.c,847,hwirq:0x19,hint:0x19,nr_irqs:0x89kernel/irq/irqdomain.c,852,hwirq:0x19,virq:0x89kernel/irq/irqdomain.c,847,hwirq:0x1a,hint:0x1a,nr_irqs:0x8akernel/irq/irqdomain.c,852,hwirq:0x1a,virq:0x8akernel/irq/irqdomain.c,847,hwirq:0x1b,hint:0x1b,nr_irqs:0x8bkernel/irq/irqdomain.c,852,hwirq:0x1b,virq:0x8bkernel/irq/irqdomain.c,847,hwirq:0x1c,hint:0x1c,nr_irqs:0x8ckernel/irq/irqdomain.c,852,hwirq:0x1c,virq:0x8ckernel/irq/irqdomain.c,847,hwirq:0x1d,hint:0x1d,nr_irqs:0x8dkernel/irq/irqdomain.c,852,hwirq:0x1d,virq:0x8dkernel/irq/irqdomain.c,847,hwirq:0x1e,hint:0x1e,nr_irqs:0x8ekernel/irq/irqdomain.c,852,hwirq:0x1e,virq:0x8ekernel/irq/irqdomain.c,847,hwirq:0x1f,hint:0x1f,nr_irqs:0x8fkernel/irq/irqdomain.c,852,hwirq:0x1f,virq:0x8f
//include/linux/irq.h#define irq_alloc_descs(irq, from, cnt, node) \ __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)#define irq_alloc_desc(node) \ irq_alloc_descs(-1, 0, 1, node)#define irq_alloc_desc_at(at, node) \ irq_alloc_descs(at, at, 1, node)#define irq_alloc_desc_from(from, node) \ irq_alloc_descs(-1, from, 1, node)#define irq_alloc_descs_from(from, cnt, node) \ irq_alloc_descs(-1, from, cnt, node)
//kernel/irq/irqdesc.c/** * irq_alloc_descs - allocate and initialize a range of irq descriptors * @irq: Allocate for specific irq number if irq >= 0 * @from: Start the search from this irq number * @cnt: Number of consecutive irqs to allocate. * @node: Preferred node on which the irq descriptor should be allocated * @owner: Owning module (can be NULL) * * Returns the first irq number or error code */int __ref__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, struct module *owner){ int start, ret; if (!cnt) return -EINVAL; if (irq >= 0) { if (from > irq) return -EINVAL; from = irq; } else { /* * For interrupts which are freely allocated the * architecture can force a lower bound to the @from * argument. x86 uses this to exclude the GSI space. */ from = arch_dynirq_lower_bound(from); } mutex_lock(&sparse_irq_lock); start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, from, cnt, 0); /* *添加打印 *early_print("%s,%d,start:0x%x,form:0x%x,cnt:0x%x\n", * __FILE__,__LINE__,start,from,cnt); *打印信息如下 */ ret = -EEXIST; if (irq >=0 && start != irq) goto err; if (start + cnt > nr_irqs) { ret = irq_expand_nr_irqs(start + cnt); if (ret) goto err; } bitmap_set(allocated_irqs, start, cnt); mutex_unlock(&sparse_irq_lock); return alloc_descs(start, cnt, node, owner);err: mutex_unlock(&sparse_irq_lock); return ret;}EXPORT_SYMBOL_GPL(__irq_alloc_descs);//kernel/softirq.cunsigned int __weak arch_dynirq_lower_bound(unsigned int from){ return from;}kernel/irq/irqdesc.c,457,start:0x10,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x11,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x12,form:0x2,cnt:0x1kernel/irq/irqdesc.c,457,start:0x13,form:0x3,cnt:0x1kernel/irq/irqdesc.c,457,start:0x14,form:0x4,cnt:0x1kernel/irq/irqdesc.c,457,start:0x15,form:0x5,cnt:0x1kernel/irq/irqdesc.c,457,start:0x16,form:0x6,cnt:0x1kernel/irq/irqdesc.c,457,start:0x17,form:0x7,cnt:0x1kernel/irq/irqdesc.c,457,start:0x18,form:0x8,cnt:0x1kernel/irq/irqdesc.c,457,start:0x19,form:0x9,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1a,form:0xa,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1b,form:0xb,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1c,form:0xc,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1d,form:0xd,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1e,form:0xe,cnt:0x1kernel/irq/irqdesc.c,457,start:0x1f,form:0xf,cnt:0x1kernel/irq/irqdesc.c,457,start:0x20,form:0x10,cnt:0x1kernel/irq/irqdesc.c,457,start:0x21,form:0x11,cnt:0x1kernel/irq/irqdesc.c,457,start:0x22,form:0x12,cnt:0x1kernel/irq/irqdesc.c,457,start:0x23,form:0x13,cnt:0x1kernel/irq/irqdesc.c,457,start:0x24,form:0x14,cnt:0x1kernel/irq/irqdesc.c,457,start:0x25,form:0x15,cnt:0x1kernel/irq/irqdesc.c,457,start:0x26,form:0x16,cnt:0x1kernel/irq/irqdesc.c,457,start:0x27,form:0x17,cnt:0x1kernel/irq/irqdesc.c,457,start:0x28,form:0x18,cnt:0x1kernel/irq/irqdesc.c,457,start:0x29,form:0x19,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2a,form:0x1a,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2b,form:0x1b,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2c,form:0x1c,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2d,form:0x1d,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2e,form:0x1e,cnt:0x1kernel/irq/irqdesc.c,457,start:0x2f,form:0x1f,cnt:0x1kernel/irq/irqdesc.c,457,start:0x30,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x31,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x32,form:0x2,cnt:0x1kernel/irq/irqdesc.c,457,start:0x33,form:0x3,cnt:0x1kernel/irq/irqdesc.c,457,start:0x34,form:0x4,cnt:0x1kernel/irq/irqdesc.c,457,start:0x35,form:0x5,cnt:0x1kernel/irq/irqdesc.c,457,start:0x36,form:0x6,cnt:0x1kernel/irq/irqdesc.c,457,start:0x37,form:0x7,cnt:0x1kernel/irq/irqdesc.c,457,start:0x38,form:0x8,cnt:0x1kernel/irq/irqdesc.c,457,start:0x39,form:0x9,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3a,form:0xa,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3b,form:0xb,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3c,form:0xc,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3d,form:0xd,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3e,form:0xe,cnt:0x1kernel/irq/irqdesc.c,457,start:0x3f,form:0xf,cnt:0x1kernel/irq/irqdesc.c,457,start:0x40,form:0x10,cnt:0x1kernel/irq/irqdesc.c,457,start:0x41,form:0x11,cnt:0x1kernel/irq/irqdesc.c,457,start:0x42,form:0x12,cnt:0x1kernel/irq/irqdesc.c,457,start:0x43,form:0x13,cnt:0x1kernel/irq/irqdesc.c,457,start:0x44,form:0x14,cnt:0x1kernel/irq/irqdesc.c,457,start:0x45,form:0x15,cnt:0x1kernel/irq/irqdesc.c,457,start:0x46,form:0x16,cnt:0x1kernel/irq/irqdesc.c,457,start:0x47,form:0x17,cnt:0x1kernel/irq/irqdesc.c,457,start:0x48,form:0x18,cnt:0x1kernel/irq/irqdesc.c,457,start:0x49,form:0x19,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4a,form:0x1a,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4b,form:0x1b,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4c,form:0x1c,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4d,form:0x1d,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4e,form:0x1e,cnt:0x1kernel/irq/irqdesc.c,457,start:0x4f,form:0x1f,cnt:0x1kernel/irq/irqdesc.c,457,start:0x50,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x51,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x52,form:0x2,cnt:0x1kernel/irq/irqdesc.c,457,start:0x53,form:0x3,cnt:0x1kernel/irq/irqdesc.c,457,start:0x54,form:0x4,cnt:0x1kernel/irq/irqdesc.c,457,start:0x55,form:0x5,cnt:0x1kernel/irq/irqdesc.c,457,start:0x56,form:0x6,cnt:0x1kernel/irq/irqdesc.c,457,start:0x57,form:0x7,cnt:0x1kernel/irq/irqdesc.c,457,start:0x58,form:0x8,cnt:0x1kernel/irq/irqdesc.c,457,start:0x59,form:0x9,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5a,form:0xa,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5b,form:0xb,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5c,form:0xc,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5d,form:0xd,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5e,form:0xe,cnt:0x1kernel/irq/irqdesc.c,457,start:0x5f,form:0xf,cnt:0x1kernel/irq/irqdesc.c,457,start:0x60,form:0x10,cnt:0x1kernel/irq/irqdesc.c,457,start:0x61,form:0x11,cnt:0x1kernel/irq/irqdesc.c,457,start:0x62,form:0x12,cnt:0x1kernel/irq/irqdesc.c,457,start:0x63,form:0x13,cnt:0x1kernel/irq/irqdesc.c,457,start:0x64,form:0x14,cnt:0x1kernel/irq/irqdesc.c,457,start:0x65,form:0x15,cnt:0x1kernel/irq/irqdesc.c,457,start:0x66,form:0x16,cnt:0x1kernel/irq/irqdesc.c,457,start:0x67,form:0x17,cnt:0x1kernel/irq/irqdesc.c,457,start:0x68,form:0x18,cnt:0x1kernel/irq/irqdesc.c,457,start:0x69,form:0x19,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6a,form:0x1a,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6b,form:0x1b,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6c,form:0x1c,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6d,form:0x1d,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6e,form:0x1e,cnt:0x1kernel/irq/irqdesc.c,457,start:0x6f,form:0x1f,cnt:0x1kernel/irq/irqdesc.c,457,start:0x70,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x71,form:0x1,cnt:0x1kernel/irq/irqdesc.c,457,start:0x72,form:0x2,cnt:0x1kernel/irq/irqdesc.c,457,start:0x73,form:0x3,cnt:0x1kernel/irq/irqdesc.c,457,start:0x74,form:0x4,cnt:0x1kernel/irq/irqdesc.c,457,start:0x75,form:0x5,cnt:0x1kernel/irq/irqdesc.c,457,start:0x76,form:0x6,cnt:0x1kernel/irq/irqdesc.c,457,start:0x77,form:0x7,cnt:0x1kernel/irq/irqdesc.c,457,start:0x78,form:0x8,cnt:0x1kernel/irq/irqdesc.c,457,start:0x79,form:0x9,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7a,form:0xa,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7b,form:0xb,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7c,form:0xc,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7d,form:0xd,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7e,form:0xe,cnt:0x1kernel/irq/irqdesc.c,457,start:0x7f,form:0xf,cnt:0x1kernel/irq/irqdesc.c,457,start:0x80,form:0x10,cnt:0x1kernel/irq/irqdesc.c,457,start:0x81,form:0x11,cnt:0x1kernel/irq/irqdesc.c,457,start:0x82,form:0x12,cnt:0x1kernel/irq/irqdesc.c,457,start:0x83,form:0x13,cnt:0x1kernel/irq/irqdesc.c,457,start:0x84,form:0x14,cnt:0x1kernel/irq/irqdesc.c,457,start:0x85,form:0x15,cnt:0x1kernel/irq/irqdesc.c,457,start:0x86,form:0x16,cnt:0x1kernel/irq/irqdesc.c,457,start:0x87,form:0x17,cnt:0x1kernel/irq/irqdesc.c,457,start:0x88,form:0x18,cnt:0x1kernel/irq/irqdesc.c,457,start:0x89,form:0x19,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8a,form:0x1a,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8b,form:0x1b,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8c,form:0x1c,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8d,form:0x1d,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8e,form:0x1e,cnt:0x1kernel/irq/irqdesc.c,457,start:0x8f,form:0x1f,cnt:0x1//kernel/irq/irqdesc.cstatic int irq_expand_nr_irqs(unsigned int nr) { if (nr > IRQ_BITMAP_BITS) return -ENOMEM; nr_irqs = nr; return 0;}
//kernel/irq/irqdesc.cstatic int alloc_descs(unsigned int start, unsigned int cnt, int node, struct module *owner){ struct irq_desc *desc; int i; for (i = 0; i < cnt; i++) { desc = alloc_desc(start + i, node, owner); if (!desc) goto err; mutex_lock(&sparse_irq_lock); irq_insert_desc(start + i, desc); mutex_unlock(&sparse_irq_lock); } return start;err: for (i--; i >= 0; i--) free_desc(start + i); mutex_lock(&sparse_irq_lock); bitmap_clear(allocated_irqs, start, cnt); mutex_unlock(&sparse_irq_lock); return -ENOMEM;}
//kernel/irq/irqdesc.cstatic struct irq_desc *alloc_desc(int irq, int node, struct module *owner){ struct irq_desc *desc; gfp_t gfp = GFP_KERNEL; desc = kzalloc_node(sizeof(*desc), gfp, 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, gfp, node)) goto err_kstat; raw_spin_lock_init(&desc->lock); lockdep_set_class(&desc->lock, &irq_desc_lock_class); desc_set_defaults(irq, desc, node, owner); return desc;err_kstat: free_percpu(desc->kstat_irqs);err_desc: kfree(desc); return NULL;}
//kernel/irq/irqdesc.cstatic void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, struct module *owner){ int cpu; desc->irq_common_data.handler_data = NULL; desc->irq_common_data.msi_desc = NULL; desc->irq_data.common = &desc->irq_common_data; desc->irq_data.irq = irq; desc->irq_data.chip = &no_irq_chip; desc->irq_data.chip_data = NULL; irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); desc->handle_irq = handle_bad_irq; desc->depth = 1; desc->irq_count = 0; desc->irqs_unhandled = 0; desc->name = NULL; desc->owner = owner; for_each_possible_cpu(cpu) *per_cpu_ptr(desc->kstat_irqs, cpu) = 0; desc_smp_init(desc, node);}//kernel/irq/settings.h#define IRQ_PER_CPU GOT_YOU_MORON#define IRQ_NO_BALANCING GOT_YOU_MORON#define IRQ_LEVEL GOT_YOU_MORON#define IRQ_NOPROBE GOT_YOU_MORON#define IRQ_NOREQUEST GOT_YOU_MORON#define IRQ_NOTHREAD GOT_YOU_MORON#define IRQ_NOAUTOEN GOT_YOU_MORON#define IRQ_NESTED_THREAD GOT_YOU_MORON#define IRQ_PER_CPU_DEVID GOT_YOU_MORON#define IRQ_IS_POLLED GOT_YOU_MORON#define IRQ_DISABLE_UNLAZY GOT_YOU_MORON#undef IRQF_MODIFY_MASK#define IRQF_MODIFY_MASK GOT_YOU_MORONstatic inline voidirq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set){ desc->status_use_accessors &= ~(clr & _IRQF_MODIFY_MASK); desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK);}
//kernel/irq/irqdomain.cint irq_domain_associate(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq){ struct irq_data *irq_data = irq_get_irq_data(virq); int ret; if (WARN(hwirq >= domain->hwirq_max, "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name)) return -EINVAL; if (WARN(!irq_data, "error: virq%i is not allocated", virq)) return -EINVAL; if (WARN(irq_data->domain, "error: virq%i is already associated", virq)) return -EINVAL; mutex_lock(&irq_domain_mutex); irq_data->hwirq = hwirq; irq_data->domain = domain; if (domain->ops->map) { /* *从driver/irqchip/irq-vic.c分析完成了irq_data中irq_chip的绑定,见下面22 */ ret = domain->ops->map(domain, virq, hwirq); if (ret != 0) { /* * If map() returns -EPERM, this interrupt is protected * by the firmware or some other service and shall not * be mapped. Don't bother telling the user about it. */ if (ret != -EPERM) { pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n", domain->name, hwirq, virq, ret); } irq_data->domain = NULL; irq_data->hwirq = 0; mutex_unlock(&irq_domain_mutex); return ret; } /* If not already assigned, give the domain the chip's name */ if (!domain->name && irq_data->chip) domain->name = irq_data->chip->name; } if (hwirq < domain->revmap_size) { domain->linear_revmap[hwirq] = virq; } else { mutex_lock(&revmap_trees_mutex); radix_tree_insert(&domain->revmap_tree, hwirq, irq_data); mutex_unlock(&revmap_trees_mutex); } mutex_unlock(&irq_domain_mutex); irq_clear_status_flags(virq, IRQ_NOREQUEST); return 0;}EXPORT_SYMBOL_GPL(irq_domain_associate);//kernel/irq/chip.cstruct irq_data *irq_get_irq_data(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); return desc ? &desc->irq_data : NULL;}//kernel/irq/irqdesc.cstruct irq_desc *irq_to_desc(unsigned int irq){ return radix_tree_lookup(&irq_desc_tree, irq);}EXPORT_SYMBOL(irq_to_desc);
//kernel/irq/irqdomain.c/** * irq_find_mapping() - Find a linux irq from an hw irq number. * @domain: domain owning this hardware interrupt * @hwirq: hardware irq number in that domain space */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) { //代表的hwirq和virq是直接映射 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;}EXPORT_SYMBOL_GPL(irq_find_mapping);//kernel/irq/irqdomain.c/** * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain * @domain: domain to match * @virq: IRQ number to get irq_data */struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, unsigned int virq){ struct irq_data *irq_data = irq_get_irq_data(virq); return (irq_data && irq_data->domain == domain) ? irq_data : NULL;}
//drivers/irqchip/irq-vic.cstatic const struct irq_domain_ops vic_irqdomain_ops = { /* *map函数的调用流程为irq_create_mapping-->irq_domain_associate-->map */ .map = vic_irqdomain_map, .xlate = irq_domain_xlate_onetwocell,};//drivers/irqchip/irq-vic.c/* *在drivers/irqchip/irq-vic.c中的vic_register函数中调用 *v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,&vic_irqdomain_ops, v); * 填充到了struct domain结构体变量中 */static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq){ struct vic_device *v = d->host_data; /* Skip invalid IRQs, only register handlers for the real ones */ if (!(v->valid_sources & (1 << hwirq))) return -EPERM; irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); irq_set_chip_data(irq, v->base); irq_set_probe(irq); return 0;}//include/linux/irq.hstatic inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle){ irq_set_chip_and_handler_name(irq, chip, handle, NULL);}//kernel/irq/chip.cvoid irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle, const char *name){ irq_set_chip(irq, chip); __irq_set_handler(irq, handle, 0, name);}EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);//kernel/irq/chip.c/** * irq_set_chip - set the irq chip for an irq * @irq: irq number * @chip: pointer to irq chip description structure */int irq_set_chip(unsigned int irq, struct irq_chip *chip){ unsigned long flags; struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); if (!desc) return -EINVAL; if (!chip) chip = &no_irq_chip; desc->irq_data.chip = chip; irq_put_desc_unlock(desc, flags); /* * For !CONFIG_SPARSE_IRQ make the irq show up in * allocated_irqs. */ irq_mark_irq(irq); return 0;}EXPORT_SYMBOL(irq_set_chip);//kernel/irq/chip.cvoid __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name){ unsigned long flags; struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); if (!desc) return; __irq_do_set_handler(desc, handle, is_chained, name); irq_put_desc_busunlock(desc, flags);}EXPORT_SYMBOL_GPL(__irq_set_handler);//kernel/irq/chip.cvoid __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle, int is_chained, const char *name){ if (!handle) { handle = handle_bad_irq; } else { struct irq_data *irq_data = &desc->irq_data;#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /* * With hierarchical domains we might run into a * situation where the outermost chip is not yet set * up, but the inner chips are there. Instead of * bailing we install the handler, but obviously we * cannot enable/startup the interrupt at this point. */ while (irq_data) { if (irq_data->chip != &no_irq_chip) break; /* * Bail out if the outer chip is not set up * and the interrrupt supposed to be started * right away. */ if (WARN_ON(is_chained)) return; /* Try the parent */ irq_data = irq_data->parent_data; }#endif if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip)) return; } /* Uninstall? */ if (handle == handle_bad_irq) { if (desc->irq_data.chip != &no_irq_chip) mask_ack_irq(desc); irq_state_set_disabled(desc); if (is_chained) desc->action = NULL; desc->depth = 1; } desc->handle_irq = handle; desc->name = name; if (handle != handle_bad_irq && is_chained) { irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); irq_settings_set_nothread(desc); desc->action = &chained_action; irq_startup(desc, true); }}//kernel/irq/chip.c/** * irq_set_chip_data - set irq chip data for an irq * @irq: Interrupt number * @data: Pointer to chip specific data * * Set the hardware irq chip data for an irq */int irq_set_chip_data(unsigned int irq, void *data){ unsigned long flags; struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); if (!desc) return -EINVAL; desc->irq_data.chip_data = data; irq_put_desc_unlock(desc, flags); return 0;}//include/linux/irq.hstatic inline void irq_set_probe(unsigned int irq){ irq_modify_status(irq, IRQ_NOPROBE, 0); }//kernel/irq/chip.cvoid irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) { unsigned long flags; struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); if (!desc) return; irq_settings_clr_and_set(desc, clr, set); irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); if (irq_settings_has_no_balance_set(desc)) irqd_set(&desc->irq_data, IRQD_NO_BALANCING); if (irq_settings_is_per_cpu(desc)) irqd_set(&desc->irq_data, IRQD_PER_CPU); if (irq_settings_can_move_pcntxt(desc)) irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); if (irq_settings_is_level(desc)) irqd_set(&desc->irq_data, IRQD_LEVEL); irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); irq_put_desc_unlock(desc, flags);}EXPORT_SYMBOL_GPL(irq_modify_status);//kernel/irq/internals.hstatic inline bool irqd_has_set(struct irq_data *d, unsigned int mask){ return __irqd_to_state(d) & mask;}//include/linux/irq.h#define __irqd_to_state(d) ((d)->common->state_use_accessors)
每个中断控制器对应一个struct irq_domain结构体变量,在linux系统中这些struct irq_domain会被链接到irq_domain_list链表中,struct irq_domain中变量hwirq_max中记录该中断控制器可用的最大硬件中断号,revmap_size记录了struct irq_domain中linear_revmap[]数组的大小,在hwirq小于revmap_size时,即linear_revmap[]未填充满时, linear_revmap[]使用hwirq作为索引来保存对应的虚拟中断号virq。当hwirq大于revmap_size时,即linear_revmap[]填充满时,使用revmap_tree基数树保存hwirq对应的irq_data。
每一个硬件中断号hwirq对应一个struct irq_desc结构体变量,struct irq_desc结构体变量中包含一个struct irq_data结构体变量,struct irq_data结构体中会记录对应的硬件中断号hwirq,虚拟中断号virq,同时记录该中断对应的中断控制器的struct irq_domain指针。所有的已使用的虚拟中断号virq都被记录在allocated_irqs的全局位图变量中,所有申请的struct irq_desc结构体变量会通过虚拟中断号virq保存在irq_desc_tree基数树中。struct irq_desc结构体还记录中断处理struct iqraction结构体指针。同时在struct irq_data包含具体的struct irq_chip结构体,该结构体定义具体中断控制器的操作接口。
Original: https://www.cnblogs.com/yifeichongtian2021/p/15512307.html
Author: 壹飞冲天
Title: Linux ARM中断控制器注册(4)【转】
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585773/
转载文章受原作者版权保护。转载请注明原作者出处!