1. /kernel/irq.c softirq_init 2.6.32.25
1.1 for_each_possible_cpu
for ( ( ( cpu ) ) = - 1 ; ( ( cpu ) ) = cpumask_next ( ( ( cpu ) ) , ( cpu_possible_mask ) ) , ( ( cpu ) ) < nr_cpu_ids ; ) |
1.2 per_cpu(tasklet_vec, cpu);
//取per_cpu_tasklet_vec[cpu],即cpu的tasklet_vec结构。
per_cpu(tasklet_vec, cpu); ( * ( { unsigned long __ptr ; __ptr = ( unsigned long ) ( ( & per_cpu__tasklet_vec ) ) ; ( typeof ( ( & per_cpu__tasklet_vec ) ) ) ( __ptr + ( ( ( __per_cpu_offset [ cpu ] ) ) ) ) ; } ) ) ; |
1.3 tasklet_vec / tasklet_hi_vec
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec); static __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct tasklet_head ) per_cpu__tasklet_vec ; |
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec); static __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct tasklet_head ) per_cpu__tasklet_hi_vec ; |
struct tasklet_head
struct tasklet_head{ struct tasklet_struct *head; struct tasklet_struct **tail; }; |
struct tasklet_struct
struct tasklet_struct{ struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; }; |
1.4 softirq_work_list
DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); extern __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct list_head [ NR_SOFTIRQS ] ) per_cpu__softirq_work_list ; |
DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct list_head [ NR_SOFTIRQS ] ) per_cpu__softirq_work_list ; |
1.5 x86_init
extern struct x86_init_ops x86_init; struct x86_init_ops { struct x86_init_resources resources; struct x86_init_mpparse mpparse; struct x86_init_irqs irqs; struct x86_init_oem oem; struct x86_init_paging paging; struct x86_init_timers timers; }; struct x86_init_resources { void (*probe_roms)(void); void (*reserve_resources)(void); char *(*memory_setup)(void); }; struct x86_init_mpparse { void (*mpc_record)(unsigned int mode); void (*setup_ioapic_ids)(void); int (*mpc_apic_id)(struct mpc_cpu *m); void (*smp_read_mpc_oem)(struct mpc_table *mpc); void (*mpc_oem_pci_bus)(struct mpc_bus *m); void (*mpc_oem_bus_info)(struct mpc_bus *m, char *name); void (*find_smp_config)(unsigned int reserve); void (*get_smp_config)(unsigned int early); }; struct x86_init_irqs { void (*pre_vector_init)(void); void (*intr_init)(void); void (*trap_init)(void); }; struct x86_init_oem { void (*arch_setup)(void); void (*banner)(void); }; struct x86_init_paging { void (*pagetable_setup_start)(pgd_t *base); void (*pagetable_setup_done)(pgd_t *base); }; struct x86_init_timers { void (*setup_percpu_clockev)(void); void (*tsc_pre_init)(void); void (*timer_init)(void); }; |
1.6 test_and_set_bit
BTS—Bit Test and Set
Description:
Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset operand (second operand), stores the value of the bit in the CF flag, and sets the selected bit in the bit string to 1. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value:
• If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). This allows any bit position to be selected.
• If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size.
See also: Bit(BitBase, BitOffset) on page 3-14.
Some assemblers support immediate bit offsets larger than 31 by using the imme-diate bit offset field in combination with the displacement field of the memory operand. See “BT—Bit Test” in this chapter for more information on this addressing mechanism.
This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically.
In 64-bit mode, the instruction’s default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits.
Operation
CF ← Bit(BitBase, BitOffset);
Bit(BitBase, BitOffset) ← 1;
Flags Affected
The CF flag contains the value of the selected bit before it is set. The ZF flag is unaf-
fected. The OF, SF, AF, and PF flags are undefined.
SBB—Integer Subtraction with Borrow;
Description:
Adds the source operand (second operand) and the carry (CF) flag, and subtracts the result from the destination operand (first operand). The result of the subtraction is stored in the destination operand. The destination operand can be a register or a memory location; the source operand can be an immediate, a register, or a memory location. (However, two memory operands cannot be used in one instruction.) The state of the CF flag represents a borrow from a previous subtraction.
When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format.
The SBB instruction does not distinguish between signed or unsigned operands. Instead, the processor evaluates the result for both data types and sets the OF and CF flags to indicate a borrow in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result.
The SBB instruction is usually executed as part of a multibyte or multiword subtrac-tion in which a SUB instruction is followed by a SBB instruction.
This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically.
In 64-bit mode, the instruction’s default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits.
Operation
DEST ← (DEST – (SRC + CF));
Flags Affected
The OF, SF, ZF, AF, PF, and CF flags are set according to the result.
// \linux-2.6.32.25\arch\x86\include\asm\ bitops.h static inline int test_and_set_bit(int nr, volatile unsigned long *addr){ int oldbit; asm volatile(LOCK_PREFIX "bts %2,%1\n\t" "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory"); return oldbit; } #define ADDR BITOP_ADDR(addr) #define BITOP_ADDR(x) "=m" (*(volatile long *) (x)) #define LOCK_PREFIX \ ".section .smp_locks,\"a\"\n" \ _ASM_ALIGN "\n" \ _ASM_PTR "661f\n" /* address */ \ ".previous\n" \ "661:\n\tlock; " #define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8) #define _ASM_PTR __ASM_SEL(.long, .quad) #define __ASM_SEL(a,b) __ASM_FORM(a) #ifdef __ASSEMBLY__ #define __ASM_FORM(x) x #define __ASM_EX_SEC .section __ex_table, "a" #else # define __ASM_FORM(x) " " #x " " # define __ASM_EX_SEC " .section __ex_table,\"a\"\n" #endif
LOCK_PRIFIX根据宏定义展开过后为:".section .smp_locks,\"a\"\n .balign 4 \n .long 661f\n.previous\n661:\n\tlock; " ;
//\linux-2.6.32.25\include\asm-generic\bitops\ atomic.h static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); unsigned long old; unsigned long flags; _atomic_spin_lock_irqsave(p, flags); old = *p; *p = old | mask; _atomic_spin_unlock_irqrestore(p, flags); return (old & mask) != 0; } 有两个test_and_set_bit定义,一直搞不清楚到底是用的哪一个,什么时候用哪一个?分析了第一个,第二个还没来得及分析。 |
2. raise_softirq_irqoff softirq.c 2.6.38.2
2.1 重要宏定义和数据结构
1. /*Softirq.c*/ 2. void raise_softirq(unsigned int nr) 3. { 4. unsigned long flags; 5. 6. local_irq_save(flags); 7. raise_softirq_irqoff(nr); 8. local_irq_restore(flags); 9. } 10. 11. /*Softirq.c*/ 12. inline void raise_softirq_irqoff(unsigned int nr) 13. { 14. __raise_softirq_irqoff(nr); 15. 16. /* 17. * If we're in an interrupt or softirq, we're done 18. * (this also catches softirq-disabled code). We will 19. * actually run the softirq once we return from 20. * the irq or softirq. 21. * 22. * Otherwise we wake up ksoftirqd to make sure we 23. * schedule the softirq soon. 24. */ 25. if (!in_interrupt()) 26. wakeup_softirqd(); 27. } 28. 29. /*include/linux/Interrupt.h*/ 30. static inline void __raise_softirq_irqoff(unsigned int nr) 31. { 32. trace_softirq_raise(nr); 33. or_softirq_pending(1UL << nr); 34. } 35. 36. /*include/linux/Interrupt.h*/ 37. #ifndef __ARCH_SET_SOFTIRQ_PENDING 38. #define set_softirq_pending(x) (local_softirq_pending() = (x)) 39. #define or_softirq_pending(x) (local_softirq_pending() |= (x)) 40. #endif 41. 42. 43. /*include/linux/Interrupt.h*/ 44. #ifndef __ARCH_IRQ_STAT 45. extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */ 46. #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) 47. #endif 48. 49. /* arch independent irq_stat fields */ 50. #define local_softirq_pending() \ 51. __IRQ_STAT(smp_processor_id(), __softirq_pending) 52. /********************************************************/ 53. /*arch/x86/include/asm/Hardirq.h*/ 54. typedef struct { 55. unsigned int __softirq_pending; 56. unsigned int __nmi_count; /* arch dependent */ 57. unsigned int irq0_irqs; 58. #ifdef CONFIG_X86_LOCAL_APIC 59. unsigned int apic_timer_irqs; /* arch dependent */ 60. unsigned int irq_spurious_count; 61. #endif 62. unsigned int x86_platform_ipis; /* arch dependent */ 63. unsigned int apic_perf_irqs; 64. unsigned int apic_irq_work_irqs; 65. #ifdef CONFIG_SMP 66. unsigned int irq_resched_count; 67. unsigned int irq_call_count; 68. unsigned int irq_tlb_count; 69. #endif 70. #ifdef CONFIG_X86_THERMAL_VECTOR 71. unsigned int irq_thermal_count; 72. #endif 73. #ifdef CONFIG_X86_MCE_THRESHOLD 74. unsigned int irq_threshold_count; 75. #endif 76. } ____cacheline_aligned irq_cpustat_t; 77. 78. DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); 79. 80. /*include/linux/percpu_defs.h*/ 81. #define DECLARE_PER_CPU_SHARED_ALIGNED(type, name) \ 82. DECLARE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \ 83. ____cacheline_aligned_in_smp 84. #define DECLARE_PER_CPU_SECTION(type, name, sec) \ 85. extern __PCPU_ATTRS(sec) __typeof__(type) name 86. 87. #define __PCPU_DUMMY_ATTRS \ 88. __attribute__((section(".discard"), unused)) 89. 90. #define __PCPU_ATTRS(sec) \ 91. __percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \ 92. PER_CPU_ATTRIBUTES 93. 94. 95. /*include/asm-generic/Percpu.h*/ 96. #define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned" 97. 98. #ifndef PER_CPU_ATTRIBUTES 99. #define PER_CPU_ATTRIBUTES 100. #endif 101. /*include/linux/Cache.h*/ 102. #define ____cacheline_aligned_in_smp ____cacheline_aligned 103. 104. 105. /*include/linux/compiler.h*/ 106. # define __percpu |
2.2 or_softirq_pending ( 1UL << nr ) ;
( irq_stat [ smp_processor_id ( ) ] . __softirq_pending ) |= ( 1UL << nr ) ) ; |
2.3 local_softirq_pending();
( irq_stat [ smp_processor_id ( ) ] . __softirq_pending ) ; |
2.4 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
extern __attribute__ ( ( section ( PER_CPU_BASE_SECTION "..shared_aligned" ) ) ) __typeof__ ( irq_cpustat_t ) irq_stat ____cacheline_aligned ; |
2.5 irq_cpustat_t
/*arch/x86/include/asm/Hardirq.h*/ typedef struct { unsigned int __softirq_pending; unsigned int __nmi_count; /* arch dependent */ unsigned int irq0_irqs; #ifdef CONFIG_X86_LOCAL_APIC unsigned int apic_timer_irqs; /* arch dependent */ unsigned int irq_spurious_count; #endif unsigned int x86_platform_ipis; /* arch dependent */ unsigned int apic_perf_irqs; unsigned int apic_irq_work_irqs; #ifdef CONFIG_SMP unsigned int irq_resched_count; unsigned int irq_call_count; unsigned int irq_tlb_count; #endif #ifdef CONFIG_X86_THERMAL_VECTOR unsigned int irq_thermal_count; #endif #ifdef CONFIG_X86_MCE_THRESHOLD unsigned int irq_threshold_count; #endif } ____cacheline_aligned irq_cpustat_t; |
2.6 流程总结
来源:https://www.cnblogs.com/justinzhang/archive/2011/07/18/2109930.html