/** * 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 * * Returns the first irq number or error code */ int __ref irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node) { int start, ret; if (!cnt) return -EINVAL; mutex_lock(&sparse_irq_lock); start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0); ret = -EEXIST; if (irq >=0 && start != irq) goto err; ret = -ENOMEM; if (start >= nr_irqs) goto err; bitmap_set(allocated_irqs, start, cnt); mutex_unlock(&sparse_irq_lock); return alloc_descs(start, cnt, node); err: mutex_unlock(&sparse_irq_lock); return ret; }
/** * 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); 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; }
/** * 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; } mutex_lock(&sparse_irq_lock); start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, from, cnt, 0); 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; }
// ARM10C 20141115 // irq_start: -1, 16, gic_irqs: 144, numa_node_id(): 0, THIS_MODULE: ((struct module *)0) // ARM10C 20141213 // first_irq: 160, 160, size: 256, 0, THIS_MODULE: ((struct module *)0) int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, struct module *owner) { int start, ret; // cnt: 144 // cnt: 256 if (!cnt) return -EINVAL; // irq: -1 // irq: 160 if (irq >= 0) { // from: 160, irq: 160 if (from > irq) return -EINVAL; // from: 160, irq: 160 from = irq; // from: 160 } mutex_lock(&sparse_irq_lock); // sparse_irq_lock을 이용한 mutex lock 수행 // sparse_irq_lock을 이용한 mutex lock 수행 // IRQ_BITMAP_BITS: 8212, from: 16, cnt: 144 // bitmap_find_next_zero_area(allocated_irqs, 8212, 16, 144, 0): 16 // IRQ_BITMAP_BITS: 8212, from: 160, cnt: 256 // bitmap_find_next_zero_area(allocated_irqs, 8212, 160, 256, 0): 160 start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, from, cnt, 0); // start: 16 // start: 160 // EEXIST: 17 // EEXIST: 17 ret = -EEXIST; // ret: -17 // ret: -17 // irq: -1, start: 16 // irq: 160, start: 160 if (irq >=0 && start != irq) goto err; // start: 16, cnt: 144, nr_irqs: 16 // start: 160, cnt: 256, nr_irqs: 160 if (start + cnt > nr_irqs) { // start: 16, cnt: 144 // irq_expand_nr_irqs(160): 0 // start: 160, cnt: 256 // irq_expand_nr_irqs(416): 0 ret = irq_expand_nr_irqs(start + cnt); // ret: 0 // ret: 0 // irq_expand_nr_irqs(160)에서 한일: // 전역변수 nr_irqs 값을 160으로 갱신 // irq_expand_nr_irqs(416)에서 한일: // 전역변수 nr_irqs 값을 416으로 갱신 // ret: 0 // ret: 0 if (ret) goto err; } // start: 16, cnt: 144 // start: 160, cnt: 256 bitmap_set(allocated_irqs, start, cnt); // bitmap_set(16, 144)에서 한일: // allocated_irqs 의 16 bit 부터 144 bit 만큼을 1로 set // bitmap_set(160, 256)에서 한일: // allocated_irqs 의 160 bit 부터 256 bit 만큼을 1로 set mutex_unlock(&sparse_irq_lock); // sparse_irq_lock을 이용한 mutex unlock 수행 // sparse_irq_lock을 이용한 mutex unlock 수행 // start: 16, cnt: 144, node: 0, owner: NULL // alloc_descs(16, 144, 0, NULL): 16 // start: 160, cnt: 256, node: 0, owner: NULL // alloc_descs(160, 256, 0, NULL): 160 return alloc_descs(start, cnt, node, owner); // return 16 // return 160 /* // alloc_descs(16)에서 한일: // struct irq_desc의 자료 구조크기 만큼 160개의 메모리를 할당 받아 // radix tree 구조로 구성 // // irq 16 ~ 159를 위한 struct irq_desc 메모리를 할당 받아 초기화 수행 // (kmem_cache#28-oX (irq 16...159))->lock 을 이용한 spinlock 초기화 수행 // (kmem_cache#28-oX (irq 16...159))->status_use_accessors: 0xc00 // (kmem_cache#28-oX (irq 16...159))->handle_irq: handle_bad_irq // (kmem_cache#28-oX (irq 16...159))->depth: 1 // (kmem_cache#28-oX (irq 16...159))->irq_count: 0 // (kmem_cache#28-oX (irq 16...159))->irqs_unhandled: 0 // (kmem_cache#28-oX (irq 16...159))->name: NULL // (kmem_cache#28-oX (irq 16...159))->owner: null // (kmem_cache#28-oX (irq 16...159))->kstat_irqs: pcp 4 byte 공간 // [pcp0...3] (kmem_cache#28-oX (irq 16...159))->kstat_irqs: 0 // (kmem_cache#28-oX (irq 16...159))->irq_data.irq: 16...159 // (kmem_cache#28-oX (irq 16...159))->irq_data.chip: &no_irq_chip // (kmem_cache#28-oX (irq 16...159))->irq_data.chip_data: NULL // (kmem_cache#28-oX (irq 16...159))->irq_data.handler_data: NULL // (kmem_cache#28-oX (irq 16...159))->irq_data.msi_desc: NULL // (kmem_cache#28-oX (irq 16...159))->irq_data.state_use_accessors: 0x10000 // (kmem_cache#28-oX (irq 16...159))->irq_data.node: 0 // (kmem_cache#28-oX (irq 16...159))->irq_data.affinity.bits[0]: 0xF // // radix tree의 root node: &irq_desc_tree 값을 변경 // (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1) // (&irq_desc_tree)->height: 2 // // (kmem_cache#20-o1)->height: 2 // (kmem_cache#20-o1)->count: 3 // (kmem_cache#20-o1)->parent: NULL // (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소) // // (kmem_cache#20-o0)->height: 1 // (kmem_cache#20-o0)->count: 64 // (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63) // // (kmem_cache#20-o2)->height: 1 // (kmem_cache#20-o2)->count: 64 // (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127) // // (kmem_cache#20-o3)->height: 1 // (kmem_cache#20-o3)->count: 32 // (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...159) // // (&irq_desc_tree)->rnode --> +-----------------------+ // | radix_tree_node | // | (kmem_cache#20-o1) | // +-----------------------+ // | height: 2 | count: 3 | // +-----------------------+ // | radix_tree_node 0 ~ 2 | // +-----------------------+ // / | \ // slot: 0 / slot: 1 | \ slot: 2 // +-----------------------+ +-----------------------+ +-----------------------+ // | radix_tree_node | | radix_tree_node | | radix_tree_node | // | (kmem_cache#20-o0) | | (kmem_cache#20-o2) | | (kmem_cache#20-o3) | // +-----------------------+ +-----------------------+ +-----------------------+ // | height: 1 | count: 64 | | height: 1 | count: 64 | | height: 1 | count: 32 | // +-----------------------+ +-----------------------+ +-----------------------+ // | irq 0 ~ 63 | | irq 64 ~ 127 | | irq 128 ~ 159 | // +-----------------------+ +-----------------------+ +-----------------------+ */ /* // alloc_descs(160)에서 한일: // struct irq_desc의 자료 구조크기 만큼 256개의 메모리를 할당 받아 // radix tree 구조로 구성 // // irq 160 ~ 415를 위한 struct irq_desc 메모리를 할당 받아 초기화 수행 // (kmem_cache#28-oX (irq 160...415))->lock 을 이용한 spinlock 초기화 수행 // (kmem_cache#28-oX (irq 160...415))->status_use_accessors: 0xc00 // (kmem_cache#28-oX (irq 160...415))->handle_irq: handle_bad_irq // (kmem_cache#28-oX (irq 160...415))->depth: 1 // (kmem_cache#28-oX (irq 160...415))->irq_count: 0 // (kmem_cache#28-oX (irq 160...415))->irqs_unhandled: 0 // (kmem_cache#28-oX (irq 160...415))->name: NULL // (kmem_cache#28-oX (irq 160...415))->owner: null // (kmem_cache#28-oX (irq 160...415))->kstat_irqs: pcp 4 byte 공간 // [pcp0...3] (kmem_cache#28-oX (irq 160...415))->kstat_irqs: 0 // (kmem_cache#28-oX (irq 160...415))->irq_data.irq: 16...415 // (kmem_cache#28-oX (irq 160...415))->irq_data.chip: &no_irq_chip // (kmem_cache#28-oX (irq 160...415))->irq_data.chip_data: NULL // (kmem_cache#28-oX (irq 160...415))->irq_data.handler_data: NULL // (kmem_cache#28-oX (irq 160...415))->irq_data.msi_desc: NULL // (kmem_cache#28-oX (irq 160...415))->irq_data.state_use_accessors: 0x10000 // (kmem_cache#28-oX (irq 160...415))->irq_data.node: 0 // (kmem_cache#28-oX (irq 160...415))->irq_data.affinity.bits[0]: 0xF // // radix tree의 root node: &irq_desc_tree 값을 변경 // (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1) // (&irq_desc_tree)->height: 2 // // (kmem_cache#20-o1)->height: 2 // (kmem_cache#20-o1)->count: 7 // (kmem_cache#20-o1)->parent: NULL // (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[3]: kmem_cache#20-o4 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[4]: kmem_cache#20-o5 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[5]: kmem_cache#20-o6 (radix height 1 관리 주소) // (kmem_cache#20-o1)->slots[6]: kmem_cache#20-o7 (radix height 1 관리 주소) // // (kmem_cache#20-o0)->height: 1 // (kmem_cache#20-o0)->count: 64 // (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63) // // (kmem_cache#20-o2)->height: 1 // (kmem_cache#20-o2)->count: 64 // (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127) // // (kmem_cache#20-o3)->height: 1 // (kmem_cache#20-o3)->count: 64 // (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...191) // // (kmem_cache#20-o4)->height: 1 // (kmem_cache#20-o4)->count: 64 // (kmem_cache#20-o4)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o4)->slots[0...63]: kmem_cache#28-oX (irq 192...255) // // (kmem_cache#20-o5)->height: 1 // (kmem_cache#20-o5)->count: 64 // (kmem_cache#20-o5)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o5)->slots[0...63]: kmem_cache#28-oX (irq 256...319) // // (kmem_cache#20-o6)->height: 1 // (kmem_cache#20-o6)->count: 64 // (kmem_cache#20-o6)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o6)->slots[0...63]: kmem_cache#28-oX (irq 320...383) // // (kmem_cache#20-o7)->height: 1 // (kmem_cache#20-o7)->count: 32 // (kmem_cache#20-o7)->parent: kmem_cache#20-o1 (RADIX_LSB: 1) // (kmem_cache#20-o7)->slots[0...31]: kmem_cache#28-oX (irq 384...415) // // (&irq_desc_tree)->rnode --> +-----------------------+ // | radix_tree_node | // | (kmem_cache#20-o1) | // +-----------------------+ // | height: 2 | count: 7 | // +-----------------------+ // | radix_tree_node 0 ~ 6 | \ // / +-----------------------+ \ \ // / / | | \ \ \ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ // slot: 0 / | slot: 1 | | | \ slot: 2 | // +-----------------------+ | +-----------------------+ | +-----------------------+ | // | radix_tree_node | | | radix_tree_node | | | radix_tree_node | | // | (kmem_cache#20-o0) | | | (kmem_cache#20-o2) | | | (kmem_cache#20-o3) | | // +-----------------------+ | +-----------------------+ | +-----------------------+ | // | height: 1 | count: 64 | | | height: 1 | count: 64 | | | height: 1 | count: 64 | | // +-----------------------+ | +-----------------------+ | +-----------------------+ | // | irq 0 ~ 63 | | | irq 64 ~ 127 | | | irq 128 ~ 191 | | // +-----------------------+ | +-----------------------+ | +-----------------------+ | // / | \ | // slot: 3 / slot: 4 | \ slot: 5 \ slot: 6 // +-----------------------+ +-----------------------+ +-----------------------+ +-----------------------+ // | radix_tree_node | | radix_tree_node | | radix_tree_node | | radix_tree_node | // | (kmem_cache#20-o4) | | (kmem_cache#20-o5) | | (kmem_cache#20-o6) | | (kmem_cache#20-o7) | // +-----------------------+ +-----------------------+ +-----------------------+ +-----------------------+ // | height: 1 | count: 64 | | height: 1 | count: 64 | | height: 1 | count: 64 | | height: 1 | count: 32 | // +-----------------------+ +-----------------------+ +-----------------------+ +-----------------------+ // | irq 192 ~ 255 | | irq 256 ~ 319 | | irq 320 ~ 383 | | irq 384 ~ 415 | // +-----------------------+ +-----------------------+ +-----------------------+ +-----------------------+ */ err: mutex_unlock(&sparse_irq_lock); return ret; }