linux/Documentation/cli-sti-removal.txt
<<
>>
Prefs
   1
   2#### cli()/sti() removal guide, started by Ingo Molnar <mingo@redhat.com>
   3
   4
   5as of 2.5.28, five popular macros have been removed on SMP, and
   6are being phased out on UP:
   7
   8 cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags)
   9
  10until now it was possible to protect driver code against interrupt
  11handlers via a cli(), but from now on other, more lightweight methods
  12have to be used for synchronization, such as spinlocks or semaphores.
  13
  14for 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
  40was SMP-correct because the cli() function ensured that no
  41interrupt handler (amongst them the above irq_handler()) function
  42would execute while the cli()-ed section is executing.
  43
  44but 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
  76the 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 
  91to make the transition easier, we've still kept the cli(), sti(),
  92save_flags(), save_flags_cli() and restore_flags() macros defined
  93on UP systems - but their usage will be phased out until 2.6 is
  94released.
  95
  96drivers that want to disable local interrupts (interrupts on the
  97current 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
 102but beware, their meaning and semantics are much simpler, far from
 103that of the old cli(), sti(), save_flags(flags) and restore_flags(flags)
 104SMP 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
 120local_irq_restore can restore into both irqs on and irqs off state.)
 121
 122another related change is that synchronize_irq() now takes a parameter:
 123synchronize_irq(irq). This change too has the purpose of making SMP
 124synchronization more lightweight - this way you can wait for your own
 125interrupt handler to finish, no need to wait for other IRQ sources.
 126
 127
 128why were these changes done? The main reason was the architectural burden
 129of maintaining the cli()/sti() interface - it became a real problem. The
 130new interrupt system is much more streamlined, easier to understand, debug,
 131and it's also a bit faster - the same happened to it that will happen to
 132cli()/sti() using drivers once they convert to spinlocks :-)
 133
 134
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.