]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | |
2 | #### cli()/sti() removal guide, started by Ingo Molnar <[email protected]> | |
3 | ||
4 | ||
5 | as of 2.5.28, five popular macros have been removed on SMP, and | |
6 | are being phased out on UP: | |
7 | ||
8 | cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags) | |
9 | ||
10 | until now it was possible to protect driver code against interrupt | |
11 | handlers via a cli(), but from now on other, more lightweight methods | |
12 | have to be used for synchronization, such as spinlocks or semaphores. | |
13 | ||
14 | for example, driver code that used to do something like: | |
15 | ||
16 | struct driver_data; | |
17 | ||
18 | irq_handler (...) | |
19 | { | |
20 | .... | |
21 | driver_data.finish = 1; | |
22 | driver_data.new_work = 0; | |
23 | .... | |
24 | } | |
25 | ||
26 | ... | |
27 | ||
28 | ioctl_func (...) | |
29 | { | |
30 | ... | |
31 | cli(); | |
32 | ... | |
33 | driver_data.finish = 0; | |
34 | driver_data.new_work = 2; | |
35 | ... | |
36 | sti(); | |
37 | ... | |
38 | } | |
39 | ||
40 | was SMP-correct because the cli() function ensured that no | |
41 | interrupt handler (amongst them the above irq_handler()) function | |
42 | would execute while the cli()-ed section is executing. | |
43 | ||
44 | but from now on a more direct method of locking has to be used: | |
45 | ||
46 | spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; | |
47 | struct driver_data; | |
48 | ||
49 | irq_handler (...) | |
50 | { | |
51 | unsigned long flags; | |
52 | .... | |
53 | spin_lock_irqsave(&driver_lock, flags); | |
54 | .... | |
55 | driver_data.finish = 1; | |
56 | driver_data.new_work = 0; | |
57 | .... | |
58 | spin_unlock_irqrestore(&driver_lock, flags); | |
59 | .... | |
60 | } | |
61 | ||
62 | ... | |
63 | ||
64 | ioctl_func (...) | |
65 | { | |
66 | ... | |
67 | spin_lock_irq(&driver_lock); | |
68 | ... | |
69 | driver_data.finish = 0; | |
70 | driver_data.new_work = 2; | |
71 | ... | |
72 | spin_unlock_irq(&driver_lock); | |
73 | ... | |
74 | } | |
75 | ||
76 | the above code has a number of advantages: | |
77 | ||
78 | - the locking relation is easier to understand - actual lock usage | |
79 | pinpoints the critical sections. cli() usage is too opaque. | |
80 | Easier to understand means it's easier to debug. | |
81 | ||
82 | - it's faster, because spinlocks are faster to acquire than the | |
83 | potentially heavily-used IRQ lock. Furthermore, your driver does | |
84 | not have to wait eg. for a big heavy SCSI interrupt to finish, | |
85 | because the driver_lock spinlock is only used by your driver. | |
86 | cli() on the other hand was used by many drivers, and extended | |
87 | the critical section to the whole IRQ handler function - creating | |
88 | serious lock contention. | |
89 | ||
90 | ||
91 | to make the transition easier, we've still kept the cli(), sti(), | |
92 | save_flags(), save_flags_cli() and restore_flags() macros defined | |
93 | on UP systems - but their usage will be phased out until 2.6 is | |
94 | released. | |
95 | ||
96 | drivers that want to disable local interrupts (interrupts on the | |
97 | current CPU), can use the following five macros: | |
98 | ||
99 | local_irq_disable(), local_irq_enable(), local_save_flags(flags), | |
100 | local_irq_save(flags), local_irq_restore(flags) | |
101 | ||
102 | but beware, their meaning and semantics are much simpler, far from | |
103 | that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) | |
104 | SMP meaning: | |
105 | ||
106 | local_irq_disable() => turn local IRQs off | |
107 | ||
108 | local_irq_enable() => turn local IRQs on | |
109 | ||
110 | local_save_flags(flags) => save the current IRQ state into flags. The | |
111 | state can be on or off. (on some | |
112 | architectures there's even more bits in it.) | |
113 | ||
114 | local_irq_save(flags) => save the current IRQ state into flags and | |
115 | disable interrupts. | |
116 | ||
117 | local_irq_restore(flags) => restore the IRQ state from flags. | |
118 | ||
119 | (local_irq_save can save both irqs on and irqs off state, and | |
120 | local_irq_restore can restore into both irqs on and irqs off state.) | |
121 | ||
122 | another related change is that synchronize_irq() now takes a parameter: | |
123 | synchronize_irq(irq). This change too has the purpose of making SMP | |
124 | synchronization more lightweight - this way you can wait for your own | |
125 | interrupt handler to finish, no need to wait for other IRQ sources. | |
126 | ||
127 | ||
128 | why were these changes done? The main reason was the architectural burden | |
129 | of maintaining the cli()/sti() interface - it became a real problem. The | |
130 | new interrupt system is much more streamlined, easier to understand, debug, | |
131 | and it's also a bit faster - the same happened to it that will happen to | |
132 | cli()/sti() using drivers once they convert to spinlocks :-) | |
133 |