--- linux/drivers/net/eepro100.c.orig Sun Jul 21 20:37:11 2002 +++ linux/drivers/net/eepro100.c Sun Jul 21 20:38:03 2002 @@ -1354,7 +1354,7 @@ udelay(10); /* Disable interrupts. */ outw(SCBMaskAll, ioaddr + SCBCmd); - synchronize_irq(); + synchronize_irq(dev->irq); speedo_tx_buffer_gc(dev); /* Free as much as possible. It helps to recover from a hang because of out-of-memory. --- linux/drivers/char/n_tty.c.orig Sun Jun 9 07:26:33 2002 +++ linux/drivers/char/n_tty.c Sun Jul 21 21:04:09 2002 @@ -807,7 +807,7 @@ I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - cli(); + __cli(); // FIXME: is this safe? memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -843,7 +843,7 @@ set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - sti(); + __sti(); // FIXME: is this safe? tty->raw = 0; tty->real_raw = 0; } else { --- linux/drivers/char/vt.c.orig Sun Jun 9 07:30:53 2002 +++ linux/drivers/char/vt.c Sun Jul 21 21:12:17 2002 @@ -113,8 +113,8 @@ if (hz > 20 && hz < 32767) count = 1193180 / hz; - save_flags(flags); - cli(); + __save_flags(flags); // FIXME: is this safe? + __cli(); del_timer(&sound_timer); if (count) { /* enable counter 2 */ @@ -131,7 +131,7 @@ } } else kd_nosound(0); - restore_flags(flags); + __restore_flags(flags); return; } --- linux/drivers/char/tty_ioctl.c.orig Sun Jun 9 07:30:01 2002 +++ linux/drivers/char/tty_ioctl.c Sun Jul 21 21:03:49 2002 @@ -97,7 +97,7 @@ int canon_change; struct termios old_termios = *tty->termios; - cli(); + __cli(); // FIXME: is this safe? *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -107,7 +107,7 @@ tty->canon_data = 0; tty->erasing = 0; } - sti(); + __sti(); // FIXME: is this safe? if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ wake_up_interruptible(&tty->read_wait); --- linux/drivers/char/tty_io.c.orig Sun Jul 21 20:37:10 2002 +++ linux/drivers/char/tty_io.c Sun Jul 21 21:05:39 2002 @@ -456,11 +456,12 @@ } file_list_unlock(); - /* FIXME! What are the locking issues here? This may me overdoing things.. */ + /* FIXME! What are the locking issues here? This may me overdoing things.. + * this question is especially important now that we've removed the irqlock. */ { unsigned long flags; - save_flags(flags); cli(); + __save_flags(flags); __cli(); // FIXME: is this safe? if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (tty->driver.flush_buffer) @@ -468,7 +469,7 @@ if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); - restore_flags(flags); + __restore_flags(flags); // FIXME: is this safe? } wake_up_interruptible(&tty->write_wait); @@ -1900,7 +1901,7 @@ fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; - save_flags(flags); cli(); + __save_flags(flags); __cli(); // FIXME: is this safe? tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { @@ -1908,13 +1909,13 @@ fp = tty->flip.flag_buf; tty->flip.buf_num = 1; - save_flags(flags); cli(); + __save_flags(flags); __cli(); // FIXME: is this safe? tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; - restore_flags(flags); + __restore_flags(flags); // FIXME: is this safe? tty->ldisc.receive_buf(tty, cp, fp, count); } --- linux/drivers/ide/main.c.orig Sun Jul 21 20:37:12 2002 +++ linux/drivers/ide/main.c Sun Jul 21 21:06:28 2002 @@ -1091,18 +1091,18 @@ { unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + __save_flags(flags); // FIXME: is this safe? + __cli(); #if 0 if (__MOD_IN_USE(ata_ops(drive)->owner)) { - restore_flags(flags); + __restore_flags(flags); // FIXME: is this safe? return 1; } #endif if (drive->usage || drive->busy || !ata_ops(drive)) { - restore_flags(flags); /* all CPUs */ + __restore_flags(flags); // FIXME: is this safe? return 1; } @@ -1111,7 +1111,7 @@ #endif drive->driver = NULL; - restore_flags(flags); /* all CPUs */ + __restore_flags(flags); // FIXME: is this safe? return 0; } --- linux/drivers/block/genhd.c.orig Sun Jul 21 20:37:07 2002 +++ linux/drivers/block/genhd.c Sun Jul 21 23:49:11 2002 @@ -209,7 +209,6 @@ { rwlock_init(&gendisk_lock); blk_dev_init(); - sti(); #ifdef CONFIG_I2O i2o_init(); #endif --- linux/drivers/block/ll_rw_blk.c.orig Sun Jul 21 23:54:46 2002 +++ linux/drivers/block/ll_rw_blk.c Sun Jul 21 23:54:49 2002 @@ -2047,9 +2047,6 @@ #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD) hd_init(); #endif -#if defined(__i386__) /* Do we even need this? */ - outb_p(0xc, 0x3f2); -#endif return 0; }; --- linux/arch/i386/kernel/irq.c.orig Sun Jul 21 20:37:06 2002 +++ linux/arch/i386/kernel/irq.c Sun Jul 21 20:38:03 2002 @@ -184,250 +184,12 @@ return 0; } -/* - * Global interrupt locks for SMP. Allow interrupts to come in on any - * CPU, yet make cli/sti act globally to protect critical regions.. - */ - -#ifdef CONFIG_SMP -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */ - -extern void show_stack(unsigned long* esp); - -static void show(char * str) +#if CONFIG_SMP +inline void synchronize_irq(unsigned int irq) { - int i; - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [",irqs_running()); - for(i=0;i < NR_CPUS;i++) - printk(" %d",local_irq_count(i)); - printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < NR_CPUS;i++) - printk(" %d",local_bh_count(i)); - - printk(" ]\nStack dumps:"); - for(i = 0; i < NR_CPUS; i++) { - unsigned long esp; - if (i == cpu) - continue; - printk("\nCPU %d:",i); - esp = init_tss[i].esp0; - if (!esp) { - /* tss->esp0 is set to NULL in cpu_init(), - * it's initialized when the cpu returns to user - * space. -- manfreds - */ - printk(" "); - continue; - } - esp &= ~(THREAD_SIZE-1); - esp += sizeof(struct thread_info); - show_stack((void*)esp); - } - printk("\nCPU %d:",cpu); - show_stack(NULL); - printk("\n"); + while (irq_desc[irq].status & IRQ_INPROGRESS) + cpu_relax(); } - -#define MAXCOUNT 100000000 - -/* - * I had a lockup scenario where a tight loop doing - * spin_unlock()/spin_lock() on CPU#1 was racing with - * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but - * apparently the spin_unlock() information did not make it - * through to CPU#0 ... nasty, is this by design, do we have to limit - * 'memory update oscillation frequency' artificially like here? - * - * Such 'high frequency update' races can be avoided by careful design, but - * some of our major constructs like spinlocks use similar techniques, - * it would be nice to clarify this issue. Set this define to 0 if you - * want to check whether your system freezes. I suspect the delay done - * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but - * i thought that such things are guaranteed by design, since we use - * the 'LOCK' prefix. - */ -#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0 - -#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND -# define SYNC_OTHER_CORES(x) udelay(x+1) -#else -/* - * We have to allow irqs to arrive between __sti and __cli - */ -# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") -#endif - -static inline void wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - - for (;;) { - - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - clear_bit(0,&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - SYNC_OTHER_CORES(cpu); - __cli(); - if (irqs_running()) - continue; - if (global_irq_lock) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (!test_and_set_bit(0,&global_irq_lock)) - break; - } - } -} - -/* - * This is called when we want to synchronize with - * interrupts. We may for example tell a device to - * stop sending interrupts: but to make sure there - * are no interrupts that are executing on another - * CPU we need to call this function. - */ -void synchronize_irq(void) -{ - if (irqs_running()) { - /* Stupid approach */ - cli(); - sti(); - } -} - -static inline void get_irqlock(int cpu) -{ - if (test_and_set_bit(0,&global_irq_lock)) { - /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait.. */ - do { - do { - rep_nop(); - } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); - } - /* - * We also to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu); - - /* - * Ok, finally.. - */ - global_irq_holder = cpu; -} - -#define EFLAGS_IF_SHIFT 9 - -/* - * A global "cli()" while in an interrupt context - * turns into just a local cli(). Interrupts - * should use spinlocks for the (very unlikely) - * case that they ever want to protect against - * each other. - * - * If we already have local interrupts disabled, - * this will not turn a local disable into a - * global one (problems with spinlocks: this makes - * save_flags+cli+sti usable inside a spinlock). - */ -void __global_cli(void) -{ - unsigned int flags; - - __save_flags(flags); - if (flags & (1 << EFLAGS_IF_SHIFT)) { - int cpu; - __cli(); - cpu = smp_processor_id(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); - } -} - -void __global_sti(void) -{ - int cpu = get_cpu(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); - __sti(); - put_cpu(); -} - -/* - * SMP flags value to restore to: - * 0 - global cli - * 1 - global sti - * 2 - local cli - * 3 - local sti - */ -unsigned long __global_save_flags(void) -{ - int retval; - int local_enabled; - unsigned long flags; - int cpu = smp_processor_id(); - - __save_flags(flags); - local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { - if (local_enabled) - retval = 1; - if (global_irq_holder == cpu) - retval = 0; - } - return retval; -} - -void __global_restore_flags(unsigned long flags) -{ - switch (flags) { - case 0: - __global_cli(); - break; - case 1: - __global_sti(); - break; - case 2: - __cli(); - break; - case 3: - __sti(); - break; - default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); - } -} - #endif /* @@ -439,12 +201,7 @@ */ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { - int status; - int cpu = smp_processor_id(); - - irq_enter(cpu, irq); - - status = 1; /* Force the "do bottom halves" bit */ + int status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) __sti(); @@ -458,8 +215,6 @@ add_interrupt_randomness(irq); __cli(); - irq_exit(cpu, irq); - return status; } @@ -511,13 +266,7 @@ void disable_irq(unsigned int irq) { disable_irq_nosync(irq); - - if (!local_irq_count(smp_processor_id())) { - do { - barrier(); - cpu_relax(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); - } + synchronize_irq(irq); } /** @@ -581,6 +330,7 @@ struct irqaction * action; unsigned int status; + irq_enter(); kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); @@ -640,6 +390,8 @@ desc->handler->end(irq); spin_unlock(&desc->lock); + irq_exit(); + if (softirq_pending(cpu)) do_softirq(); return 1; @@ -768,13 +520,8 @@ } spin_unlock_irqrestore(&desc->lock,flags); -#ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ - while (desc->status & IRQ_INPROGRESS) { - barrier(); - cpu_relax(); - } -#endif + synchronize_irq(irq); kfree(action); return; } @@ -826,7 +573,7 @@ /* Wait for longstanding interrupts to trigger. */ for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ synchronize_irq(); + /* about 20ms delay */ barrier(); /* * enable any unassigned irqs @@ -849,7 +596,7 @@ * Wait for spurious interrupts to trigger */ for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ synchronize_irq(); + /* about 100ms delay */ barrier(); /* * Now filter out any obviously spurious interrupts --- linux/arch/i386/kernel/apic.c.orig Sun Jul 21 20:37:10 2002 +++ linux/arch/i386/kernel/apic.c Sun Jul 21 20:38:03 2002 @@ -1084,9 +1084,9 @@ * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ - irq_enter(cpu, 0); + irq_enter(); smp_local_timer_interrupt(®s); - irq_exit(cpu, 0); + irq_exit(); if (softirq_pending(cpu)) do_softirq(); --- linux/arch/i386/kernel/i386_ksyms.c.orig Sun Jul 21 20:37:07 2002 +++ linux/arch/i386/kernel/i386_ksyms.c Sun Jul 21 20:38:03 2002 @@ -132,13 +132,7 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); -/* Global SMP irq stuff */ -EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); +/* Global SMP stuff */ EXPORT_SYMBOL(smp_call_function); /* TLB flushing */ --- linux/arch/i386/kernel/smpboot.c.orig Sun Jul 21 20:37:07 2002 +++ linux/arch/i386/kernel/smpboot.c Sun Jul 21 20:38:03 2002 @@ -1060,7 +1060,6 @@ boot_cpu_logical_apicid = logical_smp_processor_id(); map_cpu_to_boot_apicid(0, boot_cpu_apicid); - global_irq_holder = NO_PROC_ID; current_thread_info()->cpu = 0; smp_tune_scheduling(); --- linux/arch/i386/kernel/entry.S.orig Sun Jul 21 20:37:12 2002 +++ linux/arch/i386/kernel/entry.S Sun Jul 21 20:38:03 2002 @@ -72,12 +72,8 @@ #ifdef CONFIG_PREEMPT #define preempt_stop cli -#define INC_PRE_COUNT(reg) incl TI_PRE_COUNT(reg); -#define DEC_PRE_COUNT(reg) decl TI_PRE_COUNT(reg); #else #define preempt_stop -#define INC_PRE_COUNT(reg) -#define DEC_PRE_COUNT(reg) #define resume_kernel restore_all #endif @@ -191,7 +187,6 @@ ALIGN ret_from_intr: preempt_stop - DEC_PRE_COUNT(%ebx) ret_from_exception: movl EFLAGS(%esp), %eax # mix EFLAGS and CS movb CS(%esp), %al @@ -338,9 +333,8 @@ ALIGN common_interrupt: SAVE_ALL - GET_THREAD_INFO(%ebx) - INC_PRE_COUNT(%ebx) call do_IRQ + GET_THREAD_INFO(%ebx) jmp ret_from_intr #define BUILD_INTERRUPT(name, nr) \ @@ -348,7 +342,6 @@ pushl $nr-256; \ SAVE_ALL \ GET_THREAD_INFO(%ebx); \ - INC_PRE_COUNT(%ebx) \ call smp_/**/name; \ jmp ret_from_intr; --- linux/arch/i386/kernel/apm.c.orig Sun Jul 21 20:37:10 2002 +++ linux/arch/i386/kernel/apm.c Sun Jul 21 22:36:42 2002 @@ -222,6 +222,8 @@ #include +extern rwlock_t xtime_lock; +extern spinlock_t i8253_lock; extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); @@ -1141,40 +1143,25 @@ static void set_time(void) { - unsigned long flags; - - if (got_clock_diff) { /* Must know time zone in order to set clock */ - save_flags(flags); - cli(); + if (got_clock_diff) /* Must know time zone in order to set clock */ CURRENT_TIME = get_cmos_time() + clock_cmos_diff; - restore_flags(flags); - } } static void get_time_diff(void) { #ifndef CONFIG_APM_RTC_IS_GMT - unsigned long flags; - /* * Estimate time zone so that set_time can update the clock */ - save_flags(flags); clock_cmos_diff = -get_cmos_time(); - cli(); clock_cmos_diff += CURRENT_TIME; got_clock_diff = 1; - restore_flags(flags); #endif } -static void reinit_timer(void) +static inline void reinit_timer(void) { #ifdef INIT_TIMER_AFTER_SUSPEND - unsigned long flags; - - save_flags(flags); - cli(); /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ udelay(10); @@ -1182,7 +1169,6 @@ udelay(10); outb(LATCH >> 8 , 0x40); /* MSB */ udelay(10); - restore_flags(flags); #endif } @@ -1203,13 +1189,21 @@ } printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n"); } + /* serialize with the timer interrupt */ + write_lock_irq(&xtime_lock); + + /* protect against access to timer chip registers */ + spin_lock(&i8253_lock); + get_time_diff(); - cli(); err = set_system_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); ignore_normal_resume = 1; - sti(); + + spin_unlock(&i8253_lock); + write_unlock_irq(&xtime_lock); + if (err == APM_NO_ERROR) err = APM_SUCCESS; if (err != APM_SUCCESS) @@ -1232,8 +1226,12 @@ { int err; + /* serialize with the timer interrupt */ + write_lock_irq(&xtime_lock); /* If needed, notify drivers here */ get_time_diff(); + write_unlock_irq(&xtime_lock); + err = set_system_power_state(APM_STATE_STANDBY); if ((err != APM_SUCCESS) && (err != APM_NO_ERROR)) apm_error("standby", err); @@ -1321,7 +1319,9 @@ ignore_bounce = 1; if ((event != APM_NORMAL_RESUME) || (ignore_normal_resume == 0)) { + write_lock_irq(&xtime_lock); set_time(); + write_unlock_irq(&xtime_lock); pm_send_all(PM_RESUME, (void *)0); queue_event(event, NULL); } @@ -1336,7 +1336,9 @@ break; case APM_UPDATE_TIME: + write_lock_irq(&xtime_lock); set_time(); + write_unlock_irq(&xtime_lock); break; case APM_CRITICAL_SUSPEND: --- linux/arch/i386/kernel/nmi.c.orig Sun Jul 21 20:37:06 2002 +++ linux/arch/i386/kernel/nmi.c Sun Jul 21 20:38:03 2002 @@ -78,7 +78,7 @@ printk(KERN_INFO "testing NMI watchdog ... "); memcpy(tmp, irq_stat, sizeof(tmp)); - sti(); + __sti(); mdelay((10*1000)/nmi_hz); // wait 10 ticks for (cpu = 0; cpu < NR_CPUS; cpu++) { --- linux/arch/i386/kernel/io_apic.c.orig Sun Jul 21 20:37:10 2002 +++ linux/arch/i386/kernel/io_apic.c Sun Jul 21 20:38:03 2002 @@ -1219,7 +1219,7 @@ { unsigned int t1 = jiffies; - sti(); + __sti(); /* Let ten ticks pass... */ mdelay((10 * 1000) / HZ); --- linux/arch/i386/kernel/mca.c.orig Sun Jun 9 07:27:54 2002 +++ linux/arch/i386/kernel/mca.c Sun Jul 21 22:49:42 2002 @@ -102,6 +102,12 @@ static struct MCA_info* mca_info = NULL; +/* + * Motherboard register spinlock. Untested on SMP at the moment, but + * are there any MCA SMP boxes? + */ +static spinlock_t mca_lock = SPIN_LOCK_UNLOCKED; + /* MCA registers */ #define MCA_MOTHERBOARD_SETUP_REG 0x94 @@ -213,8 +219,11 @@ } memset(mca_info, 0, sizeof(struct MCA_info)); - save_flags(flags); - cli(); + /* + * We do not expect many MCA interrupts during initialization, + * but let us be safe: + */ + spin_lock_irq(&mca_lock); /* Make sure adapter setup is off */ @@ -300,8 +309,7 @@ outb_p(0, MCA_ADAPTER_SETUP_REG); /* Enable interrupts and return memory start */ - - restore_flags(flags); + spin_unlock_irq(&mca_lock); for (i = 0; i < MCA_STANDARD_RESOURCES; i++) request_resource(&ioport_resource, mca_standard_resources + i); @@ -514,8 +522,7 @@ if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0; if(reg < 0 || reg >= 8) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&mca_lock, flags); /* Make sure motherboard setup is off */ @@ -566,7 +573,7 @@ mca_info->slot[slot].pos[reg] = byte; - restore_flags(flags); + spin_unlock_irqrestore(&mca_lock, flags); return byte; } /* mca_read_pos() */ @@ -610,8 +617,7 @@ if(mca_info == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&mca_lock, flags); /* Make sure motherboard setup is off */ @@ -623,7 +629,7 @@ outb_p(byte, MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); - restore_flags(flags); + spin_unlock_irqrestore(&mca_lock, flags); /* Update the global register list, while we have the byte */ --- linux/arch/i386/kernel/process.c.orig Sun Jul 21 20:37:04 2002 +++ linux/arch/i386/kernel/process.c Sun Jul 21 21:08:53 2002 @@ -290,7 +290,7 @@ { unsigned long flags; - cli(); + __cli(); /* Write zero to CMOS register number 0x0f, which the BIOS POST routine will recognize as telling it to do a proper reboot. (Well --- linux/arch/i386/kernel/vm86.c.orig Sun Jun 9 07:27:22 2002 +++ linux/arch/i386/kernel/vm86.c Sun Jul 21 22:55:57 2002 @@ -571,6 +571,8 @@ struct task_struct *tsk; int sig; } vm86_irqs[16]; + +static spinlock_t irqbits_lock = SPIN_LOCK_UNLOCKED; static int irqbits; #define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \ @@ -580,9 +582,8 @@ static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) { int irq_bit; unsigned long flags; - - save_flags(flags); - cli(); + + spin_lock_irqsave(&irqbits_lock, flags); irq_bit = 1 << intno; if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) goto out; @@ -591,14 +592,19 @@ send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); /* else user will poll for IRQs */ out: - restore_flags(flags); + spin_unlock_irqrestore(&irqbits_lock, flags); } static inline void free_vm86_irq(int irqnumber) { + unsigned long flags; + free_irq(irqnumber,0); vm86_irqs[irqnumber].tsk = 0; + + spin_lock_irqsave(&irqbits_lock, flags); irqbits &= ~(1 << irqnumber); + spin_unlock_irqrestore(&irqbits_lock, flags); } static inline int task_valid(struct task_struct *tsk) @@ -635,11 +641,10 @@ if ( (irqnumber<3) || (irqnumber>15) ) return 0; if (vm86_irqs[irqnumber].tsk != current) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&irqbits_lock, flags); bit = irqbits & (1 << irqnumber); irqbits &= ~bit; - restore_flags(flags); + spin_unlock_irqrestore(&irqbits_lock, flags); return bit; } --- linux/arch/i386/mm/fault.c.orig Sun Jul 21 20:37:09 2002 +++ linux/arch/i386/mm/fault.c Sun Jul 21 20:38:03 2002 @@ -107,27 +107,25 @@ */ void bust_spinlocks(int yes) { + int loglevel_save = console_loglevel; + spin_lock_init(&timerlist_lock); if (yes) { oops_in_progress = 1; -#ifdef CONFIG_SMP - global_irq_lock = 0; /* Many serial drivers do __global_cli() */ -#endif - } else { - int loglevel_save = console_loglevel; + return; + } #ifdef CONFIG_VT - unblank_screen(); + unblank_screen(); #endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; - } + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); --- linux/include/linux/smp_lock.h.orig Sun Jun 9 07:28:14 2002 +++ linux/include/linux/smp_lock.h Sun Jul 21 20:38:03 2002 @@ -7,7 +7,7 @@ #define lock_kernel() do { } while(0) #define unlock_kernel() do { } while(0) -#define release_kernel_lock(task, cpu) do { } while(0) +#define release_kernel_lock(task) do { } while(0) #define reacquire_kernel_lock(task) do { } while(0) #define kernel_locked() 1 --- linux/include/linux/spinlock.h.orig Sun Jul 21 20:37:06 2002 +++ linux/include/linux/spinlock.h Sun Jul 21 20:38:03 2002 @@ -2,6 +2,7 @@ #define __LINUX_SPINLOCK_H #include +#include #include #include #include @@ -120,36 +121,6 @@ #ifdef CONFIG_PREEMPT -asmlinkage void preempt_schedule(void); - -#define preempt_get_count() (current_thread_info()->preempt_count) - -#define preempt_disable() \ -do { \ - ++current_thread_info()->preempt_count; \ - barrier(); \ -} while (0) - -#define preempt_enable_no_resched() \ -do { \ - --current_thread_info()->preempt_count; \ - barrier(); \ -} while (0) - -#define preempt_enable() \ -do { \ - --current_thread_info()->preempt_count; \ - barrier(); \ - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ - preempt_schedule(); \ -} while (0) - -#define preempt_check_resched() \ -do { \ - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ - preempt_schedule(); \ -} while (0) - #define spin_lock(lock) \ do { \ preempt_disable(); \ @@ -178,12 +149,6 @@ 1 : ({preempt_enable(); 0;});}) #else - -#define preempt_get_count() (0) -#define preempt_disable() do { } while (0) -#define preempt_enable_no_resched() do {} while(0) -#define preempt_enable() do { } while (0) -#define preempt_check_resched() do { } while (0) #define spin_lock(lock) _raw_spin_lock(lock) #define spin_trylock(lock) _raw_spin_trylock(lock) --- linux/include/linux/irq_cpustat.h.orig Sun Jun 9 07:29:10 2002 +++ linux/include/linux/irq_cpustat.h Sun Jul 21 20:38:03 2002 @@ -29,8 +29,6 @@ /* arch independent irq_stat fields */ #define softirq_pending(cpu) __IRQ_STAT((cpu), __softirq_pending) -#define local_irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) -#define local_bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) #define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) #define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) /* arch dependent irq_stat fields */ --- linux/include/linux/preempt.h.orig Sun Jul 21 20:38:03 2002 +++ linux/include/linux/preempt.h Sun Jul 21 20:38:03 2002 @@ -0,0 +1,46 @@ +#ifndef __LINUX_PREEMPT_H +#define __LINUX_PREEMPT_H + +#include + +#define preempt_count() (current_thread_info()->preempt_count) + +#ifdef CONFIG_PREEMPT + +extern void preempt_schedule(void); + +#define preempt_disable() \ +do { \ + preempt_count()++; \ + barrier(); \ +} while (0) + +#define preempt_enable_no_resched() \ +do { \ + preempt_count()--; \ + barrier(); \ +} while (0) + +#define preempt_enable() \ +do { \ + preempt_enable_no_resched(); \ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ + preempt_schedule(); \ +} while (0) + +#define preempt_check_resched() \ +do { \ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ + preempt_schedule(); \ +} while (0) + +#else + +#define preempt_disable() do { } while (0) +#define preempt_enable_no_resched() do {} while(0) +#define preempt_enable() do { } while (0) +#define preempt_check_resched() do { } while (0) + +#endif + +#endif /* __LINUX_PREEMPT_H */ --- linux/include/asm-generic/smplock.h.orig Sun Jun 9 07:26:53 2002 +++ linux/include/asm-generic/smplock.h Sun Jul 21 20:38:03 2002 @@ -13,11 +13,10 @@ /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ +#define release_kernel_lock(task) \ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ - release_irqlock(cpu); \ __sti(); \ } while (0) --- linux/include/asm-i386/system.h.orig Sun Jul 21 20:37:27 2002 +++ linux/include/asm-i386/system.h Sun Jul 21 20:43:14 2002 @@ -319,24 +319,14 @@ #define local_irq_disable() __cli() #define local_irq_enable() __sti() -#ifdef CONFIG_SMP - -extern void __global_cli(void); -extern void __global_sti(void); -extern unsigned long __global_save_flags(void); -extern void __global_restore_flags(unsigned long); -#define cli() __global_cli() -#define sti() __global_sti() -#define save_flags(x) ((x)=__global_save_flags()) -#define restore_flags(x) __global_restore_flags(x) - -#else - -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) - +/* + * Compatibility macros - they will be removed after some time. + */ +#if !CONFIG_SMP +# define sti() __sti() +# define cli() __cli() +# define save_flags(flags) __save_flags(flags) +# define restore_flags(flags) __restore_flags(flags) #endif /* --- linux/include/asm-i386/hardirq.h.orig Sun Jul 21 20:37:07 2002 +++ linux/include/asm-i386/hardirq.h Sun Jul 21 21:09:54 2002 @@ -8,8 +8,6 @@ /* assembly code in softirq.h is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; - unsigned int __local_irq_count; - unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ unsigned long idle_timestamp; @@ -18,77 +16,27 @@ #include /* Standard mappings for irq_cpustat_t above */ +#define IRQ_OFFSET 64 + /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? */ -#define in_interrupt() ({ int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); }) - -#define in_irq() (local_irq_count(smp_processor_id()) != 0) - -#ifndef CONFIG_SMP - -#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -#define hardirq_endlock(cpu) do { } while (0) +#define in_interrupt() \ + ((preempt_count() & ~PREEMPT_ACTIVE) >= IRQ_OFFSET) -#define irq_enter(cpu, irq) (local_irq_count(cpu)++) -#define irq_exit(cpu, irq) (local_irq_count(cpu)--) +#define in_irq in_interrupt -#define synchronize_irq() barrier() +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) -#define release_irqlock(cpu) do { } while (0) +#define irq_enter() (preempt_count() += IRQ_OFFSET) +#define irq_exit() (preempt_count() -= IRQ_OFFSET) +#ifndef CONFIG_SMP +# define synchronize_irq(irq) barrier() #else - -#include -#include - -extern unsigned char global_irq_holder; -extern unsigned volatile long global_irq_lock; /* long for set_bit -RR */ - -static inline int irqs_running (void) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) - if (local_irq_count(i)) - return 1; - return 0; -} - -static inline void release_irqlock(int cpu) -{ - /* if we didn't own the irq lock, just ignore.. */ - if (global_irq_holder == (unsigned char) cpu) { - global_irq_holder = NO_PROC_ID; - clear_bit(0,&global_irq_lock); - } -} - -static inline void irq_enter(int cpu, int irq) -{ - ++local_irq_count(cpu); - - while (test_bit(0,&global_irq_lock)) { - cpu_relax(); - } -} - -static inline void irq_exit(int cpu, int irq) -{ - --local_irq_count(cpu); -} - -static inline int hardirq_trylock(int cpu) -{ - return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock); -} - -#define hardirq_endlock(cpu) do { } while (0) - -extern void synchronize_irq(void); - + extern void synchronize_irq(unsigned int irq); #endif /* CONFIG_SMP */ #endif /* __ASM_HARDIRQ_H */ --- linux/include/asm-i386/softirq.h.orig Sun Jun 9 07:29:29 2002 +++ linux/include/asm-i386/softirq.h Sun Jul 21 20:38:03 2002 @@ -1,50 +1,27 @@ #ifndef __ASM_SOFTIRQ_H #define __ASM_SOFTIRQ_H -#include +#include #include -#define __cpu_bh_enable(cpu) \ - do { barrier(); local_bh_count(cpu)--; preempt_enable(); } while (0) -#define cpu_bh_disable(cpu) \ - do { preempt_disable(); local_bh_count(cpu)++; barrier(); } while (0) +#define local_bh_disable() \ + do { preempt_count() += IRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= IRQ_OFFSET; } while (0) -#define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) - -#define in_softirq() (local_bh_count(smp_processor_id()) != 0) - -/* - * NOTE: this assembly code assumes: - * - * (char *)&local_bh_count - 8 == (char *)&softirq_pending - * - * If you change the offsets in irq_stat then you have to - * update this code as well. - */ -#define _local_bh_enable() \ +#define local_bh_enable() \ do { \ - unsigned int *ptr = &local_bh_count(smp_processor_id()); \ - \ - barrier(); \ - if (!--*ptr) \ - __asm__ __volatile__ ( \ - "cmpl $0, -8(%0);" \ - "jnz 2f;" \ - "1:;" \ - \ - LOCK_SECTION_START("") \ - "2: pushl %%eax; pushl %%ecx; pushl %%edx;" \ - "call %c1;" \ - "popl %%edx; popl %%ecx; popl %%eax;" \ - "jmp 1b;" \ - LOCK_SECTION_END \ - \ - : /* no output */ \ - : "r" (ptr), "i" (do_softirq) \ - /* no registers clobbered */ ); \ + if (unlikely((preempt_count() == IRQ_OFFSET) && \ + softirq_pending(smp_processor_id()))) { \ + __local_bh_enable(); \ + do_softirq(); \ + preempt_check_resched(); \ + } else { \ + __local_bh_enable(); \ + preempt_check_resched(); \ + } \ } while (0) -#define local_bh_enable() do { _local_bh_enable(); preempt_enable(); } while (0) +#define in_softirq() in_interrupt() #endif /* __ASM_SOFTIRQ_H */ --- linux/include/asm-i386/smplock.h.orig Sun Jun 9 07:28:43 2002 +++ linux/include/asm-i386/smplock.h Sun Jul 21 20:38:03 2002 @@ -12,15 +12,9 @@ #ifdef CONFIG_SMP #define kernel_locked() spin_is_locked(&kernel_flag) -#define check_irq_holder(cpu) \ -do { \ - if (global_irq_holder == (cpu)) \ - BUG(); \ -} while(0) #else #ifdef CONFIG_PREEMPT -#define kernel_locked() preempt_get_count() -#define check_irq_holder(cpu) do { } while(0) +#define kernel_locked() preempt_count() #else #define kernel_locked() 1 #endif @@ -29,12 +23,10 @@ /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ +#define release_kernel_lock(task) \ do { \ - if (unlikely(task->lock_depth >= 0)) { \ + if (unlikely(task->lock_depth >= 0)) \ spin_unlock(&kernel_flag); \ - check_irq_holder(cpu); \ - } \ } while (0) /* --- linux/net/core/skbuff.c.orig Sun Jul 21 20:37:07 2002 +++ linux/net/core/skbuff.c Sun Jul 21 20:38:03 2002 @@ -318,7 +318,7 @@ dst_release(skb->dst); if(skb->destructor) { - if (in_irq()) + if (0 && in_irq()) printk(KERN_WARNING "Warning: kfree_skb on " "hard IRQ %p\n", NET_CALLER(skb)); skb->destructor(skb); --- linux/kernel/exit.c.orig Sun Jul 21 20:37:13 2002 +++ linux/kernel/exit.c Sun Jul 21 20:38:03 2002 @@ -530,10 +530,10 @@ tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); - if (unlikely(preempt_get_count())) + if (unlikely(preempt_count())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, - preempt_get_count()); + preempt_count()); fake_volatile: acct_process(code); --- linux/kernel/sched.c.orig Sun Jul 21 20:37:27 2002 +++ linux/kernel/sched.c Sun Jul 21 21:20:57 2002 @@ -747,6 +747,7 @@ out_unlock: spin_unlock(&busiest->lock); out: + ; } /* @@ -797,7 +798,8 @@ task_t *p = current; if (p == rq->idle) { - if (local_bh_count(cpu) || local_irq_count(cpu) > 1) + /* note: this timer irq context must be accounted for as well */ + if (preempt_count() >= 2*IRQ_OFFSET) kstat.per_cpu_system[cpu] += sys_ticks; #if CONFIG_SMP idle_tick(rq); @@ -888,7 +890,7 @@ prev = current; rq = this_rq(); - release_kernel_lock(prev, smp_processor_id()); + release_kernel_lock(prev); prev->sleep_timestamp = jiffies; spin_lock_irq(&rq->lock); @@ -896,7 +898,7 @@ * if entering off of a kernel preemption go straight * to picking the next task. */ - if (unlikely(preempt_get_count() & PREEMPT_ACTIVE)) + if (unlikely(preempt_count() & PREEMPT_ACTIVE)) goto pick_next_task; switch (prev->state) { @@ -1710,7 +1712,9 @@ __restore_flags(flags); /* Set the preempt count _outside_ the spinlocks! */ +#if CONFIG_PREEMPT idle->thread_info->preempt_count = (idle->lock_depth >= 0); +#endif } #if CONFIG_SMP --- linux/kernel/softirq.c.orig Sun Jul 21 20:37:11 2002 +++ linux/kernel/softirq.c Sun Jul 21 20:44:28 2002 @@ -61,17 +61,17 @@ asmlinkage void do_softirq() { - int cpu; __u32 pending; long flags; __u32 mask; + int cpu; if (in_interrupt()) return; local_irq_save(flags); - cpu = smp_processor_id(); + pending = softirq_pending(cpu); if (pending) { @@ -111,7 +111,7 @@ } /* - * This function must run with irq disabled! + * This function must run with irqs disabled! */ inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) { @@ -126,7 +126,7 @@ * Otherwise we wake up ksoftirqd to make sure we * schedule the softirq soon. */ - if (!(local_irq_count(cpu) | local_bh_count(cpu))) + if (!in_interrupt()) wakeup_softirqd(cpu); } @@ -290,22 +290,16 @@ static void bh_action(unsigned long nr) { - int cpu = smp_processor_id(); - if (!spin_trylock(&global_bh_lock)) goto resched; - if (!hardirq_trylock(cpu)) - goto resched_unlock; - if (bh_base[nr]) bh_base[nr](); - hardirq_endlock(cpu); + hardirq_endlock(); spin_unlock(&global_bh_lock); return; -resched_unlock: spin_unlock(&global_bh_lock); resched: mark_bh(nr); --- linux/kernel/panic.c.orig Sun Jul 21 20:37:11 2002 +++ linux/kernel/panic.c Sun Jul 21 20:38:03 2002 @@ -94,7 +94,7 @@ #if defined(CONFIG_ARCH_S390) disabled_wait(caller); #endif - sti(); + __sti(); for(;;) { CHECK_EMERGENCY_SYNC } --- linux/init/main.c.orig Sun Jul 21 20:37:13 2002 +++ linux/init/main.c Sun Jul 21 20:38:03 2002 @@ -373,7 +373,7 @@ } kmem_cache_init(); - sti(); + __sti(); calibrate_delay(); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok &&