| #### cli()/sti() removal guide, started by Ingo Molnar <mingo@redhat.com> | |
| as of 2.5.28, five popular macros have been removed on SMP, and | |
| are being phased out on UP: | |
| cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags) | |
| until now it was possible to protect driver code against interrupt | |
| handlers via a cli(), but from now on other, more lightweight methods | |
| have to be used for synchronization, such as spinlocks or semaphores. | |
| for example, driver code that used to do something like: | |
| struct driver_data; | |
| irq_handler (...) | |
| { | |
| .... | |
| driver_data.finish = 1; | |
| driver_data.new_work = 0; | |
| .... | |
| } | |
| ... | |
| ioctl_func (...) | |
| { | |
| ... | |
| cli(); | |
| ... | |
| driver_data.finish = 0; | |
| driver_data.new_work = 2; | |
| ... | |
| sti(); | |
| ... | |
| } | |
| was SMP-correct because the cli() function ensured that no | |
| interrupt handler (amongst them the above irq_handler()) function | |
| would execute while the cli()-ed section is executing. | |
| but from now on a more direct method of locking has to be used: | |
| spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; | |
| struct driver_data; | |
| irq_handler (...) | |
| { | |
| unsigned long flags; | |
| .... | |
| spin_lock_irqsave(&driver_lock, flags); | |
| .... | |
| driver_data.finish = 1; | |
| driver_data.new_work = 0; | |
| .... | |
| spin_unlock_irqrestore(&driver_lock, flags); | |
| .... | |
| } | |
| ... | |
| ioctl_func (...) | |
| { | |
| ... | |
| spin_lock_irq(&driver_lock); | |
| ... | |
| driver_data.finish = 0; | |
| driver_data.new_work = 2; | |
| ... | |
| spin_unlock_irq(&driver_lock); | |
| ... | |
| } | |
| the above code has a number of advantages: | |
| - the locking relation is easier to understand - actual lock usage | |
| pinpoints the critical sections. cli() usage is too opaque. | |
| Easier to understand means it's easier to debug. | |
| - it's faster, because spinlocks are faster to acquire than the | |
| potentially heavily-used IRQ lock. Furthermore, your driver does | |
| not have to wait eg. for a big heavy SCSI interrupt to finish, | |
| because the driver_lock spinlock is only used by your driver. | |
| cli() on the other hand was used by many drivers, and extended | |
| the critical section to the whole IRQ handler function - creating | |
| serious lock contention. | |
| to make the transition easier, we've still kept the cli(), sti(), | |
| save_flags(), save_flags_cli() and restore_flags() macros defined | |
| on UP systems - but their usage will be phased out until 2.6 is | |
| released. | |
| drivers that want to disable local interrupts (interrupts on the | |
| current CPU), can use the following five macros: | |
| local_irq_disable(), local_irq_enable(), local_save_flags(flags), | |
| local_irq_save(flags), local_irq_restore(flags) | |
| but beware, their meaning and semantics are much simpler, far from | |
| that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) | |
| SMP meaning: | |
| local_irq_disable() => turn local IRQs off | |
| local_irq_enable() => turn local IRQs on | |
| local_save_flags(flags) => save the current IRQ state into flags. The | |
| state can be on or off. (on some | |
| architectures there's even more bits in it.) | |
| local_irq_save(flags) => save the current IRQ state into flags and | |
| disable interrupts. | |
| local_irq_restore(flags) => restore the IRQ state from flags. | |
| (local_irq_save can save both irqs on and irqs off state, and | |
| local_irq_restore can restore into both irqs on and irqs off state.) | |
| another related change is that synchronize_irq() now takes a parameter: | |
| synchronize_irq(irq). This change too has the purpose of making SMP | |
| synchronization more lightweight - this way you can wait for your own | |
| interrupt handler to finish, no need to wait for other IRQ sources. | |
| why were these changes done? The main reason was the architectural burden | |
| of maintaining the cli()/sti() interface - it became a real problem. The | |
| new interrupt system is much more streamlined, easier to understand, debug, | |
| and it's also a bit faster - the same happened to it that will happen to | |
| cli()/sti() using drivers once they convert to spinlocks :-) | |