diff options
Diffstat (limited to 'arch')
111 files changed, 1426 insertions, 1401 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index fa9e06371..309a308a4 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -13,10 +13,21 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< O_TARGET := kernel.o -O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - ptrace.o time.o semaphore.o i8259.o +O_OBJS := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \ + signal.o setup.o ptrace.o time.o semaphore.o OX_OBJS := alpha_ksyms.o +L_TARGET := rest.a +L_OBJS := irq_i8259.o irq_srm.o \ + es1888.o smc37c669.o smc37c93x.o ns87312.o + +ifdef CONFIG_SMP +O_OBJS += smp.o irq_smp.o +endif + +ifdef CONFIG_PCI +L_OBJS += pci.o pci_iommu.o +endif ifdef CONFIG_ALPHA_GENERIC @@ -25,13 +36,9 @@ O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ - sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \ - es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o pci_iommu.o -else + sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o -ifdef CONFIG_PCI -O_OBJS += pci.o pci_iommu.o -endif +else # Core logic support ifdef CONFIG_ALPHA_APECS @@ -67,10 +74,10 @@ ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) O_OBJS += sys_alcor.o endif ifneq ($(CONFIG_ALPHA_CABRIOLET)$(CONFIG_ALPHA_EB164)$(CONFIG_ALPHA_EB66P)$(CONFIG_ALPHA_LX164)$(CONFIG_ALPHA_PC164),) -O_OBJS += sys_cabriolet.o ns87312.o +O_OBJS += sys_cabriolet.o endif ifdef CONFIG_ALPHA_DP264 -O_OBJS += sys_dp264.o es1888.o smc37c669.o +O_OBJS += sys_dp264.o endif ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) O_OBJS += sys_eb64p.o @@ -82,7 +89,7 @@ ifdef CONFIG_ALPHA_JENSEN O_OBJS += sys_jensen.o endif ifdef CONFIG_ALPHA_MIATA -O_OBJS += sys_miata.o es1888.o smc37c669.o +O_OBJS += sys_miata.o endif ifdef CONFIG_ALPHA_MIKASA O_OBJS += sys_mikasa.o @@ -106,25 +113,18 @@ ifdef CONFIG_ALPHA_SABLE O_OBJS += sys_sable.o endif ifneq ($(CONFIG_ALPHA_BOOK1)$(CONFIG_ALPHA_AVANTI)$(CONFIG_ALPHA_NONAME)$(CONFIG_ALPHA_P2K)$(CONFIG_ALPHA_XL),) -O_OBJS += sys_sio.o ns87312.o +O_OBJS += sys_sio.o endif ifdef CONFIG_ALPHA_SX164 -O_OBJS += sys_sx164.o smc37c669.o +O_OBJS += sys_sx164.o endif ifdef CONFIG_ALPHA_TAKARA -O_OBJS += sys_takara.o ns87312.o -endif - -# Device support -ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),) -O_OBJS += smc37c93x.o +O_OBJS += sys_takara.o endif endif # GENERIC -ifdef CONFIG_SMP -O_OBJS += smp.o -endif +O_OBJS += $(L_TARGET) all: kernel.o head.o diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c index 9ea4f53e9..51e5b1174 100644 --- a/arch/alpha/kernel/core_apecs.c +++ b/arch/alpha/kernel/core_apecs.c @@ -385,7 +385,7 @@ apecs_init_arch(void) * Window 1 is direct access 1GB at 1GB * Window 2 is scatter-gather 8MB at 8MB (for isa) */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); hose->sg_pci = NULL; __direct_map_base = 0x40000000; __direct_map_size = 0x40000000; diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 36b9a1fa9..b8a7f18ee 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -405,10 +405,12 @@ cia_init_arch(void) * ??? We ought to scale window 1 with memory. */ - /* NetBSD hints that page tables must be aligned to 32K due - to a hardware bug. No description of what models affected. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 32768); - hose->sg_pci = iommu_arena_new(0x40000000, 0x08000000, 32768); + /* ??? NetBSD hints that page tables must be aligned to 32K, + possibly due to a hardware bug. This is over-aligned + from the 8K alignment one would expect for an 8MB window. + No description of what CIA revisions affected. */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x8000); + hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c index 2bee78a1b..8039c0d14 100644 --- a/arch/alpha/kernel/core_lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -307,7 +307,7 @@ lca_init_arch(void) * Window 0 is direct access 1GB at 1GB * Window 1 is scatter-gather 8MB at 8MB (for isa) */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); hose->sg_pci = NULL; __direct_map_base = 0x40000000; __direct_map_size = 0x40000000; diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index ac97ce1fe..7564d83e9 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -404,8 +404,8 @@ mcpcia_startup_hose(struct pci_controler *hose) * ??? We ought to scale window 1 with memory. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); - hose->sg_pci = iommu_arena_new(0x40000000, 0x08000000, PAGE_SIZE); + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; diff --git a/arch/alpha/kernel/core_pyxis.c b/arch/alpha/kernel/core_pyxis.c index 80ee8ba7f..f6106c475 100644 --- a/arch/alpha/kernel/core_pyxis.c +++ b/arch/alpha/kernel/core_pyxis.c @@ -36,7 +36,6 @@ */ #define DEBUG_CONFIG 0 - #if DEBUG_CONFIG # define DBG_CNF(args) printk args #else @@ -304,7 +303,7 @@ pyxis_enable_irq(unsigned int irq) pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); } -static inline void +static void pyxis_disable_irq(unsigned int irq) { pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); @@ -318,6 +317,13 @@ pyxis_startup_irq(unsigned int irq) } static void +pyxis_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + pyxis_enable_irq(irq); +} + +static void pyxis_mask_and_ack_irq(unsigned int irq) { unsigned long bit = 1UL << (irq - 16); @@ -340,7 +346,7 @@ static struct hw_interrupt_type pyxis_irq_type = { enable: pyxis_enable_irq, disable: pyxis_disable_irq, ack: pyxis_mask_and_ack_irq, - end: pyxis_enable_irq, + end: pyxis_end_irq, }; void @@ -382,7 +388,7 @@ init_pyxis_irqs(unsigned long ignore_mask) for (i = 16; i < 48; ++i) { if ((ignore_mask >> i) & 1) continue; - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &pyxis_irq_type; } @@ -427,6 +433,8 @@ pyxis_broken_pci_tbi(struct pci_controler *hose, ctrl = *(vuip)PYXIS_CTRL; *(vuip)PYXIS_CTRL = ctrl | 4; mb(); + *(vuip)PYXIS_CTRL; + mb(); /* Read from PCI dense memory space at TBI_ADDR, skipping 64k on each read. This forces SG TLB misses. It appears that @@ -441,6 +449,8 @@ pyxis_broken_pci_tbi(struct pci_controler *hose, mb(); *(vuip)PYXIS_CTRL = ctrl; mb(); + *(vuip)PYXIS_CTRL; + mb(); __restore_flags(flags); } @@ -473,31 +483,31 @@ pyxis_init_arch(void) struct pci_controler *hose; unsigned int temp; -#if 0 - printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK); - printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR); - printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ); - printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK); - printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE); - printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO); - printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG); - printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT); -#endif - - /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. - */ + /* Set up error reporting. Make sure CPU_PE is OFF in the mask. */ temp = *(vuip)PYXIS_ERR_MASK; - temp &= ~4; - *(vuip)PYXIS_ERR_MASK = temp; - mb(); - *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ + *(vuip)PYXIS_ERR_MASK = temp & ~4; + /* Enable master/target abort. */ temp = *(vuip)PYXIS_ERR; - temp |= 0x180; /* master/target abort */ - *(vuip)PYXIS_ERR = temp; + *(vuip)PYXIS_ERR = temp | 0x180; + + /* Clear the PYXIS_CFG register, which gets used for PCI Config + Space accesses. That is the way we want to use it, and we do + not want to depend on what ARC or SRM might have left behind. */ + *(vuip)PYXIS_CFG = 0; + + /* Zero the HAEs. */ + *(vuip)PYXIS_HAE_MEM = 0; + *(vuip)PYXIS_HAE_IO = 0; + + /* Finally, check that the PYXIS_CTRL1 has IOA_BEN set for + enabling byte/word PCI bus space(s) access. */ + temp = *(vuip)PYXIS_CTRL1; + *(vuip)PYXIS_CTRL1 = temp | 1; + + /* Syncronize with all previous changes. */ mb(); - *(vuip)PYXIS_ERR; /* re-read to force write */ + *(vuip)PYXIS_REV; /* * Create our single hose. @@ -524,10 +534,41 @@ pyxis_init_arch(void) * address range. */ - /* NetBSD hints that page tables must be aligned to 32K due - to a hardware bug. No description of what models affected. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 32768); - hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 32768); +#if 1 + /* ??? There's some bit of syncronization wrt writing new tlb + entries that's missing. Sometimes it works, sometimes invalid + tlb machine checks, sometimes hard lockup. And this just within + the boot sequence. + + I've tried extra memory barriers, extra alignment, pyxis + register reads, tlb flushes, and loopback tlb accesses. + + I guess the pyxis revision in the sx164 is just too buggy... */ + + hose->sg_isa = hose->sg_pci = NULL; + __direct_map_base = 0x40000000; + __direct_map_size = 0x80000000; + + *(vuip)PYXIS_W0_BASE = 0x40000000 | 1; + *(vuip)PYXIS_W0_MASK = (0x40000000 - 1) & 0xfff00000; + *(vuip)PYXIS_T0_BASE = 0; + + *(vuip)PYXIS_W1_BASE = 0x80000000 | 1; + *(vuip)PYXIS_W1_MASK = (0x40000000 - 1) & 0xfff00000; + *(vuip)PYXIS_T1_BASE = 0; + + *(vuip)PYXIS_W2_BASE = 0; + *(vuip)PYXIS_W3_BASE = 0; + + alpha_mv.mv_pci_tbi = NULL; + mb(); +#else + /* ??? NetBSD hints that page tables must be aligned to 32K, + possibly due to a hardware bug. This is over-aligned + from the 8K alignment one would expect for an 8MB window. + No description of what CIA revisions affected. */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x08000); + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0x20000); __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; @@ -553,36 +594,7 @@ pyxis_init_arch(void) pyxis_enable_broken_tbi(hose->sg_pci); alpha_mv.mv_pci_tbi(hose, 0, -1); - - /* - * Next, clear the PYXIS_CFG register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... - */ - temp = *(vuip)PYXIS_CFG; - if (temp != 0) { - *(vuip)PYXIS_CFG = 0; - mb(); - *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - /* Zero the HAE. */ - *(vuip)PYXIS_HAE_MEM = 0U; mb(); - *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ - *(vuip)PYXIS_HAE_IO = 0; mb(); - *(vuip)PYXIS_HAE_IO; /* re-read to force write */ - - /* - * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for - * enabling byte/word PCI bus space(s) access. - */ - temp = *(vuip) PYXIS_CTRL1; - if (!(temp & 1)) { - *(vuip)PYXIS_CTRL1 = temp | 1; - mb(); - *(vuip)PYXIS_CTRL1; /* re-read */ - } +#endif } static inline void diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index 1452b6336..1fa5a8088 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -343,13 +343,9 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) * because of an idiot-syncrasy of the CYPRESS chip. It may * respond to a PCI bus address in the last 1MB of the 4GB * address range. - * - * Note that the TLB lookup logic uses bitwise concatenation, - * not addition, so the required arena alignment is based on - * the size of the window. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 0x00800000>>10); - hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 0x08000000>>10); + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 613a633ba..bc8ca101a 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -17,304 +17,85 @@ #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> +#include <linux/interrupt.h> #include <linux/malloc.h> #include <linux/random.h> #include <linux/init.h> -#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/proc_fs.h> #include <asm/system.h> #include <asm/io.h> -#include <asm/dma.h> #include <asm/bitops.h> -#include <asm/machvec.h> - -#include "proto.h" -#include "irq_impl.h" - -#define vulp volatile unsigned long * -#define vuip volatile unsigned int * - -/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it lives - in the per-cpu structure for cache reasons. */ -#ifndef CONFIG_SMP -int __local_irq_count; -int __local_bh_count; -unsigned long __irq_attempt[NR_IRQS]; -#endif - -#ifdef CONFIG_ALPHA_GENERIC -#define ACTUAL_NR_IRQS alpha_mv.nr_irqs -#else -#define ACTUAL_NR_IRQS NR_IRQS -#endif - -/* Hack minimum IPL during interupt processing for broken hardware. */ - -#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK -int __min_ipl; -#endif +#include <asm/uaccess.h> /* - * Performance counter hook. A module can override this to - * do something useful. + * Controller mappings for all interrupt sources: */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED} +}; -static void -dummy_perf(unsigned long vector, struct pt_regs *regs) -{ - printk(KERN_CRIT "Performance counter interrupt!\n"); -} - -void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf; - -/* - * Dispatch device interrupts. - */ - -/* - * Handle ISA interrupt via the PICs. - */ - -#if defined(CONFIG_ALPHA_GENERIC) -# define IACK_SC alpha_mv.iack_sc -#elif defined(CONFIG_ALPHA_APECS) -# define IACK_SC APECS_IACK_SC -#elif defined(CONFIG_ALPHA_LCA) -# define IACK_SC LCA_IACK_SC -#elif defined(CONFIG_ALPHA_CIA) -# define IACK_SC CIA_IACK_SC -#elif defined(CONFIG_ALPHA_PYXIS) -# define IACK_SC PYXIS_IACK_SC -#elif defined(CONFIG_ALPHA_TSUNAMI) -# define IACK_SC TSUNAMI_IACK_SC -#elif defined(CONFIG_ALPHA_POLARIS) -# define IACK_SC POLARIS_IACK_SC -#elif defined(CONFIG_ALPHA_IRONGATE) -# define IACK_SC IRONGATE_IACK_SC -#endif - -#if defined(IACK_SC) -void -isa_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - /* - * Generate a PCI interrupt acknowledge cycle. The PIC will - * respond with the interrupt vector of the highest priority - * interrupt that is pending. The PALcode sets up the - * interrupts vectors such that irq level L generates vector L. - */ - int j = *(vuip) IACK_SC; - j &= 0xff; - if (j == 7) { - if (!(inb(0x20) & 0x80)) { - /* It's only a passive release... */ - return; - } - } - handle_irq(j, regs); -} -#endif -#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC) -void -isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pic; - - /* - * It seems to me that the probability of two or more *device* - * interrupts occurring at almost exactly the same time is - * pretty low. So why pay the price of checking for - * additional interrupts here if the common case can be - * handled so much easier? - */ - /* - * The first read of gives you *all* interrupting lines. - * Therefore, read the mask register and and out those lines - * not enabled. Note that some documentation has 21 and a1 - * write only. This is not true. - */ - pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= 0xFFFB; /* mask out cascade & hibits */ +static void register_irq_proc(unsigned int irq); - while (pic) { - int j = ffz(~pic); - pic &= pic - 1; - handle_irq(j, regs); - } -} -#endif +unsigned long irq_err_count; /* - * Handle interrupts from the SRM, assuming no additional weirdness. + * Special irq handlers. */ -static inline void -srm_enable_irq(unsigned int irq) -{ - cserve_ena(irq - 16); -} - -static void -srm_disable_irq(unsigned int irq) -{ - cserve_dis(irq - 16); -} - -static unsigned int -srm_startup_irq(unsigned int irq) -{ - srm_enable_irq(irq); - return 0; -} - -static struct hw_interrupt_type srm_irq_type = { - typename: "SRM", - startup: srm_startup_irq, - shutdown: srm_disable_irq, - enable: srm_enable_irq, - disable: srm_disable_irq, - ack: srm_disable_irq, - end: srm_enable_irq, -}; - -void -srm_device_interrupt(unsigned long vector, struct pt_regs * regs) -{ - int irq = (vector - 0x800) >> 4; - handle_irq(irq, regs); -} - -void __init -init_srm_irqs(long max, unsigned long ignore_mask) -{ - long i; - - for (i = 16; i < max; ++i) { - if (i < 64 && ((ignore_mask >> i) & 1)) - continue; - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].handler = &srm_irq_type; - } -} +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } /* - * The not-handled irq handler. + * Generic no controller code */ -static void -noirq_enable_disable(unsigned int irq) -{ -} - -static unsigned int -noirq_startup(unsigned int irq) -{ - return 0; -} +static void no_irq_enable_disable(unsigned int irq) { } +static unsigned int no_irq_startup(unsigned int irq) { return 0; } static void -noirq_ack(unsigned int irq) +no_irq_ack(unsigned int irq) { - printk(KERN_CRIT "Unexpected IRQ %u\n", irq); + irq_err_count++; + printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq); } -static struct hw_interrupt_type no_irq_type = { +struct hw_interrupt_type no_irq_type = { typename: "none", - startup: noirq_startup, - shutdown: noirq_enable_disable, - enable: noirq_enable_disable, - disable: noirq_enable_disable, - ack: noirq_ack, - end: noirq_enable_disable, -}; - -/* - * The special RTC interrupt type. The interrupt itself was - * processed by PALcode, and comes in via entInt vector 1. - */ - -static struct hw_interrupt_type rtc_irq_type = { - typename: "RTC", - startup: noirq_startup, - shutdown: noirq_enable_disable, - enable: noirq_enable_disable, - disable: noirq_enable_disable, - ack: noirq_enable_disable, - end: noirq_enable_disable, -}; - -void __init -init_rtc_irq(void) -{ - irq_desc[RTC_IRQ].status = IRQ_DISABLED; - irq_desc[RTC_IRQ].handler = &rtc_irq_type; -} - -/* - * Special irq handlers. - */ - -void -no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} - -/* - * Common irq handlers. - */ - -struct irqaction isa_cascade_irqaction = { - handler: no_action, - name: "isa-cascade" -}; - -struct irqaction timer_cascade_irqaction = { - handler: no_action, - name: "timer-cascade" -}; - -struct irqaction halt_switch_irqaction = { - handler: no_action, - name: "halt-switch" -}; - - -spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { - [0 ... NR_IRQS-1] = { 0, &no_irq_type, } + startup: no_irq_startup, + shutdown: no_irq_enable_disable, + enable: no_irq_enable_disable, + disable: no_irq_enable_disable, + ack: no_irq_ack, + end: no_irq_enable_disable, }; int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { - int status, cpu = smp_processor_id(); - int old_ipl, ipl; + int status; + int cpu = smp_processor_id(); kstat.irqs[cpu][irq]++; irq_enter(cpu, irq); status = 1; /* Force the "do bottom halves" bit */ - old_ipl = ipl = getipl(); do { - int new_ipl = IPL_MIN; - if (action->flags & SA_INTERRUPT) - new_ipl = IPL_MAX; - if (new_ipl != ipl) { - setipl(new_ipl); - ipl = new_ipl; - } + if (!(action->flags & SA_INTERRUPT)) + __sti(); + else + __cli(); status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - if (ipl != old_ipl) - setipl(old_ipl); - if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); + __cli(); + irq_exit(cpu, irq); return status; @@ -326,17 +107,18 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs, * hardware disable after having gotten the irq * controller lock. */ -void +void inline disable_irq_nosync(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - if (!irq_desc[irq].depth++) { - irq_desc[irq].status |= IRQ_DISABLED | IRQ_MASKED; - irq_desc[irq].handler->disable(irq); + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } /* @@ -358,32 +140,29 @@ disable_irq(unsigned int irq) void enable_irq(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - switch (irq_desc[irq].depth) { - case 1: - { - unsigned int status = irq_desc[irq].status; - - status &= ~(IRQ_DISABLED | IRQ_MASKED); + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - status |= IRQ_REPLAY; - /* ??? We can't re-send on (most?) alpha hw. - hw_resend_irq(irq_desc[irq].handler,irq); */ + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); } - irq_desc[irq].status = status; - irq_desc[irq].handler->enable(irq); + desc->handler->enable(irq); /* fall-through */ - } + } default: - irq_desc[irq].depth--; + desc->depth--; break; case 0: printk(KERN_ERR "enable_irq() unbalanced from %p\n", __builtin_return_address(0)); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } int @@ -392,6 +171,7 @@ setup_irq(unsigned int irq, struct irqaction * new) int shared = 0; struct irqaction *old, **p; unsigned long flags; + irq_desc_t *desc = irq_desc + irq; /* * Some drivers like serial.c use request_irq() heavily, @@ -413,12 +193,12 @@ setup_irq(unsigned int irq, struct irqaction * new) /* * The following block of code has to be executed atomically */ - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return -EBUSY; } @@ -433,14 +213,181 @@ setup_irq(unsigned int irq, struct irqaction * new) *p = new; if (!shared) { - irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_MASKED); - irq_desc[irq].handler->startup(irq); + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); return 0; } +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; + +#define HEX_DIGITS 16 + +static int +irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%016lx\n", irq_affinity[(long)data]); +} + +static unsigned int +parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int +irq_affinity_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (long) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_present_mask)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int +prof_cpu_mask_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int +prof_cpu_mask_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void +register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = ~0UL; + +void +init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == &no_irq_type) + continue; + register_irq_proc(i); + } +} + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -488,6 +435,7 @@ request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), void free_irq(unsigned int irq, void *dev_id) { + irq_desc_t *desc; struct irqaction **p; unsigned long flags; @@ -496,8 +444,9 @@ free_irq(unsigned int irq, void *dev_id) return; } - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; for (;;) { struct irqaction * action = *p; if (action) { @@ -508,26 +457,29 @@ free_irq(unsigned int irq, void *dev_id) /* Found - now remove it from the list of entries. */ *pp = action->next; - if (!irq_desc[irq].action) { - irq_desc[irq].status |= IRQ_DISABLED|IRQ_MASKED; - irq_desc[irq].handler->shutdown(irq); + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); +#ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU. */ - while (irq_desc[irq].status & IRQ_INPROGRESS) + while (desc->status & IRQ_INPROGRESS) barrier(); +#endif kfree(action); return; } printk(KERN_ERR "Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return; } } -int get_irq_list(char *buf) +int +get_irq_list(char *buf) { int i, j; struct irqaction * action; @@ -576,246 +528,10 @@ int get_irq_list(char *buf) cpu_data[cpu_logical_map(j)].smp_local_irq_count); p += sprintf(p, "\n"); #endif + p += sprintf(p, "ERR: %10lu\n", irq_err_count); return p - buf; } -#ifdef CONFIG_SMP -/* Who has global_irq_lock. */ -int global_irq_holder = NO_PROC_ID; - -/* This protects IRQ's. */ -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; - -/* Global IRQ locking depth. */ -atomic_t global_irq_count = ATOMIC_INIT(0); - -static void *previous_irqholder = NULL; - -#define MAXCOUNT 100000000 - -static void show(char * str, void *where); - -static inline void -wait_on_irq(int cpu, void *where) -{ - int count = MAXCOUNT; - - for (;;) { - - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!atomic_read(&global_irq_count)) { - if (local_bh_count(cpu) - || !spin_is_locked(&global_bh_lock)) - break; - } - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - spin_unlock(&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq", where); - count = MAXCOUNT; - } - __sti(); - udelay(1); /* make sure to run pending irqs */ - __cli(); - - if (atomic_read(&global_irq_count)) - continue; - if (spin_is_locked(&global_irq_lock)) - continue; - if (!local_bh_count(cpu) - && spin_is_locked(&global_bh_lock)) - continue; - if (spin_trylock(&global_irq_lock)) - break; - } - } -} - -static inline void -get_irqlock(int cpu, void* where) -{ - if (!spin_trylock(&global_irq_lock)) { - /* Do we already hold the lock? */ - if (cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait. */ - spin_lock(&global_irq_lock); - } - - /* - * Ok, we got the lock bit. - * But that's actually just the easy part.. Now - * we need to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu, where); - - /* - * Finally. - */ -#if DEBUG_SPINLOCK - global_irq_lock.task = current; - global_irq_lock.previous = where; -#endif - global_irq_holder = cpu; - previous_irqholder = where; -} - -void -__global_cli(void) -{ - int cpu = smp_processor_id(); - void *where = __builtin_return_address(0); - - /* - * Maximize ipl. If ipl was previously 0 and if this thread - * is not in an irq, then take global_irq_lock. - */ - if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu)) - get_irqlock(cpu, where); -} - -void -__global_sti(void) -{ - int cpu = smp_processor_id(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); - __sti(); -} - -/* - * 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 & 7)); - /* 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(KERN_ERR "global_restore_flags: %08lx (%p)\n", - flags, __builtin_return_address(0)); - } -} - -static void -show(char * str, void *where) -{ -#if 0 - int i; - unsigned long *stack; -#endif - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d: %p\n", str, cpu, where); - printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), - cpu_data[0].irq_count, - cpu_data[1].irq_count); - - printk("bh: %d [%d %d]\n", - spin_is_locked(&global_bh_lock) ? 1 : 0, - cpu_data[0].bh_count, - cpu_data[1].bh_count); -#if 0 - stack = (unsigned long *) &str; - for (i = 40; i ; i--) { - unsigned long x = *++stack; - if (x > (unsigned long) &init_task_union && - x < (unsigned long) &vsprintf) { - printk("<[%08lx]> ", x); - } - } -#endif -} - -/* - * From its use, I infer that synchronize_irq() stalls a thread until - * the effects of a command to an external device are known to have - * taken hold. Typically, the command is to stop sending interrupts. - * The strategy here is wait until there is at most one processor - * (this one) in an irq. The memory barrier serializes the write to - * the device and the subsequent accesses of global_irq_count. - * --jmartin - */ -#define DEBUG_SYNCHRONIZE_IRQ 0 - -void -synchronize_irq(void) -{ -#if 0 - /* Joe's version. */ - int cpu = smp_processor_id(); - int local_count; - int global_count; - int countdown = 1<<24; - void *where = __builtin_return_address(0); - - mb(); - do { - local_count = local_irq_count(cpu); - global_count = atomic_read(&global_irq_count); - if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) { - printk("%d:%d/%d\n", cpu, local_count, global_count); - show("synchronize_irq", where); - break; - } - } while (global_count != local_count); -#else - /* Jay's version. */ - if (atomic_read(&global_irq_count)) { - cli(); - sti(); - } -#endif -} -#endif /* CONFIG_SMP */ /* * do_IRQ handles all normal device IRQ's (the special @@ -836,39 +552,26 @@ handle_irq(int irq, struct pt_regs * regs) * handled by some other CPU. (or is disabled) */ int cpu = smp_processor_id(); - irq_desc_t *desc; + irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; if ((unsigned) irq > ACTUAL_NR_IRQS) { + irq_err_count++; printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n", irq); return; } irq_attempt(cpu, irq)++; - desc = irq_desc + irq; - spin_lock_irq(&irq_controller_lock); /* mask also the RTC */ + spin_lock_irq(&desc->lock); /* mask also the higher prio events */ desc->handler->ack(irq); - status = desc->status; - -#ifndef CONFIG_SMP - /* Look for broken irq masking. */ - if (status & IRQ_MASKED) { - static unsigned long last_printed; - if (time_after(jiffies, last_printed+HZ)) { - printk(KERN_CRIT "Mask didn't work for irq %d!\n", irq); - last_printed = jiffies; - } - } -#endif - /* * REPLAY is when Linux resends an IRQ that was dropped earlier. * WAITING is used by probe to mark irqs that are being tested. */ - status &= ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING | IRQ_MASKED; /* we _want_ to handle it */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ /* * If the IRQ is disabled for whatever reason, we cannot @@ -881,7 +584,6 @@ handle_irq(int irq, struct pt_regs * regs) status |= IRQ_INPROGRESS; /* we are handling it */ } desc->status = status; - spin_unlock(&irq_controller_lock); /* * If there is no IRQ handler or it was disabled, exit early. @@ -890,7 +592,7 @@ handle_irq(int irq, struct pt_regs * regs) * will take care of it. */ if (!action) - return; + goto out; /* * Edge triggered interrupts need to remember pending events. @@ -902,22 +604,23 @@ handle_irq(int irq, struct pt_regs * regs) * SMP environment. */ for (;;) { + spin_unlock(&desc->lock); handle_IRQ_event(irq, regs, action); - spin_lock(&irq_controller_lock); + spin_lock(&desc->lock); if (!(desc->status & IRQ_PENDING) || (desc->status & IRQ_LEVEL)) break; desc->status &= ~IRQ_PENDING; - spin_unlock(&irq_controller_lock); - } - status = desc->status & ~IRQ_INPROGRESS; - if (!(status & IRQ_DISABLED)) { - status &= ~IRQ_MASKED; - desc->handler->end(irq); } - desc->status = status; - spin_unlock(&irq_controller_lock); + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); } /* @@ -932,17 +635,20 @@ unsigned long probe_irq_on(void) { int i; + irq_desc_t *desc; unsigned long delay; unsigned long val; /* Something may have generated an irq long ago and we want to flush such a longstanding irq before considering it as spurious. */ - spin_lock_irq(&irq_controller_lock); - for (i = NR_IRQS-1; i >= 0; i--) + for (i = NR_IRQS-1; i >= 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); if (!irq_desc[i].action) - if(irq_desc[i].handler->startup(i)) - irq_desc[i].status |= IRQ_PENDING; - spin_unlock_irq(&irq_controller_lock); + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } /* Wait for longstanding interrupts to trigger. */ for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) @@ -951,15 +657,17 @@ probe_irq_on(void) /* enable any unassigned irqs (we must startup again here because if a longstanding irq happened in the previous stage, it may have masked itself) first, enable any unassigned irqs. */ - spin_lock_irq(&irq_controller_lock); for (i = NR_IRQS-1; i >= 0; i--) { - if (!irq_desc[i].action) { - irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; - if(irq_desc[i].handler->startup(i)) - irq_desc[i].status |= IRQ_PENDING; + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); /* * Wait for spurious interrupts to trigger @@ -971,24 +679,24 @@ probe_irq_on(void) * Now filter out any obviously spurious interrupts */ val = 0; - spin_lock_irq(&irq_controller_lock); for (i=0; i<NR_IRQS; i++) { - unsigned int status = irq_desc[i].status; - - if (!(status & IRQ_AUTODETECT)) - continue; - - /* It triggered already - consider it spurious. */ - if (!(status & IRQ_WAITING)) { - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); - continue; + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; } - - if (i < 64) - val |= 1 << i; + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return val; } @@ -997,26 +705,29 @@ probe_irq_on(void) * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). */ -unsigned int probe_irq_mask(unsigned long val) +unsigned int +probe_irq_mask(unsigned long val) { int i; unsigned int mask; mask = 0; - spin_lock_irq(&irq_controller_lock); for (i = 0; i < 16; i++) { - unsigned int status = irq_desc[i].status; + irq_desc_t *desc = irq_desc + i; + unsigned int status; - if (!(status & IRQ_AUTODETECT)) - continue; + spin_lock_irq(&desc->lock); + status = desc->status; - if (!(status & IRQ_WAITING)) - mask |= 1 << i; + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) + mask |= 1 << i; - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return mask & val; } @@ -1034,183 +745,26 @@ probe_irq_off(unsigned long val) nr_irqs = 0; irq_found = 0; - spin_lock_irq(&irq_controller_lock); for (i=0; i<NR_IRQS; i++) { - unsigned int status = irq_desc[i].status; + irq_desc_t *desc = irq_desc + i; + unsigned int status; - if (!(status & IRQ_AUTODETECT)) - continue; + spin_lock_irq(&desc->lock); + status = desc->status; - if (!(status & IRQ_WAITING)) { - if (!nr_irqs) - irq_found = i; - nr_irqs++; + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); } - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); if (nr_irqs > 1) irq_found = -irq_found; return irq_found; } - - -/* - * The main interrupt entry point. - */ - -asmlinkage void -do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) -{ - switch (type) { - case 0: -#ifdef CONFIG_SMP - handle_ipi(®s); - return; -#else - printk(KERN_CRIT "Interprocessor interrupt? " - "You must be kidding!\n"); -#endif - break; - case 1: -#ifdef CONFIG_SMP - cpu_data[smp_processor_id()].smp_local_irq_count++; - smp_percpu_timer_interrupt(®s); - if (smp_processor_id() == boot_cpuid) -#endif - handle_irq(RTC_IRQ, ®s); - return; - case 2: - alpha_mv.machine_check(vector, la_ptr, ®s); - return; - case 3: - alpha_mv.device_interrupt(vector, ®s); - return; - case 4: - perf_irq(vector, ®s); - return; - default: - printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n", - type, vector); - } - printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps); -} - -void __init -common_init_isa_dma(void) -{ - outb(0, DMA1_RESET_REG); - outb(0, DMA2_RESET_REG); - outb(0, DMA1_CLR_MASK_REG); - outb(0, DMA2_CLR_MASK_REG); -} - -void __init -init_IRQ(void) -{ - wrent(entInt, 0); - alpha_mv.init_irq(); -} - - -/* - */ -#define MCHK_K_TPERR 0x0080 -#define MCHK_K_TCPERR 0x0082 -#define MCHK_K_HERR 0x0084 -#define MCHK_K_ECC_C 0x0086 -#define MCHK_K_ECC_NC 0x0088 -#define MCHK_K_OS_BUGCHECK 0x008A -#define MCHK_K_PAL_BUGCHECK 0x0090 - -#ifndef CONFIG_SMP -struct mcheck_info __mcheck_info; -#endif - -void -process_mcheck_info(unsigned long vector, unsigned long la_ptr, - struct pt_regs *regs, const char *machine, - int expected) -{ - struct el_common *mchk_header; - const char *reason; - - /* - * See if the machine check is due to a badaddr() and if so, - * ignore it. - */ - -#if DEBUG_MCHECK > 0 - printk(KERN_CRIT "%s machine check %s\n", machine, - expected ? "expected." : "NOT expected!!!"); -#endif - - if (expected) { - int cpu = smp_processor_id(); - mcheck_expected(cpu) = 0; - mcheck_taken(cpu) = 1; - return; - } - - mchk_header = (struct el_common *)la_ptr; - - printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n", - machine, vector, regs->pc, mchk_header->code); - - switch ((unsigned int) mchk_header->code) { - /* Machine check reasons. Defined according to PALcode sources. */ - case 0x80: reason = "tag parity error"; break; - case 0x82: reason = "tag control parity error"; break; - case 0x84: reason = "generic hard error"; break; - case 0x86: reason = "correctable ECC error"; break; - case 0x88: reason = "uncorrectable ECC error"; break; - case 0x8A: reason = "OS-specific PAL bugcheck"; break; - case 0x90: reason = "callsys in kernel mode"; break; - case 0x96: reason = "i-cache read retryable error"; break; - case 0x98: reason = "processor detected hard error"; break; - - /* System specific (these are for Alcor, at least): */ - case 0x202: reason = "system detected hard error"; break; - case 0x203: reason = "system detected uncorrectable ECC error"; break; - case 0x204: reason = "SIO SERR occurred on PCI bus"; break; - case 0x205: reason = "parity error detected by CIA"; break; - case 0x206: reason = "SIO IOCHK occurred on ISA bus"; break; - case 0x207: reason = "non-existent memory error"; break; - case 0x208: reason = "MCHK_K_DCSR"; break; - case 0x209: reason = "PCI SERR detected"; break; - case 0x20b: reason = "PCI data parity error detected"; break; - case 0x20d: reason = "PCI address parity error detected"; break; - case 0x20f: reason = "PCI master abort error"; break; - case 0x211: reason = "PCI target abort error"; break; - case 0x213: reason = "scatter/gather PTE invalid error"; break; - case 0x215: reason = "flash ROM write error"; break; - case 0x217: reason = "IOA timeout detected"; break; - case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; - case 0x21b: reason = "EISA fail-safe timer timeout"; break; - case 0x21d: reason = "EISA bus time-out"; break; - case 0x21f: reason = "EISA software generated NMI"; break; - case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; - default: reason = "unknown"; break; - } - - printk(KERN_CRIT "machine check type: %s%s\n", - reason, mchk_header->retry ? " (retryable)" : ""); - - dik_show_regs(regs, NULL); - -#if DEBUG_MCHECK > 1 - { - /* Dump the logout area to give all info. */ - unsigned long *ptr = (unsigned long *)la_ptr; - long i; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%8lx %016lx %016lx\n", - i*sizeof(long), ptr[i], ptr[i+1]); - } - } -#endif -} diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h index ff8067a00..9818476f2 100644 --- a/arch/alpha/kernel/irq_impl.h +++ b/arch/alpha/kernel/irq_impl.h @@ -19,6 +19,7 @@ extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *); extern void srm_device_interrupt(unsigned long, struct pt_regs *); extern void pyxis_device_interrupt(unsigned long, struct pt_regs *); +extern struct irqaction timer_irqaction; extern struct irqaction isa_cascade_irqaction; extern struct irqaction timer_cascade_irqaction; extern struct irqaction halt_switch_irqaction; @@ -33,27 +34,37 @@ extern void i8259a_enable_irq(unsigned int); extern void i8259a_disable_irq(unsigned int); extern void i8259a_mask_and_ack_irq(unsigned int); extern unsigned int i8259a_startup_irq(unsigned int); +extern void i8259a_end_irq(unsigned int); extern struct hw_interrupt_type i8259a_irq_type; extern void init_i8259a_irqs(void); -extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); extern void handle_irq(int irq, struct pt_regs * regs); +extern unsigned long prof_cpu_mask; + static inline void alpha_do_profile(unsigned long pc) { - if (prof_buffer && current->pid) { - extern char _stext; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } + extern char _stext; + + if (!prof_buffer) + return; + + /* + * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. + * (default is all CPUs.) + */ + if (!((1<<smp_processor_id()) & prof_cpu_mask)) + return; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len - 1) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); } diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index 421591104..cc55781cb 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -44,7 +44,6 @@ mv_switch_mm: ev4_switch_mm, \ mv_activate_mm: ev4_activate_mm, \ mv_flush_tlb_current: ev4_flush_tlb_current, \ - mv_flush_tlb_other: ev4_flush_tlb_other, \ mv_flush_tlb_current_page: ev4_flush_tlb_current_page #define DO_EV5_MMU \ @@ -52,7 +51,6 @@ mv_switch_mm: ev5_switch_mm, \ mv_activate_mm: ev5_activate_mm, \ mv_flush_tlb_current: ev5_flush_tlb_current, \ - mv_flush_tlb_other: ev5_flush_tlb_other, \ mv_flush_tlb_current_page: ev5_flush_tlb_current_page #define DO_EV6_MMU \ @@ -60,7 +58,6 @@ mv_switch_mm: ev5_switch_mm, \ mv_activate_mm: ev5_activate_mm, \ mv_flush_tlb_current: ev5_flush_tlb_current, \ - mv_flush_tlb_other: ev5_flush_tlb_other, \ mv_flush_tlb_current_page: ev5_flush_tlb_current_page #define IO_LITE(UP,low) \ diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index f91978732..3aee6ec34 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -123,6 +123,24 @@ static inline u8 bridge_swizzle(u8 pin, u8 slot) _ctl_; }) +/* A PCI IOMMU allocation arena. There are typically two of these + regions per bus. */ +/* ??? The 8400 has a 32-byte pte entry, and the entire table apparently + lives directly on the host bridge (no tlb?). We don't support this + machine, but if we ever did, we'd need to parameterize all this quite + a bit further. Probably with per-bus operation tables. */ + +struct pci_iommu_arena +{ + spinlock_t lock; + struct pci_controler *hose; + unsigned long *ptes; + dma_addr_t dma_base; + unsigned int size; + unsigned int next_entry; +}; + + /* The hose list. */ extern struct pci_controler *hose_head, **hose_tail; extern struct pci_controler *pci_isa_hose; @@ -132,8 +150,9 @@ extern u8 common_swizzle(struct pci_dev *, u8 *); extern struct pci_controler *alloc_pci_controler(void); extern struct resource *alloc_resource(void); -extern struct pci_iommu_arena *iommu_arena_new(dma_addr_t, unsigned long, - unsigned long); +extern struct pci_iommu_arena *iommu_arena_new(struct pci_controler *, + dma_addr_t, unsigned long, + unsigned long); extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n); extern const char *const pci_io_names[]; diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index f5a9bd990..9e7e13e9b 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -27,6 +27,8 @@ # define DBGA2(args...) #endif +#define DEBUG_NODIRECT 0 + static inline unsigned long mk_iommu_pte(unsigned long paddr) @@ -41,23 +43,29 @@ calc_npages(long bytes) } struct pci_iommu_arena * -iommu_arena_new(dma_addr_t base, unsigned long window_size, - unsigned long align) +iommu_arena_new(struct pci_controler *hose, dma_addr_t base, + unsigned long window_size, unsigned long align) { - unsigned long entries, mem_size, mem_pages; + unsigned long mem_size; struct pci_iommu_arena *arena; - entries = window_size >> PAGE_SHIFT; - mem_size = entries * sizeof(unsigned long); - mem_pages = calc_npages(mem_size); + mem_size = window_size / (PAGE_SIZE / sizeof(unsigned long)); + + /* Note that the TLB lookup logic uses bitwise concatenation, + not addition, so the required arena alignment is based on + the size of the window. Retain the align parameter so that + particular systems can over-align the arena. */ + if (align < mem_size) + align = mem_size; arena = alloc_bootmem(sizeof(*arena)); - arena->ptes = __alloc_bootmem(mem_pages * PAGE_SIZE, align, 0); + arena->ptes = __alloc_bootmem(mem_size, align, 0); spin_lock_init(&arena->lock); + arena->hose = hose; arena->dma_base = base; arena->size = window_size; - arena->alloc_hint = 0; + arena->next_entry = 0; return arena; } @@ -74,20 +82,22 @@ iommu_arena_alloc(struct pci_iommu_arena *arena, long n) /* Search forward for the first sequence of N empty ptes. */ beg = arena->ptes; end = beg + (arena->size >> PAGE_SHIFT); - p = beg + arena->alloc_hint; + p = beg + arena->next_entry; i = 0; while (i < n && p < end) i = (*p++ == 0 ? i + 1 : 0); - if (p >= end) { - /* Failure. Assume the hint was wrong and go back to + if (i < n) { + /* Reached the end. Flush the TLB and restart the search from the beginning. */ + alpha_mv.mv_pci_tbi(arena->hose, 0, -1); + p = beg; i = 0; while (i < n && p < end) i = (*p++ == 0 ? i + 1 : 0); - if (p >= end) { + if (i < n) { spin_unlock_irqrestore(&arena->lock, flags); return -1; } @@ -100,7 +110,7 @@ iommu_arena_alloc(struct pci_iommu_arena *arena, long n) for (p = p - n, i = 0; i < n; ++i) p[i] = ~1UL; - arena->alloc_hint = p - beg + n; + arena->next_entry = p - beg + n; spin_unlock_irqrestore(&arena->lock, flags); return p - beg; @@ -115,7 +125,6 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n) p = arena->ptes + ofs; for (i = 0; i < n; ++i) p[i] = 0; - arena->alloc_hint = ofs; } /* Map a single buffer of the indicate size for PCI DMA in streaming @@ -138,6 +147,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) paddr = virt_to_phys(cpu_addr); +#if !DEBUG_NODIRECT /* First check to see if we can use the direct map window. */ if (paddr + size + __direct_map_base - 1 <= max_dma && paddr + size <= __direct_map_size) { @@ -148,6 +158,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) return ret; } +#endif /* If the machine doesn't define a pci_tbi routine, we have to assume it doesn't support sg mapping. */ @@ -199,6 +210,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, if (direction == PCI_DMA_NONE) BUG(); +#if !DEBUG_NODIRECT if (dma_addr >= __direct_map_base && dma_addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ @@ -208,6 +220,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, return; } +#endif arena = hose->sg_pci; if (!arena || dma_addr < arena->dma_base) @@ -224,10 +237,9 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, npages = calc_npages((dma_addr & ~PAGE_MASK) + size); iommu_arena_free(arena, dma_ofs, npages); - alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); - DBGA2("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", - dma_addr, size, npages, __builtin_return_address(0)); + DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", + dma_addr, size, npages, __builtin_return_address(0)); } @@ -347,6 +359,7 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, unsigned long *ptes; long npages, dma_ofs, i; +#if !DEBUG_NODIRECT /* If everything is physically contiguous, and the addresses fall into the direct-map window, use it. */ if (leader->dma_address == 0 @@ -360,6 +373,7 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, return 0; } +#endif /* Otherwise, we'll use the iommu to make the pages virtually contiguous. */ @@ -376,56 +390,38 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, DBGA(" sg_fill: [%p,%lx] -> sg %x np %ld\n", leader->address, size, out->dma_address, npages); + /* All virtually contiguous. We need to find the length of each + physically contiguous subsegment to fill in the ptes. */ ptes = &arena->ptes[dma_ofs]; sg = leader; - if (0 && leader->dma_address == 0) { - /* All physically contiguous. We already have the - length, all we need is to fill in the ptes. */ - - paddr = virt_to_phys(sg->address) & PAGE_MASK; - for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) - *ptes++ = mk_iommu_pte(paddr); - -#if DEBUG_ALLOC > 0 - DBGA(" (0) [%p,%x] np %ld\n", - sg->address, sg->length, npages); - for (++sg; sg < end && (int) sg->dma_address < 0; ++sg) - DBGA(" (%ld) [%p,%x] cont\n", - sg - leader, sg->address, sg->length); -#endif - } else { - /* All virtually contiguous. We need to find the - length of each physically contiguous subsegment - to fill in the ptes. */ - do { - struct scatterlist *last_sg = sg; + do { + struct scatterlist *last_sg = sg; - size = sg->length; - paddr = virt_to_phys(sg->address); + size = sg->length; + paddr = virt_to_phys(sg->address); - while (sg+1 < end && (int) sg[1].dma_address == -1) { - size += sg[1].length; - sg++; - } + while (sg+1 < end && (int) sg[1].dma_address == -1) { + size += sg[1].length; + sg++; + } - npages = calc_npages((paddr & ~PAGE_MASK) + size); + npages = calc_npages((paddr & ~PAGE_MASK) + size); - paddr &= PAGE_MASK; - for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) - *ptes++ = mk_iommu_pte(paddr); + paddr &= PAGE_MASK; + for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) + *ptes++ = mk_iommu_pte(paddr); #if DEBUG_ALLOC > 0 - DBGA(" (%ld) [%p,%x] np %ld\n", + DBGA(" (%ld) [%p,%x] np %ld\n", + last_sg - leader, last_sg->address, + last_sg->length, npages); + while (++last_sg <= sg) { + DBGA(" (%ld) [%p,%x] cont\n", last_sg - leader, last_sg->address, - last_sg->length, npages); - while (++last_sg <= sg) { - DBGA(" (%ld) [%p,%x] cont\n", - last_sg - leader, last_sg->address, - last_sg->length); - } + last_sg->length); + } #endif - } while (++sg < end && (int) sg->dma_address < 0); - } + } while (++sg < end && (int) sg->dma_address < 0); return 1; } @@ -472,13 +468,9 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, /* Third, iterate over the scatterlist leaders and allocate dma space as needed. */ for (out = sg; sg < end; ++sg) { - int ret; - if ((int) sg->dma_address < 0) continue; - - ret = sg_fill(sg, end, out, arena, max_dma); - if (ret < 0) + if (sg_fill(sg, end, out, arena, max_dma) < 0) goto error; out++; } @@ -517,7 +509,6 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, struct pci_iommu_arena *arena; struct scatterlist *end; dma_addr_t max_dma; - dma_addr_t fstart, fend; if (direction == PCI_DMA_NONE) BUG(); @@ -531,42 +522,32 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, if (!arena || arena->dma_base + arena->size > max_dma) arena = hose->sg_isa; - fstart = -1; - fend = 0; for (end = sg + nents; sg < end; ++sg) { unsigned long addr, size; + long npages, ofs; addr = sg->dma_address; size = sg->dma_length; - if (!size) break; +#if !DEBUG_NODIRECT if (addr >= __direct_map_base && addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ DBGA(" (%ld) direct [%lx,%lx]\n", sg - end + nents, addr, size); - } else { - long npages, ofs; - dma_addr_t tend; - - DBGA(" (%ld) sg [%lx,%lx]\n", - sg - end + nents, addr, size); + continue; + } +#endif - npages = calc_npages((addr & ~PAGE_MASK) + size); - ofs = (addr - arena->dma_base) >> PAGE_SHIFT; - iommu_arena_free(arena, ofs, npages); + DBGA(" (%ld) sg [%lx,%lx]\n", + sg - end + nents, addr, size); - tend = addr + size - 1; - if (fstart > addr) - fstart = addr; - if (fend < tend) - fend = tend; - } + npages = calc_npages((addr & ~PAGE_MASK) + size); + ofs = (addr - arena->dma_base) >> PAGE_SHIFT; + iommu_arena_free(arena, ofs, npages); } - if (fend) - alpha_mv.mv_pci_tbi(hose, fstart, fend); DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); } @@ -580,6 +561,7 @@ pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) struct pci_controler *hose; struct pci_iommu_arena *arena; +#if !DEBUG_NODIRECT /* If there exists a direct map, and the mask fits either MAX_DMA_ADDRESS defined such that GFP_DMA does something useful, or the total system memory as shifted by the @@ -588,6 +570,7 @@ pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask || __direct_map_base + (max_low_pfn<<PAGE_SHIFT)-1 <= mask)) return 1; +#endif /* Check that we have a scatter-gather arena that fits. */ hose = pdev ? pdev->sysdata : pci_isa_hose; diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index a8859059b..8e7bbcfaf 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -10,7 +10,6 @@ struct pt_regs; struct task_struct; struct pci_dev; struct pci_controler; -struct irqaction; /* core_apecs.c */ extern struct pci_ops apecs_pci_ops; @@ -81,14 +80,13 @@ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); extern void smp_percpu_timer_interrupt(struct pt_regs *); -extern unsigned long cpu_present_mask; /* bios32.c */ /* extern void reset_for_srm(void); */ /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); -extern void common_init_rtc(struct irqaction *); +extern void common_init_rtc(void); extern unsigned long est_cycle_freq; /* smc37c93x.c */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 1311d939b..615914535 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -487,6 +487,7 @@ setup_arch(char **cmdline_p) #ifdef __SMP__ setup_smp(); #endif + paging_init(); } static char sys_unknown[] = "Unknown"; diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index cc5d8b16b..ff12b9e8d 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -437,6 +437,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } + if (err) + goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -499,6 +501,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index be1a6440e..ab1fb9ab2 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -972,6 +972,33 @@ flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) flush_tlb_mm(mm); } +static void +ipi_flush_icache_page(void *x) +{ + struct mm_struct *mm = (struct mm_struct *) x; + if (mm == current->active_mm) + __load_new_mm_context(mm); +} + +void +flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + struct mm_struct *mm = vma->vm_mm; + + if ((vma->vm_flags & VM_EXEC) == 0) + return; + + mm->context = 0; + if (mm == current->active_mm) { + __load_new_mm_context(mm); + if (atomic_read(&mm->mm_users) <= 1) + return; + } + + if (smp_call_function(ipi_flush_icache_page, mm, 1, 1)) { + printk(KERN_CRIT "flush_icache_page: timed out\n"); + } +} int smp_info(char *buffer) diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index 5498c72ec..867d762f8 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -48,7 +48,7 @@ alcor_enable_irq(unsigned int irq) alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); } -static inline void +static void alcor_disable_irq(unsigned int irq) { alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); @@ -81,6 +81,13 @@ alcor_isa_mask_and_ack_irq(unsigned int irq) *(vuip)GRU_INT_CLEAR = 0; mb(); } +static void +alcor_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + alcor_enable_irq(irq); +} + static struct hw_interrupt_type alcor_irq_type = { typename: "ALCOR", startup: alcor_startup_irq, @@ -88,7 +95,7 @@ static struct hw_interrupt_type alcor_irq_type = { enable: alcor_enable_irq, disable: alcor_disable_irq, ack: alcor_mask_and_ack_irq, - end: alcor_enable_irq, + end: alcor_end_irq, }; static void @@ -134,13 +141,12 @@ alcor_init_irq(void) on while IRQ probing. */ if (i >= 16+20 && i <= 16+30) continue; - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &alcor_irq_type; } i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq; init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); setup_irq(16+31, &isa_cascade_irqaction); diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index acea58d1e..8e016ada0 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -65,6 +65,13 @@ cabriolet_startup_irq(unsigned int irq) return 0; /* never anything pending */ } +static void +cabriolet_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + cabriolet_enable_irq(irq); +} + static struct hw_interrupt_type cabriolet_irq_type = { typename: "CABRIOLET", startup: cabriolet_startup_irq, @@ -72,7 +79,7 @@ static struct hw_interrupt_type cabriolet_irq_type = { enable: cabriolet_enable_irq, disable: cabriolet_disable_irq, ack: cabriolet_disable_irq, - end: cabriolet_enable_irq, + end: cabriolet_end_irq, }; static void @@ -103,7 +110,6 @@ static void __init cabriolet_init_irq(void) { init_i8259a_irqs(); - init_rtc_irq(); if (alpha_using_srm) { alpha_mv.device_interrupt = srm_device_interrupt; @@ -117,7 +123,7 @@ cabriolet_init_irq(void) outb(0xff, 0x806); for (i = 16; i < 35; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &cabriolet_irq_type; } } diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 7414b8cc2..63abc109f 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -35,6 +35,10 @@ /* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; +/* dp264 boards handle at max four CPUs */ +static unsigned long cpu_irq_affinity[4]; + +spinlock_t dp264_irq_lock = SPIN_LOCK_UNLOCKED; static void tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) @@ -50,9 +54,14 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) mask0 = mask1 = mask2 = mask3 = mask; maskB = mask | isa_enable; if (bcpu == 0) mask0 = maskB; - if (bcpu == 1) mask1 = maskB; - if (bcpu == 2) mask2 = maskB; - if (bcpu == 3) mask3 = maskB; + else if (bcpu == 1) mask1 = maskB; + else if (bcpu == 2) mask2 = maskB; + else if (bcpu == 3) mask3 = maskB; + + mask0 &= cpu_irq_affinity[0]; + mask1 &= cpu_irq_affinity[1]; + mask2 &= cpu_irq_affinity[2]; + mask3 &= cpu_irq_affinity[3]; dim0 = &cchip->dim0.csr; dim1 = &cchip->dim1.csr; @@ -73,10 +82,12 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) *dim2; *dim3; #else - volatile unsigned long *dimB = &cchip->dim1.csr; + volatile unsigned long *dimB; if (bcpu == 0) dimB = &cchip->dim0.csr; - if (bcpu == 2) dimB = &cchip->dim2.csr; - if (bcpu == 3) dimB = &cchip->dim3.csr; + else if (bcpu == 1) dimB = &cchip->dim1.csr; + else if (bcpu == 2) dimB = &cchip->dim2.csr; + else if (bcpu == 3) dimB = &cchip->dim3.csr; + *dimB = mask | isa_enable; mb(); *dimB; @@ -95,18 +106,22 @@ clipper_update_irq_hw(unsigned long mask) tsunami_update_irq_hw(mask, 1UL << 55); } -static inline void +static void dp264_enable_irq(unsigned int irq) { + spin_lock(&dp264_irq_lock); cached_irq_mask |= 1UL << irq; dp264_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); } static void dp264_disable_irq(unsigned int irq) { + spin_lock(&dp264_irq_lock); cached_irq_mask &= ~(1UL << irq); dp264_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); } static unsigned int @@ -116,18 +131,29 @@ dp264_startup_irq(unsigned int irq) return 0; /* never anything pending */ } -static inline void +static void +dp264_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + dp264_enable_irq(irq); +} + +static void clipper_enable_irq(unsigned int irq) { + spin_lock(&dp264_irq_lock); cached_irq_mask |= 1UL << irq; clipper_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); } static void clipper_disable_irq(unsigned int irq) { + spin_lock(&dp264_irq_lock); cached_irq_mask &= ~(1UL << irq); clipper_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); } static unsigned int @@ -137,6 +163,47 @@ clipper_startup_irq(unsigned int irq) return 0; /* never anything pending */ } +static void +clipper_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + clipper_enable_irq(irq); +} + +static void +cpu_set_irq_affinity(unsigned int irq, unsigned long affinity) +{ + int cpu; + + for (cpu = 0; cpu < 4; cpu++) { + unsigned long aff = cpu_irq_affinity[cpu]; + if (affinity & (1UL << cpu)) + aff |= 1UL << irq; + else + aff &= ~(1UL << irq); + cpu_irq_affinity[cpu] = aff; + } + +} + +static void +dp264_set_affinity(unsigned int irq, unsigned long affinity) +{ + spin_lock(&dp264_irq_lock); + cpu_set_irq_affinity(irq, affinity); + dp264_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); +} + +static void +clipper_set_affinity(unsigned int irq, unsigned long affinity) +{ + spin_lock(&dp264_irq_lock); + cpu_set_irq_affinity(irq, affinity); + clipper_update_irq_hw(cached_irq_mask); + spin_unlock(&dp264_irq_lock); +} + static struct hw_interrupt_type dp264_irq_type = { typename: "DP264", startup: dp264_startup_irq, @@ -144,7 +211,8 @@ static struct hw_interrupt_type dp264_irq_type = { enable: dp264_enable_irq, disable: dp264_disable_irq, ack: dp264_disable_irq, - end: dp264_enable_irq, + end: dp264_end_irq, + set_affinity: dp264_set_affinity, }; static struct hw_interrupt_type clipper_irq_type = { @@ -154,7 +222,8 @@ static struct hw_interrupt_type clipper_irq_type = { enable: clipper_enable_irq, disable: clipper_disable_irq, ack: clipper_disable_irq, - end: clipper_enable_irq, + end: clipper_end_irq, + set_affinity: clipper_set_affinity, }; static void @@ -249,6 +318,8 @@ init_tsunami_irqs(struct hw_interrupt_type * ops) static void __init dp264_init_irq(void) { + int cpu; + outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); @@ -257,10 +328,12 @@ dp264_init_irq(void) if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; + /* this is single threaded by design so no need of any smp lock */ + for (cpu = 0; cpu < 4; cpu++) + cpu_irq_affinity[cpu] = ~0UL; dp264_update_irq_hw(0UL); init_i8259a_irqs(); - init_rtc_irq(); init_tsunami_irqs(&dp264_irq_type); } @@ -278,7 +351,6 @@ clipper_init_irq(void) clipper_update_irq_hw(0UL); init_i8259a_irqs(); - init_rtc_irq(); init_tsunami_irqs(&clipper_irq_type); } diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c index 0820bd5a0..b3e9e3867 100644 --- a/arch/alpha/kernel/sys_eb64p.c +++ b/arch/alpha/kernel/sys_eb64p.c @@ -48,7 +48,7 @@ eb64p_enable_irq(unsigned int irq) eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq)); } -static inline void +static void eb64p_disable_irq(unsigned int irq) { eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq); @@ -61,6 +61,13 @@ eb64p_startup_irq(unsigned int irq) return 0; /* never anything pending */ } +static void +eb64p_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + eb64p_enable_irq(irq); +} + static struct hw_interrupt_type eb64p_irq_type = { typename: "EB64P", startup: eb64p_startup_irq, @@ -68,7 +75,7 @@ static struct hw_interrupt_type eb64p_irq_type = { enable: eb64p_enable_irq, disable: eb64p_disable_irq, ack: eb64p_disable_irq, - end: eb64p_enable_irq, + end: eb64p_end_irq, }; static void @@ -119,10 +126,9 @@ eb64p_init_irq(void) outb(0xff, 0x27); init_i8259a_irqs(); - init_rtc_irq(); for (i = 16; i < 32; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &eb64p_irq_type; } diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c index c4d120799..9e4fbe569 100644 --- a/arch/alpha/kernel/sys_eiger.c +++ b/arch/alpha/kernel/sys_eiger.c @@ -76,6 +76,13 @@ eiger_startup_irq(unsigned int irq) return 0; /* never anything pending */ } +static void +eiger_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + eiger_enable_irq(irq); +} + static struct hw_interrupt_type eiger_irq_type = { typename: "EIGER", startup: eiger_startup_irq, @@ -83,7 +90,7 @@ static struct hw_interrupt_type eiger_irq_type = { enable: eiger_enable_irq, disable: eiger_disable_irq, ack: eiger_disable_irq, - end: eiger_enable_irq, + end: eiger_end_irq, }; static void @@ -147,10 +154,9 @@ eiger_init_irq(void) eiger_update_irq_hw(i, -1); init_i8259a_irqs(); - init_rtc_irq(); for (i = 16; i < 128; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &eiger_irq_type; } } diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index 98dea0902..2f5400632 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -71,7 +71,7 @@ static struct hw_interrupt_type jensen_local_irq_type = { enable: i8259a_enable_irq, disable: i8259a_disable_irq, ack: jensen_local_ack, - end: i8259a_enable_irq, + end: i8259a_end_irq, }; static void @@ -110,7 +110,6 @@ static void __init jensen_init_irq(void) { init_i8259a_irqs(); - init_rtc_irq(); irq_desc[1].handler = &jensen_local_irq_type; irq_desc[4].handler = &jensen_local_irq_type; diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index 06457a0e8..0191ef91b 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -70,7 +70,6 @@ miata_init_irq(void) #endif init_i8259a_irqs(); - init_rtc_irq(); /* Not interested in the bogus interrupts (3,10), Fan Fault (0), NMI (1), or EIDE (9). diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index 936fa4f17..a66731154 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -48,7 +48,7 @@ mikasa_enable_irq(unsigned int irq) mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16)); } -static inline void +static void mikasa_disable_irq(unsigned int irq) { mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16))); @@ -61,6 +61,13 @@ mikasa_startup_irq(unsigned int irq) return 0; } +static void +mikasa_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + mikasa_enable_irq(irq); +} + static struct hw_interrupt_type mikasa_irq_type = { typename: "MIKASA", startup: mikasa_startup_irq, @@ -68,7 +75,7 @@ static struct hw_interrupt_type mikasa_irq_type = { enable: mikasa_enable_irq, disable: mikasa_disable_irq, ack: mikasa_disable_irq, - end: mikasa_enable_irq, + end: mikasa_end_irq, }; static void @@ -108,12 +115,11 @@ mikasa_init_irq(void) mikasa_update_irq_hw(0); for (i = 16; i < 32; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &mikasa_irq_type; } init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c index 621df72f8..32653e3a7 100644 --- a/arch/alpha/kernel/sys_nautilus.c +++ b/arch/alpha/kernel/sys_nautilus.c @@ -54,7 +54,6 @@ static void __init nautilus_init_irq(void) { init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index 31eac0da4..523d29853 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -45,13 +45,13 @@ noritake_update_irq_hw(int irq, int mask) outw(mask, port); } -static inline void +static void noritake_enable_irq(unsigned int irq) { noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16)); } -static inline void +static void noritake_disable_irq(unsigned int irq) { noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16))); @@ -135,12 +135,11 @@ noritake_init_irq(void) outw(0, 0x54c); for (i = 16; i < 48; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &noritake_irq_type; } init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index f956626a4..3ccce8640 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -41,6 +41,7 @@ static unsigned int hose_irq_masks[4] = { 0xff0000, 0xfe0000, 0xff0000, 0xff0000 }; static unsigned int cached_irq_masks[4]; +spinlock_t rawhide_irq_lock = SPIN_LOCK_UNLOCKED; static inline void rawhide_update_irq_hw(int hose, int mask) @@ -50,7 +51,7 @@ rawhide_update_irq_hw(int hose, int mask) *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)); } -static void +static inline void rawhide_enable_irq(unsigned int irq) { unsigned int mask, hose; @@ -59,9 +60,11 @@ rawhide_enable_irq(unsigned int irq) hose = irq / 24; irq -= hose * 24; + spin_lock(&rawhide_irq_lock); mask = cached_irq_masks[hose] |= 1 << irq; mask |= hose_irq_masks[hose]; rawhide_update_irq_hw(hose, mask); + spin_unlock(&rawhide_irq_lock); } static void @@ -73,9 +76,11 @@ rawhide_disable_irq(unsigned int irq) hose = irq / 24; irq -= hose * 24; + spin_lock(&rawhide_irq_lock); mask = cached_irq_masks[hose] &= ~(1 << irq); mask |= hose_irq_masks[hose]; rawhide_update_irq_hw(hose, mask); + spin_unlock(&rawhide_irq_lock); } @@ -86,6 +91,13 @@ rawhide_startup_irq(unsigned int irq) return 0; } +static void +rawhide_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + rawhide_enable_irq(irq); +} + static struct hw_interrupt_type rawhide_irq_type = { typename: "RAWHIDE", startup: rawhide_startup_irq, @@ -93,7 +105,7 @@ static struct hw_interrupt_type rawhide_irq_type = { enable: rawhide_enable_irq, disable: rawhide_disable_irq, ack: rawhide_disable_irq, - end: rawhide_enable_irq, + end: rawhide_end_irq, }; static void @@ -138,12 +150,11 @@ rawhide_init_irq(void) } for (i = 16; i < 128; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &rawhide_irq_type; } init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index ae89e81b2..01d80ab97 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -64,7 +64,7 @@ ruffian_init_irq(void) } static void __init -ruffian_init_rtc(struct irqaction *action) +ruffian_init_rtc(void) { /* Ruffian does not have the RTC connected to the CPU timer interrupt. Instead, it uses the PIT connected to IRQ 0. */ @@ -78,7 +78,7 @@ ruffian_init_rtc(struct irqaction *action) outb(0x31, 0x42); outb(0x13, 0x42); - setup_irq(0, action); + setup_irq(0, &timer_irqaction); } static void diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c index d5299d008..2d5927c84 100644 --- a/arch/alpha/kernel/sys_rx164.c +++ b/arch/alpha/kernel/sys_rx164.c @@ -65,6 +65,13 @@ rx164_startup_irq(unsigned int irq) return 0; } +static void +rx164_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + rx164_enable_irq(irq); +} + static struct hw_interrupt_type rx164_irq_type = { typename: "RX164", startup: rx164_startup_irq, @@ -72,7 +79,7 @@ static struct hw_interrupt_type rx164_irq_type = { enable: rx164_enable_irq, disable: rx164_disable_irq, ack: rx164_disable_irq, - end: rx164_enable_irq, + end: rx164_end_irq, }; static void @@ -109,12 +116,11 @@ rx164_init_irq(void) rx164_update_irq_hw(0); for (i = 16; i < 40; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &rx164_irq_type; } init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); setup_irq(16+20, &isa_cascade_irqaction); diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c index e2a69b5c7..b27d757b2 100644 --- a/arch/alpha/kernel/sys_sable.c +++ b/arch/alpha/kernel/sys_sable.c @@ -30,6 +30,7 @@ #include "pci_impl.h" #include "machvec_impl.h" +spinlock_t sable_irq_lock = SPIN_LOCK_UNLOCKED; /* * For SABLE, which is really baroque, we manage 40 IRQ's, but the @@ -137,8 +138,10 @@ sable_enable_irq(unsigned int irq) unsigned long bit, mask; bit = sable_irq_swizzle.irq_to_mask[irq]; + spin_lock(&sable_irq_lock); mask = sable_irq_swizzle.shadow_mask &= ~(1UL << bit); sable_update_irq_hw(bit, mask); + spin_unlock(&sable_irq_lock); } static void @@ -147,8 +150,10 @@ sable_disable_irq(unsigned int irq) unsigned long bit, mask; bit = sable_irq_swizzle.irq_to_mask[irq]; + spin_lock(&sable_irq_lock); mask = sable_irq_swizzle.shadow_mask |= 1UL << bit; sable_update_irq_hw(bit, mask); + spin_unlock(&sable_irq_lock); } static unsigned int @@ -159,14 +164,23 @@ sable_startup_irq(unsigned int irq) } static void +sable_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + sable_enable_irq(irq); +} + +static void sable_mask_and_ack_irq(unsigned int irq) { unsigned long bit, mask; bit = sable_irq_swizzle.irq_to_mask[irq]; + spin_lock(&sable_irq_lock); mask = sable_irq_swizzle.shadow_mask |= 1UL << bit; sable_update_irq_hw(bit, mask); sable_ack_irq_hw(bit); + spin_unlock(&sable_irq_lock); } static struct hw_interrupt_type sable_irq_type = { @@ -176,7 +190,7 @@ static struct hw_interrupt_type sable_irq_type = { enable: sable_enable_irq, disable: sable_disable_irq, ack: sable_mask_and_ack_irq, - end: sable_enable_irq, + end: sable_end_irq, }; static void @@ -204,11 +218,10 @@ sable_init_irq(void) outb(0x44, 0x535); /* enable cascades in master */ for (i = 0; i < 40; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &sable_irq_type; } - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index 0230ec6d9..e378408f2 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -42,7 +42,6 @@ sio_init_irq(void) alpha_mv.device_interrupt = srm_device_interrupt; init_i8259a_irqs(); - init_rtc_irq(); common_init_isa_dma(); } diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c index 806241a32..bad57d35e 100644 --- a/arch/alpha/kernel/sys_sx164.c +++ b/arch/alpha/kernel/sys_sx164.c @@ -43,7 +43,6 @@ sx164_init_irq(void) alpha_mv.device_interrupt = srm_device_interrupt; init_i8259a_irqs(); - init_rtc_irq(); /* Not interested in the bogus interrupts (0,3,4,5,40-47), NMI (1), or HALT (2). */ diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index 360f135b6..a0bc57125 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -66,6 +66,13 @@ takara_startup_irq(unsigned int irq) return 0; /* never anything pending */ } +static void +takara_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + takara_enable_irq(irq); +} + static struct hw_interrupt_type takara_irq_type = { typename: "TAKARA", startup: takara_startup_irq, @@ -73,7 +80,7 @@ static struct hw_interrupt_type takara_irq_type = { enable: takara_enable_irq, disable: takara_disable_irq, ack: takara_disable_irq, - end: takara_enable_irq, + end: takara_end_irq, }; static void @@ -126,7 +133,6 @@ takara_init_irq(void) long i; init_i8259a_irqs(); - init_rtc_irq(); if (alpha_using_srm) { alpha_mv.device_interrupt = takara_srm_device_interrupt; @@ -146,7 +152,7 @@ takara_init_irq(void) takara_update_irq_hw(i, -1); for (i = 16; i < 128; ++i) { - irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].handler = &takara_irq_type; } diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index d7b5cee8c..291682e33 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -163,7 +163,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, } void -common_init_rtc(struct irqaction *action) +common_init_rtc() { unsigned char x; @@ -192,18 +192,12 @@ common_init_rtc(struct irqaction *action) outb(0x31, 0x42); outb(0x13, 0x42); - setup_irq(RTC_IRQ, action); + init_rtc_irq(); } void time_init(void) { - static struct irqaction timer_irqaction = { - handler: timer_interrupt, - flags: SA_INTERRUPT, - name: "timer", - }; - unsigned int year, mon, day, hour, min, sec, cc1, cc2; unsigned long cycle_freq, one_percent; long diff; @@ -292,7 +286,9 @@ time_init(void) state.partial_tick = 0L; /* Startup the timer source. */ - alpha_mv.init_rtc(&timer_irqaction); + alpha_mv.init_rtc(); + + do_get_fast_time = do_gettimeofday; } /* diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 4da99bad2..3d9c8e75e 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -38,9 +38,18 @@ extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); unsigned long last_asn = ASN_FIRST_VERSION; #endif -void ev5_flush_tlb_current(struct mm_struct *mm) +extern void +__load_new_mm_context(struct mm_struct *next_mm) { - ev5_activate_mm(NULL, mm, smp_processor_id()); + unsigned long mmc; + + mmc = __get_new_mm_context(next_mm, smp_processor_id()); + next_mm->context = mmc; + current->thread.asn = mmc & HARDWARE_ASN_MASK; + current->thread.ptbr + = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT; + + __reload_thread(¤t->thread); } diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index d2992a491..d92f2b093 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -46,13 +46,12 @@ endif ifeq ($(CONFIG_ARCH_SA1100),y) OBJS += head-sa1100.o -ifeq ($(CONFIG_SA1100_VICTOR),y) -ZTEXTADDR = 0x00002000 -ZBSSADDR = 0xc0100000 -else ZTEXTADDR = 0xc0008000 -endif ZRELADDR = 0xc0008000 +ifeq ($(CONFIG_SA1100_VICTOR),y) + ZTEXTADDR = 0x00002000 + ZBSSADDR = 0xc0100000 +endif endif # diff --git a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S index 90018e52b..4464157c3 100644 --- a/arch/arm/boot/compressed/head-sa1100.S +++ b/arch/arm/boot/compressed/head-sa1100.S @@ -11,6 +11,8 @@ .section ".start", #alloc, #execinstr +__SA1100_start: + #ifndef CONFIG_ARCH_SA1100 #error What am I doing here... #endif @@ -58,6 +60,65 @@ orr r0, r0, #0x1000 @ set Icache mcr p15, 0, r0, c1, c0, 0 +#ifdef CONFIG_SA1100_BRUTUS + @ Initialize UART1 for early serial communication + @ since UART3 is used by angelboot. It is routed to + @ alternate GPIO functions on Brutus. + b 1f + +GPIO_BASE: .long 0x90040000 +#define GPDR 0x04 +#define GAFR 0x1c + +PPC_BASE: .long 0x90060000 +#define PPAR 0x08 + +UART1_BASE: .long 0x80010000 +#define UTCR0 0x00 +#define UTCR1 0x04 +#define UTCR2 0x08 +#define UTCR3 0x0c +#define UTSR0 0x1c +#define UTSR1 0x20 + +#define BAUD_DIV_230400 0x000 +#define BAUD_DIV_115200 0x001 +#define BAUD_DIV_57600 0x003 +#define BAUD_DIV_38400 0x005 +#define BAUD_DIV_19200 0x00b +#define BAUD_DIV_9600 0x017 +#define BAUD_DIV BAUD_DIV_9600 + +1: ldr r0, GPIO_BASE + ldr r1, [r0, #GPDR] + bic r1, r1, #1<<15 + orr r1, r1, #1<<14 + str r1, [r0, #GPDR] + ldr r1, [r0, #GAFR] + orr r1, r1, #(1<<15)|(1<<14) + str r1, [r0, #GAFR] + ldr r0, PPC_BASE + ldr r1, [r0, #PPAR] + orr r1, r1, #1<<12 + str r1, [r0, #PPAR] + ldr r0, UART1_BASE +1: ldr r1, [r0, #UTSR1] + tst r1, #1<<0 @ TBY + bne 1b + mov r1, #0 + str r1, [r0, #UTCR3] + mov r1, #0x08 @ 8N1 + str r1, [r0, #UTCR0] + mov r1, #BAUD_DIV + str r1, [r0, #UTCR2] + mov r1, r1, lsr #8 + str r1, [r0, #UTCR1] + mov r1, #0x03 @ RXE + TXE + str r1, [r0, #UTCR3] + mov r1, #0xff @ flush status reg + str r1, [r0, #UTSR0] +#endif + @ set registers for entry mov r0, #0 mov r1, #16 diff --git a/arch/arm/config.in b/arch/arm/config.in index be7102698..5e9cc8bfc 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -92,6 +92,8 @@ else if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then define_bool CONFIG_CPU_32v4 y if [ "$CONFIG_ARCH_SA1100" = "y" ]; then @@ -122,6 +124,7 @@ fi # These machines have ISA-DMA # if [ "$CONFIG_CATS" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then define_bool CONFIG_ISA_DMA y else @@ -186,6 +189,8 @@ if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ fi endmenu +source drivers/ieee1394/Config.in + source drivers/i2o/Config.in source drivers/pnp/Config.in @@ -209,6 +214,8 @@ fi source drivers/usb/Config.in +source drivers/misc/Config.in + if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' @@ -256,7 +263,10 @@ if [ "$CONFIG_SCSI" != "n" ]; then fi endmenu -if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then +if [ "$CONFIG_ARCH_ACORN" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment comment 'Sound' diff --git a/arch/arm/kernel/arthur.c b/arch/arm/kernel/arthur.c index 9994fdd4a..77c7d7396 100644 --- a/arch/arm/kernel/arthur.c +++ b/arch/arm/kernel/arthur.c @@ -1,6 +1,6 @@ /* * Arthur personality - * Copyright (C) 1998 Philip Blundell + * Copyright (C) 1998-1999 Philip Blundell */ #include <linux/personality.h> @@ -8,35 +8,36 @@ #include <linux/stddef.h> #include <linux/signal.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/ptrace.h> -/* RISC OS doesn't have many signals, and a lot of those that it does +/* Arthur doesn't have many signals, and a lot of those that it does have don't map easily to any Linux equivalent. Never mind. */ -#define RISCOS_SIGABRT 1 -#define RISCOS_SIGFPE 2 -#define RISCOS_SIGILL 3 -#define RISCOS_SIGINT 4 -#define RISCOS_SIGSEGV 5 -#define RISCOS_SIGTERM 6 -#define RISCOS_SIGSTAK 7 -#define RISCOS_SIGUSR1 8 -#define RISCOS_SIGUSR2 9 -#define RISCOS_SIGOSERROR 10 +#define ARTHUR_SIGABRT 1 +#define ARTHUR_SIGFPE 2 +#define ARTHUR_SIGILL 3 +#define ARTHUR_SIGINT 4 +#define ARTHUR_SIGSEGV 5 +#define ARTHUR_SIGTERM 6 +#define ARTHUR_SIGSTAK 7 +#define ARTHUR_SIGUSR1 8 +#define ARTHUR_SIGUSR2 9 +#define ARTHUR_SIGOSERROR 10 -static unsigned long riscos_to_linux_signals[32] = { +static unsigned long arthur_to_linux_signals[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; -static unsigned long linux_to_riscos_signals[32] = { - 0, -1, RISCOS_SIGINT, -1, - RISCOS_SIGILL, 5, RISCOS_SIGABRT, 7, - RISCOS_SIGFPE, 9, RISCOS_SIGUSR1, RISCOS_SIGSEGV, - RISCOS_SIGUSR2, 13, 14, RISCOS_SIGTERM, +static unsigned long linux_to_arthur_signals[32] = { + 0, -1, ARTHUR_SIGINT, -1, + ARTHUR_SIGILL, 5, ARTHUR_SIGABRT, 7, + ARTHUR_SIGFPE, 9, ARTHUR_SIGUSR1, ARTHUR_SIGSEGV, + ARTHUR_SIGUSR2, 13, 14, ARTHUR_SIGTERM, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, @@ -52,12 +53,12 @@ static void arthur_lcall7(int nr, struct pt_regs *regs) send_sig_info(SIGSWI, &info, current); } -static struct exec_domain riscos_exec_domain = { +static struct exec_domain arthur_exec_domain = { "Arthur", /* name */ (lcall7_func)arthur_lcall7, PER_RISCOS, PER_RISCOS, - riscos_to_linux_signals, - linux_to_riscos_signals, + arthur_to_linux_signals, + linux_to_arthur_signals, #ifdef MODULE &__this_module, /* No usage counter. */ #else @@ -71,18 +72,15 @@ static struct exec_domain riscos_exec_domain = { * processes are using it. */ -#ifdef MODULE -int init_module(void) -#else -int initialise_arthur(void) -#endif +int __init arthur_init(void) { - return register_exec_domain(&riscos_exec_domain); + return register_exec_domain(&arthur_exec_domain); } -#ifdef MODULE -void cleanup_module(void) +void __exit arthur_exit(void) { - unregister_exec_domain(&riscos_exec_domain); + unregister_exec_domain(&arthur_exec_domain); } -#endif + +module_init(arthur_init); +module_exit(arthur_exit); diff --git a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S index f2dc9e36c..d6fa94867 100644 --- a/arch/arm/kernel/entry-armo.S +++ b/arch/arm/kernel/entry-armo.S @@ -22,6 +22,7 @@ * adhering to the above criteria. */ #include <linux/linkage.h> +#include <linux/config.h> #include <asm/assembler.h> #include <asm/errno.h> @@ -29,6 +30,12 @@ #include "../lib/constants.h" + .macro zero_fp +#ifdef CONFIG_FRAME_POINTER + mov fp, #0 +#endif + .endm + .text @ Offsets into task structure @@ -213,7 +220,7 @@ irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 stmfd sp!, {r0 - r12} ;\ mov r0, #-1 ;\ str r0, [sp, #S_OLD_R0] ;\ - mov fp, #0 + zero_fp #define SVC_IRQ_SAVE_ALL \ str sp, [sp, #-16]! ;\ @@ -224,7 +231,7 @@ irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 stmfd sp!, {r0 - r12} ;\ mov r0, #-1 ;\ str r0, [sp, #S_OLD_R0] ;\ - mov fp, #0 + zero_fp #define SVC_RESTORE_ALL \ ldmfd sp, {r0 - pc}^ @@ -261,7 +268,7 @@ vector_undefinstr: tst lr,#3 bne __und_svc save_user_regs - mov fp, #0 + zero_fp teqp pc, #I_BIT | MODE_SVC .Lbug_undef: ldr r4, .LC2 @@ -283,6 +290,10 @@ __und_svc: SVC_SAVE_ALL @ Non-user mode bl SYMBOL_NAME(do_undefinstr) SVC_RESTORE_ALL +#ifdef CONFIG_NWFPE + /* The FPE is always present */ + .equ fpe_not_present, 0 +#else /* We get here if an undefined instruction happens and the floating * point emulator is not present. If the offending instruction was * a WFS, we just perform a normal return as if we had emulated the @@ -319,6 +330,7 @@ wfs_mask_data: .word 0x0e200110 @ WFS/RFS .word 0x0d0d0100 @ LDF [sp]/STF [sp] .word 0x0d0b0100 @ LDF [fp]/STF [fp] .word 0x0f0f0f00 +#endif .LC2: .word SYMBOL_NAME(fp_enter) @@ -686,7 +698,7 @@ ENTRY(__switch_to) /* * initialise the trap system */ -ENTRY(trap_init) +ENTRY(__trap_init) stmfd sp!, {r4 - r7, lr} adr r1, .Ljump_addresses ldmia r1, {r1 - r7, ip, lr} diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index f4f03ee93..fe3939888 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -24,6 +24,12 @@ #define MODE_SVC 0x13 #endif + .macro zero_fp +#ifdef CONFIG_FRAME_POINTER + mov fp, #0 +#endif + .endm + .text #define PF_TRACESYS 0x20 @@ -421,7 +427,7 @@ __und_invalid: sub sp, sp, #S_FRAME_SIZE ldr r4, .LCund mov r1, #BAD_UNDEFINSTR @ int reason -1: mov fp, #0 +1: zero_fp ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0 add r4, sp, #S_PC stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0 @@ -573,7 +579,7 @@ __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 stmdb r3, {sp, lr}^ alignment_trap r4, r7, __temp_abt - mov fp, #0 + zero_fp #ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc @@ -595,7 +601,7 @@ __irq_usr: sub sp, sp, #S_FRAME_SIZE stmia r8, {r5 - r7} @ save pc, psr, old_r0 stmdb r8, {sp, lr}^ alignment_trap r4, r7, __temp_irq - mov fp, #0 + zero_fp 1: get_irqnr_and_base r0, r6, r5 movne r1, sp adrsvc ne, lr, 1b @@ -615,7 +621,7 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save user r0 - r12 alignment_trap r4, r7, __temp_und - mov fp, #0 + zero_fp adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return @@ -641,7 +647,7 @@ __pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr alignment_trap r4, r7, __temp_abt - mov fp, #0 + zero_fp msr cpsr_c, #MODE_SVC @ Enable interrupts mov r0, r5 @ address (pc) mov r1, sp @ regs @@ -688,11 +694,11 @@ t: .ascii "Prefetch -> undefined instruction\n\0" ENTRY(__switch_to) stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr - stmfd sp!, {ip} @ Save cpsr_SVC + str ip, [sp, #-4]! @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC ldr r2, [r1, #TSS_DOMAIN] - ldmfd sp!, {ip} + ldr ip, [sp], #4 mcr p15, 0, r2, c3, c0 @ Set domain register msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 5dc61c6d7..97dfef0c1 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -4,16 +4,6 @@ */ #define S_OFF 8 -#define SYSCALL_REGS r4, r5 - -/* - * Define to favour ARM8, ARM9 and StrongARM cpus. This says that it is - * cheaper to use two LDR instructions than a two-register LDM, if the - * latter would entail calculating an address specially. - */ -#if defined(CONFIG_CPU_SA110) -#define HARVARD_CACHE -#endif .macro get_softirq, rd #ifdef __SMP__ @@ -85,7 +75,7 @@ tip .req r7 @ temporary IP .align 5 vector_swi: save_user_regs mask_pc lr, lr - mov fp, #0 + zero_fp ldr scno, [lr, #-4] @ get SWI instruction arm700_bug_check scno, ip #ifdef CONFIG_ALIGNMENT_TRAP @@ -95,9 +85,7 @@ vector_swi: save_user_regs #endif enable_irqs ip - stmdb sp!, {SYSCALL_REGS} @ new style: (r0 = arg1, r4 = arg5, r5 = arg6) - @ Note that we dont have to handle - @ sys_syscalls arg7 here + str r4, [sp, #-S_OFF]! @ push fifth arg adrsvc al, lr, fast_syscall_return bic scno, scno, #0xff000000 @ mask off SWI op-code @@ -141,10 +129,11 @@ vector_swi: save_user_regs b SYMBOL_NAME(deferred) .align 5 - + .type __softirq_state, #object __softirq_state: .word SYMBOL_NAME(softirq_state) + .type sys_call_table, #object ENTRY(sys_call_table) #include "calls.S" @@ -153,15 +142,18 @@ ENTRY(sys_call_table) */ @ r0 = syscall number @ r5 = syscall table + .type sys_syscall, #function SYMBOL_NAME(sys_syscall): eor scno, r0, #OS_NUMBER << 20 cmp scno, #NR_syscalls @ check range add ip, sp, #S_OFF - ldmleib ip, {r0 - r3, SYSCALL_REGS} @ get our args - stmleia sp, {SYSCALL_REGS} @ Put our arg on the stack + stmleia sp, {r5, r6} @ shuffle args + movle r0, r1 + movle r1, r2 + movle r2, r3 + movle r3, r4 ldrle pc, [tbl, scno, lsl #2] - mov r0, #-ENOSYS - RETINSTR(mov,pc,lr) + b sys_ni_syscall sys_fork_wrapper: add r0, sp, #S_OFF @@ -199,6 +191,23 @@ sys_sigaltstack_wrapper: ldr r2, [sp, #S_OFF + S_SP] b do_sigaltstack +/* + * Note: off_4k (r5) is always units of 4K. If we can't do the requested + * offset, we return EINVAL. + */ +sys_mmap2: +#if PAGE_SHIFT > 12 + tst r5, #PGOFF_MASK + moveq r5, r5, lsr #PGOFF_SHIFT + streq r5, [sp, #4] + beq do_mmap2 + mov r0, #-EINVAL + RETINSTR(mov,pc, lr) +#else + str r5, [sp, #4] + b do_mmap2 +#endif + .data ENTRY(fp_enter) diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c index e06c8092d..8dcad0b93 100644 --- a/arch/arm/kernel/hw-footbridge.c +++ b/arch/arm/kernel/hw-footbridge.c @@ -68,13 +68,13 @@ static inline void wb977_ww(int reg, int val) /* * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE */ -spinlock_t __netwinder_data gpio_lock = SPIN_LOCK_UNLOCKED; +spinlock_t gpio_lock = SPIN_LOCK_UNLOCKED; -static unsigned int __netwinder_data current_gpio_op = 0; -static unsigned int __netwinder_data current_gpio_io = 0; -static unsigned int __netwinder_data current_cpld = 0; +static unsigned int current_gpio_op = 0; +static unsigned int current_gpio_io = 0; +static unsigned int current_cpld = 0; -void __netwinder_text gpio_modify_op(int mask, int set) +void gpio_modify_op(int mask, int set) { unsigned int new_gpio, changed; @@ -119,7 +119,7 @@ static inline void __gpio_modify_io(int mask, int in) } } -void __netwinder_text gpio_modify_io(int mask, int in) +void gpio_modify_io(int mask, int in) { /* Open up the SuperIO chip */ wb977_open(); @@ -130,7 +130,7 @@ void __netwinder_text gpio_modify_io(int mask, int in) wb977_close(); } -int __netwinder_text gpio_read(void) +int gpio_read(void) { return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; } @@ -360,7 +360,7 @@ static void __init wb977_init(void) wb977_close(); } -void __netwinder_text cpld_modify(int mask, int set) +void cpld_modify(int mask, int set) { int msk; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 6e3c863d5..699cea4ab 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -471,6 +471,10 @@ out: return irq_found; } +void __init init_irq_proc(void) +{ +} + void __init init_IRQ(void) { extern void init_dma(void); diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c index 90f2fe109..05f232f57 100644 --- a/arch/arm/kernel/leds-footbridge.c +++ b/arch/arm/kernel/leds-footbridge.c @@ -37,7 +37,7 @@ extern spinlock_t gpio_lock; #ifdef CONFIG_FOOTBRIDGE -static void __ebsa285_text ebsa285_leds_event(led_event_t evt) +static void ebsa285_leds_event(led_event_t evt) { unsigned long flags; @@ -129,7 +129,7 @@ static void __ebsa285_text ebsa285_leds_event(led_event_t evt) #ifdef CONFIG_ARCH_NETWINDER -static void __netwinder_text netwinder_leds_event(led_event_t evt) +static void netwinder_leds_event(led_event_t evt) { unsigned long flags; diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index a2f7292f6..5815529aa 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -767,6 +767,8 @@ void __init setup_arch(char **cmdline_p) setup_bootmem(); request_standard_resources(mdesc); + paging_init(); + #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 47b2930c2..9abb9e617 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -50,7 +50,7 @@ asmlinkage int sys_pipe(unsigned long * fildes) } /* common code for old and new mmaps */ -static inline long do_mmap2( +inline long do_mmap2( unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) @@ -79,27 +79,6 @@ out: return error; } -#define PGOFF_SHIFT (PAGE_SHIFT - 12) -#define PGOFF_MASK (~((1 << PGOFF_SHIFT) - 1)) - -/* - * Note: off_4k is always units of 4K. If we can't do the requested - * offset, we return EINVAL. - */ -asmlinkage long -sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long off_4k) -{ - unsigned long pgoff; - - if (off_4k & ~PGOFF_MASK) - return -EINVAL; - - pgoff = off_4k >> PGOFF_SHIFT; - - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - struct mmap_arg_struct { unsigned long addr; unsigned long len; diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S index e1651904f..3544ac89d 100644 --- a/arch/arm/lib/findbit.S +++ b/arch/arm/lib/findbit.S @@ -53,10 +53,10 @@ ENTRY(find_next_zero_bit) beq Lfindzbit1lp @ If new byte, goto old routine ldrb r3, [r0, r2, lsr#3] orr r3, r3, #0xFF00 @ Set top bits so we wont get confused - stmfd sp!, {r4} + str r4, [sp, #-4]! and r4, r2, #7 mov r3, r3, lsr r4 @ Shift right by no. of bits - ldmfd sp!, {r4} + ldr r4, [sp], #4 and r3, r3, #0xFF teq r3, #0xFF orreq r2, r2, #7 diff --git a/arch/arm/lib/getconsdata.c b/arch/arm/lib/getconsdata.c index aaa7a7ad2..8b6a0affa 100644 --- a/arch/arm/lib/getconsdata.c +++ b/arch/arm/lib/getconsdata.c @@ -91,3 +91,5 @@ unsigned long PAGE_SZ = PAGE_SIZE; unsigned long KSWI_BASE = 0x900000; unsigned long KSWI_SYS_BASE = 0x9f0000; unsigned long SYS_ERROR0 = 0x9f0000; +unsigned long PGOFF_SHIFT = PAGE_SHIFT - 12; +unsigned long PGOFF_MASK = (1 << (PAGE_SHIFT - 12)) - 1; diff --git a/arch/arm/lib/strrchr.S b/arch/arm/lib/strrchr.S index ad5a46089..c9145d7af 100644 --- a/arch/arm/lib/strrchr.S +++ b/arch/arm/lib/strrchr.S @@ -12,7 +12,7 @@ .text ENTRY(strrchr) - stmfd sp!, {lr} + str lr, [sp, #-4]! mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 7101b2936..76d1a5c74 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -1,13 +1,14 @@ /* * Dynamic DMA mapping support. */ - +#include <linux/config.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <linux/interrupt.h> #include <linux/errno.h> +#include <linux/pci.h> #include <asm/io.h> #include <asm/pgalloc.h> @@ -49,6 +50,22 @@ no_page: return NULL; } +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle) +{ + void *__ret; + int __gfp = GFP_KERNEL; + +#ifdef CONFIG_PCI + if ((hwdev) == NULL || + (hwdev)->dma_mask != 0xffffffff) +#endif + __gfp |= GFP_DMA; + + __ret = consistent_alloc(__gfp, (size), + (handle)); + return __ret; +} + /* * free a page as defined by the above mapping. We expressly forbid * calling this from interrupt context. diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 5151591b8..4a23d14bd 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -351,7 +351,7 @@ do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) #endif -static struct fsr_info { +static const struct fsr_info { int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); int sig; char *name; @@ -384,7 +384,7 @@ static struct fsr_info { asmlinkage void do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { - struct fsr_info *inf; + const struct fsr_info *inf; if (user_mode(regs) && addr == regs->ARM_pc) { static int first = 1; diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c index d04808ffa..c34c37203 100644 --- a/arch/arm/mm/fault-common.c +++ b/arch/arm/mm/fault-common.c @@ -6,7 +6,7 @@ */ #include <linux/config.h> -extern void die(const char *msg, struct pt_regs *regs, unsigned int err); +extern void die(const char *msg, struct pt_regs *regs, int err); /* * This is useful to dump out the page tables associated with diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 92007d975..ddc69089a 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -60,6 +60,8 @@ __setup("noalign", noalign_setup); __setup("nocache", nocache_setup); __setup("nowb", nowrite_setup); +#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) + /* * need to get a 16k page for level 1 */ @@ -71,9 +73,9 @@ pgd_t *get_pgd_slow(void) if (pgd) { pgd_t *init = pgd_offset_k(0); - memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + memzero(pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); + memcpy(pgd + FIRST_KERNEL_PGD_NR, init + FIRST_KERNEL_PGD_NR, + (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t)); /* diff --git a/arch/arm/mm/mm-nexuspci.c b/arch/arm/mm/mm-nexuspci.c index 5b66faa51..ccb6c8a5c 100644 --- a/arch/arm/mm/mm-nexuspci.c +++ b/arch/arm/mm/mm-nexuspci.c @@ -2,9 +2,9 @@ * arch/arm/mm/mm-nexuspci.c * from arch/arm/mm/mm-ebsa110.c * - * Extra MM routines for the NexusPCI architecture + * Extra MM routines for the FTV/PCI architecture * - * Copyright (C) 1998 Phil Blundell + * Copyright (C) 1998-1999 Phil Blundell * Copyright (C) 1998-1999 Russell King */ @@ -18,14 +18,14 @@ #include "map.h" -#define SIZE(x) (sizeof(x) / sizeof(x[0])) - -const struct map_desc io_desc[] __initdata = { - { 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffc00000, 0x60000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xfe000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xfd000000, 0x88000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 } +struct map_desc io_desc[] __initdata = { + { INTCONT_BASE, INTCONT_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { PLX_BASE, PLX_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIO_BASE, PLX_IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + { DUART_BASE, DUART_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { STATUS_BASE, STATUS_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 } }; +#define SIZE(x) (sizeof(x) / sizeof(x[0])) + unsigned int __initdata io_desc_size = SIZE(io_desc); diff --git a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in index 5fbafe77a..94c155232 100644 --- a/arch/arm/vmlinux-armo.lds.in +++ b/arch/arm/vmlinux-armo.lds.in @@ -28,6 +28,11 @@ SECTIONS *(.init.task) } + /DISCARD/ : { /* Exit code and data */ + *(.text.exit) + *(.data.exit) + } + _text = .; /* Text and read-only data */ .text : { *(.text) diff --git a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in index 93b8946e7..d2a79ca9d 100644 --- a/arch/arm/vmlinux-armv.lds.in +++ b/arch/arm/vmlinux-armv.lds.in @@ -25,22 +25,6 @@ SECTIONS __init_end = .; } - .ebsa285 : { - __ebsa285_begin = .; - *(.text.ebsa285) - *(.data.ebsa285) - . = ALIGN(4096); - __ebsa285_end = .; - } - - .netwinder : { - __netwinder_begin = .; - *(.text.netwinder) - *(.data.netwinder) - . = ALIGN(4096); - __netwinder_end = .; - } - .text : { /* Real text segment */ _text = .; /* Text and read-only data */ *(.text) @@ -65,11 +49,26 @@ SECTIONS . = ALIGN(8192); - .data : { /* Data */ + .data : { + /* + * first, the init task union, aligned + * to an 8192 byte boundary. + */ *(.init.task) + + /* + * then the cacheline aligned data + */ + . = ALIGN(32); + *(.data.cacheline_aligned) + + /* + * and the usual data section + */ *(.data) CONSTRUCTORS - _edata = .; /* End of data section */ + + _edata = .; } .bss : { diff --git a/arch/i386/config.in b/arch/i386/config.in index e074ea81d..1d5c0d5f7 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -49,8 +49,8 @@ if [ "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_USE_3DNOW y fi -if [ "$CONFIG_PROC_FS" = "y" ]; then - tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +if [ "$CONFIG_DEVFS_FS" = "y" ]; then + tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE fi choice 'High Memory Support' \ @@ -139,30 +139,31 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -source drivers/parport/Config.in +bool 'Power Management support' CONFIG_PM -bool 'ACPI support' CONFIG_ACPI +dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM if [ "$CONFIG_ACPI" != "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP + bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP fi fi -tristate 'Advanced Power Management BIOS support' CONFIG_APM +dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM if [ "$CONFIG_APM" != "n" ]; then - bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND - bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE - bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE - bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE - bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT - bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS - bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF + bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND + bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE + bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE + bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK + bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE + bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT + bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS + bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi endmenu +source drivers/parport/Config.in source drivers/pnp/Config.in diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 34b453c2c..f2517c27d 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -27,7 +27,6 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y -# CONFIG_MICROCODE is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set @@ -74,9 +73,10 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y -# CONFIG_PARPORT is not set +CONFIG_PM=y CONFIG_ACPI=y # CONFIG_APM is not set +# CONFIG_PARPORT is not set # # Plug and Play configuration @@ -96,6 +96,7 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -264,6 +265,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set CONFIG_DUMMY=m +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 3b7bb1258..6671bb35b 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -40,7 +40,6 @@ else endif endif -ifeq ($(CONFIG_PROC_FS),y) ifeq ($(CONFIG_MICROCODE),y) OX_OBJS += microcode.o else @@ -48,7 +47,6 @@ else MX_OBJS += microcode.o endif endif -endif ifeq ($(CONFIG_ACPI),y) O_OBJS += acpi.o diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 6228805db..b19097420 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -977,11 +977,9 @@ static void acpi_enter_sx(acpi_sstate_t state) typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK); - if (state != ACPI_S0) { - acpi_sleep_start = get_cmos_time(); - acpi_enter_dx(ACPI_D3); - acpi_sleep_state = state; - } + acpi_sleep_start = get_cmos_time(); + acpi_enter_dx(ACPI_D3); + acpi_sleep_state = state; // clear wake status acpi_write_pm1_status(acpi_facp, ACPI_WAK); @@ -996,17 +994,11 @@ static void acpi_enter_sx(acpi_sstate_t state) outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt); } - if (state == ACPI_S0) { - acpi_sleep_state = state; - acpi_enter_dx(ACPI_D0); - acpi_sleep_start = 0; - } - else if (state == ACPI_S1) { - // wait until S1 is entered - while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ; - // finished sleeping, update system time - acpi_update_clock(); - } + // wait until S1 is entered + while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ; + // finished sleeping, update system time + acpi_update_clock(); + acpi_enter_dx(ACPI_D0); } } @@ -1292,7 +1284,6 @@ static int acpi_do_sleep(ctl_table *ctl, { #ifdef CONFIG_ACPI_S1_SLEEP acpi_enter_sx(ACPI_S1); - acpi_enter_sx(ACPI_S0); #endif } file->f_pos += *len; diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index ec33f2269..b14f8caf3 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -131,7 +131,7 @@ static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; static void end_8259A_irq (unsigned int irq) { - if (!(irq_desc[irq].status & IRQ_DISABLED)) + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_8259A_irq(irq); } diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 129a587f0..02669540f 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/sched.h> @@ -1160,7 +1161,7 @@ static void end_level_ioapic_irq (unsigned int i) static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } -static void set_ioapic_affinity (unsigned int irq, unsigned int mask) +static void set_ioapic_affinity (unsigned int irq, unsigned long mask) { unsigned long flags; /* diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 7054249e6..4163626f4 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -32,7 +32,6 @@ #include <linux/kernel_stat.h> #include <linux/irq.h> #include <linux/proc_fs.h> -#include <linux/irq.h> #include <asm/io.h> #include <asm/smp.h> @@ -184,24 +183,43 @@ int get_irq_list(char *buf) unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; +extern void show_stack(unsigned long* esp); + static void show(char * str) { int i; - unsigned long *stack; int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%d %d]\n", - irqs_running(), local_irq_count(0), local_irq_count(1)); - printk("bh: %d [%d %d]\n", - spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count(0), local_bh_count(1)); - stack = (unsigned long *) &stack; - for (i = 40; i ; i--) { - unsigned long x = *++stack; - if (x > (unsigned long) &get_option && x < (unsigned long) &vsprintf) { - printk("<[%08lx]> ", x); + printk("irq: %d [",irqs_running()); + for(i=0;i < smp_num_cpus;i++) + printk(" %d",local_irq_count(i)); + printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); + for(i=0;i < smp_num_cpus;i++) + printk(" %d",local_bh_count(i)); + + printk(" ]\nStack dumps:"); + for(i=0;i< smp_num_cpus;i++) { + unsigned long esp; + if(i==cpu) + continue; + printk("\nCPU %d:",i); + esp = init_tss[i].esp0; + if(esp==NULL) { + /* tss->esp0 is set to NULL in cpu_init(), + * it's initialized when the cpu returns to user + * space. -- manfreds + */ + printk(" <unknown> "); + continue; } - } + esp &= ~(THREAD_SIZE-1); + esp += sizeof(struct task_struct); + show_stack((void*)esp); + } + printk("\nCPU %d:",cpu); + show_stack(NULL); + printk("\n"); } #define MAXCOUNT 100000000 @@ -874,7 +892,7 @@ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 @@ -883,7 +901,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, { if (count < HEX_DIGITS+1) return -EINVAL; - return sprintf (page, "%08x\n", irq_affinity[(int)data]); + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); } static unsigned int parse_hex_value (const char *buffer, @@ -926,7 +944,7 @@ out: static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { - int irq = (int) data, full_count = count, err; + int irq = (long) data, full_count = count, err; unsigned long new_value; if (!irq_desc[irq].handler->set_affinity) @@ -993,7 +1011,7 @@ static void register_irq_proc (unsigned int irq) entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); entry->nlink = 1; - entry->data = (void *)irq; + entry->data = (void *)(long)irq; entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 84490b40b..f858d7da9 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -23,20 +23,23 @@ * 1.02 21 February 2000, Tigran Aivazian <tigran@sco.com> * Added 'device trimming' support. open(O_WRONLY) zeroes * and frees the saved copy of applied microcode. + * 1.03 29 February 2000, Tigran Aivazian <tigran@sco.com> + * Made to use devfs (/dev/cpu/microcode) + cleanups. */ #include <linux/init.h> +#include <linux/slab.h> #include <linux/sched.h> #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/smp_lock.h> -#include <linux/proc_fs.h> +#include <linux/devfs_fs_kernel.h> #include <asm/msr.h> #include <asm/uaccess.h> #include <asm/processor.h> -#define MICROCODE_VERSION "1.02" +#define MICROCODE_VERSION "1.03" MODULE_DESCRIPTION("CPU (P6) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>"); @@ -60,9 +63,10 @@ static void do_update_one(void *); static unsigned long microcode_status = 0; /* the actual array of microcode blocks, each 2048 bytes */ -static struct microcode * microcode = NULL; +static struct microcode *microcode = NULL; static unsigned int microcode_num = 0; static char *mc_applied = NULL; /* holds an array of applied microcode blocks */ +static unsigned int mc_fsize; /* used often, so compute once at microcode_init() */ static struct file_operations microcode_fops = { read: microcode_read, @@ -71,23 +75,25 @@ static struct file_operations microcode_fops = { release: microcode_release, }; -static struct proc_dir_entry *proc_microcode; +static devfs_handle_t devfs_handle; static int __init microcode_init(void) { - proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver); - if (!proc_microcode) { - printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n"); - return -ENOMEM; - } - proc_microcode->proc_fops = µcode_fops; + devfs_handle = devfs_register(NULL, "cpu/microcode", 0, DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUSR | S_IWUSR, 0, 0, µcode_fops, NULL); + if (!devfs_handle) { + printk(KERN_ERR "microcode: can't create /dev/cpu/microcode\n"); + return -ENOMEM; + } + /* XXX assume no hotplug CPUs so smp_num_cpus does not change */ + mc_fsize = smp_num_cpus * sizeof(struct microcode); printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); return 0; } static void __exit microcode_exit(void) { - remove_proc_entry("microcode", proc_root_driver); + devfs_unregister(devfs_handle); if (mc_applied) kfree(mc_applied); printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); @@ -108,25 +114,21 @@ static int microcode_open(struct inode *inode, struct file *file) if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) return -EBUSY; - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - proc_microcode->size = 0; - if (mc_applied) { - memset(mc_applied, 0, smp_num_cpus * sizeof(struct microcode)); - kfree(mc_applied); - mc_applied = NULL; - } + if ((file->f_flags & O_ACCMODE) == O_WRONLY && mc_applied) { + devfs_set_file_size(devfs_handle, 0); + memset(mc_applied, 0, mc_fsize); + kfree(mc_applied); + mc_applied = NULL; } MOD_INC_USE_COUNT; - return 0; } static int microcode_release(struct inode *inode, struct file *file) { - MOD_DEC_USE_COUNT; - clear_bit(MICROCODE_IS_OPEN, µcode_status); + MOD_DEC_USE_COUNT; return 0; } @@ -156,19 +158,17 @@ static int do_microcode_update(void) memcpy(m, µcode[update_req[i].slot], sizeof(struct microcode)); } } - return error ? -EIO : 0; + return error; } static void do_update_one(void *arg) { - struct update_req *req; - struct cpuinfo_x86 * c; + int cpu_num = smp_processor_id(); + struct cpuinfo_x86 *c = cpu_data + cpu_num; + struct update_req *req = (struct update_req *)arg + cpu_num; unsigned int pf = 0, val[2], rev, sig; - int i, cpu_num; + int i; - cpu_num = smp_processor_id(); - c = cpu_data + cpu_num; - req = (struct update_req *)arg + cpu_num; req->err = 1; /* be pessimistic */ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6) @@ -210,8 +210,8 @@ static void do_update_one(void *arg) req->err = 0; req->slot = i; - printk(KERN_ERR "microcode: CPU%d microcode updated " - "from revision %d to %d, date=%08x\n", + printk(KERN_ERR "microcode: CPU%d updated from revision " + "%d to %d, date=%08x\n", cpu_num, rev, val[1], m->date); } break; @@ -220,12 +220,10 @@ static void do_update_one(void *arg) static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) { - size_t fsize = smp_num_cpus * sizeof(struct microcode); - - if (!proc_microcode->size || *ppos >= fsize) - return 0; /* EOF */ - if (*ppos + len > fsize) - len = fsize - *ppos; + if (*ppos >= mc_fsize) + return 0; + if (*ppos + len > mc_fsize) + len = mc_fsize - *ppos; if (copy_to_user(buf, mc_applied + *ppos, len)) return -EFAULT; *ppos += len; @@ -242,33 +240,34 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l return -EINVAL; } if (!mc_applied) { - int size = smp_num_cpus * sizeof(struct microcode); - mc_applied = kmalloc(size, GFP_KERNEL); + mc_applied = kmalloc(mc_fsize, GFP_KERNEL); if (!mc_applied) { - printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); + printk(KERN_ERR "microcode: out of memory for saved microcode\n"); return -ENOMEM; } - memset(mc_applied, 0, size); + memset(mc_applied, 0, mc_fsize); } lock_kernel(); microcode_num = len/sizeof(struct microcode); microcode = vmalloc(len); if (!microcode) { - unlock_kernel(); - return -ENOMEM; + ret = -ENOMEM; + goto out_unlock; } if (copy_from_user(microcode, buf, len)) { - vfree(microcode); - unlock_kernel(); - return -EFAULT; + ret = -EFAULT; + goto out_vfree; } - ret = do_microcode_update(); - if (!ret) { - proc_microcode->size = smp_num_cpus * sizeof(struct microcode); - ret = (ssize_t)len; + if(do_microcode_update()) { + ret = -EIO; + goto out_vfree; } + devfs_set_file_size(devfs_handle, mc_fsize); + ret = (ssize_t)len; +out_vfree: vfree(microcode); +out_unlock: unlock_kernel(); return ret; } diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index d5b2b0062..a76c92d25 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -1044,6 +1044,45 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt) printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); } +static void set_level_irq(unsigned irq) +{ + unsigned char mask = 1 << (irq & 7); + unsigned int port = 0x4d0 + (irq >> 3); + unsigned char val = inb(port); + + if (val & mask) { + printk("PCI irq %d was level\n", irq); + return; + } + printk("PCI irq %d was edge, turning into level-triggered\n", irq); + outb(val | mask, port); +} + +static int ali_set_irq(struct pci_dev *router, unsigned pirq, unsigned irq) +{ + if (irq < 15) { + static unsigned char irqmap[16] = { + 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 + }; + unsigned char val = irqmap[irq]; + if (val && pirq < 8) { + u8 byte; + unsigned offset = 0x48 + (pirq >> 1); + unsigned shift = (pirq & 1) << 2; + pci_read_config_byte(router, offset, &byte); + printk("ALI: old %04x=%02x\n", offset, byte); + byte &= ~(0xf << shift); + byte |= val << shift; + printk("ALI: new %04x=%02x\n", offset, byte); + pci_write_config_byte(router, offset, byte); + set_level_irq(irq); + return irq; + } + } + return 0; +} + + /* * In case BIOS forgets to tell us about IRQ, we try to look it up in the routing * table, but unfortunately we have to know the interrupt router chip. @@ -1135,6 +1174,10 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r DBG(" -> [PIIX] sink\n"); break; case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): + newirq = ali_set_irq(router, pirq-1, newirq); + if (newirq) + msg = "ALI"; + break; default: DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); if (newirq && mask == (1 << newirq)) { diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 19f7022a4..a043b4cfe 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -693,7 +693,6 @@ asmlinkage int sys_execve(struct pt_regs regs) int error; char * filename; - lock_kernel(); filename = getname((char *) regs.ebx); error = PTR_ERR(filename); if (IS_ERR(filename)) @@ -703,7 +702,6 @@ asmlinkage int sys_execve(struct pt_regs regs) current->flags &= ~PF_DTRACE; putname(filename); out: - unlock_kernel(); return error; } diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index a973746b9..d9af88d82 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -419,13 +419,19 @@ static void setup_frame(int sig, struct k_sigaction *ka, ? current->exec_domain->signal_invmap[sig] : sig), &frame->sig); + if (err) + goto give_sigsegv; err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); + if (err) + goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } + if (err) + goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -486,6 +492,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= __copy_to_user(&frame->info, info, sizeof(*info)); + if (err) + goto give_sigsegv; /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); @@ -497,6 +505,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 7400b628b..3a7004970 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> +#include <linux/interrupt.h> #ifdef CONFIG_MCA #include <linux/mca.h> diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 8b1324520..b9e535a71 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -631,13 +631,14 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + if (start < end) + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(mem_map + MAP_NR(start)); set_page_count(mem_map+MAP_NR(start), 1); free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif diff --git a/arch/mips/arc/console.c b/arch/mips/arc/console.c index 4675eb4a1..4de5130fb 100644 --- a/arch/mips/arc/console.c +++ b/arch/mips/arc/console.c @@ -4,8 +4,9 @@ * Copyright (C) 1996 David S. Miller (dm@sgi.com) * Compability with board caches, Ulf Carlsson * - * $Id: console.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ +#include <linux/config.h> #include <linux/init.h> #include <asm/sgialib.h> #include <asm/bcache.h> diff --git a/arch/mips/arc/init.c b/arch/mips/arc/init.c index 32117b858..81cf6cf74 100644 --- a/arch/mips/arc/init.c +++ b/arch/mips/arc/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.3 1999/08/20 21:59:01 ralf Exp $ +/* $Id: init.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ * This file is subject to the terms and conditions of the GNU General Public+ * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -9,7 +9,6 @@ */ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/config.h> #include <asm/sgialib.h> diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c index 4582297c2..d1c530fda 100644 --- a/arch/mips/arc/memory.c +++ b/arch/mips/arc/memory.c @@ -4,7 +4,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: memory.c,v 1.9 2000/01/27 01:05:23 ralf Exp $ + * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -13,7 +13,6 @@ #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/swap.h> -#include <linux/config.h> #include <asm/sgialib.h> #include <asm/page.h> diff --git a/arch/mips/arc/printf.c b/arch/mips/arc/printf.c index 17e5fe352..78b1b5937 100644 --- a/arch/mips/arc/printf.c +++ b/arch/mips/arc/printf.c @@ -4,8 +4,9 @@ * * Copyright (C) 1996 David S. Miller (dm@sgi.com) * - * $Id: printf.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ +#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> diff --git a/arch/mips/baget/balo_supp.S b/arch/mips/baget/balo_supp.S index 6b79d22d3..96f2a8f50 100644 --- a/arch/mips/baget/balo_supp.S +++ b/arch/mips/baget/balo_supp.S @@ -1,10 +1,9 @@ -/* $Id$ +/* $Id: balo_supp.S,v 1.1 1999/01/17 03:49:38 ralf Exp $ * balo_supp.S: BAget Loader supplement * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov */ -#include <linux/config.h> #include <asm/asm.h> #include <asm/regdef.h> #include <asm/stackframe.h> diff --git a/arch/mips/baget/prom/init.c b/arch/mips/baget/prom/init.c index ad576f984..a87c004ec 100644 --- a/arch/mips/baget/prom/init.c +++ b/arch/mips/baget/prom/init.c @@ -3,10 +3,9 @@ * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * - * $Id: init.c,v 1.2 1999/08/17 22:18:38 ralf Exp $ + * $Id: init.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ #include <linux/init.h> -#include <linux/config.h> #include <asm/bootinfo.h> char arcs_cmdline[CL_SIZE]; diff --git a/arch/mips/baget/setup.c b/arch/mips/baget/setup.c index 07a7ede00..dd0a7733e 100644 --- a/arch/mips/baget/setup.c +++ b/arch/mips/baget/setup.c @@ -1,11 +1,10 @@ -/* $Id: setup.c,v 1.3 1999/08/13 17:07:26 harald Exp $ +/* $Id: setup.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ * * setup.c: Baget/MIPS specific setup, including init of the feature struct. * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * */ -#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> diff --git a/arch/mips/ddb5074/irq.c b/arch/mips/ddb5074/irq.c index 1faba4c5c..4fee350e2 100644 --- a/arch/mips/ddb5074/irq.c +++ b/arch/mips/ddb5074/irq.c @@ -4,9 +4,10 @@ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> * Sony Suprastructure Center Europe (SUPC-E), Brussels * - * $Id$ + * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ */ +#include <linux/config.h> #include <linux/init.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c index 50dffdcc2..e0f39c666 100644 --- a/arch/mips/ddb5074/pci.c +++ b/arch/mips/ddb5074/pci.c @@ -5,16 +5,14 @@ * Albert Dorofeev <albert@sonycom.com> * Sony Suprastructure Center Europe (SUPC-E), Brussels * - * $Id: pci.c,v 1.3 2000/02/16 01:45:55 ralf Exp $ + * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ */ #include <linux/init.h> -#include <linux/config.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/types.h> #include <linux/sched.h> -#include <linux/pci.h> #include <linux/ioport.h> #include <asm-mips/nile4.h> diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c index 421d4058b..27b31818a 100644 --- a/arch/mips/dec/prom/cmdline.c +++ b/arch/mips/dec/prom/cmdline.c @@ -3,11 +3,10 @@ * * Copyright (C) 1998 Harald Koerfgen * - * $Id: cmdline.c,v 1.1 1999/01/17 03:49:44 ralf Exp $ + * $Id: cmdline.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/config.h> #include <linux/string.h> #include <asm/bootinfo.h> diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index dbb1e98bc..6acacc1c4 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -3,10 +3,9 @@ * * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine * - * $Id: identify.c,v 1.1 1999/01/17 03:49:44 ralf Exp $ + * $Id: identify.c,v 1.2 1999/10/09 00:00:58 ralf Exp $ */ #include <linux/init.h> -#include <linux/config.h> #include <linux/kernel.h> #include <linux/string.h> diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 41ea11b98..fa9e68e6f 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -1,4 +1,4 @@ -/* $Id: irixelf.c,v 1.24 2000/02/04 07:40:23 ralf Exp $ +/* $Id: irixelf.c,v 1.25 2000/03/02 02:36:50 ralf Exp $ * * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. @@ -29,6 +29,7 @@ #include <linux/shm.h> #include <linux/personality.h> #include <linux/elfcore.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> @@ -449,29 +450,31 @@ static inline int look_for_irix_interpreter(char **name, *name = NULL; for(i = 0; i < pnum; i++, epp++) { - if(epp->p_type != PT_INTERP) + if (epp->p_type != PT_INTERP) continue; /* It is illegal to have two interpreters for one executable. */ - if(*name != NULL) + if (*name != NULL) goto out; *name = (char *) kmalloc((epp->p_filesz + strlen(IRIX_INTERP_PREFIX)), GFP_KERNEL); - if(!*name) + if (!*name) return -ENOMEM; strcpy(*name, IRIX_INTERP_PREFIX); retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16), epp->p_filesz, 1); - if(retval < 0) + if (retval < 0) goto out; old_fs = get_fs(); set_fs(get_ds()); + lock_kernel(); dentry = namei(*name); + unlock_kernel(); set_fs(old_fs); - if(IS_ERR(dentry)) { + if (IS_ERR(dentry)) { retval = PTR_ERR(dentry); goto out; } @@ -485,7 +488,9 @@ static inline int look_for_irix_interpreter(char **name, return 0; dput_and_out: + lock_kernel(); dput(dentry); + unlock_kernel(); out: kfree(*name); return retval; @@ -566,7 +571,9 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp, old_fs = get_fs(); set_fs(get_ds()); + lock_kernel(); dput(identry); + unlock_kernel(); if(*eentry == 0xffffffff) return -1; @@ -682,10 +689,10 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm, &interpreter_dentry, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); - if(retval) + if (retval) goto out_free_file; - if(elf_interpreter) { + if (elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); if(retval) goto out_free_interp; @@ -811,7 +818,9 @@ out: return retval; out_free_dentry: + lock_kernel(); dput(interpreter_dentry); + unlock_kernel(); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); diff --git a/arch/mips/kernel/r2300_misc.S b/arch/mips/kernel/r2300_misc.S index 149012a1f..30031e295 100644 --- a/arch/mips/kernel/r2300_misc.S +++ b/arch/mips/kernel/r2300_misc.S @@ -1,4 +1,4 @@ -/* $Id: r2300_misc.S,v 1.7 1999/10/09 00:00:58 ralf Exp $ +/* $Id: r2300_misc.S,v 1.8 1999/12/08 22:05:10 harald Exp $ * misc.S: Misc. exception handling code for R3000/R2000. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse @@ -10,8 +10,6 @@ * Copyright (c) 1998 Harald Koerfgen * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov */ -#include <linux/config.h> - #include <asm/asm.h> #include <asm/current.h> #include <asm/bootinfo.h> diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 0f5124280..d2df0dc20 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -1,4 +1,4 @@ -/* $Id: syscall.c,v 1.12 1999/12/04 03:59:00 ralf Exp $ +/* $Id: syscall.c,v 1.13 2000/02/04 07:40:23 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -129,7 +129,6 @@ asmlinkage int sys_execve(struct pt_regs regs) int error; char * filename; - lock_kernel(); filename = getname((char *) (long)regs.regs[4]); error = PTR_ERR(filename); if (IS_ERR(filename)) @@ -139,7 +138,6 @@ asmlinkage int sys_execve(struct pt_regs regs) putname(filename); out: - unlock_kernel(); return error; } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 362d6a760..0c07b8dd6 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -1,4 +1,4 @@ -/* $Id: sysirix.c,v 1.23 2000/02/04 07:40:23 ralf Exp $ +/* $Id: sysirix.c,v 1.24 2000/02/05 06:47:08 ralf Exp $ * * sysirix.c: IRIX system call emulation. * @@ -878,7 +878,6 @@ asmlinkage int irix_exec(struct pt_regs *regs) int error, base = 0; char *filename; - lock_kernel(); if(regs->regs[2] == 1000) base = 1; filename = getname((char *) (long)regs->regs[base + 4]); @@ -890,7 +889,6 @@ asmlinkage int irix_exec(struct pt_regs *regs) putname(filename); out: - unlock_kernel(); return error; } diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index a35da14d2..ea36ed5b2 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.13 1999/10/09 00:00:58 ralf Exp $ +/* $Id: time.c,v 1.14 2000/01/26 00:07:44 ralf Exp $ * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Copyright (C) 1996, 1997, 1998 Ralf Baechle @@ -6,6 +6,7 @@ * This file contains the time handling details for PC-style clocks as * found in some MIPS systems. */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/sched.h> diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c index afbbef5eb..cb5e1e66d 100644 --- a/arch/mips/mm/loadmmu.c +++ b/arch/mips/mm/loadmmu.c @@ -3,8 +3,9 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: loadmmu.c,v 1.14 2000/01/27 01:05:23 ralf Exp $ + * $Id: loadmmu.c,v 1.15 2000/02/24 00:12:40 ralf Exp $ */ +#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c index cab112c29..06d8573cb 100644 --- a/arch/mips/sgi/kernel/indy_int.c +++ b/arch/mips/sgi/kernel/indy_int.c @@ -1,4 +1,4 @@ -/* $Id: indy_int.c,v 1.17 2000/02/04 07:40:23 ralf Exp $ +/* $Id: indy_int.c,v 1.18 2000/03/02 02:36:50 ralf Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. @@ -9,7 +9,6 @@ * - Indigo2 changes * - Interrupt handling fixes */ -#include <linux/config.h> #include <linux/init.h> #include <linux/errno.h> diff --git a/arch/mips64/arc/init.c b/arch/mips64/arc/init.c index 496f296ef..b961fc899 100644 --- a/arch/mips64/arc/init.c +++ b/arch/mips64/arc/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.3 1999/10/19 20:51:45 ralf Exp $ +/* $Id: init.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -10,7 +10,6 @@ */ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/config.h> #include <asm/sgialib.h> diff --git a/arch/mips64/arc/memory.c b/arch/mips64/arc/memory.c index 78a37a841..58d4835ea 100644 --- a/arch/mips64/arc/memory.c +++ b/arch/mips64/arc/memory.c @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.4 2000/01/17 23:32:46 ralf Exp $ +/* $Id: memory.c,v 1.5 2000/01/27 23:21:57 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -13,7 +13,6 @@ * because on some machines like SGI IP27 the ARC memory configuration data * completly bogus and alternate easier to use mechanisms are available. */ -#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/types.h> @@ -21,7 +20,6 @@ #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/swap.h> -#include <linux/config.h> #include <asm/sgialib.h> #include <asm/page.h> diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index b40469cfc..4caa8e70d 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -134,6 +134,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set diff --git a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c index 6983cfdc2..109c4d37b 100644 --- a/arch/mips64/kernel/signal32.c +++ b/arch/mips64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: signal32.c,v 1.2 2000/02/18 00:03:48 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -8,7 +8,6 @@ * Copyright (C) 1994 - 1999 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include <linux/config.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> diff --git a/arch/mips64/kernel/syscall.c b/arch/mips64/kernel/syscall.c index 67d84f874..ea225ff08 100644 --- a/arch/mips64/kernel/syscall.c +++ b/arch/mips64/kernel/syscall.c @@ -1,4 +1,4 @@ -/* $Id: syscall.c,v 1.2 2000/01/29 01:41:59 ralf Exp $ +/* $Id: syscall.c,v 1.3 2000/02/04 07:40:24 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -7,7 +7,6 @@ * Copyright (C) 1995 - 1999 by Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/linkage.h> #include <linux/mm.h> @@ -109,7 +108,6 @@ asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs) int error; char * filename; - lock_kernel(); filename = getname((char *) (long)regs.regs[4]); error = PTR_ERR(filename); if (IS_ERR(filename)) @@ -119,7 +117,6 @@ asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs) putname(filename); out: - unlock_kernel(); return error; } diff --git a/arch/mips64/sgi-ip27/ip27-init.c b/arch/mips64/sgi-ip27/ip27-init.c index f6b3d6e09..e09bc6036 100644 --- a/arch/mips64/sgi-ip27/ip27-init.c +++ b/arch/mips64/sgi-ip27/ip27-init.c @@ -7,7 +7,6 @@ #include <asm/sn/klconfig.h> #include <asm/ioc3.h> #include <asm/mipsregs.h> -#include <asm/sn/klconfig.h> #include <asm/sn/gda.h> typedef unsigned long cpumask_t; /* into asm/sn/types.h */ diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c index c9e6fe150..d7ddb8682 100644 --- a/arch/mips64/sgi-ip27/ip27-irq.c +++ b/arch/mips64/sgi-ip27/ip27-irq.c @@ -1,11 +1,10 @@ -/* $Id: ip27-irq.c,v 1.6 2000/02/10 05:58:56 dagum Exp $ +/* $Id: ip27-irq.c,v 1.7 2000/03/02 02:36:50 ralf Exp $ * * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. * * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include <linux/config.h> #include <linux/init.h> #include <linux/errno.h> diff --git a/arch/mips64/sgi-ip27/ip27-rtc.c b/arch/mips64/sgi-ip27/ip27-rtc.c index bf85c06f2..e5f174ab1 100644 --- a/arch/mips64/sgi-ip27/ip27-rtc.c +++ b/arch/mips64/sgi-ip27/ip27-rtc.c @@ -192,16 +192,9 @@ static int rtc_release(struct inode *inode, struct file *file) */ static struct file_operations rtc_fops = { - NULL, /* No llseek (yet) */ - NULL, /* No read (yet) */ - NULL, /* No write */ - NULL, /* No readdir */ - NULL, /* No poll (yet) */ - rtc_ioctl, - NULL, /* No mmap */ - rtc_open, - NULL, /* flush */ - rtc_release + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, }; static struct miscdevice rtc_dev= diff --git a/arch/mips64/sgi-ip27/ip27-setup.c b/arch/mips64/sgi-ip27/ip27-setup.c index c97eeb8b6..f0d7d66ab 100644 --- a/arch/mips64/sgi-ip27/ip27-setup.c +++ b/arch/mips64/sgi-ip27/ip27-setup.c @@ -1,4 +1,4 @@ -/* $Id: ip27-setup.c,v 1.3 2000/01/21 22:34:03 ralf Exp $ +/* $Id: ip27-setup.c,v 1.6 2000/02/05 02:12:32 kanoj Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -19,7 +19,6 @@ #include <asm/sn/klconfig.h> #include <asm/ioc3.h> #include <asm/mipsregs.h> -#include <asm/sn/klconfig.h> /* Check against user dumbness. */ #ifdef CONFIG_VT diff --git a/arch/mips64/sgi-ip27/ip27-timer.c b/arch/mips64/sgi-ip27/ip27-timer.c index c75fa725f..ff6ea60e7 100644 --- a/arch/mips64/sgi-ip27/ip27-timer.c +++ b/arch/mips64/sgi-ip27/ip27-timer.c @@ -1,4 +1,4 @@ -/* $Id: ip27-timer.c,v 1.2 2000/01/27 01:05:24 ralf Exp $ +/* $Id: ip27-timer.c,v 1.3 2000/02/18 09:54:40 ulfc Exp $ * * Copytight (C) 1999 Ralf Baechle (ralf@gnu.org) * Copytight (C) 1999 Silicon Graphics, Inc. @@ -148,13 +148,10 @@ void do_settimeofday(struct timeval *tv) } /* Includes for ioc3_init(). */ -#include <linux/init.h> #include <asm/sn/types.h> #include <asm/sn/sn0/addrs.h> #include <asm/sn/sn0/hubni.h> #include <asm/sn/sn0/hubio.h> -#include <asm/sn/klconfig.h> -#include <asm/ioc3.h> #include <asm/pci/bridge.h> /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. diff --git a/arch/sparc/config.in b/arch/sparc/config.in index ebaa64806..756e531c2 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.86 2000/02/10 02:51:10 davem Exp $ +# $Id: config.in,v 1.87 2000/02/27 19:34:12 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -163,6 +163,7 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then tristate ' Dummy net driver support' CONFIG_DUMMY + tristate ' Bonding driver support' CONFIG_BONDING tristate ' PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 7589958c8..580d004d7 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -218,6 +218,7 @@ CONFIG_SCSI_FCAL=m # CONFIG_NETDEVICES=y CONFIG_DUMMY=m +CONFIG_BONDING=m CONFIG_PPP=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m @@ -240,7 +241,7 @@ CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index f0dbea065..e9b506e10 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.34 2000/02/18 13:48:48 davem Exp $ +/* $Id: ioport.c,v 1.35 2000/02/27 08:16:25 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 335eba208..b497201f5 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.13 2000/02/12 03:05:37 zaitcev Exp $ +/* $Id: pcic.c,v 1.14 2000/03/01 02:53:28 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -884,13 +884,6 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size { } -#if 0 -int pci_assign_resource(struct pci_dev *dev, int i) -{ - return -ENOSYS; /* :-)... actually implement this soon */ -} -#endif - int pcibios_enable_device(struct pci_dev *pdev) { return 0; diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index c24d8649c..d167d5de7 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.145 2000/01/29 01:08:56 anton Exp $ +/* $Id: process.c,v 1.146 2000/03/01 02:53:27 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -652,7 +652,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(regs->u_regs[UREG_G1] == 0) base = 1; - lock_kernel(); filename = getname((char *)regs->u_regs[base + UREG_I0]); error = PTR_ERR(filename); if(IS_ERR(filename)) @@ -661,7 +660,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs) (char **) regs->u_regs[base + UREG_I2], regs); putname(filename); out: - unlock_kernel(); return error; } diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index bee2a5574..47c6a5afd 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.95 2000/02/10 02:51:12 davem Exp $ +# $Id: config.in,v 1.99 2000/02/27 19:34:17 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -112,6 +112,7 @@ if [ "$CONFIG_PCI" = "y" ]; then define_bool CONFIG_IDEDMA_NEW_DRIVE_LISTINGS y define_bool CONFIG_BLK_DEV_NS87415 y define_bool CONFIG_BLK_DEV_CMD64X y + define_bool CONFIG_BLK_DEV_IDE_MODES y fi fi @@ -200,6 +201,7 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then tristate ' Dummy net driver support' CONFIG_DUMMY + tristate ' Bonding driver support' CONFIG_BONDING tristate ' PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 12e9432a7..7e7a45a70 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -136,6 +136,7 @@ CONFIG_IDEDMA_AUTO=y CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y CONFIG_BLK_DEV_NS87415=y CONFIG_BLK_DEV_CMD64X=y +CONFIG_BLK_DEV_IDE_MODES=y # # Networking options @@ -254,6 +255,7 @@ CONFIG_SCSI_FCAL=m # CONFIG_NETDEVICES=y CONFIG_DUMMY=m +CONFIG_BONDING=m CONFIG_PPP=m # CONFIG_PPP_ASYNC is not set # CONFIG_PPP_SYNC_TTY is not set diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ed9e49685..d2bc6baf5 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.84 2000/02/25 05:44:41 davem Exp $ +/* $Id: irq.c,v 1.85 2000/03/02 02:00:24 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -955,7 +955,7 @@ int probe_irq_off(unsigned long mask) void init_timers(void (*cfunc)(int, void *, struct pt_regs *), unsigned long *clock) { - unsigned long flags; + unsigned long pstate; extern unsigned long timer_tick_offset; int node, err; #ifdef __SMP__ @@ -978,31 +978,57 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *), prom_halt(); } - save_and_cli(flags); + /* Guarentee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); /* Set things up so user can access tick register for profiling - * purposes. + * purposes. Also workaround BB_ERRATA_1 by doing a dummy + * read back of %tick after writing it. */ __asm__ __volatile__(" sethi %%hi(0x80000000), %%g1 - sllx %%g1, 32, %%g1 - rd %%tick, %%g2 + ba,pt %%xcc, 1f + sllx %%g1, 32, %%g1 + .align 64 + 1: rd %%tick, %%g2 add %%g2, 6, %%g2 andn %%g2, %%g1, %%g2 wrpr %%g2, 0, %%tick -" : /* no outputs */ + rdpr %%tick, %%g0" + : /* no outputs */ : /* no inputs */ : "g1", "g2"); + /* Workaround for Spitfire Errata (#54 I think??), I discovered + * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch + * number 103640. + * + * On Blackbird writes to %tick_cmpr can fail, the + * workaround seems to be to execute the wr instruction + * at the start of an I-cache line, and perform a dummy + * read back from %tick_cmpr right after writing to it. -DaveM + */ __asm__ __volatile__(" rd %%tick, %%g1 - add %%g1, %0, %%g1 - wr %%g1, 0x0, %%tick_cmpr" + ba,pt %%xcc, 1f + add %%g1, %0, %%g1 + .align 64 + 1: wr %%g1, 0x0, %%tick_cmpr + rd %%tick_cmpr, %%g0" : /* no outputs */ : "r" (timer_tick_offset) : "g1"); - restore_flags(flags); + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); + sti(); } diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 3cf95bb86..cd28d9392 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.15 2000/02/08 05:11:29 jj Exp $ +/* $Id: pci.c,v 1.16 2000/03/01 02:53:33 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -218,11 +218,6 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size { } -int pci_assign_resource(struct pci_dev *dev, int i) -{ - return -ENOSYS; /* :-)... actually implement this soon */ -} - int pcibios_enable_device(struct pci_dev *pdev) { return 0; diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 503f5b875..dd71b1e92 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.103 2000/01/21 11:38:53 jj Exp $ +/* $Id: process.c,v 1.104 2000/03/01 02:53:32 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -779,24 +779,22 @@ asmlinkage int sparc_execve(struct pt_regs *regs) /* User register window flush is done by entry.S */ /* Check for indirect call. */ - if(regs->u_regs[UREG_G1] == 0) + if (regs->u_regs[UREG_G1] == 0) base = 1; - lock_kernel(); filename = getname((char *)regs->u_regs[base + UREG_I0]); error = PTR_ERR(filename); - if(IS_ERR(filename)) + if (IS_ERR(filename)) goto out; error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], (char **) regs->u_regs[base + UREG_I2], regs); putname(filename); - if(!error) { + if (!error) { fprs_write(0); current->thread.xfsr[0] = 0; current->thread.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: - unlock_kernel(); return error; } diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 273c12de1..175372877 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -119,6 +119,7 @@ extern void cpu_probe(void); void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); + unsigned long pstate; inherit_locked_prom_mappings(0); @@ -127,18 +128,37 @@ void __init smp_callin(void) cpu_probe(); - /* Master did this already, now is the time for us to do it. */ + /* Guarentee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + /* Set things up so user can access tick register for profiling + * purposes. Also workaround BB_ERRATA_1 by doing a dummy + * read back of %tick after writing it. + */ __asm__ __volatile__(" sethi %%hi(0x80000000), %%g1 - sllx %%g1, 32, %%g1 - rd %%tick, %%g2 + ba,pt %%xcc, 1f + sllx %%g1, 32, %%g1 + .align 64 +1: rd %%tick, %%g2 add %%g2, 6, %%g2 andn %%g2, %%g1, %%g2 wrpr %%g2, 0, %%tick -" : /* no outputs */ + rdpr %%tick, %%g0" + : /* no outputs */ : /* no inputs */ : "g1", "g2"); + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); + smp_setup_percpu_timer(); __sti(); @@ -598,7 +618,7 @@ extern void update_one_process(struct task_struct *p, unsigned long ticks, void smp_percpu_timer_interrupt(struct pt_regs *regs) { - unsigned long compare, tick; + unsigned long compare, tick, pstate; int cpu = smp_processor_id(); int user = user_mode(regs); @@ -664,27 +684,87 @@ do { hardirq_enter(cpu); \ prof_counter(cpu) = prof_multiplier(cpu); } + /* Guarentee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + /* Workaround for Spitfire Errata (#54 I think??), I discovered + * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch + * number 103640. + * + * On Blackbird writes to %tick_cmpr can fail, the + * workaround seems to be to execute the wr instruction + * at the start of an I-cache line, and perform a dummy + * read back from %tick_cmpr right after writing to it. -DaveM + * + * Just to be anal we add a workaround for Spitfire + * Errata 50 by preventing pipeline bypasses on the + * final read of the %tick register into a compare + * instruction. The Errata 50 description states + * that %tick is not prone to this bug, but I am not + * taking any chances. + */ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" - "add %0, %2, %0\n\t" - "wr %0, 0x0, %%tick_cmpr\n\t" - "rd %%tick, %1" + "ba,pt %%xcc, 1f\n\t" + " add %0, %2, %0\n\t" + ".align 64\n" + "1: wr %0, 0x0, %%tick_cmpr\n\t" + "rd %%tick_cmpr, %%g0\n\t" + "rd %%tick, %1\n\t" + "mov %1, %1" : "=&r" (compare), "=r" (tick) : "r" (current_tick_offset)); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); } while (tick >= compare); } static void __init smp_setup_percpu_timer(void) { int cpu = smp_processor_id(); + unsigned long pstate; prof_counter(cpu) = prof_multiplier(cpu) = 1; - __asm__ __volatile__("rd %%tick, %%g1\n\t" - "add %%g1, %0, %%g1\n\t" - "wr %%g1, 0x0, %%tick_cmpr" + /* Guarentee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + /* Workaround for Spitfire Errata (#54 I think??), I discovered + * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch + * number 103640. + * + * On Blackbird writes to %tick_cmpr can fail, the + * workaround seems to be to execute the wr instruction + * at the start of an I-cache line, and perform a dummy + * read back from %tick_cmpr right after writing to it. -DaveM + */ + __asm__ __volatile__(" + rd %%tick, %%g1 + ba,pt %%xcc, 1f + add %%g1, %0, %%g1 + .align 64 + 1: wr %%g1, 0x0, %%tick_cmpr + rd %%tick_cmpr, %%g0" + : /* no outputs */ + : "r" (current_tick_offset) + : "g1"); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : /* no outputs */ - : "r" (current_tick_offset) - : "g1"); + : "r" (pstate)); } void __init smp_tick_init(void) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 1ebb7772c..6e2d566b2 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.132 2000/02/16 07:31:35 davem Exp $ +/* $Id: sys_sparc32.c,v 1.133 2000/03/01 02:53:33 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -3086,7 +3086,10 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); + lock_kernel(); dentry = open_namei(filename, 0, 0); + unlock_kernel(); + retval = PTR_ERR(dentry); if (IS_ERR(dentry)) return retval; @@ -3097,11 +3100,15 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count32(argv)) < 0) { + lock_kernel(); dput(dentry); + unlock_kernel(); return bprm.argc; } if ((bprm.envc = count32(envp)) < 0) { + lock_kernel(); dput(dentry); + unlock_kernel(); return bprm.envc; } @@ -3129,8 +3136,11 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) out: /* Something went wrong, return the inode and free the argument pages*/ - if (bprm.dentry) + if (bprm.dentry) { + lock_kernel(); dput(bprm.dentry); + unlock_kernel(); + } for (i=0 ; i<MAX_ARG_PAGES ; i++) if (bprm.page[i]) @@ -3154,7 +3164,6 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if((u32)regs->u_regs[UREG_G1] == 0) base = 1; - lock_kernel(); filename = getname32((char *)AA(regs->u_regs[base + UREG_I0])); error = PTR_ERR(filename); if(IS_ERR(filename)) @@ -3171,7 +3180,6 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) regs->tstate &= ~TSTATE_PEF; } out: - unlock_kernel(); return error; } diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 57f5b1622..e599b48cb 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.23 1999/09/21 14:35:27 davem Exp $ +/* $Id: time.c,v 1.24 2000/03/02 02:00:25 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -69,20 +69,53 @@ static __inline__ void timer_check_rtc(void) static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - unsigned long ticks; + unsigned long ticks, pstate; write_lock(&xtime_lock); do { do_timer(regs); + /* Guarentee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + /* Workaround for Spitfire Errata (#54 I think??), I discovered + * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch + * number 103640. + * + * On Blackbird writes to %tick_cmpr can fail, the + * workaround seems to be to execute the wr instruction + * at the start of an I-cache line, and perform a dummy + * read back from %tick_cmpr right after writing to it. -DaveM + * + * Just to be anal we add a workaround for Spitfire + * Errata 50 by preventing pipeline bypasses on the + * final read of the %tick register into a compare + * instruction. The Errata 50 description states + * that %tick is not prone to this bug, but I am not + * taking any chances. + */ __asm__ __volatile__(" rd %%tick_cmpr, %0 - add %0, %2, %0 - wr %0, 0, %%tick_cmpr - rd %%tick, %1" + ba,pt %%xcc, 1f + add %0, %2, %0 + .align 64 + 1: wr %0, 0, %%tick_cmpr + rd %%tick_cmpr, %%g0 + rd %%tick, %1 + mov %1, %1" : "=&r" (timer_tick_compare), "=r" (ticks) : "r" (timer_tick_offset)); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); } while (ticks >= timer_tick_compare); timer_check_rtc(); |