]> git.neil.brown.name Git - history.git/commitdiff
Ingo Molnar's update to remove irqlock (documentation and fixing
authorLinus Torvalds <torvalds@penguin.transmeta.com>
Mon, 22 Jul 2002 06:42:32 +0000 (23:42 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Mon, 22 Jul 2002 06:42:32 +0000 (23:42 -0700)
a number of drivers)

13 files changed:
Documentation/cli-sti-removal.txt
Documentation/preempt-locking.txt
arch/i386/kernel/apic.c
arch/i386/kernel/bluesmoke.c
arch/i386/kernel/entry.S
arch/i386/kernel/smp.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/plip.c
drivers/net/tulip/de2104x.c
drivers/scsi/qlogicisp.c
include/linux/interrupt.h
include/linux/smp.h

index 8192ffefc7116c4beb950543012324678ca2232d..13c744dac8661a0b1bd48ed6542540191842807f 100644 (file)
@@ -2,10 +2,10 @@
 #### cli()/sti() removal guide, started by Ingo Molnar <mingo@redhat.com>
 
 
-as of 2.5.28, four popular macros have been removed on SMP, and
+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), restore_flags(flags)
+ 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
@@ -86,25 +86,44 @@ the above code has a number of advantages:
   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() and restore_flags() macros defined on UP systems - but
-their usage will be phased out until the 2.6 kernel is released.
+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 four macros:
+current CPU), can use the following five macros:
 
-  __cli(), __sti(), __save_flags(flags), __restore_flags(flags)
+  local_irq_disable(), local_irq_enable(), local_irq_save(flags),
+  local_irq_save_off(flags), local_irq_restore(flags)
 
 but beware, their meaning and semantics are much simpler, far from
-that of cli(), sti(), save_flags(flags) and restore_flags(flags).
+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_irq_save(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_off(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.
+to make the transition easier, we've still kept the cli(), sti(),
+save_flags() and restore_flags() macros defined on UP systems - but
+their usage will be phased out until the 2.6 kernel is released.
 
 
 why were these changes done? The main reason was the architectural burden
index 580814915c70e968eead8609057077cf086f1355..08e6035a0e13313bbc6eaedc522ccf351af8d762 100644 (file)
@@ -82,6 +82,13 @@ Note that you do not need to explicitly prevent preemption if you are holding
 any locks or interrupts are disabled, since preemption is implicitly disabled
 in those cases.
 
+But keep in mind that 'irqs disabled' is a fundamentally unsafe way of
+disabling preemption - any spin_unlock() decreasing the preemption count
+to 0 might trigger a reschedule. A simple printk() might trigger a reschedule.
+So use this implicit preemption-disabling property only if you know that the
+affected codepath does not do any of this. Best policy is to use this only for
+small, atomic code that you wrote and which calls no complex functions.
+
 Example:
 
        cpucache_t *cc; /* this is per-CPU */
index 15ba757d2d6bd0ec65884cbe1805e4e7b9a3fd91..801d4f2139b1323a9c3b0e7ebc271198813902e7 100644 (file)
@@ -1099,6 +1099,7 @@ asmlinkage void smp_spurious_interrupt(void)
 {
        unsigned long v;
 
+       irq_enter();
        /*
         * Check if this really is a spurious interrupt and ACK it
         * if it is a vectored one.  Just in case...
@@ -1111,6 +1112,7 @@ asmlinkage void smp_spurious_interrupt(void)
        /* see sw-dev-man vol 3, chapter 7.4.13.5 */
        printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n",
                        smp_processor_id());
+       irq_exit();
 }
 
 /*
@@ -1121,6 +1123,7 @@ asmlinkage void smp_error_interrupt(void)
 {
        unsigned long v, v1;
 
+       irq_enter();
        /* First tickle the hardware, only then report what went on. -- REW */
        v = apic_read(APIC_ESR);
        apic_write(APIC_ESR, 0);
@@ -1140,6 +1143,7 @@ asmlinkage void smp_error_interrupt(void)
        */
        printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n",
                smp_processor_id(), v , v1);
+       irq_exit();
 }
 
 /*
index 9a1c05eddf55e9be3a75fbb215dfe3aa71902a0d..ee0a5ca7f3cab1709bd93ec1d647ee3fcf58679c 100644 (file)
@@ -74,7 +74,9 @@ static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_therm
 
 asmlinkage void smp_thermal_interrupt(struct pt_regs regs)
 {
+       irq_enter();
        vendor_thermal_interrupt(&regs);
+       irq_exit();
 }
 
 /* P4/Xeon Thermal regulation detect and init */
index e5f506df853368bf7d95e70e733144e8a6c200df..641062bbcbf201c64bd91ce941ef32c3ac6d0a67 100644 (file)
@@ -186,7 +186,6 @@ ENTRY(ret_from_fork)
        # userspace resumption stub bypassing syscall exit tracing
        ALIGN
 ret_from_intr:
-       preempt_stop
 ret_from_exception:
        movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
        movb CS(%esp), %al
index 2098fcf2679af5cf3ebe17735eb70398a52909b3..4387535fc71e133ac99a960336e54b5767960cc6 100644 (file)
@@ -387,7 +387,7 @@ asmlinkage void smp_invalidate_interrupt (void)
        clear_bit(cpu, &flush_cpumask);
 
 out:
-       put_cpu();
+       put_cpu_no_resched();
 }
 
 static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
index 9b7bfac1c4a35a6c09c97c9d62f909b318ab52d6..5fa80ade4429e2550e524675b0e600e24feb173c 100644 (file)
@@ -926,13 +926,15 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev)
 
 static void cp_stop_hw (struct cp_private *cp)
 {
+       struct net_device *dev = cp->dev;
+
        cpw16(IntrMask, 0);
        cpr16(IntrMask);
        cpw8(Cmd, 0);
        cpw16(CpCmd, 0);
        cpr16(CpCmd);
        cpw16(IntrStatus, ~(cpr16(IntrStatus)));
-       synchronize_irq();
+       synchronize_irq(dev->irq);
        udelay(10);
 
        cp->rx_tail = 0;
index 6eb8e2ff52d4a966fe5de4ef891c994ec2c1d2f8..76a257ea33e0da20ecf5cb52b69ae7064f71d5d5 100644 (file)
@@ -2130,7 +2130,9 @@ static int rtl8139_close (struct net_device *dev)
 
        spin_unlock_irqrestore (&tp->lock, flags);
 
-       synchronize_irq ();
+       /* TODO: isn't this code racy? we synchronize the IRQ and then free it, */ 
+       /* but another IRQ could've happened in between the sync and free */ 
+       synchronize_irq (dev->irq);
        free_irq (dev->irq, dev);
 
        rtl8139_tx_clear (tp);
index 864d9b833043a41a6452a043c897bd7b7f129bfd..47a9422e672c52e7b789fa2357010861c13796c0 100644 (file)
@@ -518,7 +518,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
        spin_unlock_irq(&nl->lock);
        if (error == HS_TIMEOUT) {
                DISABLE(dev->irq);
-               synchronize_irq();
+               synchronize_irq(dev->irq);
        }
        disable_parport_interrupts (dev);
        netif_stop_queue (dev);
@@ -840,7 +840,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
                        if (c0 & 0x08) {
                                spin_unlock_irq(&nl->lock);
                                DISABLE(dev->irq);
-                               synchronize_irq();
+                               synchronize_irq(dev->irq);
                                if (nl->connection == PLIP_CN_RECEIVE) {
                                        /* Interrupted.
                                           We don't need to enable irq,
@@ -1178,7 +1178,7 @@ plip_close(struct net_device *dev)
 
        netif_stop_queue (dev);
        DISABLE(dev->irq);
-       synchronize_irq();
+       synchronize_irq(dev->irq);
 
        if (dev->irq == -1)
        {
index 80dcf338487baf187d65fa6aedadc0a9f7c83370..fe9796509be80e65e8f3cdbbeab598cea916b5d9 100644 (file)
@@ -1455,7 +1455,7 @@ static void de_tx_timeout (struct net_device *dev)
        /* Update the error counts. */
        __de_get_stats(de);
 
-       synchronize_irq();
+       synchronize_irq(dev->irq);
        de_clean_rings(de);
 
        de_init_hw(de);
index 4d233ac5d9b08b224b12127814c7dba69b1b974c..446c1c9308f7c091599aa2513663f6703e40dae6 100644 (file)
@@ -84,14 +84,11 @@ struct {
 {                                                              \
        unsigned long flags;                                    \
                                                                \
-       save_flags(flags);                                      \
-       cli();                                                  \
        trace.buf[trace.next].name  = (w);                      \
        trace.buf[trace.next].time  = jiffies;                  \
        trace.buf[trace.next].index = (i);                      \
        trace.buf[trace.next].addr  = (long) (a);               \
        trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1);    \
-       restore_flags(flags);                                   \
 }
 
 #else
@@ -1704,9 +1701,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
 
        ENTER("isp1020_load_parameters");
 
-       save_flags(flags);
-       cli();
-
        hwrev = isp_inw(host, ISP_CFG0) & ISP_CFG0_HWMSK;
        isp_cfg1 = ISP_CFG1_F64 | ISP_CFG1_BENAB;
        if (hwrev == ISP_CFG0_1040A) {
@@ -1724,7 +1718,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set initiator id failure\n");
                return 1;
        }
@@ -1736,7 +1729,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set retry count failure\n");
                return 1;
        }
@@ -1747,7 +1739,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : async data setup time failure\n");
                return 1;
        }
@@ -1759,7 +1750,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set active negation state failure\n");
                return 1;
        }
@@ -1771,7 +1761,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set pci control parameter failure\n");
                return 1;
        }
@@ -1782,7 +1771,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set tag age limit failure\n");
                return 1;
        }
@@ -1793,7 +1781,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set selection timeout failure\n");
                return 1;
        }
@@ -1812,7 +1799,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
                isp1020_mbox_command(host, param);
 
                if (param[0] != MBOX_COMMAND_COMPLETE) {
-                       restore_flags(flags);
                        printk("qlogicisp : set target parameter failure\n");
                        return 1;
                }
@@ -1827,7 +1813,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
                        isp1020_mbox_command(host, param);
 
                        if (param[0] != MBOX_COMMAND_COMPLETE) {
-                               restore_flags(flags);
                                printk("qlogicisp : set device queue "
                                       "parameter failure\n");
                                return 1;
@@ -1854,7 +1839,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set response queue failure\n");
                return 1;
        }
@@ -1879,13 +1863,10 @@ static int isp1020_load_parameters(struct Scsi_Host *host)
        isp1020_mbox_command(host, param);
 
        if (param[0] != MBOX_COMMAND_COMPLETE) {
-               restore_flags(flags);
                printk("qlogicisp : set request queue failure\n");
                return 1;
        }
 
-       restore_flags(flags);
-
        LEAVE("isp1020_load_parameters");
 
        return 0;
index 3870d26066e909765121ffc1034e3eb39eba7d17..09e6b86ee763fb21ec0d1110b6b37d3c9c06efd7 100644 (file)
@@ -44,6 +44,16 @@ enum {
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
+/*
+ * Temporary defines for UP kernels, until all code gets fixed.
+ */
+#if !CONFIG_SMP
+# define cli()                 local_irq_disable()
+# define sti()                 local_irq_enable()
+# define save_flags(x)         local_irq_save(x)
+# define restore_flags(x)      local_irq_restore(x)
+# define save_and_cli(x)       local_irq_save_off(x)
+#endif
 
 
 /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
index 6e89d1d34bd8fa99d633063610ab4e2444426006..fff7c165ac2dce4349e525b16b46295f745f5fc0 100644 (file)
@@ -95,7 +95,8 @@ static inline void smp_send_reschedule_all(void) { }
 
 #endif /* !SMP */
 
-#define get_cpu()      ({ preempt_disable(); smp_processor_id(); })
-#define put_cpu()      preempt_enable()
+#define get_cpu()              ({ preempt_disable(); smp_processor_id(); })
+#define put_cpu()              preempt_enable()
+#define put_cpu_no_resched()   preempt_enable_no_resched()
 
 #endif /* __LINUX_SMP_H */