diff options
| author | David S. Miller <davem@nuts.davemloft.net> | 2004-04-22 01:25:25 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.davemloft.net> | 2004-04-22 01:25:25 -0700 |
| commit | 88d0505c93f592c135ea730df4cebad96fd0df64 (patch) | |
| tree | 950f1cf8636de5a1aab640b59cd92764b0f14c7c | |
| parent | 16a76bdbafd6c681dd15419183308bba1dd58063 (diff) | |
| parent | 98a5d354daf5357590bfc25521c91d67dc93de96 (diff) | |
Merge nuts.davemloft.net:/disk1/BK/network-2.6
into nuts.davemloft.net:/disk1/BK/net-2.6
155 files changed, 4875 insertions, 1374 deletions
@@ -1944,6 +1944,12 @@ S: 8786 Niwot Road S: Niwot, Colorado 80503 S: USA +N: Pete Popov +E: pete_popov@yahoo.com +D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging +S: San Jose, CA 95134 +S: USA + N: Robert M. Love E: rml@tech9.net E: rml@ufl.edu diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt new file mode 100644 index 000000000000..78a77624a716 --- /dev/null +++ b/Documentation/s390/crypto/crypto-API.txt @@ -0,0 +1,83 @@ +crypto-API support for z990 Message Security Assist (MSA) instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +AUTHOR: Thomas Spatzier (tspat@de.ibm.com) + + +1. Introduction crypto-API +~~~~~~~~~~~~~~~~~~~~~~~~~~ +See Documentation/crypto/api-intro.txt for an introduction/description of the +kernel crypto API. +According to api-intro.txt support for z990 crypto instructions has been added +in the algorithm api layer of the crypto API. Several files containing z990 +optimized implementations of crypto algorithms are placed in the +arch/s390/crypto directory. + + +2. Probing for availability of MSA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It should be possible to use Kernels with the z990 crypto implementations both +on machines with MSA available an on those without MSA (pre z990 or z990 +without MSA). Therefore a simple probing mechanisms has been implemented: +In the init function of each crypto module the availability of MSA and of the +respective crypto algorithm in particular will be tested. If the algorithm is +available the module will load and register its algorithm with the crypto API. + +If the respective crypto algorithm is not available, the init function will +return -ENOSYS. In that case a fallback to the standard software implementation +of the crypto algorithm must be taken ( -> the standard crypto modules are +also build when compiling the kernel). + + +3. Ensuring z990 crypto module preference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If z990 crypto instructions are available the optimized modules should be +preferred instead of standard modules. + +3.1. compiled-in modules +~~~~~~~~~~~~~~~~~~~~~~~~ +For compiled-in modules it has to be ensured that the z990 modules are linked +before the standard crypto modules. Then, on system startup the init functions +of z990 crypto modules will be called first and query for availability of z990 +crypto instructions. If instruction is available, the z990 module will register +its crypto algorithm implementation -> the load of the standard module will fail +since the algorithm is already registered. +If z990 crypto instruction is not available the load of the z990 module will +fail -> the standard module will load and register its algorithm. + +3.2. dynamic modules +~~~~~~~~~~~~~~~~~~~~ +A system administrator has to take care of giving preference to z990 crypto +modules. If MSA is available appropriate lines have to be added to +/etc/modprobe.conf. + +Example: z990 crypto instruction for SHA1 algorithm is available + + add the following line to /etc/modprobe.conf (assuming the + z990 crypto modules for SHA1 is called sha1_z990): + + alias sha1 sha1_z990 + + -> when the sha1 algorithm is requested through the crypto API + (which has a module autoloader) the z990 module will be loaded. + +TBD: a userspace module probin mechanism + something like 'probe sha1 sha1_z990 sha1' in modprobe.conf + -> try module sha1_z990, if it fails to load load standard module sha1 + the 'probe' statement is currently not supported in modprobe.conf + + +4. Currently implemented z990 crypto algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following crypto algorithms with z990 MSA support are currently implemented. +The name of each algorithm under which it is registered in crypto API and the +name of the respective module is given in square brackets. + +- SHA1 Digest Algorithm [sha1 -> sha1_z990] +- DES Encrypt/Decrypt Algorithm (64bit key) [des -> des_z990] +- Tripple DES Encrypt/Decrypt Algorithm (128bit key) [des3_ede128 -> des_z990] +- Tripple DES Encrypt/Decrypt Algorithm (192bit key) [des3_ede -> des_z990] + +In order to load, for example, the sha1_z990 module when the sha1 algorithm is +requested (see 3.2.) add 'alias sha1 sha1_z990' to /etc/modprobe.conf. + @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 6 -EXTRAVERSION =-rc1 +EXTRAVERSION =-rc2 NAME=Zonked Quokka # *DOCUMENTATION* diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 0e317230f81e..c51bf8dbfc8a 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -415,16 +415,12 @@ init_irq_proc (void) #endif /* - * Create entries for all existing IRQs. If the number of IRQs - * is greater the 1/4 the total dynamic inode space for /proc, - * don't pollute the inode space + * Create entries for all existing IRQs. */ - if (ACTUAL_NR_IRQS < (PROC_NDYNAMIC / 4)) { - for (i = 0; i < ACTUAL_NR_IRQS; i++) { - if (irq_desc[i].handler == &no_irq_type) - continue; - register_irq_proc(i); - } + for (i = 0; i < ACTUAL_NR_IRQS; i++) { + if (irq_desc[i].handler == &no_irq_type) + continue; + register_irq_proc(i); } } diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 8906f66b65e7..52348791ce1e 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -137,18 +137,6 @@ dik_show_trace(unsigned long *sp) printk("\n"); } -void show_trace_task(struct task_struct * tsk) -{ - struct thread_info *ti = tsk->thread_info; - unsigned long fp, sp = ti->pcb.ksp, base = (unsigned long) ti; - - if (sp > base && sp+6*8 < base + 16*1024) { - fp = ((unsigned long*)sp)[6]; - if (fp > sp && fp < base + 16*1024) - dik_show_trace((unsigned long *)fp); - } -} - static int kstack_depth_to_print = 24; void show_stack(struct task_struct *task, unsigned long *sp) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3a1fd4205e01..43329eaf2f9b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -145,6 +145,11 @@ config ARCH_S3C2410 config ARCH_OMAP bool "TI OMAP" +config ARCH_VERSATILE_PB + bool "Versatile PB" + help + This enables support for ARM Ltd Versatile PB board. + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -262,7 +267,7 @@ config ICST525 config ARM_AMBA bool - depends on ARCH_INTEGRATOR + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB default y config ISA @@ -514,7 +519,7 @@ config CMDLINE config LEDS bool "Timer and CPU usage LEDs" - depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP + depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE_PB help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. @@ -527,8 +532,8 @@ config LEDS system, but the driver will do nothing. config LEDS_TIMER - bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T) - depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP + bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE_PB) + depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE_PB default y if ARCH_EBSA110 help If you say Y here, one of the system LEDs (the green one on the @@ -543,7 +548,7 @@ config LEDS_TIMER config LEDS_CPU bool "CPU usage LED" - depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T) + depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE_PB) help If you say Y here, the red LED will be used to give a good real time indication of CPU usage, by lighting whenever the idle task diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 1f9f913fb63f..0dea4d3f5b4a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -94,6 +94,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_ADIFCC) := adifcc machine-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_S3C2410) := s3c2410 + machine-$(CONFIG_ARCH_VERSATILE_PB) := versatile TEXTADDR := $(textaddr-y) ifeq ($(incdir-y),) diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 32581b7883c3..65ba5bf38ae6 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -56,6 +56,9 @@ params_phys-$(CONFIG_ARCH_OMAP) := 0x10000100 initrd_phys-$(CONFIG_ARCH_OMAP) := 0x10800000 zreladdr-$(CONFIG_ARCH_S3C2410) := 0x30008000 params_phys-$(CONFIG_ARCH_S3C2410) := 0x30000100 + zreladdr-$(CONFIG_ARCH_VERSATILE_PB) := 0x00008000 +params_phys-$(CONFIG_ARCH_VERSATILE_PB) := 0x00000100 +initrd_phys-$(CONFIG_ARCH_VERSATILE_PB) := 0x00800000 ZRELADDR := $(zreladdr-y) ZTEXTADDR := $(ztextaddr-y) diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index 5db32be694c0..319b21e4fc78 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S @@ -550,6 +550,35 @@ 1002: @ exit busyuart .endm + +#elif defined(CONFIG_ARCH_VERSATILE_PB) + +#include <asm/hardware/amba_serial.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x10000000 + movne \rx, #0xf1000000 @ virtual base + orr \rx, \rx, #0x001F0000 + orr \rx, \rx, #0x00001000 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #UART01x_DR] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm #else #error Unknown architecture #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 9f65d5d21c1c..0bb77b9fb0ab 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -463,6 +463,37 @@ ENTRY(soft_irq_mask) .macro irq_prio_table .endm +#elif defined(CONFIG_ARCH_VERSATILE_PB) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =IO_ADDRESS(VERSATILE_VIC_BASE) + ldr \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status + mov \irqnr, #0 + teq \irqstat, #0 + beq 1003f + +1001: tst \irqstat, #15 + bne 1002f + add \irqnr, \irqnr, #4 + movs \irqstat, \irqstat, lsr #4 + bne 1001b +1002: tst \irqstat, #1 + bne 1003f + add \irqnr, \irqnr, #1 + movs \irqstat, \irqstat, lsr #1 + bne 1002b +1003: /* EQ will be set if no irqs pending */ + +@ clz \irqnr, \irqstat +@1003: /* EQ will be set if we reach MAXIRQNUM */ + .endm + + .macro irq_prio_table + .endm + #elif defined(CONFIG_ARCH_CLPS711X) #include <asm/hardware/clps7111.h> diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S index 304d7bc469e6..d3a81da57c3e 100644 --- a/arch/arm/lib/findbit.S +++ b/arch/arm/lib/findbit.S @@ -51,6 +51,39 @@ ENTRY(_find_next_zero_bit_le) add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +/* + * Purpose : Find a 'one' bit + * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit); + */ +ENTRY(_find_first_bit_le) + teq r1, #0 + beq 3f + mov r2, #0 +1: ldrb r3, [r0, r2, lsr #3] + movs r3, r3 + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer +2: cmp r2, r1 @ any more? + blo 1b +3: mov r0, r1 @ no free bits + RETINSTR(mov,pc,lr) + +/* + * Purpose : Find next 'one' bit + * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) + */ +ENTRY(_find_next_bit_le) + teq r1, #0 + beq 2b + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + ldrb r3, [r0, r2, lsr #3] + movs r3, r3, lsr ip @ shift off unused bits + bne .found + orr r2, r2, #7 @ if zero, then no bits here + add r2, r2, #1 @ align bit pointer + b 2b @ loop for next bit + #ifdef __ARMEB__ ENTRY(_find_first_zero_bit_be) @@ -78,6 +111,30 @@ ENTRY(_find_next_zero_bit_be) addeq r2, r2, #1 @ align bit pointer beq 2b @ loop for next bit +ENTRY(_find_first_bit_be) + teq r1, #0 + beq 3f + mov r2, #0 +1: eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] + movs r3, r3 + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer +2: cmp r2, r1 @ any more? + blo 1b +3: mov r0, r1 @ no free bits + RETINSTR(mov,pc,lr) + +ENTRY(_find_next_bit_be) + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] + movs r3, r3, lsr ip @ shift off unused bits + orreq r2, r2, #7 @ if zero, then no bits here + addeq r2, r2, #1 @ align bit pointer + beq 2b @ loop for next bit + #endif /* diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile new file mode 100644 index 000000000000..fbf6db8a2cbe --- /dev/null +++ b/arch/arm/mach-versatile/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the linux kernel. +# + +obj-y := core.o diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c new file mode 100644 index 000000000000..22c0254b4d0d --- /dev/null +++ b/arch/arm/mach-versatile/core.c @@ -0,0 +1,507 @@ +/* + * linux/arch/arm/mach-versatile/core.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/device.h> +#include <linux/sysdev.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/leds.h> +#include <asm/mach-types.h> +#include <asm/hardware/amba.h> + +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/mmc.h> + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Versatile Vectored Interrupt Controller. + */ +#define VA_VIC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) +#define VA_SIC_BASE IO_ADDRESS(VERSATILE_SIC_BASE) + +static void vic_mask_irq(unsigned int irq) +{ + irq -= IRQ_VIC_START; + writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); +} + +static void vic_unmask_irq(unsigned int irq) +{ + irq -= IRQ_VIC_START; + writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE); +} + +static struct irqchip vic_chip = { + .ack = vic_mask_irq, + .mask = vic_mask_irq, + .unmask = vic_unmask_irq, +}; + +static void sic_mask_irq(unsigned int irq) +{ + irq -= IRQ_SIC_START; + writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); +} + +static void sic_unmask_irq(unsigned int irq) +{ + irq -= IRQ_SIC_START; + writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET); +} + +static struct irqchip sic_chip = { + .ack = sic_mask_irq, + .mask = sic_mask_irq, + .unmask = sic_unmask_irq, +}; + +static void +sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS); + + if (status == 0) { + do_bad_IRQ(irq, desc, regs); + return; + } + + do { + irq = ffs(status) - 1; + status &= ~(1 << irq); + + irq += IRQ_SIC_START; + + desc = irq_desc + irq; + desc->handle(irq, desc, regs); + } while (status); +} + +#if 1 +#define IRQ_MMCI0A IRQ_VICSOURCE22 +#define IRQ_MMCI1A IRQ_VICSOURCE23 +#define IRQ_AACI IRQ_VICSOURCE24 +#define IRQ_ETH IRQ_VICSOURCE25 +#define PIC_MASK 0xFFD00000 +#else +#define IRQ_MMCI0A IRQ_SIC_MMCI0A +#define IRQ_MMCI1A IRQ_SIC_MMCI1A +#define IRQ_AACI IRQ_SIC_AACI +#define IRQ_ETH IRQ_SIC_ETH +#define PIC_MASK 0 +#endif + +static void __init versatile_init_irq(void) +{ + unsigned int i, value; + + /* Disable all interrupts initially. */ + + writel(0, VA_VIC_BASE + VIC_INT_SELECT); + writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE); + writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR); + writel(0, VA_VIC_BASE + VIC_IRQ_STATUS); + writel(0, VA_VIC_BASE + VIC_ITCR); + writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR); + + /* + * Make sure we clear all existing interrupts + */ + writel(0, VA_VIC_BASE + VIC_VECT_ADDR); + for (i = 0; i < 19; i++) { + value = readl(VA_VIC_BASE + VIC_VECT_ADDR); + writel(value, VA_VIC_BASE + VIC_VECT_ADDR); + } + + for (i = 0; i < 16; i++) { + value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); + writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4)); + } + + writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR); + + for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) { + if (i != IRQ_VICSOURCE31) { + set_irq_chip(i, &vic_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } + + set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); + vic_unmask_irq(IRQ_VICSOURCE31); + + /* Do second interrupt controller */ + writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); + + for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) { + if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) { + set_irq_chip(i, &sic_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } + + /* + * Interrupts on secondary controller from 0 to 8 are routed to + * source 31 on PIC. + * Interrupts from 21 to 31 are routed directly to the VIC on + * the corresponding number on primary controller. This is controlled + * by setting PIC_ENABLEx. + */ + writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE); +} + +static struct map_desc versatile_io_desc[] __initdata = { + { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE }, +#ifdef CONFIG_DEBUG_LL + { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, +#endif +#ifdef FIXME + { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, + { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, + { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, + { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, +#endif +}; + +static void __init versatile_map_io(void) +{ + iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); +} + +#define VERSATILE_REFCOUNTER (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) + +/* + * This is the VersatilePB sched_clock implementation. This has + * a resolution of 41.7ns, and a maximum value of about 179s. + */ +unsigned long long sched_clock(void) +{ + unsigned long long v; + + v = (unsigned long long)readl(VERSATILE_REFCOUNTER) * 125; + do_div(v, 3); + + return v; +} + + +#define VERSATILE_FLASHCTRL (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) + +static int versatile_flash_init(void) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); + + return 0; +} + +static void versatile_flash_exit(void) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); +} + +static void versatile_flash_set_vpp(int on) +{ + u32 val; + + val = __raw_readl(VERSATILE_FLASHCTRL); + if (on) + val |= VERSATILE_FLASHPROG_FLVPPEN; + else + val &= ~VERSATILE_FLASHPROG_FLVPPEN; + __raw_writel(val, VERSATILE_FLASHCTRL); +} + +static struct flash_platform_data versatile_flash_data = { + .map_name = "cfi_probe", + .width = 4, + .init = versatile_flash_init, + .exit = versatile_flash_exit, + .set_vpp = versatile_flash_set_vpp, +}; + +static struct resource versatile_flash_resource = { + .start = VERSATILE_FLASH_BASE, + .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device versatile_flash_device = { + .name = "armflash", + .id = 0, + .dev = { + .platform_data = &versatile_flash_data, + }, + .num_resources = 1, + .resource = &versatile_flash_resource, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = VERSATILE_ETH_BASE, + .end = VERSATILE_ETH_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_ETH, + .end = IRQ_ETH, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#define VERSATILE_SYSMCI (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET) + +static unsigned int mmc_status(struct device *dev) +{ + struct amba_device *adev = container_of(dev, struct amba_device, dev); + u32 mask; + + if (adev->res.start == VERSATILE_MMCI0_BASE) + mask = 1; + else + mask = 2; + + return readl(VERSATILE_SYSMCI) & mask; +} + +static struct mmc_platform_data mmc0_plat_data = { + .mclk = 33000000, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +static struct mmc_platform_data mmc1_plat_data = { + .mclk = 33000000, + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +#define AMBA_DEVICE(name,busid,base,plat) \ +static struct amba_device name##_device = { \ + .dev = { \ + .coherent_dma_mask = ~0, \ + .bus_id = busid, \ + .platform_data = plat, \ + }, \ + .res = { \ + .start = VERSATILE_##base##_BASE, \ + .end = (VERSATILE_##base##_BASE) + SZ_4K - 1,\ + .flags = IORESOURCE_MEM, \ + }, \ + .irq = base##_IRQ, \ + .dma = base##_DMA, \ +} + +#define AACI_IRQ { IRQ_AACI, NO_IRQ } +#define AACI_DMA { 0x80, 0x81 } +#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B } +#define MMCI0_DMA { 0x84, 0 } +#define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ } +#define KMI0_DMA { 0, 0 } +#define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ } +#define KMI1_DMA { 0, 0 } +#define UART3_IRQ { IRQ_SIC_UART3, NO_IRQ } +#define UART3_DMA { 0x86, 0x87 } +#define SCI1_IRQ { IRQ_SIC_SCI3, NO_IRQ } +#define SCI1_DMA { 0x88, 0x89 } +#define MMCI1_IRQ { IRQ_MMCI1A, IRQ_SIC_MMCI1B } +#define MMCI1_DMA { 0x85, 0 } + +/* + * These devices are connected directly to the multi-layer AHB switch + */ +#define SMC_IRQ { NO_IRQ, NO_IRQ } +#define SMC_DMA { 0, 0 } +#define MPMC_IRQ { NO_IRQ, NO_IRQ } +#define MPMC_DMA { 0, 0 } +#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } +#define CLCD_DMA { 0, 0 } +#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } +#define DMAC_DMA { 0, 0 } + +/* + * These devices are connected via the core APB bridge + */ +#define SCTL_IRQ { NO_IRQ, NO_IRQ } +#define SCTL_DMA { 0, 0 } +#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } +#define WATCHDOG_DMA { 0, 0 } +#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } +#define GPIO0_DMA { 0, 0 } +#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } +#define GPIO1_DMA { 0, 0 } +#define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } +#define GPIO2_DMA { 0, 0 } +#define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } +#define GPIO3_DMA { 0, 0 } +#define RTC_IRQ { IRQ_RTCINT, NO_IRQ } +#define RTC_DMA { 0, 0 } + +/* + * These devices are connected via the DMA APB bridge + */ +#define SCI_IRQ { IRQ_SCIINT, NO_IRQ } +#define SCI_DMA { 7, 6 } +#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } +#define UART0_DMA { 15, 14 } +#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } +#define UART1_DMA { 13, 12 } +#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } +#define UART2_DMA { 11, 10 } +#define SSP_IRQ { IRQ_SSPINT, NO_IRQ } +#define SSP_DMA { 9, 8 } + +/* FPGA Primecells */ +AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); +AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &mmc0_plat_data); +AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); +AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); +AMBA_DEVICE(uart3, "fpga:09", UART3, NULL); +AMBA_DEVICE(sci1, "fpga:0a", SCI1, NULL); +AMBA_DEVICE(mmc1, "fpga:0b", MMCI1, &mmc1_plat_data); + +/* DevChip Primecells */ +AMBA_DEVICE(smc, "dev:00", SMC, NULL); +AMBA_DEVICE(mpmc, "dev:10", MPMC, NULL); +AMBA_DEVICE(clcd, "dev:20", CLCD, NULL); +AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); +AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); +AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); +AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); +AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); +AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL); +AMBA_DEVICE(gpio3, "dev:e7", GPIO3, NULL); +AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); +AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); +AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); +AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); +AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); +AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); + +static struct amba_device *amba_devs[] __initdata = { + &dmac_device, + &uart0_device, + &uart1_device, + &uart2_device, + &uart3_device, + &smc_device, + &mpmc_device, + &clcd_device, + &sctl_device, + &wdog_device, + &gpio0_device, + &gpio1_device, + &gpio2_device, + &gpio3_device, + &rtc_device, + &sci0_device, + &ssp0_device, + &aaci_device, + &mmc0_device, + &kmi0_device, + &kmi1_device, + &sci1_device, + &mmc1_device, +}; + +#define VA_LEDS_BASE (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) + +static void versatile_leds_event(led_event_t ledevt) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(VA_LEDS_BASE); + + switch (ledevt) { + case led_idle_start: + val = val & ~VERSATILE_SYS_LED0; + break; + + case led_idle_end: + val = val | VERSATILE_SYS_LED0; + break; + + case led_timer: + val = val ^ VERSATILE_SYS_LED1; + break; + + case led_halted: + val = 0; + break; + + default: + break; + } + + writel(val, VA_LEDS_BASE); + local_irq_restore(flags); +} + +static void __init versatile_init(void) +{ + int i; + + platform_add_device(&versatile_flash_device); + platform_add_device(&smc91x_device); + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + amba_device_register(d, &iomem_resource); + } + + leds_event = versatile_leds_event; +} + +MACHINE_START(VERSATILE_PB, "ARM-Versatile PB") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000) + BOOT_PARAMS(0x00000100) + MAPIO(versatile_map_io) + INITIRQ(versatile_init_irq) + INIT_MACHINE(versatile_init) +MACHINE_END diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 67c0834959ac..d7968d6896ee 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -114,8 +114,9 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T - bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_OMAP1610 + bool "Support ARM926T processor" if ARCH_INTEGRATOR + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || ARCH_OMAP1610 + default y if ARCH_VERSATILE_PB select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_COPY_V4WB diff --git a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c index d2ffd9016c07..f0a49fec0d9e 100644 --- a/arch/arm26/kernel/traps.c +++ b/arch/arm26/kernel/traps.c @@ -165,18 +165,6 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) c_backtrace(fp, processor_mode(regs)); } -/* - * This is called from SysRq-T (show_task) to display the current - * call trace for each process. Very useful. - */ -void show_trace_task(struct task_struct *tsk) -{ - if (tsk != current) { - unsigned int fp = thread_saved_fp(tsk); - c_backtrace(fp, 0x10); - } -} - /* FIXME - this is probably wrong.. */ void show_stack(struct task_struct *task, unsigned long *sp) { dump_mem("Stack: ", (unsigned long)sp, 8192+(unsigned long)task->thread_info); diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index 2a757b825c44..d9e6565655f4 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -60,14 +60,6 @@ void show_trace(unsigned long * stack) } } -void show_trace_task(struct task_struct *tsk) -{ - /* TODO, this is not really useful since its called from - * SysRq-T and we don't have a keyboard.. :) - */ -} - - /* * These constants are for searching for possible module text * segments. MODULE_RANGE is a guess of how much space is likely diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c index 300e3279ca5a..253c87bc5b32 100644 --- a/arch/h8300/kernel/traps.c +++ b/arch/h8300/kernel/traps.c @@ -156,14 +156,8 @@ void show_stack(struct task_struct *task, unsigned long *esp) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_stack(tsk,(unsigned long *)tsk->thread.esp0); -} - void dump_stack(void) { show_stack(NULL,NULL); } - EXPORT_SYMBOL(dump_stack); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c index 12ff2d16f13f..8c056882df27 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c @@ -238,6 +238,34 @@ acpi_cpufreq_verify ( } +static unsigned long +acpi_cpufreq_guess_freq ( + struct cpufreq_acpi_io *data, + unsigned int cpu) +{ + if (cpu_khz) { + /* search the closest match to cpu_khz */ + unsigned int i; + unsigned long freq; + unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000; + + for (i=0; i < (data->acpi_data.state_count - 1); i++) { + freq = freqn; + freqn = data->acpi_data.states[i+1].core_frequency * 1000; + if ((2 * cpu_khz) > (freqn + freq)) { + data->acpi_data.state = i; + return (freq); + } + } + data->acpi_data.state = data->acpi_data.state_count - 1; + return (freqn); + } else + /* assume CPU is at P0... */ + data->acpi_data.state = 0; + return data->acpi_data.states[0].core_frequency * 1000; + +} + static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -290,11 +318,8 @@ acpi_cpufreq_cpu_init ( } policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* - * The current speed is unknown and not detectable by ACPI... argh! Assume - * it's P0, it will be set to this value later during initialization. - */ - policy->cur = data->acpi_data.states[0].core_frequency * 1000; + /* The current speed is unknown and not detectable by ACPI... */ + policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); /* table init */ for (i=0; i<=data->acpi_data.state_count; i++) @@ -306,7 +331,7 @@ acpi_cpufreq_cpu_init ( data->freq_table[i].frequency = CPUFREQ_TABLE_END; } - result = cpufreq_frequency_table_cpuinfo(policy, &data->freq_table[0]); + result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); if (result) { goto err_freqfree; } @@ -321,6 +346,7 @@ acpi_cpufreq_cpu_init ( (u32) data->acpi_data.states[i].power, (u32) data->acpi_data.states[i].transition_latency); + cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); return_VALUE(result); err_freqfree: @@ -345,6 +371,7 @@ acpi_cpufreq_cpu_exit ( ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit"); if (data) { + cpufreq_frequency_table_put_attr(policy->cpu); acpi_io_data[policy->cpu] = NULL; acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); kfree(data); @@ -354,6 +381,11 @@ acpi_cpufreq_cpu_exit ( } +static struct freq_attr* acpi_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static struct cpufreq_driver acpi_cpufreq_driver = { .verify = acpi_cpufreq_verify, .target = acpi_cpufreq_target, @@ -361,6 +393,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .exit = acpi_cpufreq_cpu_exit, .name = "acpi-cpufreq", .owner = THIS_MODULE, + .attr = acpi_cpufreq_attr, }; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 8b95e88c95d3..65246256fd07 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -17,6 +17,7 @@ #include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/cpufreq.h> #include <linux/slab.h> @@ -27,6 +28,11 @@ #include <asm/io.h> #include <asm/system.h> +#ifdef CONFIG_ACPI_PROCESSOR +#include <linux/acpi.h> +#include <acpi/processor.h> +#endif + #include "powernow-k7.h" #define DEBUG @@ -57,6 +63,17 @@ struct pst_s { u8 numpstates; }; +#ifdef CONFIG_ACPI_PROCESSOR +union powernow_acpi_control_t { + struct { + unsigned long fid:5, + vid:5, + sgtc:20, + res1:2; + } bits; + unsigned long val; +}; +#endif /* divide by 1000 to get VID. */ static int mobile_vid_table[32] = { @@ -74,6 +91,12 @@ static int fid_codes[32] = { 150, 225, 160, 165, 170, 180, -1, -1, }; +/* This parameter is used in order to force ACPI instead of legacy method for + * configuration purpose. + */ + +static int powernow_acpi_force; + static struct cpufreq_frequency_table *powernow_table; static unsigned int can_scale_bus; @@ -85,6 +108,14 @@ static unsigned int fsb; static unsigned int latency; static char have_a0; +static int check_fsb(unsigned int fsbspeed) +{ + int delta; + unsigned int f = fsb / 1000; + + delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; + return (delta < 5); +} static int check_powernow(void) { @@ -140,7 +171,8 @@ static int check_powernow(void) static int get_ranges (unsigned char *pst) { - unsigned int j, speed; + unsigned int j; + unsigned int speed; u8 fid, vid; powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); @@ -151,12 +183,12 @@ static int get_ranges (unsigned char *pst) for (j=0 ; j < number_scales; j++) { fid = *pst++; - powernow_table[j].frequency = fsb * fid_codes[fid] * 100; + powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; powernow_table[j].index = fid; /* lower 8 bits */ - speed = fsb * (fid_codes[fid]/10); + speed = powernow_table[j].frequency; + if ((fid_codes[fid] % 10)==5) { - speed += fsb/2; #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) if (have_a0 == 1) powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; @@ -164,7 +196,7 @@ static int get_ranges (unsigned char *pst) } dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, - fid_codes[fid] / 10, fid_codes[fid] % 10, speed); + fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); if (speed < minimum_speed) minimum_speed = speed; @@ -176,8 +208,6 @@ static int get_ranges (unsigned char *pst) dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); } - dprintk ("\n"); - powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; powernow_table[number_scales].index = 0; @@ -234,7 +264,8 @@ static void change_speed (unsigned int index) rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); cfid = fidvidstatus.bits.CFID; - freqs.old = fsb * fid_codes[cfid] * 100; + freqs.old = fsb * fid_codes[cfid] / 10; + freqs.new = powernow_table[index].frequency; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -262,19 +293,136 @@ static void change_speed (unsigned int index) } +#ifdef CONFIG_ACPI_PROCESSOR + +struct acpi_processor_performance *acpi_processor_perf; + +static int powernow_acpi_init(void) +{ + int i; + int retval = 0; + union powernow_acpi_control_t pc; + + if (acpi_processor_perf != NULL && powernow_table != NULL) { + retval = -EINVAL; + goto err0; + } + + acpi_processor_perf = kmalloc(sizeof(struct acpi_processor_performance), + GFP_KERNEL); + + if (!acpi_processor_perf) { + retval = -ENOMEM; + goto err0; + } + + memset(acpi_processor_perf, 0, sizeof(struct acpi_processor_performance)); + + if (acpi_processor_register_performance(acpi_processor_perf, 0)) { + retval = -EIO; + goto err1; + } + + if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + number_scales = acpi_processor_perf->state_count; + + if (number_scales < 2) { + retval = -ENODEV; + goto err2; + } + + powernow_table = kmalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL); + if (!powernow_table) { + retval = -ENOMEM; + goto err2; + } + + memset(powernow_table, 0, ((number_scales + 1) * sizeof(struct cpufreq_frequency_table))); + + pc.val = (unsigned long) acpi_processor_perf->states[0].control; + for (i = 0; i < number_scales; i++) { + u8 fid, vid; + unsigned int speed; + + pc.val = (unsigned long) acpi_processor_perf->states[i].control; + dprintk (KERN_INFO PFX "acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", + i, + (u32) acpi_processor_perf->states[i].core_frequency, + (u32) acpi_processor_perf->states[i].power, + (u32) acpi_processor_perf->states[i].transition_latency, + (u32) acpi_processor_perf->states[i].control, + pc.bits.sgtc); + + vid = pc.bits.vid; + fid = pc.bits.fid; + + powernow_table[i].frequency = fsb * fid_codes[fid] / 10; + powernow_table[i].index = fid; /* lower 8 bits */ + powernow_table[i].index |= (vid << 8); /* upper 8 bits */ + + speed = powernow_table[i].frequency; + + if ((fid_codes[fid] % 10)==5) { + if (have_a0 == 1) + powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; + } + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); + dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, + mobile_vid_table[vid]%1000); + + if (latency < pc.bits.sgtc) + latency = pc.bits.sgtc; + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + } + + powernow_table[i].frequency = CPUFREQ_TABLE_END; + powernow_table[i].index = 0; + + return 0; + +err2: + acpi_processor_unregister_performance(acpi_processor_perf, 0); +err1: + kfree(acpi_processor_perf); +err0: + printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n"); + acpi_processor_perf = NULL; + return retval; +} +#else +static int powernow_acpi_init(void) +{ + printk(KERN_INFO PFX "no support for ACPI processor found." + " Please recompile your kernel with ACPI processor\n"); + return -EINVAL; +} +#endif + static int powernow_decode_bios (int maxfid, int startvid) { struct psb_s *psb; struct pst_s *pst; - struct cpuinfo_x86 *c = cpu_data; unsigned int i, j; unsigned char *p; unsigned int etuple; unsigned int ret; etuple = cpuid_eax(0x80000001); - etuple &= 0xf00; - etuple |= (c->x86_model<<4)|(c->x86_mask); for (i=0xC0000; i < 0xffff0 ; i+=16) { @@ -305,7 +453,6 @@ static int powernow_decode_bios (int maxfid, int startvid) } dprintk (KERN_INFO PFX "Settling Time: %d microseconds.\n", psb->settlingtime); dprintk (KERN_INFO PFX "Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst); - latency *= 100; /* SGTC needs to be in units of 10ns */ p += sizeof (struct psb_s); @@ -315,7 +462,8 @@ static int powernow_decode_bios (int maxfid, int startvid) pst = (struct pst_s *) p; number_scales = pst->numpstates; - if ((etuple == pst->cpuid) && (maxfid==pst->maxfid) && (startvid==pst->startvid)) + if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) && + (maxfid==pst->maxfid) && (startvid==pst->startvid)) { dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); @@ -323,7 +471,6 @@ static int powernow_decode_bios (int maxfid, int startvid) dprintk ("maxFID: 0x%x\t", pst->maxfid); dprintk ("startvid: 0x%x\n", pst->startvid); - fsb = pst->fsbspeed; ret = get_ranges ((char *) pst + sizeof (struct pst_s)); return ret; @@ -335,7 +482,7 @@ static int powernow_decode_bios (int maxfid, int startvid) } printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple); printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n"); - printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.shtml\n"); + return -EINVAL; } p++; @@ -365,6 +512,33 @@ static int powernow_verify (struct cpufreq_policy *policy) return cpufreq_frequency_table_verify(policy, powernow_table); } +/* + * We use the fact that the bus frequency is somehow + * a multiple of 100000/3 khz, then we compute sgtc according + * to this multiple. + * That way, we match more how AMD thinks all of that work. + * We will then get the same kind of behaviour already tested under + * the "well-known" other OS. + */ +static int __init fixup_sgtc(void) +{ + unsigned int sgtc; + unsigned int m; + + m = fsb / 3333; + if ((m % 10) >= 5) + m += 5; + + m /= 10; + + sgtc = 100 * m * latency; + sgtc = sgtc / 3; + if (sgtc > 0xfffff) { + printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); + sgtc = 0xfffff; + } + return sgtc; +} static int __init powernow_cpu_init (struct cpufreq_policy *policy) { @@ -376,18 +550,45 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); - result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); + /* A K7 with powernow technology is set to max frequency by BIOS */ + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + if (!fsb) { + printk(KERN_WARNING PFX "can not determine bus frequency\n"); + return -EINVAL; + } + dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); + + if ((dmi_broken & BROKEN_CPUFREQ) || powernow_acpi_force) { + printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); + result = powernow_acpi_init(); + } else { + result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); + if (result) { + printk (KERN_INFO PFX "Trying ACPI perflib\n"); + maximum_speed = 0; + minimum_speed = -1; + latency = 0; + result = powernow_acpi_init(); + if (result) { + printk (KERN_INFO PFX "ACPI and legacy methods failed\n"); + printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.shtml\n"); + } + } else { + /* SGTC use the bus clock as timer */ + latency = fixup_sgtc(); + printk(KERN_INFO PFX "SGTC: %d\n", latency); + } + } + if (result) return result; printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", - minimum_speed, maximum_speed); + minimum_speed/1000, maximum_speed/1000); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* latency is in 10 ns (look for SGTC above) for each VID - * and FID transition, so multiply that value with 20 */ - policy->cpuinfo.transition_latency = latency * 20; + policy->cpuinfo.transition_latency = 20 * latency / fsb; policy->cur = maximum_speed; @@ -418,10 +619,6 @@ static struct cpufreq_driver powernow_driver = { static int __init powernow_init (void) { - if (dmi_broken & BROKEN_CPUFREQ) { - printk (KERN_INFO PFX "Disabled at boot time by DMI,\n"); - return -ENODEV; - } if (check_powernow()==0) return -ENODEV; return cpufreq_register_driver(&powernow_driver); @@ -430,15 +627,25 @@ static int __init powernow_init (void) static void __exit powernow_exit (void) { +#ifdef CONFIG_ACPI_PROCESSOR + if (acpi_processor_perf) { + acpi_processor_unregister_performance(acpi_processor_perf, 0); + kfree(acpi_processor_perf); + } +#endif cpufreq_unregister_driver(&powernow_driver); if (powernow_table) kfree(powernow_table); } +module_param(powernow_acpi_force, int, 0444); + +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used"); + MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); MODULE_LICENSE ("GPL"); -module_init(powernow_init); +late_initcall(powernow_init); module_exit(powernow_exit); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index aa387c4b46eb..862bcf5dd997 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -32,7 +32,7 @@ #include <asm/io.h> #include <asm/delay.h> -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR #include <linux/acpi.h> #include <acpi/processor.h> #endif @@ -269,7 +269,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid dprintk(KERN_DEBUG PFX "ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", - smp_processor_id(); + smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); while (data->currvid > reqvid) { @@ -666,7 +666,7 @@ static int find_psb_table(struct powernow_k8_data *data) return -ENODEV; } -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h index 921d032c3764..20564ef0858c 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h @@ -29,7 +29,7 @@ struct powernow_k8_data { * frequency is in kHz */ struct cpufreq_frequency_table *powernow_table; -#ifdef CONFIG_X86_POWERNOW_K8_ACPI +#ifdef CONFIG_ACPI_PROCESSOR /* the acpi table needs to be kept. it's only available if ACPI was * used to determine valid frequency/vid/fid states */ struct acpi_processor_performance acpi_data; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 2adb46c0ac78..da46fb82edc9 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -195,21 +195,6 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; struct cpu_model *model; - if (!cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; - - /* Only Intel Pentium M stepping 5 for now - add new CPUs as - they appear after making sure they use PERF_CTL in the same - way. */ - if (cpu->x86_vendor != X86_VENDOR_INTEL || - cpu->x86 != 6 || - cpu->x86_model != 9 || - cpu->x86_mask != 5) { - printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " - "send /proc/cpuinfo to " MAINTAINER "\n"); - return -ENODEV; - } - for(model = models; model->model_name != NULL; model++) if (strcmp(cpu->x86_model_id, model->model_name) == 0) break; @@ -361,6 +346,7 @@ static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return static int centrino_cpu_init(struct cpufreq_policy *policy) { + struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; unsigned freq; unsigned l, h; int ret; @@ -368,6 +354,21 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -ENODEV; + if (!cpu_has(cpu, X86_FEATURE_EST)) + return -ENODEV; + + /* Only Intel Pentium M stepping 5 for now - add new CPUs as + they appear after making sure they use PERF_CTL in the same + way. */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || + cpu->x86 != 6 || + cpu->x86_model != 9 || + cpu->x86_mask != 5) { + printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " + "send /proc/cpuinfo to " MAINTAINER "\n"); + return -ENODEV; + } + if (centrino_cpu_init_acpi(policy)) { if (centrino_cpu_init_table(policy)) { return -ENODEV; diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index f424fc369fb1..0be8d6b87cf7 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -445,5 +445,5 @@ void __init init_IRQ(void) if (boot_cpu_data.hard_math && !cpu_has_fpu) setup_irq(FPU_IRQ, &fpu_irq); - irq_ctx_init(current_thread_info()->cpu); + irq_ctx_init(smp_processor_id()); } diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index d74fb46abd31..574ae5814333 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -462,8 +462,7 @@ void nmi_watchdog_tick (struct pt_regs * regs) /* Only P6 based Pentium M need to re-unmask * the apic vector but it doesn't hurt * other P6 variant */ - apic_write(APIC_LVTPC, - apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); + apic_write(APIC_LVTPC, APIC_DM_NMI); } wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index cf8da7ba4cdb..c770d878cbcf 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -123,16 +123,6 @@ void show_trace(struct task_struct *task, unsigned long * stack) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - unsigned long esp = tsk->thread.esp; - - /* User space on another CPU? */ - if ((esp ^ (unsigned long)tsk->thread_info) & ~(THREAD_SIZE - 1)) - return; - show_trace(tsk, (unsigned long *)esp); -} - void show_stack(struct task_struct *task, unsigned long *esp) { unsigned long *stack; diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 6bc3a824b0a9..1b2b4937052f 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -210,19 +210,18 @@ void unmap_hugepage_range(struct vm_area_struct *vma, { struct mm_struct *mm = vma->vm_mm; unsigned long address; - pte_t *pte; + pte_t pte; struct page *page; BUG_ON(start & (HPAGE_SIZE - 1)); BUG_ON(end & (HPAGE_SIZE - 1)); for (address = start; address < end; address += HPAGE_SIZE) { - pte = huge_pte_offset(mm, address); - if (pte_none(*pte)) + pte = ptep_get_and_clear(huge_pte_offset(mm, address)); + if (pte_none(pte)) continue; - page = pte_page(*pte); + page = pte_page(pte); huge_page_release(page); - pte_clear(pte); } mm->rss -= (end - start) >> PAGE_SHIFT; flush_tlb_range(vma, start, end); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index d72026927fec..752dbd3e93fb 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -126,11 +126,6 @@ void show_trace(struct task_struct *task, unsigned long *stack) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_trace(tsk, (long *)tsk->thread.reg29); -} - /* * The architecture-independent dump_stack generator */ diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index f83053a37644..6f1f6f738d6c 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -202,11 +202,6 @@ void show_trace(struct task_struct *task, unsigned long *stack) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - show_trace(tsk, (unsigned long *)tsk->thread.regs.ksp); -} - void die_if_kernel(char *str, struct pt_regs *regs, long err) { if (user_mode(regs)) { diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index f74b14d7e58e..7c153dc24895 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -536,10 +536,4 @@ void dump_stack(void) { show_stack(current, (unsigned long *)__get_SP()); } - EXPORT_SYMBOL(dump_stack); - -void show_trace_task(struct task_struct *tsk) -{ - show_stack(tsk, (unsigned long *)tsk->thread.ksp); -} diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 9525ee20aa0e..a4a727aab6f7 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -44,7 +44,7 @@ head-$(CONFIG_ARCH_S390_31) += arch/$(ARCH)/kernel/head.o head-$(CONFIG_ARCH_S390X) += arch/$(ARCH)/kernel/head64.o head-y += arch/$(ARCH)/kernel/init_task.o -core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ \ +core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \ arch/$(ARCH)/appldata/ libs-y += arch/$(ARCH)/lib/ drivers-y += drivers/s390/ diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile new file mode 100644 index 000000000000..96a05e6b51e0 --- /dev/null +++ b/arch/s390/crypto/Makefile @@ -0,0 +1,8 @@ +# +# Cryptographic API +# + +obj-$(CONFIG_CRYPTO_SHA1_Z990) += sha1_z990.o +obj-$(CONFIG_CRYPTO_DES_Z990) += des_z990.o des_check_key.o + +obj-$(CONFIG_CRYPTO_TEST) += crypt_z990_query.o diff --git a/arch/s390/crypto/crypt_z990.h b/arch/s390/crypto/crypt_z990.h new file mode 100644 index 000000000000..4df660b99e5a --- /dev/null +++ b/arch/s390/crypto/crypt_z990.h @@ -0,0 +1,374 @@ +/* + * Cryptographic API. + * + * Support for z990 cryptographic instructions. + * + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#ifndef _CRYPTO_ARCH_S390_CRYPT_Z990_H +#define _CRYPTO_ARCH_S390_CRYPT_Z990_H + +#include <asm/errno.h> + +#define CRYPT_Z990_OP_MASK 0xFF00 +#define CRYPT_Z990_FUNC_MASK 0x00FF + + +/*z990 cryptographic operations*/ +enum crypt_z990_operations { + CRYPT_Z990_KM = 0x0100, + CRYPT_Z990_KMC = 0x0200, + CRYPT_Z990_KIMD = 0x0300, + CRYPT_Z990_KLMD = 0x0400, + CRYPT_Z990_KMAC = 0x0500 +}; + +/*function codes for KM (CIPHER MESSAGE) instruction*/ +enum crypt_z990_km_func { + KM_QUERY = CRYPT_Z990_KM | 0, + KM_DEA_ENCRYPT = CRYPT_Z990_KM | 1, + KM_DEA_DECRYPT = CRYPT_Z990_KM | 1 | 0x80, //modifier bit->decipher + KM_TDEA_128_ENCRYPT = CRYPT_Z990_KM | 2, + KM_TDEA_128_DECRYPT = CRYPT_Z990_KM | 2 | 0x80, + KM_TDEA_192_ENCRYPT = CRYPT_Z990_KM | 3, + KM_TDEA_192_DECRYPT = CRYPT_Z990_KM | 3 | 0x80, +}; + +/*function codes for KMC (CIPHER MESSAGE WITH CHAINING) instruction*/ +enum crypt_z990_kmc_func { + KMC_QUERY = CRYPT_Z990_KMC | 0, + KMC_DEA_ENCRYPT = CRYPT_Z990_KMC | 1, + KMC_DEA_DECRYPT = CRYPT_Z990_KMC | 1 | 0x80, //modifier bit->decipher + KMC_TDEA_128_ENCRYPT = CRYPT_Z990_KMC | 2, + KMC_TDEA_128_DECRYPT = CRYPT_Z990_KMC | 2 | 0x80, + KMC_TDEA_192_ENCRYPT = CRYPT_Z990_KMC | 3, + KMC_TDEA_192_DECRYPT = CRYPT_Z990_KMC | 3 | 0x80, +}; + +/*function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) instruction*/ +enum crypt_z990_kimd_func { + KIMD_QUERY = CRYPT_Z990_KIMD | 0, + KIMD_SHA_1 = CRYPT_Z990_KIMD | 1, +}; + +/*function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) instruction*/ +enum crypt_z990_klmd_func { + KLMD_QUERY = CRYPT_Z990_KLMD | 0, + KLMD_SHA_1 = CRYPT_Z990_KLMD | 1, +}; + +/*function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) instruction*/ +enum crypt_z990_kmac_func { + KMAC_QUERY = CRYPT_Z990_KMAC | 0, + KMAC_DEA = CRYPT_Z990_KMAC | 1, + KMAC_TDEA_128 = CRYPT_Z990_KMAC | 2, + KMAC_TDEA_192 = CRYPT_Z990_KMAC | 3 +}; + +/*status word for z990 crypto instructions' QUERY functions*/ +struct crypt_z990_query_status { + u64 high; + u64 low; +}; + +/* + * Standard fixup and ex_table sections for crypt_z990 inline functions. + * label 0: the z990 crypto operation + * label 1: just after 1 to catch illegal operation exception on non-z990 + * label 6: the return point after fixup + * label 7: set error value if exception _in_ crypto operation + * label 8: set error value if illegal operation exception + * [ret] is the variable to receive the error code + * [ERR] is the error code value + */ +#ifndef __s390x__ +#define __crypt_z990_fixup \ + ".section .fixup,\"ax\" \n" \ + "7: lhi %0,%h[e1] \n" \ + " bras 1,9f \n" \ + " .long 6b \n" \ + "8: lhi %0,%h[e2] \n" \ + " bras 1,9f \n" \ + " .long 6b \n" \ + "9: l 1,0(1) \n" \ + " br 1 \n" \ + ".previous \n" \ + ".section __ex_table,\"a\" \n" \ + " .align 4 \n" \ + " .long 0b,7b \n" \ + " .long 1b,8b \n" \ + ".previous" +#else /* __s390x__ */ +#define __crypt_z990_fixup \ + ".section .fixup,\"ax\" \n" \ + "7: lhi %0,%h[e1] \n" \ + " jg 6b \n" \ + "8: lhi %0,%h[e2] \n" \ + " jg 6b \n" \ + ".previous\n" \ + ".section __ex_table,\"a\" \n" \ + " .align 8 \n" \ + " .quad 0b,7b \n" \ + " .quad 1b,8b \n" \ + ".previous" +#endif /* __s390x__ */ + +/* + * Standard code for setting the result of z990 crypto instructions. + * %0: the register which will receive the result + * [result]: the register containing the result (e.g. second operand length + * to compute number of processed bytes]. + */ +#ifndef __s390x__ +#define __crypt_z990_set_result \ + " lr %0,%[result] \n" +#else /* __s390x__ */ +#define __crypt_z990_set_result \ + " lgr %0,%[result] \n" +#endif + +/* + * Executes the KM (CIPHER MESSAGE) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_km_func + * @param param: address of parameter block; see POP for details on each func + * @param dest: address of destination memory area + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for encryption/decryption funcs + */ +static inline int +crypt_z990_km(long func, void* param, u8* dest, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register u8* __dest asm("4") = dest; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB92E0000,%1,%2 \n" //KM opcode + "1: brc 1,0b \n" //handle partial completion + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__dest), "+a" (__src), + [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_kmc_func + * @param param: address of parameter block; see POP for details on each func + * @param dest: address of destination memory area + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for encryption/decryption funcs + */ +static inline int +crypt_z990_kmc(long func, void* param, u8* dest, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register u8* __dest asm("4") = dest; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB92F0000,%1,%2 \n" //KMC opcode + "1: brc 1,0b \n" //handle partial completion + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__dest), "+a" (__src), + [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation + * of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_kimd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_kimd(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB93E0000,%1,%1 \n" //KIMD opcode + "1: brc 1,0b \n" /*handle partical completion of kimd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && (func & CRYPT_Z990_FUNC_MASK)){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_klmd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_klmd(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB93F0000,%1,%1 \n" //KLMD opcode + "1: brc 1,0b \n" /*handle partical completion of klmd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/* + * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation + * of the z990 CPU. + * @param func: the function code passed to KM; see crypt_z990_klmd_func + * @param param: address of parameter block; see POP for details on each func + * @param src: address of source memory area + * @param src_len: length of src operand in bytes + * @returns < zero for failure, 0 for the query func, number of processed bytes + * for digest funcs + */ +static inline int +crypt_z990_kmac(long func, void* param, const u8* src, long src_len) +{ + register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK; + register void* __param asm("1") = param; + register const u8* __src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + ret = 0; + __asm__ __volatile__ ( + "0: .insn rre,0xB91E0000,%5,%5 \n" //KMAC opcode + "1: brc 1,0b \n" /*handle partical completion of klmd*/ + __crypt_z990_set_result + "6: \n" + __crypt_z990_fixup + : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) + : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), + "a" (__param) + : "cc", "memory" + ); + if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){ + ret = src_len - ret; + } + return ret; +} + +/** + * Tests if a specific z990 crypto function is implemented on the machine. + * @param func: the function code of the specific function; 0 if op in general + * @return 1 if func available; 0 if func or op in general not available + */ +static inline int +crypt_z990_func_available(int func) +{ + int ret; + + struct crypt_z990_query_status status = { + .high = 0, + .low = 0 + }; + switch (func & CRYPT_Z990_OP_MASK){ + case CRYPT_Z990_KM: + ret = crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_Z990_KMC: + ret = crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_Z990_KIMD: + ret = crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0); + break; + case CRYPT_Z990_KLMD: + ret = crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0); + break; + case CRYPT_Z990_KMAC: + ret = crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0); + break; + default: + ret = 0; + return ret; + } + if (ret >= 0){ + func &= CRYPT_Z990_FUNC_MASK; + func &= 0x7f; //mask modifier bit + if (func < 64){ + ret = (status.high >> (64 - func - 1)) & 0x1; + } else { + ret = (status.low >> (128 - func - 1)) & 0x1; + } + } else { + ret = 0; + } + return ret; +} + + +#endif // _CRYPTO_ARCH_S390_CRYPT_Z990_H diff --git a/arch/s390/crypto/crypt_z990_query.c b/arch/s390/crypto/crypt_z990_query.c new file mode 100644 index 000000000000..7133983d1384 --- /dev/null +++ b/arch/s390/crypto/crypt_z990_query.c @@ -0,0 +1,111 @@ +/* + * Cryptographic API. + * + * Support for z990 cryptographic instructions. + * Testing module for querying processor crypto capabilities. + * + * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <asm/errno.h> +#include "crypt_z990.h" + +static void +query_available_functions(void) +{ + printk(KERN_INFO "#####################\n"); + //query available KM functions + printk(KERN_INFO "KM_QUERY: %d\n", + crypt_z990_func_available(KM_QUERY)); + printk(KERN_INFO "KM_DEA: %d\n", + crypt_z990_func_available(KM_DEA_ENCRYPT)); + printk(KERN_INFO "KM_TDEA_128: %d\n", + crypt_z990_func_available(KM_TDEA_128_ENCRYPT)); + printk(KERN_INFO "KM_TDEA_192: %d\n", + crypt_z990_func_available(KM_TDEA_192_ENCRYPT)); + //query available KMC functions + printk(KERN_INFO "KMC_QUERY: %d\n", + crypt_z990_func_available(KMC_QUERY)); + printk(KERN_INFO "KMC_DEA: %d\n", + crypt_z990_func_available(KMC_DEA_ENCRYPT)); + printk(KERN_INFO "KMC_TDEA_128: %d\n", + crypt_z990_func_available(KMC_TDEA_128_ENCRYPT)); + printk(KERN_INFO "KMC_TDEA_192: %d\n", + crypt_z990_func_available(KMC_TDEA_192_ENCRYPT)); + //query available KIMD fucntions + printk(KERN_INFO "KIMD_QUERY: %d\n", + crypt_z990_func_available(KIMD_QUERY)); + printk(KERN_INFO "KIMD_SHA_1: %d\n", + crypt_z990_func_available(KIMD_SHA_1)); + //query available KLMD functions + printk(KERN_INFO "KLMD_QUERY: %d\n", + crypt_z990_func_available(KLMD_QUERY)); + printk(KERN_INFO "KLMD_SHA_1: %d\n", + crypt_z990_func_available(KLMD_SHA_1)); + //query available KMAC functions + printk(KERN_INFO "KMAC_QUERY: %d\n", + crypt_z990_func_available(KMAC_QUERY)); + printk(KERN_INFO "KMAC_DEA: %d\n", + crypt_z990_func_available(KMAC_DEA)); + printk(KERN_INFO "KMAC_TDEA_128: %d\n", + crypt_z990_func_available(KMAC_TDEA_128)); + printk(KERN_INFO "KMAC_TDEA_192: %d\n", + crypt_z990_func_available(KMAC_TDEA_192)); +} + +static int +init(void) +{ + struct crypt_z990_query_status status = { + .high = 0, + .low = 0 + }; + + printk(KERN_INFO "crypt_z990: querying available crypto functions\n"); + crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0); + printk(KERN_INFO "KM: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0); + printk(KERN_INFO "KMC: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0); + printk(KERN_INFO "KIMD: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0); + printk(KERN_INFO "KLMD: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + status.high = status.low = 0; + crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0); + printk(KERN_INFO "KMAC: %016llx %016llx\n", + (unsigned long long) status.high, + (unsigned long long) status.low); + + query_available_functions(); + return -1; +} + +static void __exit +cleanup(void) +{ +} + +module_init(init); +module_exit(cleanup); + +MODULE_LICENSE("GPL"); diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h new file mode 100644 index 000000000000..c964b64111dd --- /dev/null +++ b/arch/s390/crypto/crypto_des.h @@ -0,0 +1,18 @@ +/* + * Cryptographic API. + * + * Function for checking keys for the DES and Tripple DES Encryption + * algorithms. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#ifndef __CRYPTO_DES_H__ +#define __CRYPTO_DES_H__ + +extern int crypto_des_check_key(const u8*, unsigned int, u32*); + +#endif //__CRYPTO_DES_H__ diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c new file mode 100644 index 000000000000..e3f5c5f238fe --- /dev/null +++ b/arch/s390/crypto/des_check_key.c @@ -0,0 +1,130 @@ +/* + * Cryptographic API. + * + * Function for checking keys for the DES and Tripple DES Encryption + * algorithms. + * + * Originally released as descore by Dana L. How <how@isl.stanford.edu>. + * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel. + * Derived from Cryptoapi and Nettle implementations, adapted for in-place + * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. + * + * s390 Version: + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * Derived from "crypto/des.c" + * Copyright (c) 1992 Dana L. How. + * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de> + * Copyright (c) Gisle Sflensminde <gisle@ii.uib.no> + * Copyright (C) 2001 Niels Mvller. + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/crypto.h> + +#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) + +static const u8 parity[] = { + 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, + 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, +}; + +/* + * RFC2451: Weak key checks SHOULD be performed. + */ +int +crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) +{ + u32 n, w; + + n = parity[key[0]]; n <<= 4; + n |= parity[key[1]]; n <<= 4; + n |= parity[key[2]]; n <<= 4; + n |= parity[key[3]]; n <<= 4; + n |= parity[key[4]]; n <<= 4; + n |= parity[key[5]]; n <<= 4; + n |= parity[key[6]]; n <<= 4; + n |= parity[key[7]]; + w = 0x88888888L; + + if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) + && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ + if (n < 0x41415151) { + if (n < 0x31312121) { + if (n < 0x14141515) { + /* 01 01 01 01 01 01 01 01 */ + if (n == 0x11111111) goto weak; + /* 01 1F 01 1F 01 0E 01 0E */ + if (n == 0x13131212) goto weak; + } else { + /* 01 E0 01 E0 01 F1 01 F1 */ + if (n == 0x14141515) goto weak; + /* 01 FE 01 FE 01 FE 01 FE */ + if (n == 0x16161616) goto weak; + } + } else { + if (n < 0x34342525) { + /* 1F 01 1F 01 0E 01 0E 01 */ + if (n == 0x31312121) goto weak; + /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ + if (n == 0x33332222) goto weak; + } else { + /* 1F E0 1F E0 0E F1 0E F1 */ + if (n == 0x34342525) goto weak; + /* 1F FE 1F FE 0E FE 0E FE */ + if (n == 0x36362626) goto weak; + } + } + } else { + if (n < 0x61616161) { + if (n < 0x44445555) { + /* E0 01 E0 01 F1 01 F1 01 */ + if (n == 0x41415151) goto weak; + /* E0 1F E0 1F F1 0E F1 0E */ + if (n == 0x43435252) goto weak; + } else { + /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ + if (n == 0x44445555) goto weak; + /* E0 FE E0 FE F1 FE F1 FE */ + if (n == 0x46465656) goto weak; + } + } else { + if (n < 0x64646565) { + /* FE 01 FE 01 FE 01 FE 01 */ + if (n == 0x61616161) goto weak; + /* FE 1F FE 1F FE 0E FE 0E */ + if (n == 0x63636262) goto weak; + } else { + /* FE E0 FE E0 FE F1 FE F1 */ + if (n == 0x64646565) goto weak; + /* FE FE FE FE FE FE FE FE */ + if (n == 0x66666666) goto weak; + } + } + } + } + return 0; +weak: + *flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; +} + +EXPORT_SYMBOL(crypto_des_check_key); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); diff --git a/arch/s390/crypto/des_z990.c b/arch/s390/crypto/des_z990.c new file mode 100644 index 000000000000..813cf37b1177 --- /dev/null +++ b/arch/s390/crypto/des_z990.c @@ -0,0 +1,284 @@ +/* + * Cryptographic API. + * + * z990 implementation of the DES Cipher Algorithm. + * + * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <asm/scatterlist.h> +#include <linux/crypto.h> +#include "crypt_z990.h" +#include "crypto_des.h" + +#define DES_BLOCK_SIZE 8 +#define DES_KEY_SIZE 8 + +#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE) +#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE + +#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE + +struct crypt_z990_des_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES_KEY_SIZE]; +}; + +struct crypt_z990_des3_128_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_128_KEY_SIZE]; +}; + +struct crypt_z990_des3_192_ctx { + u8 iv[DES_BLOCK_SIZE]; + u8 key[DES3_192_KEY_SIZE]; +}; + +static int +des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + struct crypt_z990_des_ctx *dctx; + int ret; + + dctx = ctx; + //test if key is valid (not a weak key) + ret = crypto_des_check_key(key, keylen, flags); + if (ret == 0){ + memcpy(dctx->key, key, keylen); + } + return ret; +} + + +static void +des_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_DEA_ENCRYPT, dctx->key, dst, src, DES_BLOCK_SIZE); +} + +static void +des_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_DEA_DECRYPT, dctx->key, dst, src, DES_BLOCK_SIZE); +} + +static struct crypto_alg des_alg = { + .cra_name = "des", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt } } +}; + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the two independent 64-bit keys are equal, + * then the DES3 operation is simply the same as DES. + * Implementers MUST reject keys that exhibit this property. + * + */ +static int +des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + int i, ret; + struct crypt_z990_des3_128_ctx *dctx; + const u8* temp_key = key; + + dctx = ctx; + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) { + + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) { + ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); + if (ret < 0) + return ret; + } + memcpy(dctx->key, key, keylen); + return 0; +} + +static void +des3_128_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_128_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src, + DES3_128_BLOCK_SIZE); +} + +static void +des3_128_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_128_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src, + DES3_128_BLOCK_SIZE); +} + +static struct crypto_alg des3_128_alg = { + .cra_name = "des3_ede128", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_128_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des3_128_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES3_128_KEY_SIZE, + .cia_max_keysize = DES3_128_KEY_SIZE, + .cia_setkey = des3_128_setkey, + .cia_encrypt = des3_128_encrypt, + .cia_decrypt = des3_128_decrypt } } +}; + +/* + * RFC2451: + * + * For DES-EDE3, there is no known need to reject weak or + * complementation keys. Any weakness is obviated by the use of + * multiple keys. + * + * However, if the first two or last two independent 64-bit keys are + * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the + * same as DES. Implementers MUST reject keys that exhibit this + * property. + * + */ +static int +des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) +{ + int i, ret; + struct crypt_z990_des3_192_ctx *dctx; + const u8* temp_key; + + dctx = ctx; + temp_key = key; + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && + memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], + DES_KEY_SIZE))) { + + *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + return -EINVAL; + } + for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) { + ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags); + if (ret < 0){ + return ret; + } + } + memcpy(dctx->key, key, keylen); + return 0; +} + +static void +des3_192_encrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_192_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src, + DES3_192_BLOCK_SIZE); +} + +static void +des3_192_decrypt(void *ctx, u8 *dst, const u8 *src) +{ + struct crypt_z990_des3_192_ctx *dctx; + + dctx = ctx; + crypt_z990_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src, + DES3_192_BLOCK_SIZE); +} + +static struct crypto_alg des3_192_alg = { + .cra_name = "des3_ede", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_des3_192_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = DES3_192_KEY_SIZE, + .cia_max_keysize = DES3_192_KEY_SIZE, + .cia_setkey = des3_192_setkey, + .cia_encrypt = des3_192_encrypt, + .cia_decrypt = des3_192_decrypt } } +}; + + + +static int +init(void) +{ + int ret; + + if (!crypt_z990_func_available(KM_DEA_ENCRYPT) || + !crypt_z990_func_available(KM_TDEA_128_ENCRYPT) || + !crypt_z990_func_available(KM_TDEA_192_ENCRYPT)){ + return -ENOSYS; + } + + ret = 0; + ret |= (crypto_register_alg(&des_alg) == 0)? 0:1; + ret |= (crypto_register_alg(&des3_128_alg) == 0)? 0:2; + ret |= (crypto_register_alg(&des3_192_alg) == 0)? 0:4; + if (ret){ + crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&des3_128_alg); + crypto_unregister_alg(&des_alg); + return -EEXIST; + } + + printk(KERN_INFO "crypt_z990: des_z990 loaded.\n"); + return 0; +} + +static void __exit +fini(void) +{ + crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&des3_128_alg); + crypto_unregister_alg(&des_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("des"); +MODULE_ALIAS("des3_ede"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); diff --git a/arch/s390/crypto/sha1_z990.c b/arch/s390/crypto/sha1_z990.c new file mode 100644 index 000000000000..298174ddf5b1 --- /dev/null +++ b/arch/s390/crypto/sha1_z990.c @@ -0,0 +1,167 @@ +/* + * Cryptographic API. + * + * z990 implementation of the SHA1 Secure Hash Algorithm. + * + * Derived from cryptoapi implementation, adapted for in-place + * scatterlist interface. Originally based on the public domain + * implementation written by Steve Reid. + * + * s390 Version: + * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation + * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * + * Derived from "crypto/sha1.c" + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> + * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/crypto.h> +#include <asm/scatterlist.h> +#include <asm/byteorder.h> +#include "crypt_z990.h" + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +struct crypt_z990_sha1_ctx { + u64 count; + u32 state[5]; + u32 buf_len; + u8 buffer[2 * SHA1_BLOCK_SIZE]; +}; + +static void +sha1_init(void *ctx) +{ + static const struct crypt_z990_sha1_ctx initstate = { + .state = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0 + }, + }; + memcpy(ctx, &initstate, sizeof(initstate)); +} + +static void +sha1_update(void *ctx, const u8 *data, unsigned int len) +{ + struct crypt_z990_sha1_ctx *sctx; + long imd_len; + + sctx = ctx; + sctx->count += len * 8; //message bit length + + //anything in buffer yet? -> must be completed + if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { + //complete full block and hash + memcpy(sctx->buffer + sctx->buf_len, data, + SHA1_BLOCK_SIZE - sctx->buf_len); + crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, + SHA1_BLOCK_SIZE); + data += SHA1_BLOCK_SIZE - sctx->buf_len; + len -= SHA1_BLOCK_SIZE - sctx->buf_len; + sctx->buf_len = 0; + } + + //rest of data contains full blocks? + imd_len = len & ~0x3ful; + if (imd_len){ + crypt_z990_kimd(KIMD_SHA_1, sctx->state, data, imd_len); + data += imd_len; + len -= imd_len; + } + //anything left? store in buffer + if (len){ + memcpy(sctx->buffer + sctx->buf_len , data, len); + sctx->buf_len += len; + } +} + + +static void +pad_message(struct crypt_z990_sha1_ctx* sctx) +{ + int index; + + index = sctx->buf_len; + sctx->buf_len = (sctx->buf_len < 56)? + SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; + //start pad with 1 + sctx->buffer[index] = 0x80; + //pad with zeros + index++; + memset(sctx->buffer + index, 0x00, sctx->buf_len - index); + //append length + memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, + sizeof sctx->count); +} + +/* Add padding and return the message digest. */ +static void +sha1_final(void* ctx, u8 *out) +{ + struct crypt_z990_sha1_ctx *sctx = ctx; + + //must perform manual padding + pad_message(sctx); + crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); + //copy digest to out + memcpy(out, sctx->state, SHA1_DIGEST_SIZE); + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); +} + +static struct crypto_alg alg = { + .cra_name = "sha1", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_z990_sha1_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA1_DIGEST_SIZE, + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final } } +}; + +static int +init(void) +{ + int ret = -ENOSYS; + + if (crypt_z990_func_available(KIMD_SHA_1)){ + ret = crypto_register_alg(&alg); + if (ret == 0){ + printk(KERN_INFO "crypt_z990: sha1_z990 loaded.\n"); + } + } + return ret; +} + +static void __exit +fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_ALIAS("sha1"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 574c1b2a9d06..8e95f1a00b11 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -18,8 +18,10 @@ CONFIG_STANDALONE=y # CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=17 CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y @@ -31,6 +33,7 @@ CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -231,8 +234,6 @@ CONFIG_IPV6=y # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set # CONFIG_IPV6_TUNNEL is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_NETFILTER is not set CONFIG_XFRM=y # CONFIG_XFRM_USER is not set @@ -242,7 +243,9 @@ CONFIG_XFRM=y # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -286,6 +289,11 @@ CONFIG_NET_CLS_POLICE=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_BONDING=m @@ -305,20 +313,16 @@ CONFIG_NET_ETHERNET=y # # Ethernet (10000 Mbit) # -# CONFIG_PPP is not set -# CONFIG_SLIP is not set # -# Wireless LAN (non-hamradio) +# Token Ring devices # -# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set # -# Token Ring devices +# Wireless LAN (non-hamradio) # -# CONFIG_TR is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces @@ -341,23 +345,10 @@ CONFIG_QETH=y # CONFIG_QETH_IPV6 is not set # CONFIG_QETH_PERF_STATS is not set CONFIG_CCWGROUP=y - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # File systems @@ -397,6 +388,7 @@ CONFIG_FS_MBCACHE=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -493,9 +485,11 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_MD4 is not set # CONFIG_CRYPTO_MD5 is not set # CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_Z990 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DES_Z990 is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 0cc8e5be48ba..b68ace7e2e4f 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -33,6 +33,8 @@ #define NUM_ACRS 16 #define TASK31_SIZE (0x80000000UL) +#undef TASK_SIZE +#define TASK_SIZE TASK31_SIZE /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 566277b9409c..df06185d54c2 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -297,64 +297,46 @@ static inline long put_tv32(struct compat_timeval *o, struct timeval *i) */ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr) { - if(call >> 16) /* hack for backward compatibility */ + if (call >> 16) /* hack for backward compatibility */ return -EINVAL; call &= 0xffff; - if (call <= SEMTIMEDOP) - switch (call) { - case SEMTIMEDOP: - if (third) - return compat_sys_semtimedop(first, - compat_ptr(ptr), second, - compat_ptr(third)); - /* else fall through for normal semop() */ - case SEMOP: - /* struct sembuf is the same on 32 and 64bit :)) */ - return sys_semtimedop (first, compat_ptr(ptr), - second, NULL); - case SEMGET: - return sys_semget (first, second, third); - case SEMCTL: - return compat_sys_semctl (first, second, third, - compat_ptr(ptr)); - default: - return -EINVAL; - }; - if (call <= MSGCTL) - switch (call) { - case MSGSND: - return compat_sys_msgsnd (first, second, third, - compat_ptr(ptr)); - case MSGRCV: - return compat_sys_msgrcv (first, second, 0, third, - 0, compat_ptr(ptr)); - case MSGGET: - return sys_msgget ((key_t) first, second); - case MSGCTL: - return compat_sys_msgctl (first, second, - compat_ptr(ptr)); - default: - return -EINVAL; - } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - return compat_sys_shmat (first, second, third, - 0, compat_ptr(ptr)); - case SHMDT: - return sys_shmdt(compat_ptr(ptr)); - case SHMGET: - return sys_shmget(first, second, third); - case SHMCTL: - return compat_sys_shmctl(first, second, - compat_ptr(ptr)); - default: - return -EINVAL; - } + switch (call) { + case SEMTIMEDOP: + return compat_sys_semtimedop(first, compat_ptr(ptr), + second, compat_ptr(third)); + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + return sys_semtimedop(first, compat_ptr(ptr), + second, NULL); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: + return compat_sys_semctl(first, second, third, + compat_ptr(ptr)); + case MSGSND: + return compat_sys_msgsnd(first, second, third, + compat_ptr(ptr)); + case MSGRCV: + return compat_sys_msgrcv(first, second, 0, third, + 0, compat_ptr(ptr)); + case MSGGET: + return sys_msgget((key_t) first, second); + case MSGCTL: + return compat_sys_msgctl(first, second, compat_ptr(ptr)); + case SHMAT: + return compat_sys_shmat(first, second, third, + 0, compat_ptr(ptr)); + case SHMDT: + return sys_shmdt(compat_ptr(ptr)); + case SHMGET: + return sys_shmget(first, second, third); + case SHMCTL: + return compat_sys_shmctl(first, second, compat_ptr(ptr)); + } - return -EINVAL; + return -ENOSYS; } asmlinkage long sys32_truncate64(const char * path, unsigned long high, unsigned long low) diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 043c25b7b8f9..66861b95da68 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1361,7 +1361,7 @@ compat_sys_mq_open_wrapper: llgtr %r5,%r5 # struct compat_mq_attr * jg compat_sys_mq_open - .globl sys_mq_unlink_wrapper + .globl sys32_mq_unlink_wrapper sys32_mq_unlink_wrapper: llgtr %r2,%r2 # const char * jg sys_mq_unlink diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 37520c7e71be..d5a9e1cdac09 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -198,7 +198,8 @@ __switch_to_noper: */ .global do_call_softirq do_call_softirq: - stm %r12,%r15,24(%r15) + stnsm 24(%r15),0xfc + stm %r12,%r15,28(%r15) lr %r12,%r15 basr %r13,0 do_call_base: @@ -211,7 +212,8 @@ do_call_base: st %r12,0(%r15) # store backchain l %r1,.Ldo_softirq-do_call_base(%r13) basr %r14,%r1 - lm %r12,%r15,24(%r12) + lm %r12,%r15,28(%r12) + ssm 24(%r15) br %r14 __critical_start: diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 89c52f6b35fe..e94e694d512c 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -186,7 +186,8 @@ __switch_to_noper: */ .global do_call_softirq do_call_softirq: - stmg %r12,%r15,48(%r15) + stnsm 48(%r15),0xfc + stmg %r12,%r15,56(%r15) lgr %r12,%r15 lg %r0,__LC_ASYNC_STACK slgr %r0,%r15 @@ -196,7 +197,8 @@ do_call_softirq: 0: aghi %r15,-STACK_FRAME_OVERHEAD stg %r12,0(%r15) # store back chain brasl %r14,do_softirq - lmg %r12,%r15,48(%r12) + lmg %r12,%r15,56(%r12) + ssm 48(%r15) br %r14 __critical_start: diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 7f0e45e001f0..7ca8a8706cca 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -254,13 +254,13 @@ void (*_machine_power_off)(void) = machine_power_off_smp; /* * Reboot, halt and power_off routines for non SMP. */ -extern void do_reipl(unsigned long devno); +extern void reipl(unsigned long devno); static void do_machine_restart_nonsmp(char * __unused) { if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0); else - do_reipl (0x10000 | S390_lowcore.ipl_device); + reipl (0x10000 | S390_lowcore.ipl_device); } static void do_machine_halt_nonsmp(void) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2ee07a475716..de99f63ec951 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -64,7 +64,7 @@ EXPORT_SYMBOL(cpu_online_map); extern char vmhalt_cmd[]; extern char vmpoff_cmd[]; -extern void do_reipl(unsigned long devno); +extern void reipl(unsigned long devno); static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); @@ -278,7 +278,7 @@ static void do_machine_restart(void * __unused) if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0); else - do_reipl (0x10000 | S390_lowcore.ipl_device); + reipl (0x10000 | S390_lowcore.ipl_device); } signal_processor(smp_processor_id(), sigp_stop); } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index d778f98a2c7c..016eb6cd48c9 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -105,17 +105,6 @@ void show_trace(struct task_struct *task, unsigned long * stack) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - /* - * We can't print the backtrace of a running process. It is - * unreliable at best and can cause kernel oopses. - */ - if (tsk->state == TASK_RUNNING) - return; - show_trace(tsk, (unsigned long *) tsk->thread.ksp); -} - void show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack; diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 5211a375afa8..3e63d8a70ed3 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -705,14 +705,8 @@ void show_task(unsigned long *sp) show_stack(NULL, sp); } -void show_trace_task(struct task_struct *tsk) -{ - show_task((unsigned long *)tsk->thread.sp); -} - void dump_stack(void) { show_stack(NULL, NULL); } - EXPORT_SYMBOL(dump_stack); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 3cf8af39ac95..47d685193ade 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1760,13 +1760,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) #endif } -void show_trace_task(struct task_struct *tsk) -{ - if (tsk) - show_stack(tsk, - (unsigned long *) tsk->thread_info->ksp); -} - void dump_stack(void) { unsigned long *ksp; diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 078dc11132d3..ce108f7d6971 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -42,19 +42,8 @@ void dump_stack(void) show_trace(&stack); } - EXPORT_SYMBOL(dump_stack); -void show_trace_task(struct task_struct *tsk) -{ - unsigned long esp = PT_REGS_SP(&tsk->thread.regs); - - /* User space on another CPU? */ - if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1)) - return; - show_trace((unsigned long *)esp); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c index 977d75772d81..2fccb4cc7b82 100644 --- a/arch/v850/kernel/process.c +++ b/arch/v850/kernel/process.c @@ -234,10 +234,3 @@ unsigned long get_wchan (struct task_struct *p) return 0; } - -void show_trace_task (struct task_struct *t) -{ - /* blarg XXX */ - printk ("show_trace_task: KSP = 0x%lx, USP = 0x%lx, UPC = 0x%lx\n", - t->thread.ksp, KSTK_ESP (t), KSTK_EIP (t)); -} diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 5afe235c0474..2efdbaa1ecfa 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -197,16 +197,6 @@ void show_trace(unsigned long *stack) printk("\n"); } -void show_trace_task(struct task_struct *tsk) -{ - unsigned long rsp = tsk->thread.rsp; - - /* User space on another CPU? */ - if ((rsp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1)) - return; - show_trace((unsigned long *)rsp); -} - void show_stack(struct task_struct *tsk, unsigned long * rsp) { unsigned long *stack; diff --git a/crypto/Kconfig b/crypto/Kconfig index 4b0925ea142b..d7c9d552fd8b 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -40,6 +40,12 @@ config CRYPTO_SHA1 help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). +config CRYPTO_SHA1_Z990 + tristate "SHA1 digest algorithm for IBM zSeries z990" + depends on CRYPTO && ARCH_S390 + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + config CRYPTO_SHA256 tristate "SHA256 digest algorithm" depends on CRYPTO @@ -67,6 +73,12 @@ config CRYPTO_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). +config CRYPTO_DES_Z990 + tristate "DES and Triple DES cipher algorithms for IBM zSeries z990" + depends on CRYPTO && ARCH_S390 + help + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + config CRYPTO_BLOWFISH tristate "Blowfish cipher algorithm" depends on CRYPTO diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f9c506d93c69..37afd96d7009 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -656,7 +656,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. */ - if (!lo_file->f_op->sendfile) + if (!file->f_op->sendfile) goto out_putf; if (!aops->prepare_write || !aops->commit_write) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b1d5dfa351ff..9d2759d8aa92 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -39,6 +39,8 @@ #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/completion.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <asm/bug.h> @@ -132,7 +134,12 @@ struct cdrom_info { char type[4]; char model[3]; }; -static struct cdrom_info viocd_unitinfo[VIOCD_MAX_CD]; +/* + * This needs to be allocated since it is passed to the + * Hypervisor and we may be a module. + */ +static struct cdrom_info *viocd_unitinfo; +static dma_addr_t unitinfo_dmaaddr; struct disk_info { struct gendisk *viocd_disk; @@ -141,13 +148,39 @@ struct disk_info { static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; #define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) -#define VIOCDI viocd_diskinfo[deviceno].viocd_info static request_queue_t *viocd_queue; static spinlock_t viocd_reqlock; #define MAX_CD_REQ 1 +/* procfs support */ +static int proc_viocd_show(struct seq_file *m, void *v) +{ + int i; + + for (i = 0; i < viocd_numdev; i++) { + seq_printf(m, "viocd device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viocd_unitinfo[i].rsrcname, + viocd_unitinfo[i].type, + viocd_unitinfo[i].model); + } + return 0; +} + +static int proc_viocd_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viocd_show, NULL); +} + +static struct file_operations proc_viocd_operations = { + .open = proc_viocd_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int viocd_blk_open(struct inode *inode, struct file *file) { struct disk_info *di = inode->i_bdev->bd_disk->private_data; @@ -184,18 +217,20 @@ struct block_device_operations viocd_fops = { /* Get info on CD devices from OS/400 */ static void __init get_viocd_info(void) { - dma_addr_t dmaaddr; HvLpEvent_Rc hvrc; int i; struct viocd_waitevent we; - dmaaddr = dma_map_single(iSeries_vio_dev, viocd_unitinfo, - sizeof(viocd_unitinfo), DMA_FROM_DEVICE); - if (dmaaddr == (dma_addr_t)-1) { - printk(VIOCD_KERN_WARNING "error allocating tce\n"); + viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (viocd_unitinfo == NULL) { + printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); return; } + memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); + init_completion(&we.com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, @@ -204,29 +239,34 @@ static void __init get_viocd_info(void) HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, dmaaddr, 0, - sizeof(viocd_unitinfo), 0); + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", (int)hvrc); - return; + goto error_ret; } wait_for_completion(&we.com); - dma_unmap_single(iSeries_vio_dev, dmaaddr, sizeof(viocd_unitinfo), - DMA_FROM_DEVICE); - if (we.rc) { const struct vio_error_entry *err = vio_lookup_rc(viocd_err_table, we.sub_result); printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", we.rc, we.sub_result, err->msg); - return; + goto error_ret; } for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) viocd_numdev++; + + return; + +error_ret: + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); + viocd_unitinfo = NULL; } static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -307,10 +347,6 @@ static int send_request(struct request *req) } dmaaddr = sg_dma_address(&sg); len = sg_dma_len(&sg); - if (dmaaddr == (dma_addr_t)-1) { - printk(VIOCD_KERN_WARNING "error allocating tce\n"); - return -1; - } hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -534,6 +570,7 @@ static int __init viocd_init(void) struct gendisk *gendisk; int deviceno; int ret = 0; + struct proc_dir_entry *e; if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); @@ -604,7 +641,7 @@ static int __init viocd_init(void) printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n", c->name); - unregister_cdrom(&VIOCDI); + unregister_cdrom(c); continue; } gendisk->major = VIOCD_MAJOR; @@ -622,6 +659,12 @@ static int __init viocd_init(void) add_disk(gendisk); } + e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); + if (e) { + e->owner = THIS_MODULE; + e->proc_fops = &proc_viocd_operations; + } + return 0; out_undo_vio: @@ -636,6 +679,7 @@ static void __exit viocd_exit(void) { int deviceno; + remove_proc_entry("iSeries/viocd", NULL); for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { struct disk_info *d = &viocd_diskinfo[deviceno]; if (unregister_cdrom(&d->viocd_info) != 0) @@ -646,7 +690,10 @@ static void __exit viocd_exit(void) put_disk(d->viocd_disk); } blk_cleanup_queue(viocd_queue); - + if (viocd_unitinfo != NULL) + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); vio_clearHandler(viomajorsubtype_cdio); unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index ea48f71926b3..e1ebc70335df 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -1275,6 +1275,9 @@ int i810_dma_mc(struct inode *inode, struct file *filp, return -EINVAL; } + if (mc.idx >= dma->buf_count || mc.idx < 0) + return -EINVAL; + i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used, mc.last_render ); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 3f2b43fe4ac6..a5915c1e764b 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -47,6 +47,8 @@ #include <linux/devfs_fs_kernel.h> #include <linux/major.h> #include <linux/completion.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <asm/uaccess.h> #include <asm/ioctls.h> @@ -56,7 +58,7 @@ #include <asm/iSeries/HvCallEvent.h> #include <asm/iSeries/HvLpConfig.h> -#define VIOTAPE_VERSION "1.1" +#define VIOTAPE_VERSION "1.2" #define VIOTAPE_MAXREQ 1 #define VIOTAPE_KERN_WARN KERN_WARNING "viotape: " @@ -269,6 +271,34 @@ static struct op_struct *op_struct_list; /* forward declaration to resolve interdependence */ static int chg_state(int index, unsigned char new_state, struct file *file); +/* procfs support */ +static int proc_viotape_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n"); + for (i = 0; i < viotape_numdev; i++) { + seq_printf(m, "viotape device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, + viotape_unitinfo[i].model); + } + return 0; +} + +static int proc_viotape_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viotape_show, NULL); +} + +static struct file_operations proc_viotape_operations = { + .open = proc_viotape_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* Decode the device minor number into its parts */ void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi) { @@ -912,6 +942,7 @@ int __init viotap_init(void) int ret; char tapename[32]; int i; + struct proc_dir_entry *e; op_struct_list = NULL; if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { @@ -988,6 +1019,12 @@ int __init viotap_init(void) viotape_unitinfo[i].model); } + e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); + if (e) { + e->owner = THIS_MODULE; + e->proc_fops = &proc_viotape_operations; + } + return 0; unreg_class: @@ -1029,6 +1066,8 @@ static void __exit viotap_exit(void) { int i, ret; + remove_proc_entry("iSeries/viotape", NULL); + for (i = 0; i < viotape_numdev; ++i) { devfs_remove("iseries/nvt%d", i); devfs_remove("iseries/vt%d", i); diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 5564eb107fdf..7cd60dc50d81 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -143,19 +143,6 @@ config ALIM7101_WDT Most people will say N. -config AMD7XX_TCO - tristate "AMD 766/768 TCO Timer/Watchdog" - depends on WATCHDOG && X86 && PCI - help - This is the driver for the hardware watchdog built in to the - AMD 766/768 chipsets. - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called amd7xx_tco. - config SC520_WDT tristate "AMD Elan SC520 processor Watchdog" depends on WATCHDOG && X86 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 7ca0de685497..6eb9a783d5a8 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o -obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o diff --git a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c deleted file mode 100644 index d29b4f2bb18c..000000000000 --- a/drivers/char/watchdog/amd7xx_tco.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * AMD 766/768 TCO Timer Driver - * (c) Copyright 2002 Zwane Mwaikambo <zwane@holomorphy.com> - * All Rights Reserved. - * - * Parts from; - * Hardware driver for the AMD 768 Random Number Generator (RNG) - * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * The author(s) of this software shall not be held liable for damages - * of any nature resulting due to the use of this software. This - * software is provided AS-IS with no warranties. - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/ioport.h> -#include <linux/spinlock.h> -#include <asm/semaphore.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/pci.h> - -#define AMDTCO_MODULE_VER "build 20021116" -#define AMDTCO_MODULE_NAME "amd7xx_tco" -#define PFX AMDTCO_MODULE_NAME ": " - -#define MAX_TIMEOUT 38 /* max of 38 seconds, although the system will only - * reset itself after the second timeout */ - -/* pmbase registers */ -#define TCO_RELOAD_REG 0x40 /* bits 0-5 are current count, 6-7 are reserved */ -#define TCO_INITVAL_REG 0x41 /* bits 0-5 are value to load, 6-7 are reserved */ -#define TCO_TIMEOUT_MASK 0x3f -#define TCO_STATUS1_REG 0x44 -#define TCO_STATUS2_REG 0x46 -#define NDTO_STS2 (1 << 1) /* we're interested in the second timeout */ -#define BOOT_STS (1 << 2) /* will be set if NDTO_STS2 was set before reboot */ -#define TCO_CTRL1_REG 0x48 -#define TCO_HALT (1 << 11) -#define NO_REBOOT (1 << 10) /* in DevB:3x48 */ - -static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n"; -static int timeout = MAX_TIMEOUT; -static u32 pmbase; /* PMxx I/O base */ -static struct pci_dev *dev; -static struct semaphore open_sem; -static spinlock_t amdtco_lock; /* only for device access */ -static char expect_close; - -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -static inline u8 seconds_to_ticks(int seconds) -{ - /* the internal timer is stored as ticks which decrement - * every 0.6 seconds */ - return (seconds * 10) / 6; -} - -static inline int ticks_to_seconds(u8 ticks) -{ - return (ticks * 6) / 10; -} - -static inline int amdtco_status(void) -{ - u16 reg; - int status = 0; - - reg = inb(pmbase+TCO_CTRL1_REG); - if ((reg & TCO_HALT) == 0) - status |= WDIOF_KEEPALIVEPING; - - reg = inb(pmbase+TCO_STATUS2_REG); - if (reg & BOOT_STS) - status |= WDIOF_CARDRESET; - - return status; -} - -static inline void amdtco_ping(void) -{ - outb(1, pmbase+TCO_RELOAD_REG); -} - -static inline int amdtco_gettimeout(void) -{ - u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; - return ticks_to_seconds(reg); -} - -static inline void amdtco_settimeout(unsigned int timeout) -{ - u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK; - outb(reg, pmbase+TCO_INITVAL_REG); -} - -static inline void amdtco_global_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - - /* clear NO_REBOOT on DevB:3x48 p97 */ - pci_read_config_word(dev, 0x48, ®); - reg &= ~NO_REBOOT; - pci_write_config_word(dev, 0x48, reg); - - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg &= ~TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_disable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg |= TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static int amdtco_fop_open(struct inode *inode, struct file *file) -{ - if (down_trylock(&open_sem)) - return -EBUSY; - - if (timeout > MAX_TIMEOUT) - timeout = MAX_TIMEOUT; - - amdtco_disable(); - amdtco_settimeout(timeout); - amdtco_global_enable(); - amdtco_enable(); - amdtco_ping(); - printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n", - amdtco_gettimeout(), timeout); - - return 0; -} - - -static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - int new_timeout; - int tmp; - - static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | WDIOF_CARDRESET, - .identity = "AMD 766/768", - }; - - switch (cmd) { - default: - return -ENOIOCTLCMD; - - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - return put_user(amdtco_status(), (int *)arg); - - case WDIOC_KEEPALIVE: - amdtco_ping(); - return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, (int *)arg)) - return -EFAULT; - - if (new_timeout < 0) - return -EINVAL; - - if (new_timeout > MAX_TIMEOUT) - new_timeout = MAX_TIMEOUT; - - timeout = new_timeout; - amdtco_settimeout(timeout); - /* fall through and return the new timeout */ - - case WDIOC_GETTIMEOUT: - return put_user(amdtco_gettimeout(), (int *)arg); - - case WDIOC_SETOPTIONS: - if (copy_from_user(&tmp, (int *)arg, sizeof tmp)) - return -EFAULT; - - if (tmp & WDIOS_DISABLECARD) - amdtco_disable(); - - if (tmp & WDIOS_ENABLECARD) - amdtco_enable(); - - return 0; - } -} - - -static int amdtco_fop_release(struct inode *inode, struct file *file) -{ - if (expect_close == 42) { - amdtco_disable(); - printk(KERN_INFO PFX "Watchdog disabled\n"); - } else { - amdtco_ping(); - printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout); - } - - expect_close = 0; - up(&open_sem); - return 0; -} - - -static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (len) { - if (!nowayout) { - size_t i; - char c; - expect_close = 0; - - for (i = 0; i != len; i++) { - if (get_user(c, data + i)) - return -EFAULT; - - if (c == 'V') - expect_close = 42; - } - } - amdtco_ping(); - } - - return len; -} - - -static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - amdtco_disable(); - - return NOTIFY_DONE; -} - - -static struct notifier_block amdtco_notifier = -{ - .notifier_call = amdtco_notify_sys, -}; - -static struct file_operations amdtco_fops = -{ - .owner = THIS_MODULE, - .write = amdtco_fop_write, - .ioctl = amdtco_fop_ioctl, - .open = amdtco_fop_open, - .release = amdtco_fop_release, -}; - -static struct miscdevice amdtco_miscdev = -{ - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &amdtco_fops, -}; - -static struct pci_device_id amdtco_pci_tbl[] = { - /* AMD 766 PCI_IDs here */ - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, -}; - -MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl); - -static int __init amdtco_init(void) -{ - int ret; - - sema_init(&open_sem, 1); - spin_lock_init(&amdtco_lock); - - dev = NULL; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_match_device (amdtco_pci_tbl, dev) != NULL) - goto found_one; - } - - return -ENODEV; - -found_one: - - if ((ret = register_reboot_notifier(&amdtco_notifier))) { - printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); - goto out_clean; - } - - if ((ret = misc_register(&amdtco_miscdev))) { - printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); - goto out_unreg_reboot; - } - - pci_read_config_dword(dev, 0x58, &pmbase); - pmbase &= 0x0000FF00; - - if (pmbase == 0) { - printk (KERN_ERR PFX "power management base not set\n"); - ret = -EIO; - goto out_unreg_misc; - } - - /* ret = 0; */ - printk(banner); - goto out_clean; - -out_unreg_misc: - misc_deregister(&amdtco_miscdev); -out_unreg_reboot: - unregister_reboot_notifier(&amdtco_notifier); -out_clean: - return ret; -} - -static void __exit amdtco_exit(void) -{ - misc_deregister(&amdtco_miscdev); - unregister_reboot_notifier(&amdtco_notifier); -} - -module_init(amdtco_init); -module_exit(amdtco_exit); - -MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>"); -MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d5a18851ae73..2c5afb66639a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -360,8 +360,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) return -EINVAL; policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); - if (!policy) - return -ENOMEM; + if (!policy) { + ret = -ENOMEM; + goto nomem_out; + } memset(policy, 0, sizeof(struct cpufreq_policy)); policy->cpu = cpu; @@ -410,7 +412,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) return 0; - err_out_unregister: +err_out_unregister: spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_cpu_data[cpu] = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -418,8 +420,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) kobject_unregister(&policy->kobj); wait_for_completion(&policy->kobj_unregister); - err_out: +err_out: kfree(policy); + +nomem_out: module_put(cpufreq_driver->owner); return ret; } diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 709dddc0d369..99ac1419dc79 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -167,8 +167,8 @@ cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, void __user *buffer, size_t *lenp) { char buf[16], *p; - int cpu = (int) ctl->extra1; - int len, left = *lenp; + int cpu = (long) ctl->extra1; + unsigned int len, left = *lenp; if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) { *lenp = 0; @@ -205,7 +205,7 @@ cpufreq_sysctl(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { - int cpu = (int) table->extra1; + int cpu = (long) table->extra1; if (!cpu_online(cpu)) return -EINVAL; diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 79c9cb80fd0a..ac2246dd7646 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -86,7 +86,7 @@ static struct edd_device *edd_devices[EDDMAXNR]; #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \ struct edd_attribute edd_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .test = _test, \ }; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a316abaf7400..b3d7a002afba 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1695,6 +1695,7 @@ static int idedisk_cleanup (ide_drive_t *drive) if (ide_unregister_subdriver(drive)) return 1; del_gendisk(g); + drive->devfs_name[0] = '\0'; g->fops = ide_fops; return 0; } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 78da95051201..4257350fa4b0 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -48,7 +48,6 @@ #include <linux/delay.h> #include <linux/ide.h> #include <linux/spinlock.h> -#include <linux/pci.h> #include <linux/kmod.h> #include <linux/pci.h> diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index d2aa9b09ab02..fb7ae0006249 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -362,7 +362,6 @@ void ide_config(dev_link_t *link) goto failed; } - MOD_INC_USE_COUNT; info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2)); info->node.major = ide_major[hd]; @@ -408,7 +407,6 @@ void ide_release(dev_link_t *link) if (link->io.NumPorts2) request_region(link->io.BasePort2, link->io.NumPorts2, info->node.dev_name); - MOD_DEC_USE_COUNT; } info->ndev = 0; link->dev = NULL; diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 234990c08a35..8dc51e2966e4 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -11,8 +11,8 @@ * and VAXstations, but can also be used on any standard RS232 with an * adaptor). * - * DISCLAUNER: This works for _me_. If you break anything by using the - * information given below, I will _not_ be lieable! + * DISCLAIMER: This works for _me_. If you break anything by using the + * information given below, I will _not_ be liable! * * RJ11 pinout: To DB9: Or DB25: * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) @@ -34,23 +34,32 @@ * Additionally, you have to get +12V from somewhere. * Most easily, you'll get that from a floppy or HDD power connector. * It's the yellow cable there (black is ground and red is +5V). + * + * The keyboard and all the commands it understands are documented in + * "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This + * document is LK201 specific, but LK401 is mostly compatible. It comes + * up in LK201 mode and doesn't report any of the additional keys it + * has. These need to be switched on with the LK_CMD_ENABLE_LK401 + * command. You'll find this document (scanned .pdf file) on MANX, + * a search engine specific to DEC documentation. Try + * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * email or by paper mail: * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), @@ -67,8 +76,7 @@ #include <linux/serio.h> #include <linux/workqueue.h> - -MODULE_AUTHOR ("Jan-Benedict Glaw <jblaw@lug-owl.de>"); +MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); MODULE_DESCRIPTION ("LK keyboard driver"); MODULE_LICENSE ("GPL"); @@ -92,6 +100,11 @@ static int ctrlclick_volume = 100; /* % */ module_param (ctrlclick_volume, int, 0); MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); +static int lk201_compose_is_alt = 0; +module_param (lk201_compose_is_alt, int, 0); +MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key " + "will act as an Alt key"); + #undef LKKBD_DEBUG @@ -126,8 +139,11 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); #define LK_CMD_SET_DEFAULTS 0xd3 #define LK_CMD_POWERCYCLE_RESET 0xfd #define LK_CMD_ENABLE_LK401 0xe9 +#define LK_CMD_REQUEST_ID 0xab /* Misc responses from keyboard */ +#define LK_STUCK_KEY 0x3d +#define LK_SELFTEST_FAILED 0x3e #define LK_ALL_KEYS_UP 0xb3 #define LK_METRONOME 0xb4 #define LK_OUTPUT_ERROR 0xb5 @@ -139,6 +155,7 @@ MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); #define LK_RESPONSE_RESERVED 0xbb #define LK_NUM_KEYCODES 256 +#define LK_NUM_IGNORE_BYTES 6 typedef u_int16_t lk_keycode_t; @@ -267,6 +284,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { struct lkkbd { lk_keycode_t keycode[LK_NUM_KEYCODES]; int ignore_bytes; + unsigned char id[LK_NUM_IGNORE_BYTES]; struct input_dev dev; struct serio *serio; struct work_struct tq; @@ -313,6 +331,82 @@ volume_to_hw (int volume_percent) return ret; } +static void +lkkbd_detection_done (struct lkkbd *lk) +{ + int i; + + /* + * Reset setting for Compose key. Let Compose be KEY_COMPOSE. + */ + lk->keycode[0xb1] = KEY_COMPOSE; + + /* + * Print keyboard name and modify Compose=Alt on user's request. + */ + switch (lk->id[4]) { + case 1: + sprintf (lk->name, "DEC LK201 keyboard"); + + if (lk201_compose_is_alt) + lk->keycode[0xb1] = KEY_LEFTALT; + break; + + case 2: + sprintf (lk->name, "DEC LK401 keyboard"); + break; + + default: + sprintf (lk->name, "Unknown DEC keyboard"); + printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " + "please report to Jan-Benedict Glaw " + "<jbglaw@lug-owl.de>\n", lk->phys); + printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); + for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) + printk (" 0x%02x", lk->id[i]); + printk ("\n"); + break; + } + printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", + lk->phys, lk->name); + + /* + * Report errors during keyboard boot-up. + */ + switch (lk->id[2]) { + case 0x00: + /* All okay */ + break; + + case LK_STUCK_KEY: + printk (KERN_ERR "lkkbd: Stuck key on keyboard at " + "%s\n", lk->phys); + break; + + case LK_SELFTEST_FAILED: + printk (KERN_ERR "lkkbd: Selftest failed on keyboard " + "at %s, keyboard may not work " + "properly\n", lk->phys); + break; + + default: + printk (KERN_ERR "lkkbd: Unknown error %02x on " + "keyboard at %s\n", lk->id[2], + lk->phys); + break; + } + + /* + * Try to hint user if there's a stuck key. + */ + if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) + printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " + "is 0x%04x\n", lk->id[3], + lk->keycode[lk->id[3]]); + + return; +} + /* * lkkbd_interrupt() is called by the low level driver when a character * is received. @@ -329,7 +423,11 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, if (lk->ignore_bytes > 0) { DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); - lk->ignore_bytes--; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; + + if (lk->ignore_bytes == 0) + lkkbd_detection_done (lk); + return IRQ_HANDLED; } @@ -375,7 +473,8 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, break; case 0x01: DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); - lk->ignore_bytes = 3; + lk->ignore_bytes = LK_NUM_IGNORE_BYTES; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; schedule_work (&lk->tq); break; @@ -389,7 +488,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, input_sync (&lk->dev); } else printk (KERN_WARNING "%s: Unknown key with " - "scancode %02x on %s.\n", + "scancode 0x%02x on %s.\n", __FILE__, data, lk->name); } @@ -467,6 +566,9 @@ lkkbd_reinit (void *data) unsigned char leds_on = 0; unsigned char leds_off = 0; + /* Ask for ID */ + lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); + /* Reset parameters */ lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); @@ -527,9 +629,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) if ((serio->type & SERIO_TYPE) != SERIO_RS232) return; - if (!(serio->type & SERIO_PROTO)) - return; - if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD) + if ((serio->type & SERIO_PROTO) != SERIO_LKKBD) return; if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) @@ -537,10 +637,16 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) memset (lk, 0, sizeof (struct lkkbd)); init_input_dev (&lk->dev); - - lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP); - lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP); - lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL); + set_bit (EV_KEY, lk->dev.evbit); + set_bit (EV_LED, lk->dev.evbit); + set_bit (EV_SND, lk->dev.evbit); + set_bit (EV_REP, lk->dev.evbit); + set_bit (LED_CAPSL, lk->dev.ledbit); + set_bit (LED_SLEEP, lk->dev.ledbit); + set_bit (LED_COMPOSE, lk->dev.ledbit); + set_bit (LED_SCROLLL, lk->dev.ledbit); + set_bit (SND_BELL, lk->dev.sndbit); + set_bit (SND_CLICK, lk->dev.sndbit); lk->serio = serio; @@ -564,14 +670,13 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) return; } - sprintf (lk->name, "LK keyboard"); + sprintf (lk->name, "DEC LK keyboard"); + sprintf (lk->phys, "%s/input0", serio->phys); memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); for (i = 0; i < LK_NUM_KEYCODES; i++) set_bit (lk->keycode[i], lk->dev.keybit); - sprintf (lk->name, "%s/input0", serio->phys); - lk->dev.name = lk->name; lk->dev.phys = lk->phys; lk->dev.id.bustype = BUS_RS232; @@ -599,9 +704,9 @@ lkkbd_disconnect (struct serio *serio) } static struct serio_dev lkkbd_dev = { - .interrupt = lkkbd_interrupt, .connect = lkkbd_connect, .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 13086cec9f49..17db090dc6f6 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -119,7 +119,7 @@ config MOUSE_RISCPC module will be called rpcmouse. config MOUSE_VSXXXAA - tristate "DEC VSXXX-AA/GA mouse and tablet" + tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet" depends on INPUT && INPUT_MOUSE select SERIO help diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index bcc0d3ae219f..c26d907e8bb9 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -11,14 +11,14 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -45,32 +45,32 @@ * * DEC socket DB9 DB25 Note * 1 (GND) 5 7 - - * 2 (RxD) 3 3 - - * 3 (TxD) 2 2 - + * 2 (RxD) 2 3 - + * 3 (TxD) 3 2 - * 4 (-12V) - - Somewhere from the PSU. At ATX, it's - * the blue wire at pin 12 of the ATX - * power connector. Please note that the - * docs say this should be +12V! However, - * I measured -12V... - * 5 (+5V) - - PSU (red wire of ATX power connector + * the thin blue wire at pin 12 of the + * ATX power connector. Only required for + * VSXXX-AA/-GA mice. + * 5 (+5V) - - PSU (red wires of ATX power connector * on pin 4, 6, 19 or 20) or HDD power - * connector (also red wire) - * 6 (not conn.) - - - + * connector (also red wire). + * 6 (+12V) - - HDD power connector, yellow wire. Only + * required for VSXXX-AB digitizer. * 7 (dev. avail.) - - The mouse shorts this one to pin 1. * This way, the host computer can detect * the mouse. To use it with the adaptor, * simply don't connect this pin. * * So to get a working adaptor, you need to connect the mouse with three - * wires to a RS232 port and two additional wires for +5V and -12V to the - * PSU. + * wires to a RS232 port and two or three additional wires for +5V, +12V and + * -12V to the PSU. * * Flow specification for the link is 4800, 8o1. - */ - -/* - * TODO list: - * - Automatically attach to a given serial port (no need for inputattach). + * + * The mice and tablet are described in "VCB02 Video Subsystem - Technical + * Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine + * specific for DEC documentation. Try + * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1 */ #include <linux/delay.h> @@ -115,6 +115,7 @@ struct vsxxxaa { unsigned char version; unsigned char country; unsigned char type; + char name[64]; char phys[32]; }; @@ -134,27 +135,34 @@ vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) { if (mouse->count == BUFLEN) { printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", - mouse->dev.name, mouse->dev.phys); + mouse->name, mouse->phys); vsxxxaa_drop_bytes (mouse, 1); } + DBG (KERN_INFO "Queueing byte 0x%02x\n", byte); mouse->buf[mouse->count++] = byte; } static void -vsxxxaa_report_mouse (struct vsxxxaa *mouse) +vsxxxaa_detection_done (struct vsxxxaa *mouse) { - char *devtype; - switch (mouse->type) { - case 0x02: devtype = "DEC mouse"; break; - case 0x04: devtype = "DEC tablet"; break; - default: devtype = "unknown DEC device"; break; + case 0x02: + sprintf (mouse->name, "DEC VSXXX-AA/GA mouse"); + break; + + case 0x04: + sprintf (mouse->name, "DEC VSXXX-AB digitizer"); + break; + + default: + sprintf (mouse->name, "unknown DEC pointer device"); + break; } - printk (KERN_INFO "Found %s version 0x%x from country 0x%x " - "on port %s\n", devtype, mouse->version, - mouse->country, mouse->dev.phys); + printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x " + "on port %s\n", mouse->name, mouse->version, + mouse->country, mouse->phys); } /* @@ -216,7 +224,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) * 0, bit 4 of byte 0 is direction. */ dx = buf[1] & 0x7f; - dx *= ((buf[0] >> 4) & 0x01)? -1: 1; + dx *= ((buf[0] >> 4) & 0x01)? 1: -1; /* * Low 7 bit of byte 2 are abs(dy), bit 7 is @@ -236,7 +244,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) vsxxxaa_drop_bytes (mouse, 3); DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", - mouse->dev.name, mouse->dev.phys, dx, dy, + mouse->name, mouse->phys, dx, dy, left? "L": "l", middle? "M": "m", right? "R": "r"); /* @@ -246,6 +254,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_TOUCH, 0); input_report_rel (dev, REL_X, dx); input_report_rel (dev, REL_Y, dy); input_sync (dev); @@ -256,7 +265,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) { struct input_dev *dev = &mouse->dev; unsigned char *buf = mouse->buf; - int left, middle, right, extra; + int left, middle, right, touch; int x, y; /* @@ -270,10 +279,12 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) */ /* - * Get X/Y position + * Get X/Y position. Y axis needs to be inverted since VSXXX-AB + * counts down->top while monitor counts top->bottom. */ x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f); y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f); + y = 1023 - y; /* * Get button state. It's bits <4..1> of byte 0. @@ -281,14 +292,14 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) left = (buf[0] & 0x02)? 1: 0; middle = (buf[0] & 0x04)? 1: 0; right = (buf[0] & 0x08)? 1: 0; - extra = (buf[0] & 0x10)? 1: 0; + touch = (buf[0] & 0x10)? 1: 0; vsxxxaa_drop_bytes (mouse, 5); DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", - mouse->dev.name, mouse->dev.phys, x, y, + mouse->name, mouse->phys, x, y, left? "L": "l", middle? "M": "m", - right? "R": "r", extra? "E": "e"); + right? "R": "r", touch? "T": "t"); /* * Report what we've found so far... @@ -297,7 +308,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); - input_report_key (dev, BTN_EXTRA, extra); + input_report_key (dev, BTN_TOUCH, touch); input_report_abs (dev, ABS_X, x); input_report_abs (dev, ABS_Y, y); input_sync (dev); @@ -334,7 +345,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) mouse->version = buf[0] & 0x0f; mouse->country = (buf[1] >> 4) & 0x07; - mouse->type = buf[1] & 0x07; + mouse->type = buf[1] & 0x0f; error = buf[2] & 0x7f; /* @@ -347,7 +358,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) right = (buf[0] & 0x01)? 1: 0; vsxxxaa_drop_bytes (mouse, 4); - vsxxxaa_report_mouse (mouse); + vsxxxaa_detection_done (mouse); if (error <= 0x1f) { /* No error. Report buttons */ @@ -355,20 +366,22 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) input_report_key (dev, BTN_LEFT, left); input_report_key (dev, BTN_MIDDLE, middle); input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_TOUCH, 0); input_sync (dev); } else { printk (KERN_ERR "Your %s on %s reports an undefined error, " - "please check it...\n", mouse->dev.name, - mouse->dev.phys); + "please check it...\n", mouse->name, + mouse->phys); } /* - * If the mouse was hot-plugged, we need to - * force differential mode now... + * If the mouse was hot-plugged, we need to force differential mode + * now... However, give it a second to recover from it's reset. */ printk (KERN_NOTICE "%s on %s: Forceing standard packet format and " - "streaming mode\n", mouse->dev.name, mouse->dev.phys); + "streaming mode\n", mouse->name, mouse->phys); mouse->serio->write (mouse->serio, 'S'); + mdelay (50); mouse->serio->write (mouse->serio, 'R'); } @@ -392,7 +405,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { printk (KERN_ERR "%s on %s: Dropping a byte to regain " "sync with mouse data stream...\n", - mouse->dev.name, mouse->dev.phys); + mouse->name, mouse->phys); vsxxxaa_drop_bytes (mouse, 1); } @@ -475,7 +488,6 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) if ((serio->type & SERIO_TYPE) != SERIO_RS232) return; - if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA) return; @@ -486,14 +498,15 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) init_input_dev (&mouse->dev); set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ - set_bit (EV_REL, mouse->dev.evbit); /* We can move */ + set_bit (EV_REL, mouse->dev.evbit); + set_bit (EV_ABS, mouse->dev.evbit); set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ set_bit (BTN_MIDDLE, mouse->dev.keybit); set_bit (BTN_RIGHT, mouse->dev.keybit); - set_bit (BTN_EXTRA, mouse->dev.keybit); /* ...and Tablet */ - set_bit (REL_X, mouse->dev.relbit); /* We can move in */ - set_bit (REL_Y, mouse->dev.relbit); /* two dimensions */ - set_bit (ABS_X, mouse->dev.absbit); /* DEC tablet support */ + set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */ + set_bit (REL_X, mouse->dev.relbit); + set_bit (REL_Y, mouse->dev.relbit); + set_bit (ABS_X, mouse->dev.absbit); set_bit (ABS_Y, mouse->dev.absbit); mouse->dev.absmin[ABS_X] = 0; @@ -504,9 +517,10 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) mouse->dev.private = mouse; serio->private = mouse; + sprintf (mouse->name, "DEC VSXXX-AA/GA mouse or VSXXX-AB digitizer"); sprintf (mouse->phys, "%s/input0", serio->phys); + mouse->dev.name = mouse->name; mouse->dev.phys = mouse->phys; - mouse->dev.name = "DEC VSXXX-AA/GA mouse or DEC tablet"; mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; @@ -516,20 +530,20 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) } /* - * Request selftest and differential stream mode. + * Request selftest. Standard packet format and differential + * mode will be requested after the device ID'ed successfully. */ mouse->serio->write (mouse->serio, 'T'); /* Test */ - mouse->serio->write (mouse->serio, 'R'); /* Differential stream */ input_register_device (&mouse->dev); - printk (KERN_INFO "input: %s on %s\n", mouse->dev.name, serio->phys); + printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } static struct serio_dev vsxxxaa_dev = { - .interrupt = vsxxxaa_interrupt, - .connect = vsxxxaa_connect, - .disconnect = vsxxxaa_disconnect + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 10a54ddd2540..cacd1f20ea5f 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -130,3 +130,13 @@ config SERIO_PCIPS2 To compile this driver as a module, choose M here: the module will be called pcips2. + +config SERIO_MACEPS2 + tristate "SGI O2 MACE PS/2 controller" + depends on SGI_IP32 && SERIO + help + Say Y here if you have SGI O2 workstation and want to use its + PS/2 ports. + + To compile this driver as a module, choose M here: the + module will be called maceps2. diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 2eb86eba6ed9..a47dec2556e8 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o +obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 6b434f8b62f1..9b36485fc605 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -69,7 +69,7 @@ static inline int i8042_platform_init(void) * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. */ -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -1; #endif diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h new file mode 100644 index 000000000000..863b9c95fbb8 --- /dev/null +++ b/drivers/input/serio/i8042-ip22io.h @@ -0,0 +1,76 @@ +#ifndef _I8042_IP22_H +#define _I8042_IP22_H + +#include <asm/sgi/ioc.h> +#include <asm/sgi/ip22.h> + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "hpc3ps2/serio0" +#define I8042_AUX_PHYS_DESC "hpc3ps2/serio1" +#define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ SGI_KEYBD_IRQ +#define I8042_AUX_IRQ SGI_KEYBD_IRQ + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data) + +static inline int i8042_read_data(void) +{ + return sgioc->kbdmouse.data; +} + +static inline int i8042_read_status(void) +{ + return sgioc->kbdmouse.command; +} + +static inline void i8042_write_data(int val) +{ + sgioc->kbdmouse.data = val; +} + +static inline void i8042_write_command(int val) +{ + sgioc->kbdmouse.command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX sgi_kh is a virtual address */ + if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) + return 1; +#endif + + i8042_reset = 1; + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb)); +#endif +} + +#endif /* _I8042_IP22_H */ diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h new file mode 100644 index 000000000000..5c20ab131488 --- /dev/null +++ b/drivers/input/serio/i8042-jazzio.h @@ -0,0 +1,69 @@ +#ifndef _I8042_JAZZ_H +#define _I8042_JAZZ_H + +#include <asm/jazz.h> + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "R4030/serio0" +#define I8042_AUX_PHYS_DESC "R4030/serio1" +#define I8042_MUX_PHYS_DESC "R4030/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ +#define I8042_AUX_IRQ JAZZ_MOUSE_IRQ + +#define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command) +#define I8042_STATUS_REG ((unsigned long)&jazz_kh->command) +#define I8042_DATA_REG ((unsigned long)&jazz_kh->data) + +static inline int i8042_read_data(void) +{ + return jazz_kh->data; +} + +static inline int i8042_read_status(void) +{ + return jazz_kh->command; +} + +static inline void i8042_write_data(int val) +{ + jazz_kh->data = val; +} + +static inline void i8042_write_command(int val) +{ + jazz_kh->command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ + if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) + return 1; +#endif + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2); +#endif +} + +#endif /* _I8042_JAZZ_H */ diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index 3d59eb2e05a7..f0f637483233 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -1,6 +1,8 @@ #ifndef _I8042_H #define _I8042_H +#include <linux/config.h> + /* * Copyright (c) 1999-2002 Vojtech Pavlik * @@ -13,7 +15,11 @@ * Arch-dependent inline functions and defines. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_MIPS_JAZZ) +#include "i8042-jazzio.h" +#elif defined(CONFIG_SGI_IP22) +#include "i8042-ip22io.h" +#elif defined(CONFIG_PPC) #include "i8042-ppcio.h" #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) #include "i8042-sparcio.h" diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c new file mode 100644 index 000000000000..c7db1de49cfc --- /dev/null +++ b/drivers/input/serio/maceps2.c @@ -0,0 +1,160 @@ +/* + * SGI O2 MACE PS2 controller driver for linux + * + * Copyright (C) 2002 Vivien Chappelier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/serio.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/ip32/mace.h> +#include <asm/ip32/ip32_ints.h> + +MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org"); +MODULE_DESCRIPTION("SGI O2 MACE PS2 controller driver"); +MODULE_LICENSE("GPL"); + +#define MACE_PS2_TIMEOUT 10000 /* in 50us unit */ + +#define PS2_STATUS_CLOCK_SIGNAL BIT(0) /* external clock signal */ +#define PS2_STATUS_CLOCK_INHIBIT BIT(1) /* clken output signal */ +#define PS2_STATUS_TX_INPROGRESS BIT(2) /* transmission in progress */ +#define PS2_STATUS_TX_EMPTY BIT(3) /* empty transmit buffer */ +#define PS2_STATUS_RX_FULL BIT(4) /* full receive buffer */ +#define PS2_STATUS_RX_INPROGRESS BIT(5) /* reception in progress */ +#define PS2_STATUS_ERROR_PARITY BIT(6) /* parity error */ +#define PS2_STATUS_ERROR_FRAMING BIT(7) /* framing error */ + +#define PS2_CONTROL_TX_CLOCK_DISABLE BIT(0) /* inhibit clock signal after TX */ +#define PS2_CONTROL_TX_ENABLE BIT(1) /* transmit enable */ +#define PS2_CONTROL_TX_INT_ENABLE BIT(2) /* enable transmit interrupt */ +#define PS2_CONTROL_RX_INT_ENABLE BIT(3) /* enable receive interrupt */ +#define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ +#define PS2_CONTROL_RESET BIT(5) /* reset */ + + +struct maceps2_data { + struct mace_ps2port *port; + int irq; +}; + +static int maceps2_write(struct serio *dev, unsigned char val) +{ + struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + unsigned int timeout = MACE_PS2_TIMEOUT; + + do { + if (mace_read(port->status) & PS2_STATUS_TX_EMPTY) { + mace_write(val, port->tx); + return 0; + } + udelay(50); + } while (timeout--); + + return -1; +} + +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct serio *dev = dev_id; + struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + unsigned int byte; + + if (mace_read(port->status) & PS2_STATUS_RX_FULL) { + byte = mace_read(port->rx); + serio_interrupt(dev, byte & 0xff, 0, regs); + } + + return IRQ_HANDLED; +} + +static int maceps2_open(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { + printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); + return -EBUSY; + } + + /* Reset port */ + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + + /* Enable interrupts */ + mace_write(PS2_CONTROL_RX_CLOCK_ENABLE | PS2_CONTROL_TX_ENABLE | + PS2_CONTROL_RX_INT_ENABLE, data->port->control); + + return 0; +} + +static void maceps2_close(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + free_irq(data->irq, dev); +} + +static struct maceps2_data port0_data, port1_data; + +static struct serio maceps2_port0 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port0", + .phys = "mace/serio0", + .driver = &port0_data, +}; + +static struct serio maceps2_port1 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port1", + .phys = "mace/serio1", + .driver = &port1_data, +}; + +static int __init maceps2_init(void) +{ + port0_data.port = &mace->perif.ps2.keyb; + port0_data.irq = MACEISA_KEYB_IRQ; + port1_data.port = &mace->perif.ps2.mouse; + port1_data.irq = MACEISA_MOUSE_IRQ; + serio_register_port(&maceps2_port0); + serio_register_port(&maceps2_port1); + + return 0; +} + +static void __exit maceps2_exit(void) +{ + serio_unregister_port(&maceps2_port0); + serio_unregister_port(&maceps2_port1); +} + +module_init(maceps2_init); +module_exit(maceps2_exit); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0270a5659727..bdfcbe09d4d5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -12,6 +12,7 @@ #include <linux/moduleparam.h> #include <linux/blkpg.h> #include <linux/bio.h> +#include <linux/buffer_head.h> #include <linux/mempool.h> #include <linux/slab.h> @@ -46,6 +47,7 @@ struct target_io { */ #define DMF_BLOCK_IO 0 #define DMF_SUSPENDED 1 +#define DMF_FS_LOCKED 2 struct mapped_device { struct rw_semaphore lock; @@ -80,6 +82,11 @@ struct mapped_device { */ uint32_t event_nr; wait_queue_head_t eventq; + + /* + * freeze/thaw support require holding onto a super block + */ + struct super_block *frozen_sb; }; #define MIN_IOS 256 @@ -885,6 +892,52 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) } /* + * Functions to lock and unlock any filesystem running on the + * device. + */ +static int __lock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __lock_fs"); + return -ENOMEM; + } + + WARN_ON(md->frozen_sb); + md->frozen_sb = freeze_bdev(bdev); + /* don't bdput right now, we don't want the bdev + * to go away while it is locked. We'll bdput + * in __unlock_fs + */ + return 0; +} + +static int __unlock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __unlock_fs"); + return -ENOMEM; + } + + thaw_bdev(bdev, md->frozen_sb); + md->frozen_sb = NULL; + bdput(bdev); + bdput(bdev); + return 0; +} + +/* * We need to be able to change a mapping table under a mounted * filesystem. For example we might want to move some data in * the background. Before the table can be swapped with @@ -896,13 +949,27 @@ int dm_suspend(struct mapped_device *md) struct dm_table *map; DECLARE_WAITQUEUE(wait, current); - down_write(&md->lock); + /* Flush I/O to the device. */ + down_read(&md->lock); + if (test_bit(DMF_BLOCK_IO, &md->flags)) { + up_read(&md->lock); + return -EINVAL; + } + + __lock_fs(md); + up_read(&md->lock); /* * First we set the BLOCK_IO flag so no more ios will be * mapped. */ + down_write(&md->lock); if (test_bit(DMF_BLOCK_IO, &md->flags)) { + /* + * If we get here we know another thread is + * trying to suspend as well, so we leave the fs + * locked for this thread. + */ up_write(&md->lock); return -EINVAL; } @@ -937,6 +1004,7 @@ int dm_suspend(struct mapped_device *md) /* were we interrupted ? */ if (atomic_read(&md->pending)) { + __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); up_write(&md->lock); return -EINTR; @@ -974,6 +1042,7 @@ int dm_resume(struct mapped_device *md) def = bio_list_get(&md->deferred); __flush_deferred_io(md, def); up_write(&md->lock); + __unlock_fs(md); dm_table_unplug_all(map); dm_table_put(map); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 4850af52dcec..97fd269a90ee 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -61,7 +61,6 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/pci.h> #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -78,10 +77,11 @@ #include <asm/iSeries/HvTypes.h> #include <asm/iSeries/HvLpEvent.h> #include <asm/iommu.h> +#include <asm/vio.h> #include "iseries_veth.h" -extern struct pci_dev *iSeries_veth_dev; +extern struct vio_dev *iSeries_veth_dev; MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>"); MODULE_DESCRIPTION("iSeries Virtual ethernet driver"); @@ -895,10 +895,10 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp, } dma_length = skb->len; - dma_address = pci_map_single(iSeries_veth_dev, skb->data, - dma_length, PCI_DMA_TODEVICE); + dma_address = vio_map_single(iSeries_veth_dev, skb->data, + dma_length, DMA_TO_DEVICE); - if (pci_dma_mapping_error(dma_address)) + if (dma_mapping_error(dma_address)) goto recycle_and_drop; /* Is it really necessary to check the length and address @@ -1016,8 +1016,8 @@ static void veth_recycle_msg(struct veth_lpar_connection *cnx, dma_address = msg->data.addr[0]; dma_length = msg->data.len[0]; - pci_unmap_single(iSeries_veth_dev, dma_address, dma_length, - PCI_DMA_TODEVICE); + vio_unmap_single(iSeries_veth_dev, dma_address, dma_length, + DMA_TO_DEVICE); if (msg->skb) { dev_kfree_skb_any(msg->skb); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 87fa182a06b3..260b12b34779 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -24,8 +24,7 @@ obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o -obj-$(CONFIG_SGI_IP27) += setup-irq.o -obj-$(CONFIG_SGI_IP32) += setup-irq.o +obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_PCI_USE_VECTOR) += msi.o diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d0ab034fa0c1..ab9f28443436 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -7,7 +7,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.136 $ + * $Revision: 1.139 $ */ #include <linux/config.h> @@ -74,6 +74,8 @@ dasd_alloc_device(void) if (device == NULL) return ERR_PTR(-ENOMEM); memset(device, 0, sizeof (struct dasd_device)); + /* open_count = 0 means device online but not in use */ + atomic_set(&device->open_count, -1); /* Get two pages for normal block device operations. */ device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); @@ -549,6 +551,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } @@ -597,6 +600,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, } strncpy((char *) &cqr->magic, magic, 4); ASCEBC((char *) &cqr->magic, 4); + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } @@ -688,9 +692,10 @@ dasd_term_IO(struct dasd_ccw_req * cqr) rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ - if (cqr->retries > 0) + if (cqr->retries > 0) { + cqr->retries--; cqr->status = DASD_CQR_QUEUED; - else + } else cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); break; @@ -982,6 +987,8 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) era = dasd_era_none; + else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) + era = dasd_era_fatal; /* don't recover this request */ else if (irb->esw.esw0.erw.cons) era = device->discipline->examine_error(cqr, irb); else @@ -1875,7 +1882,7 @@ dasd_generic_set_offline (struct ccw_device *cdev) * the blkdev_get in dasd_scan_partitions. We are only interested * in the other openers. */ - max_count = device->bdev ? 1 : 0; + max_count = device->bdev ? 0 : -1; if (atomic_read(&device->open_count) > max_count) { printk (KERN_WARNING "Can't offline dasd device with open" " count = %i.\n", diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index c6b26e729aaa..e90c1c93e19a 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -5,7 +5,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * - * $Revision: 1.28 $ + * $Revision: 1.30 $ */ #include <linux/timer.h> @@ -1763,6 +1763,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) erp->magic = default_erp->magic; erp->expires = 0; erp->retries = 256; + cqr->buildclk = get_clock(); erp->status = DASD_CQR_FILLED; /* remove the default erp */ diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1490f1e4a4ec..e7afb426b539 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -7,7 +7,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.53 $ + * $Revision: 1.54 $ */ #include <linux/config.h> @@ -1130,6 +1130,7 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); @@ -1173,6 +1174,7 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); @@ -1215,6 +1217,7 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 70ccb1110d07..9967c082c0ad 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -6,7 +6,7 @@ * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.56 $ + * $Revision: 1.57 $ */ #ifndef DASD_INT_H @@ -159,6 +159,7 @@ struct dasd_ccw_req { struct ccw1 *cpaddr; /* address of channel program */ char status; /* status of this request */ short retries; /* A retry counter */ + unsigned long flags; /* flags of this request */ /* ... and how */ unsigned long starttime; /* jiffies time of request start */ @@ -192,6 +193,9 @@ struct dasd_ccw_req { #define DASD_CQR_ERROR 0x04 /* request is completed with error */ #define DASD_CQR_FAILED 0x05 /* request is finally failed */ +/* per dasd_ccw_req flags */ +#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ + /* Signature for error recovery functions. */ typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index ef0f996fa798..ecba07756cbb 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -381,6 +381,8 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; /* Sucessfully restarted. */ break; case RAW3270_IO_STOP: + if (!rq) + break; raw3270_halt_io_nolock(rp, rq); rq->rc = -EIO; break; @@ -881,7 +883,7 @@ raw3270_activate_view(struct raw3270_view *view) if (rc) { /* Didn't work. Try to reactivate the old view. */ rp->view = oldview; - if (oldview->fn->activate(oldview) != 0) { + if (!oldview || oldview->fn->activate(oldview) != 0) { /* Didn't work as well. Try any other view. */ list_for_each_entry(nv, &rp->view_list, list) if (nv != view && nv != oldview) { diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index cffeda66520e..ccdf053b3dfd 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.117 $ + * $Revision: 1.121 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -783,3 +783,68 @@ cio_get_console_subchannel(void) } #endif +static inline int +__disable_subchannel_easy(unsigned int schid, struct schib *schib) +{ + int retry, cc; + + cc = 0; + for (retry=0;retry<3;retry++) { + schib->pmcw.ena = 0; + cc = msch(schid, schib); + if (cc) + return (cc==3?-ENODEV:-EBUSY); + stsch(schid, schib); + if (!schib->pmcw.ena) + return 0; + } + return -EBUSY; /* uhm... */ +} + +static inline int +__clear_subchannel_easy(unsigned int schid) +{ + int retry; + + if (csch(schid)) + return -ENODEV; + for (retry=0;retry<20;retry++) { + struct tpi_info ti; + + if (tpi(&ti)) { + tsch(schid, (struct irb *)__LC_IRB); + return 0; + } + udelay(100); + } + return -EBUSY; +} + +extern void do_reipl(unsigned long devno); +/* Make sure all subchannels are quiet before we re-ipl an lpar. */ +void +reipl(unsigned long devno) +{ + unsigned int schid; + + local_irq_disable(); + for (schid=0;schid<=highest_subchannel;schid++) { + struct schib schib; + if (stsch(schid, &schib)) + goto out; + if (!schib.pmcw.ena) + continue; + switch(__disable_subchannel_easy(schid, &schib)) { + case 0: + case -ENODEV: + break; + default: /* -EBUSY */ + if (__clear_subchannel_easy(schid)) + break; /* give up... */ + stsch(schid, &schib); + __disable_subchannel_easy(schid, &schib); + } + } +out: + do_reipl(devno); +} diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index eac048a1991c..763056eede77 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -440,12 +440,14 @@ ccw_device_nopath_notify(void *data) if (!ret) { if (get_device(&sch->dev)) { /* Driver doesn't want to keep device. */ + cio_disable_subchannel(sch); device_unregister(&sch->dev); sch->schib.pmcw.intparm = 0; cio_modify(sch); put_device(&sch->dev); } } else { + cio_disable_subchannel(sch); ccw_device_set_timeout(cdev, 0); cdev->private->state = DEV_STATE_DISCONNECTED; wake_up(&cdev->private->wait_q); @@ -787,6 +789,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); + ccw_device_set_timeout(cdev, 0); /* OK, i/o is dead now. Call interrupt handler. */ cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 3188cde89326..f4c9779d2d4a 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.79 $" +#define VERSION_QDIO_C "$Revision: 1.80 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); @@ -461,12 +461,12 @@ check_next: switch(slsb[f_mod_no]) { - /* the hydra has not fetched the output yet */ + /* the adapter has not fetched the output yet */ case SLSB_CU_OUTPUT_PRIMED: QDIO_DBF_TEXT5(0,trace,"outpprim"); break; - /* the hydra got it */ + /* the adapter got it */ case SLSB_P_OUTPUT_EMPTY: atomic_dec(&q->number_of_buffers_used); f++; @@ -919,7 +919,7 @@ qdio_is_inbound_q_done(struct qdio_q *q) no_used=atomic_read(&q->number_of_buffers_used); /* - * we need that one for synchronization with Hydra, as Hydra + * we need that one for synchronization with the adapter, as it * does a kind of PCI avoidance */ SYNC_MEMORY; @@ -1069,7 +1069,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) } /* * maybe we have to do work on our outbound queues... at least - * we have to check Hydra outbound-int-capable thinint-capable + * we have to check the outbound-int-capable thinint-capable * queues */ if (q->hydra_gives_outbound_pcis) { @@ -2027,7 +2027,7 @@ tiqdio_check_chsc_availability(void) goto exit; } - /* Check for hydra thin interrupts (bit 67). */ + /* Check for OSA/FCP thin interrupts (bit 67). */ hydra_thinints = ((scsc_area->general_char[2] & 0x10000000) == 0x10000000); sprintf(dbf_text,"hydrati%1x", hydra_thinints); diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index 601453f1a6b9..5771fb36360f 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -1,5 +1,5 @@ /* - * $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $ + * $Id: iucv.c,v 1.28 2004/04/15 06:34:58 braunu Exp $ * * IUCV network driver * @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.27 $ + * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.28 $ * */ @@ -351,7 +351,7 @@ do { \ static void iucv_banner(void) { - char vbuf[] = "$Revision: 1.27 $"; + char vbuf[] = "$Revision: 1.28 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -800,6 +800,7 @@ iucv_register_program (__u8 pgmname[16], if (iucv_pathid_table == NULL) { printk(KERN_WARNING "%s: iucv_pathid_table storage " "allocation failed\n", __FUNCTION__); + kfree(new_handler); return NULL; } memset (iucv_pathid_table, 0, max_connections * sizeof(handler *)); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index fb30461252ab..a65ef7677beb 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.48 2004/04/01 13:42:09 braunu Exp $ + * $Id: netiucv.c,v 1.49 2004/04/15 06:37:54 braunu Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.48 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.49 $ * */ @@ -601,11 +601,12 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) if ((skb = skb_dequeue(&conn->commit_queue))) { atomic_dec(&skb->users); dev_kfree_skb_any(skb); - } - if (privptr) { - privptr->stats.tx_packets++; - privptr->stats.tx_bytes += - (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); + if (privptr) { + privptr->stats.tx_packets++; + privptr->stats.tx_bytes += + (skb->len - NETIUCV_HDRLEN + - NETIUCV_HDRLEN); + } } } conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; @@ -1078,6 +1079,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { "%s: Could not allocate tx_skb\n", conn->netdev->name); rc = -ENOMEM; + return rc; } else { skb_reserve(nskb, NETIUCV_HDRLEN); memcpy(skb_put(nskb, skb->len), @@ -1880,7 +1882,7 @@ static struct device_driver netiucv_driver = { static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.48 $"; + char vbuf[] = "$Revision: 1.49 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 1175c1e8deac..74b167b0f29a 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -23,7 +23,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.98 $" +#define VERSION_QETH_H "$Revision: 1.100 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" @@ -423,14 +423,12 @@ struct qeth_qdio_out_q { struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; int queue_no; struct qeth_card *card; - struct tasklet_struct tasklet; spinlock_t lock; volatile int do_pack; /* * index of buffer to be filled by driver; state EMPTY or PACKING */ volatile int next_buf_to_fill; - volatile int next_buf_to_flush; /* * number of buffers that are currently filled (PRIMED) * -> these buffers are hardware-owned @@ -447,7 +445,6 @@ struct qeth_qdio_info { struct qeth_qdio_buffer_pool in_buf_pool; struct qeth_qdio_buffer_pool init_pool; int in_buf_size; - struct tasklet_struct in_tasklet; /* output */ int no_out_queues; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 414d9c3de0d5..4ee0592f21d0 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.77 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.82 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier <tspat@de.ibm.com> * - * $Revision: 1.77 $ $Date: 2004/04/06 14:38:19 $ + * $Revision: 1.82 $ $Date: 2004/04/21 08:27:21 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ qeth_eyecatcher(void) #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.77 $" +#define VERSION_QETH_C "$Revision: 1.82 $" static const char *version = "qeth S/390 OSA-Express driver (" VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; @@ -486,6 +486,7 @@ qeth_remove_device(struct ccwgroup_device *cgdev) list_del(&card->list); write_unlock_irqrestore(&qeth_card_list.rwlock, flags); unregister_netdev(card->dev); + qeth_remove_device_attributes(&cgdev->dev); qeth_free_card(card); cgdev->dev.driver_data = NULL; put_device(&cgdev->dev); @@ -822,7 +823,7 @@ qeth_register_mc_addresses(void *ptr) struct qeth_card *card; card = (struct qeth_card *) ptr; - daemonize("getmcaddr"); + daemonize("qeth_reg_mcaddrs"); QETH_DBF_TEXT(trace,4,"regmcth1"); if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD)) return 0; @@ -843,7 +844,7 @@ qeth_register_ip_address(void *ptr) struct qeth_card *card; card = (struct qeth_card *) ptr; - daemonize("regip"); + daemonize("qeth_reg_ip"); QETH_DBF_TEXT(trace,4,"regipth1"); if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD)) return 0; @@ -860,7 +861,7 @@ qeth_recover(void *ptr) int rc = 0; card = (struct qeth_card *) ptr; - daemonize("recover"); + daemonize("qeth_recover"); QETH_DBF_TEXT(trace,2,"recover1"); QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) @@ -1969,45 +1970,6 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf, return rc; } -static void -qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, - unsigned int qdio_err, unsigned int siga_err, - unsigned int queue, int first_element, int count, - unsigned long card_ptr) -{ - struct net_device *net_dev; - struct qeth_card *card; - struct qeth_qdio_buffer *buffer; - int i; - - QETH_DBF_TEXT(trace, 6, "qdinput"); - card = (struct qeth_card *) card_ptr; - net_dev = card->dev; -#ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.inbound_start_time = qeth_get_micros(); -#endif - if (status & QDIO_STATUS_LOOK_FOR_ERROR) { - if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ - QETH_DBF_TEXT(trace, 1,"qdinchk"); - QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card)); - QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count); - QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status); - qeth_schedule_recovery(card); - return; - } - } - for (i = first_element; i < (first_element + count); ++i) { - buffer = &card->qdio.in_q->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - if ((status == QDIO_STATUS_LOOK_FOR_ERROR) && - qeth_check_for_inbound_error(buffer, qdio_err, siga_err)) - buffer->state = QETH_QDIO_BUF_ERROR; - else - buffer->state = QETH_QDIO_BUF_PRIMED; - } - - tasklet_schedule(&card->qdio.in_tasklet); -} - static inline struct sk_buff * qeth_get_skb(unsigned int length) { @@ -2127,7 +2089,6 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) return htons(ETH_P_802_2); } - static inline void qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) @@ -2193,7 +2154,6 @@ qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, #endif /* CONFIG_QETH_VLAN */ } - static inline void qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) @@ -2241,6 +2201,38 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, qeth_rebuild_skb_vlan(card, skb, hdr); } +static inline void +qeth_process_inbound_buffer(struct qeth_card *card, + struct qeth_qdio_buffer *buf, int index) +{ + struct qdio_buffer_element *element; + int offset; + struct sk_buff *skb; + struct qeth_hdr *hdr; + int rxrc; + + /* get first element of current buffer */ + element = (struct qdio_buffer_element *)&buf->buffer->element[0]; + offset = 0; +#ifdef CONFIG_QETH_PERF_STATS + card->perf_stats.bufs_rec++; +#endif + while((skb = qeth_get_next_skb(card, buf->buffer, &element, + &offset, &hdr))){ + qeth_rebuild_skb(card, skb, hdr); + +#ifdef CONFIG_QETH_PERF_STATS + card->perf_stats.inbound_time += qeth_get_micros() - + card->perf_stats.inbound_start_time; + card->perf_stats.inbound_cnt++; +#endif + skb->dev = card->dev; + rxrc = netif_rx(skb); + card->dev->last_rx = jiffies; + card->stats.rx_packets++; + card->stats.rx_bytes += skb->len; + } +} static inline struct qeth_buffer_pool_entry * qeth_get_buffer_pool_entry(struct qeth_card *card) @@ -2284,7 +2276,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) buf->state = QETH_QDIO_BUF_EMPTY; } -static void +static inline void qeth_clear_output_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf) { @@ -2355,61 +2347,43 @@ qeth_put_buffer_pool_entry(struct qeth_card *card, } static void -qeth_qdio_input_tasklet(unsigned long data) +qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, + unsigned int qdio_err, unsigned int siga_err, + unsigned int queue, int first_element, int count, + unsigned long card_ptr) { - struct qeth_card *card = (struct qeth_card *) data; - int current_buf = card->qdio.in_q->next_buf_to_process; - struct qeth_qdio_buffer *buf; - struct qdio_buffer_element *element; - int offset; - struct sk_buff *skb; - struct qeth_hdr *hdr; - int rxrc; - - QETH_DBF_TEXT(trace,6,"qdintlet"); - buf = &card->qdio.in_q->bufs[current_buf]; - while((buf->state == QETH_QDIO_BUF_PRIMED) || - (buf->state == QETH_QDIO_BUF_ERROR)){ - if (buf->state == QETH_QDIO_BUF_ERROR) - goto clear_buffer; - if (netif_queue_stopped(card->dev)) - goto clear_buffer; - /* get first element of current buffer */ - element = (struct qdio_buffer_element *) - &buf->buffer->element[0]; - offset = 0; -#ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.bufs_rec++; -#endif - while((skb = qeth_get_next_skb(card, buf->buffer, &element, - &offset, &hdr))){ + struct net_device *net_dev; + struct qeth_card *card; + struct qeth_qdio_buffer *buffer; + int index; + int i; - qeth_rebuild_skb(card, skb, hdr); + QETH_DBF_TEXT(trace, 6, "qdinput"); + card = (struct qeth_card *) card_ptr; + net_dev = card->dev; #ifdef CONFIG_QETH_PERF_STATS - card->perf_stats.inbound_time += qeth_get_micros() - - card->perf_stats.inbound_start_time; - card->perf_stats.inbound_cnt++; + card->perf_stats.inbound_start_time = qeth_get_micros(); #endif - skb->dev = card->dev; - if (netif_queue_stopped(card->dev)) { - dev_kfree_skb_irq(skb); - card->stats.rx_dropped++; - } else { - rxrc = netif_rx(skb); - card->dev->last_rx = jiffies; - card->stats.rx_packets++; - card->stats.rx_bytes += skb->len; - } + if (status & QDIO_STATUS_LOOK_FOR_ERROR) { + if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ + QETH_DBF_TEXT(trace, 1,"qdinchk"); + QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card)); + QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count); + QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status); + qeth_schedule_recovery(card); + return; } -clear_buffer: - qeth_put_buffer_pool_entry(card, buf->pool_entry); - /* give buffer back to hardware */ - qeth_queue_input_buffer(card, current_buf); - current_buf = (current_buf + 1) % QDIO_MAX_BUFFERS_PER_Q; - buf = &card->qdio.in_q->bufs[current_buf]; } - /* set index for next time the tasklet is scheduled */ - card->qdio.in_q->next_buf_to_process = current_buf; + for (i = first_element; i < (first_element + count); ++i) { + index = i % QDIO_MAX_BUFFERS_PER_Q; + buffer = &card->qdio.in_q->bufs[index]; + if (!((status == QDIO_STATUS_LOOK_FOR_ERROR) && + qeth_check_for_inbound_error(buffer, qdio_err, siga_err))) + qeth_process_inbound_buffer(card, buffer, index); + /* clear buffer and give back to hardware */ + qeth_put_buffer_pool_entry(card, buffer->pool_entry); + qeth_queue_input_buffer(card, index); + } } static inline int @@ -2524,10 +2498,11 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, * switches between PACKING and non-PACKING state if needed. * has to be called holding queue->lock */ -static inline void +static inline int qeth_switch_packing_state(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; + int flush_count = 0; QETH_DBF_TEXT(trace, 6, "swipack"); if (!queue->do_pack) { @@ -2554,6 +2529,7 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); if (buffer->next_element_to_fill > 0) { buffer->state = QETH_QDIO_BUF_PRIMED; + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % @@ -2561,6 +2537,25 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) } } } + return flush_count; +} + +static inline void +qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int) +{ + struct qeth_qdio_out_buffer *buffer; + + buffer = &queue->bufs[queue->next_buf_to_fill]; + BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); + if (buffer->next_element_to_fill > 0){ + /* it's a packing buffer */ + buffer->state = QETH_QDIO_BUF_PRIMED; + atomic_inc(&queue->used_buffers); + qeth_flush_buffers(queue, under_int, queue->next_buf_to_fill, + 1); + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + } } static void @@ -2603,58 +2598,12 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, atomic_dec(&queue->set_pci_flags_count); qeth_clear_output_buffer(card, buffer); + atomic_dec(&queue->used_buffers); } - atomic_sub(count, &queue->used_buffers); - - //if (!atomic_read(&queue->set_pci_flags_count)) - tasklet_schedule(&queue->tasklet); netif_wake_queue(card->dev); } -static void -qeth_qdio_output_tasklet(unsigned long data) -{ - struct qeth_qdio_out_q *queue = (struct qeth_qdio_out_q *) data; - struct qeth_qdio_out_buffer *buffer; - int index; - int count; - - QETH_DBF_TEXT(trace, 6, "outtlet"); - - /* flush all PRIMED buffers */ - index = queue->next_buf_to_flush; - count = 0; - while (queue->bufs[index].state == QETH_QDIO_BUF_PRIMED) { - count++; - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - } - qeth_flush_buffers(queue, 0, queue->next_buf_to_flush, count); - queue->next_buf_to_flush = index; - - /* flush a buffer with data, if no more PCIs are - * outstanding */ - if (!atomic_read(&queue->set_pci_flags_count)){ - spin_lock(&queue->lock); - buffer = &queue->bufs[index]; - if (buffer->state == QETH_QDIO_BUF_PRIMED){ - qeth_flush_buffers(queue, 0, index, 1); - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - queue->next_buf_to_flush = index; - } else if (buffer->next_element_to_fill > 0){ - /* it's a packing buffer */ - BUG_ON(index != queue->next_buf_to_fill); - buffer->state = QETH_QDIO_BUF_PRIMED; - atomic_inc(&queue->used_buffers); - qeth_flush_buffers(queue, 0, index, 1); - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - queue->next_buf_to_flush = index; - queue->next_buf_to_fill = index; - } - spin_unlock(&queue->lock); - } -} - static char* qeth_create_qib_param_field(struct qeth_card *card) { @@ -2858,8 +2807,6 @@ qeth_init_qdio_info(struct qeth_card *card) card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count; INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); - card->qdio.in_tasklet.data = (unsigned long) card; - card->qdio.in_tasklet.func = qeth_qdio_input_tasklet; /* outbound */ card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; @@ -2903,13 +2850,9 @@ qeth_init_qdio_queues(struct qeth_card *card) } card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->next_buf_to_fill = 0; - card->qdio.out_qs[i]->next_buf_to_flush = 0; card->qdio.out_qs[i]->do_pack = 0; atomic_set(&card->qdio.out_qs[i]->used_buffers,0); atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0); - card->qdio.out_qs[i]->tasklet.data = - (unsigned long) card->qdio.out_qs[i]; - card->qdio.out_qs[i]->tasklet.func = qeth_qdio_output_tasklet; spin_lock_init(&card->qdio.out_qs[i]->lock); } return 0; @@ -3653,6 +3596,8 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr; struct qeth_qdio_out_buffer *buffer; int elements_needed; + int start_index; + int flush_count = 0; int rc; QETH_DBF_TEXT(trace, 6, "dosndpkt"); @@ -3671,9 +3616,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, } spin_lock(&queue->lock); - /* check if we need to switch packing state of this queue */ - if (card->info.type != QETH_CARD_TYPE_IQD) - qeth_switch_packing_state(queue); + start_index = queue->next_buf_to_fill; buffer = &queue->bufs[queue->next_buf_to_fill]; BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); if (queue->do_pack){ @@ -3682,6 +3625,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, < elements_needed){ /* ... no -> set state PRIMED */ buffer->state = QETH_QDIO_BUF_PRIMED; + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % @@ -3695,18 +3639,24 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, PRINT_WARN("qeth_do_send_packet: error during " "qeth_fill_buffer."); card->stats.tx_dropped++; - spin_unlock(&queue->lock); - return rc; - } - if (buffer->state == QETH_QDIO_BUF_PRIMED){ + } else if (buffer->state == QETH_QDIO_BUF_PRIMED){ /* next time fill the next buffer */ + flush_count++; atomic_inc(&queue->used_buffers); queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; } - spin_unlock(&queue->lock); + /* check if we need to switch packing state of this queue */ + if (card->info.type != QETH_CARD_TYPE_IQD) + flush_count += qeth_switch_packing_state(queue); + + if (flush_count) + qeth_flush_buffers(queue, 0, start_index, flush_count); - tasklet_schedule(&queue->tasklet); + if (!atomic_read(&queue->set_pci_flags_count)) + qeth_flush_buffers_on_no_pci(queue, 0); + + spin_unlock(&queue->lock); return rc; } @@ -4424,6 +4374,10 @@ qeth_delete_mc_addresses(struct qeth_card *card) if (!ipm->is_multicast) continue; iptodo = qeth_get_addr_buffer(ipm->proto); + if (!iptodo) { + QETH_DBF_TEXT(trace, 2, "dmcnomem"); + continue; + } memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr)); iptodo->users = iptodo->users * -1; if (!__qeth_insert_ip_todo(card, iptodo, 0)) @@ -4694,14 +4648,14 @@ qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) if (addr->proto == QETH_PROT_IPV4) { QETH_DBF_TEXT(trace, 2,"setaddr4"); - QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, sizeof(int)); + QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int)); } else if (addr->proto == QETH_PROT_IPV6) { QETH_DBF_TEXT(trace, 2, "setaddr6"); - QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4); - QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); + QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8); + QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8); } else { QETH_DBF_TEXT(trace, 2, "setaddr?"); - QETH_DBF_HEX(trace, 4, addr, sizeof(struct qeth_ipaddr)); + QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr)); } do { if (addr->is_multicast) @@ -4732,14 +4686,14 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) if (addr->proto == QETH_PROT_IPV4) { QETH_DBF_TEXT(trace, 2,"deladdr4"); - QETH_DBF_HEX(trace, 2, &addr->u.a4.addr, sizeof(int)); + QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int)); } else if (addr->proto == QETH_PROT_IPV6) { QETH_DBF_TEXT(trace, 2, "deladdr6"); - QETH_DBF_HEX(trace, 2, &addr->u.a6.addr, - sizeof(struct in6_addr)); + QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8); + QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8); } else { QETH_DBF_TEXT(trace, 2, "deladdr?"); - QETH_DBF_HEX(trace, 2, addr, sizeof(struct qeth_ipaddr)); + QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr)); } if (addr->is_multicast) rc = qeth_send_setdelmc(card, addr, IPA_CMD_DELIPM); @@ -6515,26 +6469,24 @@ qeth_ip_event(struct notifier_block *this, addr->u.a4.addr = ifa->ifa_address; addr->u.a4.mask = ifa->ifa_mask; addr->type = QETH_IP_TYPE_NORMAL; - } + } else + goto out; + switch(event) { case NETDEV_UP: - if (addr) { - if (!qeth_add_ip(card, addr)) - kfree(addr); - } + if (!qeth_add_ip(card, addr)) + kfree(addr); break; case NETDEV_DOWN: - if (addr) { - if (!qeth_delete_ip(card, addr)) - kfree(addr); - } + if (!qeth_delete_ip(card, addr)) + kfree(addr); break; default: break; } qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); schedule_work(&card->kernel_thread_starter); - +out: return NOTIFY_DONE; } @@ -6570,26 +6522,24 @@ qeth_ip6_event(struct notifier_block *this, memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr)); addr->u.a6.pfxlen = ifa->prefix_len; addr->type = QETH_IP_TYPE_NORMAL; - } + } else + goto out; + switch(event) { case NETDEV_UP: - if (addr){ - if (!qeth_add_ip(card, addr)) - kfree(addr); - } + if (!qeth_add_ip(card, addr)) + kfree(addr); break; case NETDEV_DOWN: - if (addr){ - if (!qeth_delete_ip(card, addr)) - kfree(addr); - } + if (!qeth_delete_ip(card, addr)) + kfree(addr); break; default: break; } qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); schedule_work(&card->kernel_thread_starter); - +out: return NOTIFY_DONE; } diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 31eb79a84c58..a6f1156440bf 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -29,7 +29,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_AUX_REVISION "$Revision: 1.105 $" +#define ZFCP_AUX_REVISION "$Revision: 1.107 $" #include "zfcp_ext.h" @@ -1078,17 +1078,6 @@ zfcp_adapter_debug_register(struct zfcp_adapter *adapter) { char dbf_name[20]; - /* debug feature area which records fsf request sequence numbers */ - sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->req_dbf = debug_register(dbf_name, - ZFCP_REQ_DBF_INDEX, - ZFCP_REQ_DBF_AREAS, - ZFCP_REQ_DBF_LENGTH); - debug_register_view(adapter->req_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->req_dbf, ZFCP_REQ_DBF_LEVEL); - debug_text_event(adapter->req_dbf, 1, "zzz"); - /* debug feature area which records SCSI command failures (hostbyte) */ rwlock_init(&adapter->cmd_dbf_lock); sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s", @@ -1131,7 +1120,7 @@ zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view); debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL); - if (adapter->req_dbf && adapter->cmd_dbf && adapter->abort_dbf && + if (adapter->cmd_dbf && adapter->abort_dbf && adapter->in_els_dbf && adapter->erp_dbf) return 0; @@ -1147,7 +1136,6 @@ void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) { debug_unregister(adapter->erp_dbf); - debug_unregister(adapter->req_dbf); debug_unregister(adapter->cmd_dbf); debug_unregister(adapter->abort_dbf); debug_unregister(adapter->in_els_dbf); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 00de5d6f0733..e4bc663cea4a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -33,7 +33,7 @@ #define ZFCP_DEF_H /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_DEF_REVISION "$Revision: 1.71 $" +#define ZFCP_DEF_REVISION "$Revision: 1.72 $" /*************************** INCLUDES *****************************************/ @@ -450,19 +450,12 @@ struct zfcp_ls_rnid_acc { #define ZFCP_ERP_DBF_LEVEL 3 #define ZFCP_ERP_DBF_NAME "zfcperp" -#define ZFCP_REQ_DBF_INDEX 1 -#define ZFCP_REQ_DBF_AREAS 1 -#define ZFCP_REQ_DBF_LENGTH 8 -#define ZFCP_REQ_DBF_LEVEL 1 -#define ZFCP_REQ_DBF_NAME "zfcpreq" - #define ZFCP_CMD_DBF_INDEX 2 #define ZFCP_CMD_DBF_AREAS 1 #define ZFCP_CMD_DBF_LENGTH 8 #define ZFCP_CMD_DBF_LEVEL 3 #define ZFCP_CMD_DBF_NAME "zfcpcmd" - #define ZFCP_ABORT_DBF_INDEX 2 #define ZFCP_ABORT_DBF_AREAS 1 #define ZFCP_ABORT_DBF_LENGTH 8 @@ -475,11 +468,6 @@ struct zfcp_ls_rnid_acc { #define ZFCP_IN_ELS_DBF_LEVEL 6 #define ZFCP_IN_ELS_DBF_NAME "zfcpels" -#define ZFCP_ADAPTER_REQ_DBF_INDEX 4 -#define ZFCP_ADAPTER_REQ_DBF_AREAS 1 -#define ZFCP_ADAPTER_REQ_DBF_LENGTH 8 -#define ZFCP_ADAPTER_REQ_DBF_LEVEL 6 - /******************** LOGGING MACROS AND DEFINES *****************************/ /* @@ -986,7 +974,6 @@ struct zfcp_adapter { struct zfcp_port *nameserver_port; /* adapter's nameserver */ debug_info_t *erp_dbf; /* S/390 debug features */ debug_info_t *abort_dbf; - debug_info_t *req_dbf; debug_info_t *in_els_dbf; debug_info_t *cmd_dbf; rwlock_t cmd_dbf_lock; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index ccac73ed538f..045d04ba8497 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -31,7 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_ERP_REVISION "$Revision: 1.49 $" +#define ZFCP_ERP_REVISION "$Revision: 1.51 $" #include "zfcp_ext.h" @@ -1865,6 +1865,7 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) case ZFCP_ERP_FAILED : atomic_inc(&port->erp_counter); if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) + zfcp_erp_port_failed(port); break; case ZFCP_ERP_EXIT : /* nothing */ @@ -1874,7 +1875,6 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ result = ZFCP_ERP_EXIT; - zfcp_erp_port_failed(port); } return result; @@ -2397,8 +2397,6 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed " "(retval=%d)\n", retval_cleanup); } - else - debug_text_event(adapter->req_dbf, 1, "q_clean"); failed_qdio_establish: atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); @@ -2468,10 +2466,8 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed on " "adapter %s\n", zfcp_get_busid_by_adapter(adapter)); - } else { + } else ZFCP_LOG_DEBUG("queues cleaned up\n"); - debug_text_event(adapter->req_dbf, 1, "q_clean"); - } /* * First we had to stop QDIO operation. @@ -2834,9 +2830,10 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) /* nameserver port may live again */ atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &adapter->nameserver_port->status); - zfcp_erp_port_reopen(adapter->nameserver_port, 0); - erp_action->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; - retval = ZFCP_ERP_CONTINUES; + if (zfcp_erp_port_reopen(adapter->nameserver_port, 0) >= 0) { + erp_action->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; + retval = ZFCP_ERP_CONTINUES; + } else retval = ZFCP_ERP_FAILED; break; } /* else nameserver port is already open, fall through */ @@ -2972,6 +2969,10 @@ zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action debug_text_event(adapter->erp_dbf, 3, "p_pstnsw_w"); debug_event(adapter->erp_dbf, 3, &erp_action->port->wwpn, sizeof (wwn_t)); + if (atomic_test_mask( + ZFCP_STATUS_COMMON_ERP_FAILED, + &adapter->nameserver_port->status)) + zfcp_erp_port_failed(erp_action->port); zfcp_erp_action_ready(erp_action); } } @@ -3357,7 +3358,7 @@ zfcp_erp_action_enqueue(int action, struct zfcp_adapter *adapter, struct zfcp_port *port, struct zfcp_unit *unit) { - int retval = -1; + int retval = 1; struct zfcp_erp_action *erp_action = NULL; int stronger_action = 0; u32 status = 0; @@ -3376,7 +3377,7 @@ zfcp_erp_action_enqueue(int action, if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status)) - goto out; + return -EIO; debug_event(adapter->erp_dbf, 4, &action, sizeof (int)); /* check whether we really need this */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c4faf9ec2b89..79bb0bab483f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -29,7 +29,7 @@ */ /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.43 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.45 $" #include "zfcp_ext.h" @@ -379,13 +379,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) zfcp_get_busid_by_adapter(adapter), fsf_req->qtcb->prefix.prot_status_qual. sequence_error.exp_req_seq_no); - debug_text_event(adapter->req_dbf, 1, "exp_seq!"); - debug_event(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.prot_status_qual. - sequence_error.exp_req_seq_no, 4); - debug_text_event(adapter->req_dbf, 1, "qtcb_seq!"); - debug_exception(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.req_seq_no, 4); debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err"); /* restart operation on this adapter */ zfcp_erp_adapter_reopen(adapter, 0); @@ -891,7 +884,6 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", zfcp_get_busid_by_adapter(adapter)); - debug_text_event(adapter->req_dbf, 1, "unso"); goto out; failed_req_send: @@ -1277,10 +1269,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) case FSF_FCP_COMMAND_DOES_NOT_EXIST: ZFCP_LOG_FLAGS(2, "FSF_FCP_COMMAND_DOES_NOT_EXIST\n"); retval = 0; - debug_text_event(new_fsf_req->adapter->req_dbf, 3, "no_exist"); - debug_event(new_fsf_req->adapter->req_dbf, 3, - &new_fsf_req->qtcb->bottom.support.req_handle, - sizeof (unsigned long)); debug_text_event(new_fsf_req->adapter->erp_dbf, 3, "fsf_s_no_exist"); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; @@ -3373,10 +3361,6 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, * (need this for look up on normal command completion) */ fsf_req->data.send_fcp_command_task.scsi_cmnd = scsi_cmnd; - debug_text_event(adapter->req_dbf, 3, "fsf/sc"); - debug_event(adapter->req_dbf, 3, &fsf_req, sizeof (unsigned long)); - debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long)); - fsf_req->data.send_fcp_command_task.start_jiffies = jiffies; fsf_req->data.send_fcp_command_task.unit = unit; ZFCP_LOG_DEBUG("unit=%p, fcp_lun=0x%016Lx\n", unit, unit->fcp_lun); @@ -3517,12 +3501,9 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, send_failed: no_fit: failed_scsi_cmnd: - /* dequeue new FSF request previously enqueued */ - debug_text_event(adapter->req_dbf, 3, "fail_sc"); - debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long)); - zfcp_fsf_req_free(fsf_req); fsf_req = NULL; + scsi_cmnd->host_scribble = NULL; success: failed_req_create: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); @@ -4267,14 +4248,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) * the new eh */ /* always call back */ - debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:"); - debug_event(fsf_req->adapter->req_dbf, 2, &scpnt, - sizeof (unsigned long)); - debug_event(fsf_req->adapter->req_dbf, 2, &scpnt->scsi_done, - sizeof (unsigned long)); - debug_event(fsf_req->adapter->req_dbf, 2, &fsf_req, - sizeof (unsigned long)); + (scpnt->scsi_done) (scpnt); + /* * We must hold this lock until scsi_done has been called. * Otherwise we may call scsi_done after abort regarding this @@ -4954,15 +4930,6 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) "to request queue.\n"); } else { req_queue->distance_from_int = new_distance_from_int; - debug_text_event(adapter->req_dbf, 1, "o:a/seq"); - debug_event(adapter->req_dbf, 1, &fsf_req, - sizeof (unsigned long)); - if (likely(inc_seq_no)) { - debug_event(adapter->req_dbf, 1, - &adapter->fsf_req_seq_no, sizeof (u32)); - } else { - debug_text_event(adapter->req_dbf, 1, "nocb"); - } /* * increase FSF sequence counter - * this must only be done for request successfully enqueued to diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 1e72bd18796b..ca238c054d5d 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -28,7 +28,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define ZFCP_QDIO_C_REVISION "$Revision: 1.16 $" +#define ZFCP_QDIO_C_REVISION "$Revision: 1.18 $" #include "zfcp_ext.h" @@ -485,10 +485,6 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) struct zfcp_fsf_req *fsf_req; int retval = 0; - /* Note: seq is entered later */ - debug_text_event(adapter->req_dbf, 1, "i:a/seq"); - debug_event(adapter->req_dbf, 1, &sbale_addr, sizeof (unsigned long)); - /* invalid (per convention used in this driver) */ if (unlikely(!sbale_addr)) { ZFCP_LOG_NORMAL("bug: invalid reqid\n"); @@ -506,11 +502,6 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) retval = -EINVAL; goto out; } - /* debug feature stuff (test for QTCB: remember new unsol. status!) */ - if (likely(fsf_req->qtcb)) { - debug_event(adapter->req_dbf, 1, - &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32)); - } ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb); if (likely(fsf_req->qtcb)) { diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 071007e0f181..ed9ebd166acc 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -31,7 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI /* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_SCSI_REVISION "$Revision: 1.59 $" +#define ZFCP_SCSI_REVISION "$Revision: 1.60 $" #include <linux/blkdev.h> @@ -297,10 +297,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, if (unlikely(tmp < 0)) { ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); retval = SCSI_MLQUEUE_HOST_BUSY; - } else { - debug_text_event(adapter->req_dbf, 3, "q_scpnt"); - debug_event(adapter->req_dbf, 3, &scpnt, - sizeof (unsigned long)); } out: diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bf653f99513d..23f452ad3f64 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -205,7 +205,7 @@ config SERIAL_AMBA_PL011 depends on ARM_AMBA select SERIAL_CORE help - This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have + This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M here. diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index daee75c13a46..482693db18a0 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -207,7 +207,7 @@ int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) /** * fb_set_cmap - set the colormap * @cmap: frame buffer colormap structure - * @kspc: boolean, 0 copy local, 1 get_user() function + * @kspc: boolean, 1 copy local, 0 get_user() function * @info: frame buffer info structure * * Sets the colormap @cmap for a screen of device @info. diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index bd6eb4940d3c..9875025aa650 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -44,7 +44,7 @@ config BINFMT_SHARED_FLAT config BINFMT_AOUT tristate "Kernel support for a.out and ECOFF binaries" - depends on (X86 && !X86_64) || ALPHA || ARM || M68K || MIPS || SPARC32 + depends on (X86 && !X86_64) || ALPHA || ARM || M68K || SPARC32 ---help--- A.out (Assembler.OUTput) is a set of formats for libraries and executables used in the earliest versions of UNIX. Linux used diff --git a/fs/block_dev.c b/fs/block_dev.c index b0314046ec4b..1b43058d8dc0 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -251,6 +251,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { memset(bdev, 0, sizeof(*bdev)); sema_init(&bdev->bd_sem, 1); + sema_init(&bdev->bd_mount_sem, 1); INIT_LIST_HEAD(&bdev->bd_inodes); INIT_LIST_HEAD(&bdev->bd_list); inode_init_once(&ei->vfs_inode); diff --git a/fs/buffer.c b/fs/buffer.c index 21b8ae31e827..7fc4e91f0ce9 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -227,6 +227,77 @@ int fsync_bdev(struct block_device *bdev) return sync_blockdev(bdev); } +/** + * freeze_bdev -- lock a filesystem and force it into a consistent state + * @bdev: blockdevice to lock + * + * This takes the block device bd_mount_sem to make sure no new mounts + * happen on bdev until thaw_bdev() is called. + * If a superblock is found on this device, we take the s_umount semaphore + * on it to make sure nobody unmounts until the snapshot creation is done. + */ +struct super_block *freeze_bdev(struct block_device *bdev) +{ + struct super_block *sb; + + down(&bdev->bd_mount_sem); + sb = get_super(bdev); + if (sb && !(sb->s_flags & MS_RDONLY)) { + sb->s_frozen = SB_FREEZE_WRITE; + wmb(); + + sync_inodes_sb(sb, 0); + DQUOT_SYNC(sb); + + lock_super(sb); + if (sb->s_dirt && sb->s_op->write_super) + sb->s_op->write_super(sb); + unlock_super(sb); + + if (sb->s_op->sync_fs) + sb->s_op->sync_fs(sb, 1); + + sync_blockdev(sb->s_bdev); + sync_inodes_sb(sb, 1); + + sb->s_frozen = SB_FREEZE_TRANS; + wmb(); + + sync_blockdev(sb->s_bdev); + + if (sb->s_op->write_super_lockfs) + sb->s_op->write_super_lockfs(sb); + } + + sync_blockdev(bdev); + return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ +} +EXPORT_SYMBOL(freeze_bdev); + +/** + * thaw_bdev -- unlock filesystem + * @bdev: blockdevice to unlock + * @sb: associated superblock + * + * Unlocks the filesystem and marks it writeable again after freeze_bdev(). + */ +void thaw_bdev(struct block_device *bdev, struct super_block *sb) +{ + if (sb) { + BUG_ON(sb->s_bdev != bdev); + + if (sb->s_op->unlockfs) + sb->s_op->unlockfs(sb); + sb->s_frozen = SB_UNFROZEN; + wmb(); + wake_up(&sb->s_wait_unfrozen); + drop_super(sb); + } + + up(&bdev->bd_mount_sem); +} +EXPORT_SYMBOL(thaw_bdev); + /* * sync everything. Start out by waking pdflush, because that writes back * all queues in parallel. diff --git a/fs/compat.c b/fs/compat.c index 40023e684520..b628d2e315f1 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -235,7 +235,7 @@ out: return error; } -/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64 */ +/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */ #define IOCTL_HASHSIZE 256 struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index de45d833d0f4..56ef9138e9cc 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -70,8 +70,10 @@ #include <net/sock.h> /* siocdevprivate_ioctl */ #include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/hci.h> +#include <net/bluetooth/rfcomm.h> + +#include <linux/capi.h> #include <scsi/scsi.h> /* Ugly hack. */ diff --git a/fs/exec.c b/fs/exec.c index c37b1478fdac..47285fe301ff 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -870,15 +870,6 @@ out: EXPORT_SYMBOL(flush_old_exec); -/* - * We mustn't allow tracing of suid binaries, unless - * the tracer has the capability to trace anything.. - */ -static inline int must_not_trace_exec(struct task_struct * p) -{ - return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP); -} - /* * Fill the binprm structure from the inode. * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes @@ -945,27 +936,7 @@ EXPORT_SYMBOL(prepare_binprm); void compute_creds(struct linux_binprm *bprm) { - task_lock(current); - if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { - current->mm->dumpable = 0; - - if (must_not_trace_exec(current) - || atomic_read(¤t->fs->count) > 1 - || atomic_read(¤t->files->count) > 1 - || atomic_read(¤t->sighand->count) > 1) { - if(!capable(CAP_SETUID)) { - bprm->e_uid = current->uid; - bprm->e_gid = current->gid; - } - } - } - - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; - - task_unlock(current); - - security_bprm_compute_creds(bprm); + security_bprm_apply_creds(bprm); } EXPORT_SYMBOL(compute_creds); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 12f71306153a..3c95df4bb817 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -599,6 +599,7 @@ struct journal_head * journal_get_descriptor_buffer(journal_t *journal) return NULL; bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + memset(bh->b_data, 0, journal->j_blocksize); bh->b_state |= (1 << BH_Dirty); BUFFER_TRACE(bh, "return this buffer"); return journal_add_journal_head(bh); diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index fc425aa0d47c..864615916862 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -117,11 +117,16 @@ static int mount_port __initdata = 0; /* Mount daemon port number */ ***************************************************************************/ enum { + /* Options that take integer arguments */ Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin, - Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_soft, Opt_hard, Opt_intr, + Opt_acregmax, Opt_acdirmin, Opt_acdirmax, + /* Options that take no arguments */ + Opt_soft, Opt_hard, Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, - Opt_broken_suid, Opt_err, + Opt_broken_suid, + /* Error token */ + Opt_err }; static match_table_t __initdata tokens = { @@ -146,9 +151,13 @@ static match_table_t __initdata tokens = { {Opt_noac, "noac"}, {Opt_lock, "lock"}, {Opt_nolock, "nolock"}, + {Opt_v2, "nfsvers=2"}, {Opt_v2, "v2"}, + {Opt_v3, "nfsvers=3"}, {Opt_v3, "v3"}, + {Opt_udp, "proto=udp"}, {Opt_udp, "udp"}, + {Opt_tcp, "proto=tcp"}, {Opt_tcp, "tcp"}, {Opt_broken_suid, "broken_suid"}, {Opt_err, NULL} @@ -169,18 +178,19 @@ static int __init root_nfs_parse(char *name, char *buf) if (!name) return 1; - if (name[0] && strcmp(name, "default")){ - strlcpy(buf, name, NFS_MAXPATHLEN); - return 1; - } + /* Set the NFS remote path */ + p = strsep(&name, ","); + if (p[0] != '\0' && strcmp(p, "default") != 0) + strlcpy(buf, p, NFS_MAXPATHLEN); + while ((p = strsep (&name, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); - /* %u tokens only */ - if (match_int(&args[0], &option)) + /* %u tokens only. Beware if you add new tokens! */ + if (token < Opt_soft && match_int(&args[0], &option)) return 0; switch (token) { case Opt_port: @@ -265,6 +275,7 @@ static int __init root_nfs_parse(char *name, char *buf) return 0; } } + return 1; } @@ -273,7 +284,7 @@ static int __init root_nfs_parse(char *name, char *buf) */ static int __init root_nfs_name(char *name) { - static char buf[NFS_MAXPATHLEN]; + static char buf[NFS_MAXPATHLEN] __initdata; char *cp; /* Set some default values */ @@ -283,9 +294,6 @@ static int __init root_nfs_name(char *name) nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; - nfs_data.bsize = 0; - nfs_data.timeo = 7; - nfs_data.retrans = 3; nfs_data.acregmin = 3; nfs_data.acregmax = 60; nfs_data.acdirmin = 30; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f2233df104a6..1ab82924fba5 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -86,7 +86,7 @@ static void reiserfs_write_super_lockfs (struct super_block * s) reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); reiserfs_block_writes(&th) ; - journal_end(&th, s, 1) ; + journal_end_sync(&th, s, 1) ; } s->s_dirt = 0; reiserfs_write_unlock(s); diff --git a/fs/super.c b/fs/super.c index f20abf04f8a5..e62838940bc7 100644 --- a/fs/super.c +++ b/fs/super.c @@ -77,6 +77,7 @@ static struct super_block *alloc_super(void) sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqonoff_sem, 1); init_rwsem(&s->s_dquot.dqptr_sem); + init_waitqueue_head(&s->s_wait_unfrozen); s->s_maxbytes = MAX_NON_LFS; s->dq_op = sb_dquot_ops; s->s_qcop = sb_quotactl_ops; @@ -623,7 +624,14 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, if (IS_ERR(bdev)) return (struct super_block *)bdev; + /* + * once the super is inserted into the list by sget, s_umount + * will protect the lockfs code from trying to start a snapshot + * while we are mounting + */ + down(&bdev->bd_mount_sem); s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); + up(&bdev->bd_mount_sem); if (IS_ERR(s)) goto out; diff --git a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c index fb317760a25e..c5059bbe5694 100644 --- a/fs/xfs/linux/xfs_ioctl.c +++ b/fs/xfs/linux/xfs_ioctl.c @@ -825,13 +825,14 @@ xfs_ioctl( case XFS_IOC_FREEZE: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_freeze(mp); + + freeze_bdev(inode->i_sb->s_bdev); return 0; case XFS_IOC_THAW: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - xfs_fs_thaw(mp); + thaw_bdev(inode->i_sb->s_bdev, inode->i_sb); return 0; case XFS_IOC_GOINGDOWN: { diff --git a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c index 2077d8536208..93bb959fef48 100644 --- a/fs/xfs/linux/xfs_lrw.c +++ b/fs/xfs/linux/xfs_lrw.c @@ -682,8 +682,6 @@ xfs_write( io = &xip->i_iocore; mp = io->io_mount; - xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE); - if (XFS_FORCED_SHUTDOWN(mp)) { return -EIO; } diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 478e7caca902..5b7f46bc34b9 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -589,28 +589,7 @@ STATIC void linvfs_freeze_fs( struct super_block *sb) { - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - - if (sb->s_flags & MS_RDONLY) - return; - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_FREEZE, 0, error); - VN_RELE(vp); -} - -STATIC void -linvfs_unfreeze_fs( - struct super_block *sb) -{ - vfs_t *vfsp = LINVFS_GET_VFS(sb); - vnode_t *vp; - int error; - - VFS_ROOT(vfsp, &vp, error); - VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, 0, XFS_IOC_THAW, 0, error); - VN_RELE(vp); + VFS_FREEZE(LINVFS_GET_VFS(sb)); } STATIC struct dentry * @@ -850,7 +829,6 @@ STATIC struct super_operations linvfs_sops = { .write_super = linvfs_write_super, .sync_fs = linvfs_sync_super, .write_super_lockfs = linvfs_freeze_fs, - .unlockfs = linvfs_unfreeze_fs, .statfs = linvfs_statfs, .remount_fs = linvfs_remount, .show_options = linvfs_show_options, diff --git a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c index 63adf1d5988e..2b75cccdfd60 100644 --- a/fs/xfs/linux/xfs_vfs.c +++ b/fs/xfs/linux/xfs_vfs.c @@ -230,6 +230,18 @@ vfs_force_shutdown( ((*bhvtovfsops(next)->vfs_force_shutdown)(next, fl, file, line)); } +void +vfs_freeze( + struct bhv_desc *bdp) +{ + struct bhv_desc *next = bdp; + + ASSERT(next); + while (! (bhvtovfsops(next))->vfs_freeze) + next = BHV_NEXT(next); + ((*bhvtovfsops(next)->vfs_freeze)(next)); +} + vfs_t * vfs_allocate( void ) { diff --git a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h index f94ce05153c3..dc1cd1973dda 100644 --- a/fs/xfs/linux/xfs_vfs.h +++ b/fs/xfs/linux/xfs_vfs.h @@ -112,6 +112,7 @@ typedef int (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t); typedef void (*vfs_init_vnode_t)(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); +typedef void (*vfs_freeze_t)(bhv_desc_t *); typedef struct vfsops { bhv_position_t vf_position; /* behavior chain position */ @@ -128,6 +129,7 @@ typedef struct vfsops { vfs_quotactl_t vfs_quotactl; /* disk quota */ vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ + vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ } vfsops_t; /* @@ -147,6 +149,7 @@ typedef struct vfsops { #define VFS_QUOTACTL(v, c,id,p, rv) ((rv) = vfs_quotactl(VHEAD(v), c,id,p)) #define VFS_INIT_VNODE(v, vp,b,ul) ( vfs_init_vnode(VHEAD(v), vp,b,ul) ) #define VFS_FORCE_SHUTDOWN(v, fl,f,l) ( vfs_force_shutdown(VHEAD(v), fl,f,l) ) +#define VFS_FREEZE(v) ( vfs_freeze(VHEAD(v)) ) /* * PVFS's. Operates on behavior descriptor pointers. @@ -164,6 +167,7 @@ typedef struct vfsops { #define PVFS_QUOTACTL(b, c,id,p, rv) ((rv) = vfs_quotactl(b, c,id,p)) #define PVFS_INIT_VNODE(b, vp,b2,ul) ( vfs_init_vnode(b, vp,b2,ul) ) #define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) ) +#define PVFS_FREEZE(b) ( vfs_freeze(b) ) extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); @@ -178,6 +182,7 @@ extern int vfs_dmapiops(bhv_desc_t *, caddr_t); extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); +extern void vfs_freeze(bhv_desc_t *); typedef struct bhv_vfsops { struct vfsops bhv_common; diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index d6a6d056c34e..37b28e59e8c1 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -582,63 +582,25 @@ xfs_fs_log_dummy(xfs_mount_t *mp) } int -xfs_fs_freeze( - xfs_mount_t *mp) -{ - vfs_t *vfsp; - /*REFERENCED*/ - int error; - - vfsp = XFS_MTOVFS(mp); - - /* Stop new writers */ - xfs_start_freeze(mp, XFS_FREEZE_WRITE); - - /* Flush the refcache */ - xfs_refcache_purge_mp(mp); - - /* Flush delalloc and delwri data */ - VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error); - - /* Pause transaction subsystem */ - xfs_start_freeze(mp, XFS_FREEZE_TRANS); - - /* Flush any remaining inodes into buffers */ - VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error); - - /* Push all buffers out to disk */ - xfs_binval(mp->m_ddev_targp); - if (mp->m_rtdev_targp) { - xfs_binval(mp->m_rtdev_targp); - } - - /* Push the superblock and write an unmount record */ - xfs_log_unmount_write(mp); - xfs_unmountfs_writesb(mp); - - return 0; -} - -int -xfs_fs_thaw( - xfs_mount_t *mp) -{ - xfs_finish_freeze(mp); - return 0; -} - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags) { - switch (inflags) - { - case XFS_FSOP_GOING_FLAGS_DEFAULT: - xfs_fs_freeze(mp); - xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); - xfs_fs_thaw(mp); + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (inflags) { + case XFS_FSOP_GOING_FLAGS_DEFAULT: { + struct vfs *vfsp = XFS_MTOVFS(mp); + struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); + + if (sb) { + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); + thaw_bdev(sb->s_bdev, sb); + } + break; + } case XFS_FSOP_GOING_FLAGS_LOGFLUSH: xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); break; diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h index 70b0f125767b..b61486173a61 100644 --- a/fs/xfs/xfs_fsops.h +++ b/fs/xfs/xfs_fsops.h @@ -60,14 +60,6 @@ xfs_reserve_blocks( xfs_fsop_resblks_t *outval); int -xfs_fs_freeze( - xfs_mount_t *mp); - -int -xfs_fs_thaw( - xfs_mount_t *mp); - -int xfs_fs_goingdown( xfs_mount_t *mp, __uint32_t inflags); diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 9ff45c11d3c8..8505f1d35429 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -820,7 +820,7 @@ xfs_log_need_covered(xfs_mount_t *mp) xlog_t *log = mp->m_log; vfs_t *vfsp = XFS_MTOVFS(mp); - if (mp->m_frozen || XFS_FORCED_SHUTDOWN(mp) || + if (vfsp->vfs_super->s_frozen || XFS_FORCED_SHUTDOWN(mp) || (vfsp->vfs_flag & VFS_RDONLY)) return 0; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index e9039e8842b0..56d104d21e63 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -140,9 +140,6 @@ xfs_mount_init(void) */ xfs_trans_ail_init(mp); - /* Init freeze sync structures */ - spinlock_init(&mp->m_freeze_lock, "xfs_freeze"); - init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0); atomic_set(&mp->m_active_trans, 0); return mp; @@ -192,8 +189,6 @@ xfs_mount_free( VFS_REMOVEBHV(vfsp, &mp->m_bhv); } - spinlock_destroy(&mp->m_freeze_lock); - sv_destroy(&mp->m_wait_unfreeze); kmem_free(mp, sizeof(xfs_mount_t)); } @@ -1586,59 +1581,3 @@ xfs_mount_log_sbunit( xfs_mod_sb(tp, fields); xfs_trans_commit(tp, 0, NULL); } - -/* Functions to lock access out of the filesystem for forced - * shutdown or snapshot. - */ - -void -xfs_start_freeze( - xfs_mount_t *mp, - int level) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - mp->m_frozen = level; - mutex_spinunlock(&mp->m_freeze_lock, s); - - if (level == XFS_FREEZE_TRANS) { - while (atomic_read(&mp->m_active_trans) > 0) - delay(100); - } -} - -void -xfs_finish_freeze( - xfs_mount_t *mp) -{ - unsigned long s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen) { - mp->m_frozen = 0; - sv_broadcast(&mp->m_wait_unfreeze); - } - - mutex_spinunlock(&mp->m_freeze_lock, s); -} - -void -xfs_check_frozen( - xfs_mount_t *mp, - bhv_desc_t *bdp, - int level) -{ - unsigned long s; - - if (mp->m_frozen) { - s = mutex_spinlock(&mp->m_freeze_lock); - - if (mp->m_frozen < level) { - mutex_spinunlock(&mp->m_freeze_lock, s); - } else { - sv_wait(&mp->m_wait_unfreeze, 0, &mp->m_freeze_lock, s); - } - } - - if (level == XFS_FREEZE_TRANS) - atomic_inc(&mp->m_active_trans); -} diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index ea86fbaffd40..e338e32d346d 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -379,10 +379,6 @@ typedef struct xfs_mount { struct xfs_dmops m_dm_ops; /* vector of DMI ops */ struct xfs_qmops m_qm_ops; /* vector of XQM ops */ struct xfs_ioops m_io_ops; /* vector of I/O ops */ - lock_t m_freeze_lock; /* Lock for m_frozen */ - uint m_frozen; /* FS frozen for shutdown or - * snapshot */ - sv_t m_wait_unfreeze;/* waiting to unfreeze */ atomic_t m_active_trans; /* number trans frozen */ } xfs_mount_t; @@ -558,16 +554,6 @@ extern void xfs_initialize_perag(xfs_mount_t *, int); extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); -/* - * Flags for freeze operations. - */ -#define XFS_FREEZE_WRITE 1 -#define XFS_FREEZE_TRANS 2 - -extern void xfs_start_freeze(xfs_mount_t *, int); -extern void xfs_finish_freeze(xfs_mount_t *); -extern void xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int); - extern struct vfsops xfs_vfsops; extern struct vnodeops xfs_vnodeops; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index af07bd91b81e..aebea7a293d6 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -131,7 +131,9 @@ xfs_trans_alloc( xfs_mount_t *mp, uint type) { - xfs_check_frozen(mp, NULL, XFS_FREEZE_TRANS); + vfs_check_frozen(XFS_MTOVFS(mp)->vfs_super, SB_FREEZE_TRANS); + atomic_inc(&mp->m_active_trans); + return (_xfs_trans_alloc(mp, type)); } diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index e0bbdbef441a..3d6822de23eb 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -1858,6 +1858,20 @@ xfs_showargs( return 0; } +STATIC void +xfs_freeze( + bhv_desc_t *bdp) +{ + xfs_mount_t *mp = XFS_BHVTOM(bdp); + + while (atomic_read(&mp->m_active_trans) > 0) + delay(100); + + /* Push the superblock and write an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); +} + vfsops_t xfs_vfsops = { BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), @@ -1874,4 +1888,5 @@ vfsops_t xfs_vfsops = { .vfs_quotactl = (vfs_quotactl_t)fs_nosys, .vfs_init_vnode = xfs_initialize_vnode, .vfs_force_shutdown = xfs_do_force_shutdown, + .vfs_freeze = xfs_freeze, }; diff --git a/include/asm-arm/arch-versatile/dma.h b/include/asm-arm/arch-versatile/dma.h new file mode 100644 index 000000000000..dcc8ac26eac0 --- /dev/null +++ b/include/asm-arm/arch-versatile/dma.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-versatile/dma.h + * + * Copyright (C) 2003 ARM Limited. + * Copyright (C) 1997,1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h new file mode 100644 index 000000000000..535b1f041b73 --- /dev/null +++ b/include/asm-arm/arch-versatile/hardware.h @@ -0,0 +1,45 @@ +/* + * linux/include/asm-arm/arch-versatile/hardware.h + * + * This file contains the hardware definitions of the Versatile PB board. + * + * Copyright (C) 2003 ARM Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <asm/sizes.h> +#include <asm/arch/platform.h> + +// FIXME = PCI settings need to be fixed!!!!! + +/* + * Similar to above, but for PCI addresses (memory, IO, Config and the + * V3 chip itself). WARNING: this has to mirror definitions in platform.h + */ +#define PCI_MEMORY_VADDR 0xe8000000 +#define PCI_CONFIG_VADDR 0xec000000 +#define PCI_V3_VADDR 0xed000000 +#define PCI_IO_VADDR 0xee000000 + +#define PCIO_BASE PCI_IO_VADDR +#define PCIMEM_BASE PCI_MEMORY_VADDR + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) + +#endif diff --git a/include/asm-arm/arch-versatile/io.h b/include/asm-arm/arch-versatile/io.h new file mode 100644 index 000000000000..542bc6b5d03c --- /dev/null +++ b/include/asm-arm/arch-versatile/io.h @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-versatile/io.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffff + +#define __io(a) ((a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#endif diff --git a/include/asm-arm/arch-versatile/irqs.h b/include/asm-arm/arch-versatile/irqs.h new file mode 100644 index 000000000000..745aa841b31a --- /dev/null +++ b/include/asm-arm/arch-versatile/irqs.h @@ -0,0 +1,211 @@ +/* + * linux/include/asm-arm/arch-versatile/irqs.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <asm/arch/platform.h> + +/* + * IRQ interrupts definitions are the same the INT definitions + * held within platform.h + */ +#define IRQ_VIC_START 0 +#define IRQ_WDOGINT (IRQ_VIC_START + INT_WDOGINT) +#define IRQ_SOFTINT (IRQ_VIC_START + INT_SOFTINT) +#define IRQ_COMMRx (IRQ_VIC_START + INT_COMMRx) +#define IRQ_COMMTx (IRQ_VIC_START + INT_COMMTx) +#define IRQ_TIMERINT0_1 (IRQ_VIC_START + INT_TIMERINT0_1) +#define IRQ_TIMERINT2_3 (IRQ_VIC_START + INT_TIMERINT2_3) +#define IRQ_GPIOINT0 (IRQ_VIC_START + INT_GPIOINT0) +#define IRQ_GPIOINT1 (IRQ_VIC_START + INT_GPIOINT1) +#define IRQ_GPIOINT2 (IRQ_VIC_START + INT_GPIOINT2) +#define IRQ_GPIOINT3 (IRQ_VIC_START + INT_GPIOINT3) +#define IRQ_RTCINT (IRQ_VIC_START + INT_RTCINT) +#define IRQ_SSPINT (IRQ_VIC_START + INT_SSPINT) +#define IRQ_UARTINT0 (IRQ_VIC_START + INT_UARTINT0) +#define IRQ_UARTINT1 (IRQ_VIC_START + INT_UARTINT1) +#define IRQ_UARTINT2 (IRQ_VIC_START + INT_UARTINT2) +#define IRQ_SCIINT (IRQ_VIC_START + INT_SCIINT) +#define IRQ_CLCDINT (IRQ_VIC_START + INT_CLCDINT) +#define IRQ_DMAINT (IRQ_VIC_START + INT_DMAINT) +#define IRQ_PWRFAILINT (IRQ_VIC_START + INT_PWRFAILINT) +#define IRQ_MBXINT (IRQ_VIC_START + INT_MBXINT) +#define IRQ_GNDINT (IRQ_VIC_START + INT_GNDINT) +#define IRQ_VICSOURCE21 (IRQ_VIC_START + INT_VICSOURCE21) +#define IRQ_VICSOURCE22 (IRQ_VIC_START + INT_VICSOURCE22) +#define IRQ_VICSOURCE23 (IRQ_VIC_START + INT_VICSOURCE23) +#define IRQ_VICSOURCE24 (IRQ_VIC_START + INT_VICSOURCE24) +#define IRQ_VICSOURCE25 (IRQ_VIC_START + INT_VICSOURCE25) +#define IRQ_VICSOURCE26 (IRQ_VIC_START + INT_VICSOURCE26) +#define IRQ_VICSOURCE27 (IRQ_VIC_START + INT_VICSOURCE27) +#define IRQ_VICSOURCE28 (IRQ_VIC_START + INT_VICSOURCE28) +#define IRQ_VICSOURCE29 (IRQ_VIC_START + INT_VICSOURCE29) +#define IRQ_VICSOURCE30 (IRQ_VIC_START + INT_VICSOURCE30) +#define IRQ_VICSOURCE31 (IRQ_VIC_START + INT_VICSOURCE31) +#define IRQ_VIC_END (IRQ_VIC_START + 31) + +#define IRQMASK_WDOGINT INTMASK_WDOGINT +#define IRQMASK_SOFTINT INTMASK_SOFTINT +#define IRQMASK_COMMRx INTMASK_COMMRx +#define IRQMASK_COMMTx INTMASK_COMMTx +#define IRQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 +#define IRQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 +#define IRQMASK_GPIOINT0 INTMASK_GPIOINT0 +#define IRQMASK_GPIOINT1 INTMASK_GPIOINT1 +#define IRQMASK_GPIOINT2 INTMASK_GPIOINT2 +#define IRQMASK_GPIOINT3 INTMASK_GPIOINT3 +#define IRQMASK_RTCINT INTMASK_RTCINT +#define IRQMASK_SSPINT INTMASK_SSPINT +#define IRQMASK_UARTINT0 INTMASK_UARTINT0 +#define IRQMASK_UARTINT1 INTMASK_UARTINT1 +#define IRQMASK_UARTINT2 INTMASK_UARTINT2 +#define IRQMASK_SCIINT INTMASK_SCIINT +#define IRQMASK_CLCDINT INTMASK_CLCDINT +#define IRQMASK_DMAINT INTMASK_DMAINT +#define IRQMASK_PWRFAILINT INTMASK_PWRFAILINT +#define IRQMASK_MBXINT INTMASK_MBXINT +#define IRQMASK_GNDINT INTMASK_GNDINT +#define IRQMASK_VICSOURCE21 INTMASK_VICSOURCE21 +#define IRQMASK_VICSOURCE22 INTMASK_VICSOURCE22 +#define IRQMASK_VICSOURCE23 INTMASK_VICSOURCE23 +#define IRQMASK_VICSOURCE24 INTMASK_VICSOURCE24 +#define IRQMASK_VICSOURCE25 INTMASK_VICSOURCE25 +#define IRQMASK_VICSOURCE26 INTMASK_VICSOURCE26 +#define IRQMASK_VICSOURCE27 INTMASK_VICSOURCE27 +#define IRQMASK_VICSOURCE28 INTMASK_VICSOURCE28 +#define IRQMASK_VICSOURCE29 INTMASK_VICSOURCE29 +#define IRQMASK_VICSOURCE30 INTMASK_VICSOURCE30 +#define IRQMASK_VICSOURCE31 INTMASK_VICSOURCE31 + +/* + * FIQ interrupts definitions are the same the INT definitions. + */ +#define FIQ_WDOGINT INT_WDOGINT +#define FIQ_SOFTINT INT_SOFTINT +#define FIQ_COMMRx INT_COMMRx +#define FIQ_COMMTx INT_COMMTx +#define FIQ_TIMERINT0_1 INT_TIMERINT0_1 +#define FIQ_TIMERINT2_3 INT_TIMERINT2_3 +#define FIQ_GPIOINT0 INT_GPIOINT0 +#define FIQ_GPIOINT1 INT_GPIOINT1 +#define FIQ_GPIOINT2 INT_GPIOINT2 +#define FIQ_GPIOINT3 INT_GPIOINT3 +#define FIQ_RTCINT INT_RTCINT +#define FIQ_SSPINT INT_SSPINT +#define FIQ_UARTINT0 INT_UARTINT0 +#define FIQ_UARTINT1 INT_UARTINT1 +#define FIQ_UARTINT2 INT_UARTINT2 +#define FIQ_SCIINT INT_SCIINT +#define FIQ_CLCDINT INT_CLCDINT +#define FIQ_DMAINT INT_DMAINT +#define FIQ_PWRFAILINT INT_PWRFAILINT +#define FIQ_MBXINT INT_MBXINT +#define FIQ_GNDINT INT_GNDINT +#define FIQ_VICSOURCE21 INT_VICSOURCE21 +#define FIQ_VICSOURCE22 INT_VICSOURCE22 +#define FIQ_VICSOURCE23 INT_VICSOURCE23 +#define FIQ_VICSOURCE24 INT_VICSOURCE24 +#define FIQ_VICSOURCE25 INT_VICSOURCE25 +#define FIQ_VICSOURCE26 INT_VICSOURCE26 +#define FIQ_VICSOURCE27 INT_VICSOURCE27 +#define FIQ_VICSOURCE28 INT_VICSOURCE28 +#define FIQ_VICSOURCE29 INT_VICSOURCE29 +#define FIQ_VICSOURCE30 INT_VICSOURCE30 +#define FIQ_VICSOURCE31 INT_VICSOURCE31 + + +#define FIQMASK_WDOGINT INTMASK_WDOGINT +#define FIQMASK_SOFTINT INTMASK_SOFTINT +#define FIQMASK_COMMRx INTMASK_COMMRx +#define FIQMASK_COMMTx INTMASK_COMMTx +#define FIQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 +#define FIQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 +#define FIQMASK_GPIOINT0 INTMASK_GPIOINT0 +#define FIQMASK_GPIOINT1 INTMASK_GPIOINT1 +#define FIQMASK_GPIOINT2 INTMASK_GPIOINT2 +#define FIQMASK_GPIOINT3 INTMASK_GPIOINT3 +#define FIQMASK_RTCINT INTMASK_RTCINT +#define FIQMASK_SSPINT INTMASK_SSPINT +#define FIQMASK_UARTINT0 INTMASK_UARTINT0 +#define FIQMASK_UARTINT1 INTMASK_UARTINT1 +#define FIQMASK_UARTINT2 INTMASK_UARTINT2 +#define FIQMASK_SCIINT INTMASK_SCIINT +#define FIQMASK_CLCDINT INTMASK_CLCDINT +#define FIQMASK_DMAINT INTMASK_DMAINT +#define FIQMASK_PWRFAILINT INTMASK_PWRFAILINT +#define FIQMASK_MBXINT INTMASK_MBXINT +#define FIQMASK_GNDINT INTMASK_GNDINT +#define FIQMASK_VICSOURCE21 INTMASK_VICSOURCE21 +#define FIQMASK_VICSOURCE22 INTMASK_VICSOURCE22 +#define FIQMASK_VICSOURCE23 INTMASK_VICSOURCE23 +#define FIQMASK_VICSOURCE24 INTMASK_VICSOURCE24 +#define FIQMASK_VICSOURCE25 INTMASK_VICSOURCE25 +#define FIQMASK_VICSOURCE26 INTMASK_VICSOURCE26 +#define FIQMASK_VICSOURCE27 INTMASK_VICSOURCE27 +#define FIQMASK_VICSOURCE28 INTMASK_VICSOURCE28 +#define FIQMASK_VICSOURCE29 INTMASK_VICSOURCE29 +#define FIQMASK_VICSOURCE30 INTMASK_VICSOURCE30 +#define FIQMASK_VICSOURCE31 INTMASK_VICSOURCE31 + +/* + * Secondary interrupt controller + */ +#define IRQ_SIC_START 32 +#define IRQ_SIC_MMCI0B (IRQ_SIC_START + SIC_INT_MMCI0B) +#define IRQ_SIC_MMCI1B (IRQ_SIC_START + SIC_INT_MMCI1B) +#define IRQ_SIC_KMI0 (IRQ_SIC_START + SIC_INT_KMI0) +#define IRQ_SIC_KMI1 (IRQ_SIC_START + SIC_INT_KMI1) +#define IRQ_SIC_SCI3 (IRQ_SIC_START + SIC_INT_SCI3) +#define IRQ_SIC_UART3 (IRQ_SIC_START + SIC_INT_UART3) +#define IRQ_SIC_CLCD (IRQ_SIC_START + SIC_INT_CLCD) +#define IRQ_SIC_TOUCH (IRQ_SIC_START + SIC_INT_TOUCH) +#define IRQ_SIC_KEYPAD (IRQ_SIC_START + SIC_INT_KEYPAD) +#define IRQ_SIC_DoC (IRQ_SIC_START + SIC_INT_DoC) +#define IRQ_SIC_MMCI0A (IRQ_SIC_START + SIC_INT_MMCI0A) +#define IRQ_SIC_MMCI1A (IRQ_SIC_START + SIC_INT_MMCI1A) +#define IRQ_SIC_AACI (IRQ_SIC_START + SIC_INT_AACI) +#define IRQ_SIC_ETH (IRQ_SIC_START + SIC_INT_ETH) +#define IRQ_SIC_USB (IRQ_SIC_START + SIC_INT_USB) +#define IRQ_SIC_PCI0 (IRQ_SIC_START + SIC_INT_PCI0) +#define IRQ_SIC_PCI1 (IRQ_SIC_START + SIC_INT_PCI1) +#define IRQ_SIC_PCI2 (IRQ_SIC_START + SIC_INT_PCI2) +#define IRQ_SIC_PCI3 (IRQ_SIC_START + SIC_INT_PCI3) +#define IRQ_SIC_END 63 + +#define SIC_IRQMASK_MMCI0B SIC_INTMASK_MMCI0B +#define SIC_IRQMASK_MMCI1B SIC_INTMASK_MMCI1B +#define SIC_IRQMASK_KMI0 SIC_INTMASK_KMI0 +#define SIC_IRQMASK_KMI1 SIC_INTMASK_KMI1 +#define SIC_IRQMASK_SCI3 SIC_INTMASK_SCI3 +#define SIC_IRQMASK_UART3 SIC_INTMASK_UART3 +#define SIC_IRQMASK_CLCD SIC_INTMASK_CLCD +#define SIC_IRQMASK_TOUCH SIC_INTMASK_TOUCH +#define SIC_IRQMASK_KEYPAD SIC_INTMASK_KEYPAD +#define SIC_IRQMASK_DoC SIC_INTMASK_DoC +#define SIC_IRQMASK_MMCI0A SIC_INTMASK_MMCI0A +#define SIC_IRQMASK_MMCI1A SIC_INTMASK_MMCI1A +#define SIC_IRQMASK_AACI SIC_INTMASK_AACI +#define SIC_IRQMASK_ETH SIC_INTMASK_ETH +#define SIC_IRQMASK_USB SIC_INTMASK_USB +#define SIC_IRQMASK_PCI0 SIC_INTMASK_PCI0 +#define SIC_IRQMASK_PCI1 SIC_INTMASK_PCI1 +#define SIC_IRQMASK_PCI2 SIC_INTMASK_PCI2 +#define SIC_IRQMASK_PCI3 SIC_INTMASK_PCI3 + +#define NR_IRQS 64 diff --git a/include/asm-arm/arch-versatile/memory.h b/include/asm-arm/arch-versatile/memory.h new file mode 100644 index 000000000000..4b7295b4a89a --- /dev/null +++ b/include/asm-arm/arch-versatile/memory.h @@ -0,0 +1,61 @@ +/* + * linux/include/asm-arm/arch-versatile/memory.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MMU_H +#define __ASM_ARCH_MMU_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xbf000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (0x40000000) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) +#define PHYS_OFFSET (0x00000000UL) + +/* + * On Versatile PB, the dram is contiguous + */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) ((x) - PAGE_OFFSET) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) ((x) + PAGE_OFFSET) + +#endif diff --git a/include/asm-arm/arch-versatile/param.h b/include/asm-arm/arch-versatile/param.h new file mode 100644 index 000000000000..34b897335f87 --- /dev/null +++ b/include/asm-arm/arch-versatile/param.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-versatile/param.h + * + * Copyright (C) 2002 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ diff --git a/include/asm-arm/arch-versatile/platform.h b/include/asm-arm/arch-versatile/platform.h new file mode 100644 index 000000000000..68be3f036600 --- /dev/null +++ b/include/asm-arm/arch-versatile/platform.h @@ -0,0 +1,488 @@ +/* + * linux/include/asm-arm/arch-versatile/platform.h + * + * Copyright (c) ARM Limited 2003. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __address_h +#define __address_h 1 + +/* + * Memory definitions + */ +#define VERSATILE_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/ +#define VERSATILE_BOOT_ROM_HI 0x30000000 +#define VERSATILE_BOOT_ROM_BASE VERSATILE_BOOT_ROM_HI /* Normal position */ +#define VERSATILE_BOOT_ROM_SIZE SZ_64M + +#define VERSATILE_SSRAM_BASE /* VERSATILE_SSMC_BASE ? */ +#define VERSATILE_SSRAM_SIZE SZ_2M + +#define VERSATILE_FLASH_BASE 0x34000000 +#define VERSATILE_FLASH_SIZE SZ_64M + +/* + * SDRAM + */ +#define VERSATILE_SDRAM_BASE 0x00000000 + +/* + * Logic expansion modules + * + */ + + +/* ------------------------------------------------------------------------ + * Versatile PB Registers + * ------------------------------------------------------------------------ + * + */ +#define VERSATILE_SYS_ID_OFFSET 0x00 +#define VERSATILE_SYS_SW_OFFSET 0x04 +#define VERSATILE_SYS_LED_OFFSET 0x08 +#define VERSATILE_SYS_OSC0_OFFSET 0x0C +#define VERSATILE_SYS_OSC1_OFFSET 0x10 +#define VERSATILE_SYS_OSC2_OFFSET 0x14 +#define VERSATILE_SYS_OSC3_OFFSET 0x18 +#define VERSATILE_SYS_OSC4_OFFSET 0x1C +#define VERSATILE_SYS_LOCK_OFFSET 0x20 +#define VERSATILE_SYS_100HZ_OFFSET 0x24 +#define VERSATILE_SYS_CFGDATA1_OFFSET 0x28 +#define VERSATILE_SYS_CFGDATA2_OFFSET 0x2C +#define VERSATILE_SYS_FLAGS_OFFSET 0x30 +#define VERSATILE_SYS_FLAGSSET_OFFSET 0x30 +#define VERSATILE_SYS_FLAGSCLR_OFFSET 0x34 +#define VERSATILE_SYS_NVFLAGS_OFFSET 0x38 +#define VERSATILE_SYS_NVFLAGSSET_OFFSET 0x38 +#define VERSATILE_SYS_NVFLAGSCLR_OFFSET 0x3C +#define VERSATILE_SYS_RESETCTL_OFFSET 0x40 +#define VERSATILE_SYS_PICCTL_OFFSET 0x44 +#define VERSATILE_SYS_MCI_OFFSET 0x48 +#define VERSATILE_SYS_FLASH_OFFSET 0x4C +#define VERSATILE_SYS_CLCD_OFFSET 0x50 +#define VERSATILE_SYS_CLCDSER_OFFSET 0x54 +#define VERSATILE_SYS_BOOTCS_OFFSET 0x58 +#define VERSATILE_SYS_24MHz_OFFSET 0x5C +#define VERSATILE_SYS_MISC_OFFSET 0x60 +#define VERSATILE_SYS_TEST_OSC0_OFFSET 0x80 +#define VERSATILE_SYS_TEST_OSC1_OFFSET 0x84 +#define VERSATILE_SYS_TEST_OSC2_OFFSET 0x88 +#define VERSATILE_SYS_TEST_OSC3_OFFSET 0x8C +#define VERSATILE_SYS_TEST_OSC4_OFFSET 0x90 + +#define VERSATILE_SYS_BASE 0x10000000 +#define VERSATILE_SYS_ID (VERSATILE_SYS_BASE + VERSATILE_SYS_ID_OFFSET) +#define VERSATILE_SYS_SW (VERSATILE_SYS_BASE + VERSATILE_SYS_SW_OFFSET) +#define VERSATILE_SYS_LED (VERSATILE_SYS_BASE + VERSATILE_SYS_LED_OFFSET) +#define VERSATILE_SYS_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC0_OFFSET) +#define VERSATILE_SYS_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC1_OFFSET) +#define VERSATILE_SYS_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC2_OFFSET) +#define VERSATILE_SYS_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC3_OFFSET) +#define VERSATILE_SYS_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_OSC4_OFFSET) +#define VERSATILE_SYS_LOCK (VERSATILE_SYS_BASE + VERSATILE_SYS_LOCK_OFFSET) +#define VERSATILE_SYS_100HZ (VERSATILE_SYS_BASE + VERSATILE_SYS_100HZ_OFFSET) +#define VERSATILE_SYS_CFGDATA1 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA1_OFFSET) +#define VERSATILE_SYS_CFGDATA2 (VERSATILE_SYS_BASE + VERSATILE_SYS_CFGDATA2_OFFSET) +#define VERSATILE_SYS_FLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGS_OFFSET) +#define VERSATILE_SYS_FLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSSET_OFFSET) +#define VERSATILE_SYS_FLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_FLAGSCLR_OFFSET) +#define VERSATILE_SYS_NVFLAGS (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGS_OFFSET) +#define VERSATILE_SYS_NVFLAGSSET (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSSET_OFFSET) +#define VERSATILE_SYS_NVFLAGSCLR (VERSATILE_SYS_BASE + VERSATILE_SYS_NVFLAGSCLR_OFFSET) +#define VERSATILE_SYS_RESETCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_RESETCTL_OFFSET) +#define VERSATILE_SYS_PICCTL (VERSATILE_SYS_BASE + VERSATILE_SYS_PICCTL_OFFSET) +#define VERSATILE_SYS_MCI (VERSATILE_SYS_BASE + VERSATILE_SYS_MCI_OFFSET) +#define VERSATILE_SYS_FLASH (VERSATILE_SYS_BASE + VERSATILE_SYS_FLASH_OFFSET) +#define VERSATILE_SYS_CLCD (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCD_OFFSET) +#define VERSATILE_SYS_CLCDSER (VERSATILE_SYS_BASE + VERSATILE_SYS_CLCDSER_OFFSET) +#define VERSATILE_SYS_BOOTCS (VERSATILE_SYS_BASE + VERSATILE_SYS_BOOTCS_OFFSET) +#define VERSATILE_SYS_24MHz (VERSATILE_SYS_BASE + VERSATILE_SYS_24MHz_OFFSET) +#define VERSATILE_SYS_MISC (VERSATILE_SYS_BASE + VERSATILE_SYS_MISC_OFFSET) +#define VERSATILE_SYS_TEST_OSC0 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC0_OFFSET) +#define VERSATILE_SYS_TEST_OSC1 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC1_OFFSET) +#define VERSATILE_SYS_TEST_OSC2 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC2_OFFSET) +#define VERSATILE_SYS_TEST_OSC3 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC3_OFFSET) +#define VERSATILE_SYS_TEST_OSC4 (VERSATILE_SYS_BASE + VERSATILE_SYS_TEST_OSC4_OFFSET) + +/* + * Values for VERSATILE_SYS_RESET_CTRL + */ +#define VERSATILE_SYS_CTRL_RESET_CONFIGCLR 0x01 +#define VERSATILE_SYS_CTRL_RESET_CONFIGINIT 0x02 +#define VERSATILE_SYS_CTRL_RESET_DLLRESET 0x03 +#define VERSATILE_SYS_CTRL_RESET_PLLRESET 0x04 +#define VERSATILE_SYS_CTRL_RESET_POR 0x05 +#define VERSATILE_SYS_CTRL_RESET_DoC 0x06 + +#define VERSATILE_SYS_CTRL_LED (1 << 0) + + +/* ------------------------------------------------------------------------ + * Versatile PB control registers + * ------------------------------------------------------------------------ + */ + +/* + * VERSATILE_IDFIELD + * + * 31:24 = manufacturer (0x41 = ARM) + * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus) + * 15:12 = FPGA (0x3 = XVC600 or XVC600E) + * 11:4 = build value + * 3:0 = revision number (0x1 = rev B (AHB)) + */ + +/* + * VERSATILE_SYS_LOCK + * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL, + * SYS_CLD, SYS_BOOTCS + */ +#define VERSATILE_SYS_LOCK_LOCKED (1 << 16) +#define VERSATILE_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */ + +/* + * VERSATILE_SYS_FLASH + */ +#define VERSATILE_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ + +/* + * VERSATILE_INTREG + * - used to acknowledge and control MMCI and UART interrupts + */ +#define VERSATILE_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */ +#define VERSATILE_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */ +#define VERSATILE_INTREG_CARDIN 0x08 /* MMCI card in detect */ + /* write 1 to acknowledge and clear */ +#define VERSATILE_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */ +#define VERSATILE_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */ + +/* + * VERSATILE peripheral addresses + */ +#define VERSATILE_PCI_CORE_BASE 0x10001000 /* PCI core control */ +#define VERSATILE_I2C_BASE 0x10002000 /* I2C control */ +#define VERSATILE_SIC_BASE 0x10003000 /* Secondary interrupt controller */ +#define VERSATILE_AACI_BASE 0x10004000 /* Audio */ +#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ +#define VERSATILE_KMI0_BASE 0x10006000 /* KMI interface */ +#define VERSATILE_KMI1_BASE 0x10007000 /* KMI 2nd interface */ +#define VERSATILE_CHAR_LCD_BASE 0x10008000 /* Character LCD */ +#define VERSATILE_UART3_BASE 0x10009000 /* UART 3 */ +#define VERSATILE_SCI1_BASE 0x1000A000 +#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */ + /* 0x1000C000 - 0x1000CFFF = reserved */ +#define VERSATILE_ETH_BASE 0x10010000 /* Ethernet */ +#define VERSATILE_USB_BASE 0x10020000 /* USB */ + /* 0x10030000 - 0x100FFFFF = reserved */ +#define VERSATILE_SMC_BASE 0x10100000 /* SMC */ +#define VERSATILE_MPMC_BASE 0x10110000 /* MPMC */ +#define VERSATILE_CLCD_BASE 0x10120000 /* CLCD */ +#define VERSATILE_DMAC_BASE 0x10130000 /* DMA controller */ +#define VERSATILE_VIC_BASE 0x10140000 /* Vectored interrupt controller */ +#define VERSATILE_PERIPH_BASE 0x10150000 /* off-chip peripherals alias from */ + /* 0x10000000 - 0x100FFFFF */ +#define VERSATILE_AHBM_BASE 0x101D0000 /* AHB monitor */ +#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */ +#define VERSATILE_WATCHDOG_BASE 0x101E1000 /* Watchdog */ +#define VERSATILE_TIMER0_1_BASE 0x101E2000 /* Timer 0 and 1 */ +#define VERSATILE_TIMER2_3_BASE 0x101E3000 /* Timer 2 and 3 */ +#define VERSATILE_GPIO0_BASE 0x101E4000 /* GPIO port 0 */ +#define VERSATILE_GPIO1_BASE 0x101E5000 /* GPIO port 1 */ +#define VERSATILE_GPIO2_BASE 0x101E6000 /* GPIO port 2 */ +#define VERSATILE_GPIO3_BASE 0x101E7000 /* GPIO port 3 */ +#define VERSATILE_RTC_BASE 0x101E8000 /* Real Time Clock */ + /* 0x101E9000 - reserved */ +#define VERSATILE_SCI_BASE 0x101F0000 /* Smart card controller */ +#define VERSATILE_UART0_BASE 0x101F1000 /* Uart 0 */ +#define VERSATILE_UART1_BASE 0x101F2000 /* Uart 1 */ +#define VERSATILE_UART2_BASE 0x101F3000 /* Uart 2 */ +#define VERSATILE_SSP_BASE 0x101F4000 /* Synchronous Serial Port */ + +#define VERSATILE_SSMC_BASE 0x20000000 /* SSMC */ +#define VERSATILE_MBX_BASE 0x40000000 /* MBX */ +#define VERSATILE_PCI_BASE 0x41000000 /* PCI Interface */ +#define VERSATILE_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */ +#define VERSATILE_LT_BASE 0x80000000 /* Logic Tile expansion */ + +/* + * Disk on Chip + */ +#define VERSATILE_DOC_BASE 0x2C000000 +#define VERSATILE_DOC_SIZE (16 << 20) +#define VERSATILE_DOC_PAGE_SIZE 512 +#define VERSATILE_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE) + +#define ERASE_UNIT_PAGES 32 +#define START_PAGE 0x80 + +/* + * LED settings, bits [7:0] + */ +#define VERSATILE_SYS_LED0 (1 << 0) +#define VERSATILE_SYS_LED1 (1 << 1) +#define VERSATILE_SYS_LED2 (1 << 2) +#define VERSATILE_SYS_LED3 (1 << 3) +#define VERSATILE_SYS_LED4 (1 << 4) +#define VERSATILE_SYS_LED5 (1 << 5) +#define VERSATILE_SYS_LED6 (1 << 6) +#define VERSATILE_SYS_LED7 (1 << 7) + +#define ALL_LEDS 0xFF + +#define LED_BANK VERSATILE_SYS_LED + +/* + * Control registers + */ +#define VERSATILE_IDFIELD_OFFSET 0x0 /* Versatile build information */ +#define VERSATILE_FLASHPROG_OFFSET 0x4 /* Flash devices */ +#define VERSATILE_INTREG_OFFSET 0x8 /* Interrupt control */ +#define VERSATILE_DECODE_OFFSET 0xC /* Fitted logic modules */ + + +/* ------------------------------------------------------------------------ + * Versatile PB Interrupt Controller - control registers + * ------------------------------------------------------------------------ + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * VERSATILE_IC_BASE + * + * Core Module interrupt controller base is + * + * VERSATILE_SYS_IC + * + */ +#define VIC_IRQ_STATUS 0 +#define VIC_FIQ_STATUS 0x04 +#define VIC_IRQ_RAW_STATUS 0x08 +#define VIC_INT_SELECT 0x0C /* 1 = FIQ, 0 = IRQ */ +#define VIC_IRQ_ENABLE 0x10 /* 1 = enable, 0 = disable */ +#define VIC_IRQ_ENABLE_CLEAR 0x14 +#define VIC_IRQ_SOFT 0x18 +#define VIC_IRQ_SOFT_CLEAR 0x1C +#define VIC_PROTECT 0x20 +#define VIC_VECT_ADDR 0x30 +#define VIC_DEF_VECT_ADDR 0x34 +#define VIC_VECT_ADDR0 0x100 /* 0 to 15 */ +#define VIC_VECT_CNTL0 0x200 /* 0 to 15 */ +#define VIC_ITCR 0x300 /* VIC test control register */ + +#define VIC_FIQ_RAW_STATUS 0x08 +#define VIC_FIQ_ENABLE 0x10 /* 1 = enable, 0 = disable */ +#define VIC_FIQ_ENABLE_CLEAR 0x14 +#define VIC_FIQ_SOFT 0x18 +#define VIC_FIQ_SOFT_CLEAR 0x1C + +#define SIC_IRQ_STATUS 0 +#define SIC_IRQ_RAW_STATUS 0x04 +#define SIC_IRQ_ENABLE 0x08 +#define SIC_IRQ_ENABLE_SET 0x08 +#define SIC_IRQ_ENABLE_CLEAR 0x0C +#define SIC_INT_SOFT_SET 0x10 +#define SIC_INT_SOFT_CLEAR 0x14 +#define SIC_INT_PIC_ENABLE 0x20 /* read status of pass through mask */ +#define SIC_INT_PIC_ENABLES 0x20 /* set interrupt pass through bits */ +#define SIC_INT_PIC_ENABLEC 0x24 /* Clear interrupt pass through bits */ + +#define VICVectCntl_Enable (1 << 5) + +/* ------------------------------------------------------------------------ + * Interrupts - bit assignment (primary) + * ------------------------------------------------------------------------ + */ + +#define INT_WDOGINT 0 /* Watchdog timer */ +#define INT_SOFTINT 1 /* Software interrupt */ +#define INT_COMMRx 2 /* Debug Comm Rx interrupt */ +#define INT_COMMTx 3 /* Debug Comm Tx interrupt */ +#define INT_TIMERINT0_1 4 /* Timer 0 and 1 */ +#define INT_TIMERINT2_3 5 /* Timer 2 and 3 */ +#define INT_GPIOINT0 6 /* GPIO 0 */ +#define INT_GPIOINT1 7 /* GPIO 1 */ +#define INT_GPIOINT2 8 /* GPIO 2 */ +#define INT_GPIOINT3 9 /* GPIO 3 */ +#define INT_RTCINT 10 /* Real Time Clock */ +#define INT_SSPINT 11 /* Synchronous Serial Port */ +#define INT_UARTINT0 12 /* UART 0 on development chip */ +#define INT_UARTINT1 13 /* UART 1 on development chip */ +#define INT_UARTINT2 14 /* UART 2 on development chip */ +#define INT_SCIINT 15 /* Smart Card Interface */ +#define INT_CLCDINT 16 /* CLCD controller */ +#define INT_DMAINT 17 /* DMA controller */ +#define INT_PWRFAILINT 18 /* Power failure */ +#define INT_MBXINT 19 /* Graphics processor */ +#define INT_GNDINT 20 /* Reserved */ + /* External interrupt signals from logic tiles or secondary controller */ +#define INT_VICSOURCE21 21 /* Disk on Chip */ +#define INT_VICSOURCE22 22 /* MCI0A */ +#define INT_VICSOURCE23 23 /* MCI1A */ +#define INT_VICSOURCE24 24 /* AACI */ +#define INT_VICSOURCE25 25 /* Ethernet */ +#define INT_VICSOURCE26 26 /* USB */ +#define INT_VICSOURCE27 27 /* PCI 0 */ +#define INT_VICSOURCE28 28 /* PCI 1 */ +#define INT_VICSOURCE29 29 /* PCI 2 */ +#define INT_VICSOURCE30 30 /* PCI 3 */ +#define INT_VICSOURCE31 31 /* SIC source */ + +/* + * Interrupt bit positions + * + */ +#define INTMASK_WDOGINT (1 << INT_WDOGINT) +#define INTMASK_SOFTINT (1 << INT_SOFTINT) +#define INTMASK_COMMRx (1 << INT_COMMRx) +#define INTMASK_COMMTx (1 << INT_COMMTx) +#define INTMASK_TIMERINT0_1 (1 << INT_TIMERINT0_1) +#define INTMASK_TIMERINT2_3 (1 << INT_TIMERINT2_3) +#define INTMASK_GPIOINT0 (1 << INT_GPIOINT0) +#define INTMASK_GPIOINT1 (1 << INT_GPIOINT1) +#define INTMASK_GPIOINT2 (1 << INT_GPIOINT2) +#define INTMASK_GPIOINT3 (1 << INT_GPIOINT3) +#define INTMASK_RTCINT (1 << INT_RTCINT) +#define INTMASK_SSPINT (1 << INT_SSPINT) +#define INTMASK_UARTINT0 (1 << INT_UARTINT0) +#define INTMASK_UARTINT1 (1 << INT_UARTINT1) +#define INTMASK_UARTINT2 (1 << INT_UARTINT2) +#define INTMASK_SCIINT (1 << INT_SCIINT) +#define INTMASK_CLCDINT (1 << INT_CLCDINT) +#define INTMASK_DMAINT (1 << INT_DMAINT) +#define INTMASK_PWRFAILINT (1 << INT_PWRFAILINT) +#define INTMASK_MBXINT (1 << INT_MBXINT) +#define INTMASK_GNDINT (1 << INT_GNDINT) +#define INTMASK_VICSOURCE21 (1 << INT_VICSOURCE21) +#define INTMASK_VICSOURCE22 (1 << INT_VICSOURCE22) +#define INTMASK_VICSOURCE23 (1 << INT_VICSOURCE23) +#define INTMASK_VICSOURCE24 (1 << INT_VICSOURCE24) +#define INTMASK_VICSOURCE25 (1 << INT_VICSOURCE25) +#define INTMASK_VICSOURCE26 (1 << INT_VICSOURCE26) +#define INTMASK_VICSOURCE27 (1 << INT_VICSOURCE27) +#define INTMASK_VICSOURCE28 (1 << INT_VICSOURCE28) +#define INTMASK_VICSOURCE29 (1 << INT_VICSOURCE29) +#define INTMASK_VICSOURCE30 (1 << INT_VICSOURCE30) +#define INTMASK_VICSOURCE31 (1 << INT_VICSOURCE31) + + +#define VERSATILE_SC_VALID_INT 0x003FFFFF + +#define MAXIRQNUM 31 +#define MAXFIQNUM 31 +#define MAXSWINUM 31 + +/* ------------------------------------------------------------------------ + * Interrupts - bit assignment (secondary) + * ------------------------------------------------------------------------ + */ +#define SIC_INT_MMCI0B 1 /* Multimedia Card 0B */ +#define SIC_INT_MMCI1B 2 /* Multimedia Card 1B */ +#define SIC_INT_KMI0 3 /* Keyboard/Mouse port 0 */ +#define SIC_INT_KMI1 4 /* Keyboard/Mouse port 1 */ +#define SIC_INT_SCI3 5 /* Smart Card interface */ +#define SIC_INT_UART3 6 /* UART 3 empty or data available */ +#define SIC_INT_CLCD 7 /* Character LCD */ +#define SIC_INT_TOUCH 8 /* Touchscreen */ +#define SIC_INT_KEYPAD 9 /* Key pressed on display keypad */ + /* 10:20 - reserved */ +#define SIC_INT_DoC 21 /* Disk on Chip memory controller */ +#define SIC_INT_MMCI0A 22 /* MMC 0A */ +#define SIC_INT_MMCI1A 23 /* MMC 1A */ +#define SIC_INT_AACI 24 /* Audio Codec */ +#define SIC_INT_ETH 25 /* Ethernet controller */ +#define SIC_INT_USB 26 /* USB controller */ +#define SIC_INT_PCI0 27 +#define SIC_INT_PCI1 28 +#define SIC_INT_PCI2 29 +#define SIC_INT_PCI3 30 + + +#define SIC_INTMASK_MMCI0B (1 << SIC_INT_MMCI0B) +#define SIC_INTMASK_MMCI1B (1 << SIC_INT_MMCI1B) +#define SIC_INTMASK_KMI0 (1 << SIC_INT_KMI0) +#define SIC_INTMASK_KMI1 (1 << SIC_INT_KMI1) +#define SIC_INTMASK_SCI3 (1 << SIC_INT_SCI3) +#define SIC_INTMASK_UART3 (1 << SIC_INT_UART3) +#define SIC_INTMASK_CLCD (1 << SIC_INT_CLCD) +#define SIC_INTMASK_TOUCH (1 << SIC_INT_TOUCH) +#define SIC_INTMASK_KEYPAD (1 << SIC_INT_KEYPAD) +#define SIC_INTMASK_DoC (1 << SIC_INT_DoC) +#define SIC_INTMASK_MMCI0A (1 << SIC_INT_MMCI0A) +#define SIC_INTMASK_MMCI1A (1 << SIC_INT_MMCI1A) +#define SIC_INTMASK_AACI (1 << SIC_INT_AACI) +#define SIC_INTMASK_ETH (1 << SIC_INT_ETH) +#define SIC_INTMASK_USB (1 << SIC_INT_USB) +#define SIC_INTMASK_PCI0 (1 << SIC_INT_PCI0) +#define SIC_INTMASK_PCI1 (1 << SIC_INT_PCI1) +#define SIC_INTMASK_PCI2 (1 << SIC_INT_PCI2) +#define SIC_INTMASK_PCI3 (1 << SIC_INT_PCI3) +/* + * Application Flash + * + */ +#define FLASH_BASE VERSATILE_FLASH_BASE +#define FLASH_SIZE VERSATILE_FLASH_SIZE +#define FLASH_END (FLASH_BASE + FLASH_SIZE - 1) +#define FLASH_BLOCK_SIZE SZ_128K + +/* + * Boot Flash + * + */ +#define EPROM_BASE VERSATILE_BOOT_ROM_HI +#define EPROM_SIZE VERSATILE_BOOT_ROM_SIZE +#define EPROM_END (EPROM_BASE + EPROM_SIZE - 1) + +/* + * Clean base - dummy + * + */ +#define CLEAN_BASE EPROM_BASE + +/* + * System controller bit assignment + */ +#define VERSATILE_REFCLK 0 +#define VERSATILE_TIMCLK 1 + +#define VERSATILE_TIMER1_EnSel 15 +#define VERSATILE_TIMER2_EnSel 17 +#define VERSATILE_TIMER3_EnSel 19 +#define VERSATILE_TIMER4_EnSel 21 + + +#define MAX_TIMER 2 +#define MAX_PERIOD 699050 +#define TICKS_PER_uSEC 1 + +/* + * These are useconds NOT ticks. + * + */ +#define mSEC_1 1000 +#define mSEC_5 (mSEC_1 * 5) +#define mSEC_10 (mSEC_1 * 10) +#define mSEC_25 (mSEC_1 * 25) +#define SEC_1 (mSEC_1 * 1000) + +#define VERSATILE_CSR_BASE 0x10000000 +#define VERSATILE_CSR_SIZE 0x10000000 + +#endif + +/* END */ diff --git a/include/asm-arm/arch-versatile/serial.h b/include/asm-arm/arch-versatile/serial.h new file mode 100644 index 000000000000..f578f8910b3e --- /dev/null +++ b/include/asm-arm/arch-versatile/serial.h @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-versatile/serial.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +/* + * This assumes you have a 14.7456 MHz clock UART. + */ +#define BASE_BAUD 115200 + + /* UART CLK PORT IRQ FLAGS */ +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0, 0, ASYNC_SKIP_TEST }, /* ttyS3 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff --git a/include/asm-arm/arch-versatile/system.h b/include/asm-arm/arch-versatile/system.h new file mode 100644 index 000000000000..8889a189739f --- /dev/null +++ b/include/asm-arm/arch-versatile/system.h @@ -0,0 +1,51 @@ +/* + * linux/include/asm-arm/arch-versatile/system.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/platform.h> + +static inline void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + unsigned int hdr_ctrl = (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_RESETCTL_OFFSET); + unsigned int val; + + /* + * To reset, we hit the on-board reset register + * in the system FPGA + */ + val = __raw_readl(hdr_ctrl); + val |= VERSATILE_SYS_CTRL_RESET_CONFIGCLR; + __raw_writel(val, hdr_ctrl); +} + +#endif diff --git a/include/asm-arm/arch-versatile/time.h b/include/asm-arm/arch-versatile/time.h new file mode 100644 index 000000000000..7d97d9565a4b --- /dev/null +++ b/include/asm-arm/arch-versatile/time.h @@ -0,0 +1,158 @@ +/* + * linux/include/asm-arm/arch-versatile/time.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <asm/system.h> +#include <asm/leds.h> + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE) +#define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20) +#define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE) +#define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20) +#define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ +#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ +#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TIMER_RELOAD (TIMER_INTERVAL) +#define TIMER_CTRL 0x80 /* Enable */ +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +extern unsigned long (*gettimeoffset)(void); + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long versatile_gettimeoffset(void) +{ + volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer0->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); + ticks2 = timer0->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = TIMER_RELOAD - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + * + * FIXME: Need to check this is effectively timer 0 that expires + */ + if (status & IRQMASK_TIMERINT0_1) + ticks1 += TIMER_RELOAD; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + + // ...clear the interrupt + timer0->TimerClear = 1; + + do_leds(); + do_timer(regs); + do_profile(regs); + + return IRQ_HANDLED; +} + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init time_init(void) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE; + + /* + * set clock frequency: + * VERSATILE_REFCLK is 32KHz + * VERSATILE_TIMCLK is 1MHz + */ + *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= + ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); + + timer_irq.handler = versatile_timer_interrupt; + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + timer3->TimerControl = 0; + + timer0->TimerLoad = TIMER_RELOAD; + timer0->TimerValue = TIMER_RELOAD; + timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ + + /* + * Make irqs happen for the system timer + */ + setup_irq(IRQ_TIMERINT0_1, &timer_irq); + gettimeoffset = versatile_gettimeoffset; +} diff --git a/include/asm-arm/arch-versatile/timex.h b/include/asm-arm/arch-versatile/timex.h new file mode 100644 index 000000000000..61da0c6ab38a --- /dev/null +++ b/include/asm-arm/arch-versatile/timex.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-versatile/timex.h + * + * Versatile PB architecture timex specifications + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/include/asm-arm/arch-versatile/uncompress.h b/include/asm-arm/arch-versatile/uncompress.h new file mode 100644 index 000000000000..148ad3755abf --- /dev/null +++ b/include/asm-arm/arch-versatile/uncompress.h @@ -0,0 +1,54 @@ +/* + * linux/include/asm-arm/arch-versatile/uncompress.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/kernel.h> + +#define AMBA_UART_DR (*(volatile unsigned char *)0x101F1000) +#define AMBA_UART_LCRH (*(volatile unsigned char *)0x101F102C) +#define AMBA_UART_CR (*(volatile unsigned char *)0x101F1030) +#define AMBA_UART_FR (*(volatile unsigned char *)0x101F1018) + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = *s; + + if (*s == '\n') { + while (AMBA_UART_FR & (1 << 5)) + barrier(); + + AMBA_UART_DR = '\r'; + } + s++; + } + while (AMBA_UART_FR & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-versatile/vmalloc.h b/include/asm-arm/arch-versatile/vmalloc.h new file mode 100644 index 000000000000..adfb34829bfc --- /dev/null +++ b/include/asm-arm/arch-versatile/vmalloc.h @@ -0,0 +1,33 @@ +/* + * linux/include/asm-arm/arch-versatile/vmalloc.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x18000000) diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h index 8ae0be984492..7fb3046c6729 100644 --- a/include/asm-arm/bitops.h +++ b/include/asm-arm/bitops.h @@ -212,6 +212,8 @@ extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p); extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_le(void * p, unsigned size); extern int _find_next_zero_bit_le(void * p, int size, int offset); +extern int _find_first_bit_le(const unsigned long *p, unsigned size); +extern int _find_next_bit_le(const unsigned long *p, int size, int offset); /* * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. @@ -224,7 +226,8 @@ extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p); extern int _test_and_change_bit_be(int nr, volatile unsigned long * p); extern int _find_first_zero_bit_be(void * p, unsigned size); extern int _find_next_zero_bit_be(void * p, int size, int offset); - +extern int _find_first_bit_be(const unsigned long *p, unsigned size); +extern int _find_next_bit_be(unsigned long *p, int size, int offset); /* * The __* form of bitops are non-atomic and may be reordered. @@ -255,6 +258,8 @@ extern int _find_next_zero_bit_be(void * p, int size, int offset); #define test_bit(nr,p) __test_bit(nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_le(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) #define WORD_BITOFF_TO_LE(x) ((x)) @@ -272,6 +277,8 @@ extern int _find_next_zero_bit_be(void * p, int size, int offset); #define test_bit(nr,p) __test_bit(nr,p) #define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_be(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_be(p,sz,off) #define WORD_BITOFF_TO_LE(x) ((x) ^ 0x18) diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index e7c7fd2265cd..0439ec64301c 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -121,6 +121,8 @@ struct thread_struct { #endif /* CONFIG_ALTIVEC */ }; +#define ARCH_MIN_TASKALIGN 16 + #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_THREAD { \ diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index ea8bf67f7007..d3e83108c064 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -553,6 +553,8 @@ struct thread_struct { #endif /* CONFIG_ALTIVEC */ }; +#define ARCH_MIN_TASKALIGN 16 + #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_THREAD { \ diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index ebe0b1221579..99cb4139354b 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -157,6 +157,8 @@ void __wait_on_buffer(struct buffer_head *); wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); void wake_up_buffer(struct buffer_head *bh); int fsync_bdev(struct block_device *); +struct super_block *freeze_bdev(struct block_device *); +void thaw_bdev(struct block_device *, struct super_block *); int fsync_super(struct super_block *); int fsync_no_super(struct block_device *); struct buffer_head *__find_get_block(struct block_device *, sector_t, int); diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 278c533b6994..aa9733c90045 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -597,7 +597,7 @@ COMPATIBLE_IOCTL(RNDGETPOOL) COMPATIBLE_IOCTL(RNDADDENTROPY) COMPATIBLE_IOCTL(RNDZAPENTCNT) COMPATIBLE_IOCTL(RNDCLEARPOOL) -/* Bluetooth ioctls */ +/* Bluetooth */ COMPATIBLE_IOCTL(HCIDEVUP) COMPATIBLE_IOCTL(HCIDEVDOWN) COMPATIBLE_IOCTL(HCIDEVRESET) @@ -631,6 +631,20 @@ COMPATIBLE_IOCTL(CMTPCONNADD) COMPATIBLE_IOCTL(CMTPCONNDEL) COMPATIBLE_IOCTL(CMTPGETCONNLIST) COMPATIBLE_IOCTL(CMTPGETCONNINFO) +/* CAPI */ +COMPATIBLE_IOCTL(CAPI_REGISTER) +COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER) +COMPATIBLE_IOCTL(CAPI_GET_VERSION) +COMPATIBLE_IOCTL(CAPI_GET_SERIAL) +COMPATIBLE_IOCTL(CAPI_GET_PROFILE) +COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD) +COMPATIBLE_IOCTL(CAPI_GET_ERRCODE) +COMPATIBLE_IOCTL(CAPI_INSTALLED) +COMPATIBLE_IOCTL(CAPI_GET_FLAGS) +COMPATIBLE_IOCTL(CAPI_SET_FLAGS) +COMPATIBLE_IOCTL(CAPI_CLR_FLAGS) +COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT) +COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ diff --git a/include/linux/fs.h b/include/linux/fs.h index ed06629b972e..8971ae34dbdf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -345,6 +345,7 @@ struct block_device { struct inode * bd_inode; /* will die */ int bd_openers; struct semaphore bd_sem; /* open/close mutex */ + struct semaphore bd_mount_sem; /* mount mutex */ struct list_head bd_inodes; void * bd_holder; int bd_holders; @@ -749,6 +750,9 @@ struct super_block { struct list_head s_instances; struct quota_info s_dquot; /* Diskquota specific options */ + int s_frozen; + wait_queue_head_t s_wait_unfrozen; + char s_id[32]; /* Informational name */ void *s_fs_info; /* Filesystem private info */ @@ -761,6 +765,18 @@ struct super_block { }; /* + * Snapshotting support. + */ +enum { + SB_UNFROZEN = 0, + SB_FREEZE_WRITE = 1, + SB_FREEZE_TRANS = 2, +}; + +#define vfs_check_frozen(sb, level) \ + wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) + +/* * Superblock locking. */ static inline void lock_super(struct super_block * sb) diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 0b12bd800fd1..2d439a8390c0 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -24,8 +24,6 @@ enum { PROC_ROOT_INO = 1, }; -/* Finally, the dynamically allocatable proc entries are reserved: */ - #define PROC_SUPER_MAGIC 0x9fa0 /* diff --git a/include/linux/sched.h b/include/linux/sched.h index 428b48964fc8..e414003e872b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -151,7 +151,6 @@ extern void init_idle(task_t *idle, int cpu); extern void show_state(void); extern void show_regs(struct pt_regs *); -extern void show_trace_task(task_t *tsk); /* * TASK is a pointer to the task whose backtrace we want to see (or NULL for current diff --git a/include/linux/security.h b/include/linux/security.h index 9baa2ed4ac96..2d16f6577669 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -44,7 +44,7 @@ extern int cap_capget (struct task_struct *target, kernel_cap_t *effective, kern extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_bprm_set_security (struct linux_binprm *bprm); -extern void cap_bprm_compute_creds (struct linux_binprm *bprm); +extern void cap_bprm_apply_creds (struct linux_binprm *bprm); extern int cap_bprm_secureexec(struct linux_binprm *bprm); extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags); extern int cap_inode_removexattr(struct dentry *dentry, char *name); @@ -102,7 +102,7 @@ struct swap_info_struct; * @bprm_free_security: * @bprm contains the linux_binprm structure to be modified. * Deallocate and clear the @bprm->security field. - * @bprm_compute_creds: + * @bprm_apply_creds: * Compute and set the security attributes of a process being transformed * by an execve operation based on the old attributes (current->security) * and the information saved in @bprm->security by the set_security hook. @@ -115,7 +115,7 @@ struct swap_info_struct; * @bprm contains the linux_binprm structure. * @bprm_set_security: * Save security information in the bprm->security field, typically based - * on information about the bprm->file, for later use by the compute_creds + * on information about the bprm->file, for later use by the apply_creds * hook. This hook may also optionally check permissions (e.g. for * transitions between security domains). * This hook may be called multiple times during a single execve, e.g. for @@ -924,7 +924,7 @@ struct swap_info_struct; * Check permission before allowing the @parent process to trace the * @child process. * Security modules may also want to perform a process tracing check - * during an execve in the set_security or compute_creds hooks of + * during an execve in the set_security or apply_creds hooks of * binprm_security_ops if the process is being traced and its security * attributes would be changed by the execve. * @parent contains the task_struct structure for parent process. @@ -1026,7 +1026,7 @@ struct security_operations { int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); - void (*bprm_compute_creds) (struct linux_binprm * bprm); + void (*bprm_apply_creds) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); int (*bprm_secureexec) (struct linux_binprm * bprm); @@ -1290,9 +1290,9 @@ static inline void security_bprm_free (struct linux_binprm *bprm) { security_ops->bprm_free_security (bprm); } -static inline void security_bprm_compute_creds (struct linux_binprm *bprm) +static inline void security_bprm_apply_creds (struct linux_binprm *bprm) { - security_ops->bprm_compute_creds (bprm); + security_ops->bprm_apply_creds (bprm); } static inline int security_bprm_set (struct linux_binprm *bprm) { @@ -1962,9 +1962,9 @@ static inline int security_bprm_alloc (struct linux_binprm *bprm) static inline void security_bprm_free (struct linux_binprm *bprm) { } -static inline void security_bprm_compute_creds (struct linux_binprm *bprm) +static inline void security_bprm_apply_creds (struct linux_binprm *bprm) { - cap_bprm_compute_creds (bprm); + cap_bprm_apply_creds (bprm); } static inline int security_bprm_set (struct linux_binprm *bprm) diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index a444c9edb9e9..3a2206f61de0 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h @@ -20,6 +20,7 @@ #include <linux/sunrpc/auth_gss.h> int gss_svc_init(void); +void gss_svc_shutdown(void); int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); #endif /* __KERNEL__ */ diff --git a/init/Kconfig b/init/Kconfig index 55261afdc3bf..337feb1026ea 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -149,7 +149,7 @@ config AUDIT config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC64) + depends on AUDIT && (X86 || PPC64 || ARCH_S390) default y if SECURITY_SELINUX default n help diff --git a/init/main.c b/init/main.c index c500c6fe296d..84cf96dddf4e 100644 --- a/init/main.c +++ b/init/main.c @@ -89,6 +89,7 @@ extern void radix_tree_init(void); extern void free_initmem(void); extern void populate_rootfs(void); extern void driver_init(void); +extern void prepare_namespace(void); #ifdef CONFIG_TC extern void tc_init(void); @@ -471,7 +472,6 @@ asmlinkage void __init start_kernel(void) signals_init(); /* rootfs populating might need page-writeback */ page_writeback_init(); - populate_rootfs(); #ifdef CONFIG_PROC_FS proc_root_init(); #endif @@ -577,8 +577,6 @@ static void run_init_process(char *init_filename) execve(init_filename, argv_init, envp_init); } -extern void prepare_namespace(void); - static int init(void * unused) { lock_kernel(); @@ -600,14 +598,15 @@ static int init(void * unused) smp_init(); do_basic_setup(); - /* - * check if there is an early userspace init, if yes - * let it do all the work - */ - if (sys_access("/init", 0) == 0) - execute_command = "/init"; - else - prepare_namespace(); + populate_rootfs(); + /* + * check if there is an early userspace init. If yes, let it do all + * the work + */ + if (sys_access("/init", 0) == 0) + execute_command = "/init"; + else + prepare_namespace(); /* * Ok, we have completed the initial bootup, and diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b1b922f09257..971124109c8c 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -984,6 +984,7 @@ out: static void __exit exit_rpcsec_gss(void) { + gss_svc_shutdown(); gss_mech_unregister_all(); rpcauth_unregister(&authgss_ops); } diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index a60a541e9f5e..dae18e9792a6 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1063,3 +1063,10 @@ gss_svc_init(void) svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); return 0; } + +void +gss_svc_shutdown(void) +{ + cache_unregister(&rsc_cache); + cache_unregister(&rsi_cache); +} diff --git a/security/capability.c b/security/capability.c index ba7daa4592dd..f1e81ba6b79d 100644 --- a/security/capability.c +++ b/security/capability.c @@ -35,7 +35,7 @@ static struct security_operations capability_ops = { .netlink_send = cap_netlink_send, .netlink_recv = cap_netlink_recv, - .bprm_compute_creds = cap_bprm_compute_creds, + .bprm_apply_creds = cap_bprm_apply_creds, .bprm_set_security = cap_bprm_set_security, .bprm_secureexec = cap_bprm_secureexec, diff --git a/security/commoncap.c b/security/commoncap.c index e902b60ecc30..07265810c353 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -115,13 +115,15 @@ int cap_bprm_set_security (struct linux_binprm *bprm) return 0; } -/* Copied from fs/exec.c */ static inline int must_not_trace_exec (struct task_struct *p) { - return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP); + return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP)) + || atomic_read(&p->fs->count) > 1 + || atomic_read(&p->files->count) > 1 + || atomic_read(&p->sighand->count) > 1; } -void cap_bprm_compute_creds (struct linux_binprm *bprm) +void cap_bprm_apply_creds (struct linux_binprm *bprm) { /* Derived from fs/exec.c:compute_creds. */ kernel_cap_t new_permitted, working; @@ -132,18 +134,26 @@ void cap_bprm_compute_creds (struct linux_binprm *bprm) new_permitted = cap_combine (new_permitted, working); task_lock(current); + + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { + current->mm->dumpable = 0; + + if (must_not_trace_exec(current) && !capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + } + + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + if (!cap_issubset (new_permitted, current->cap_permitted)) { current->mm->dumpable = 0; - if (must_not_trace_exec (current) - || atomic_read (¤t->fs->count) > 1 - || atomic_read (¤t->files->count) > 1 - || atomic_read (¤t->sighand->count) > 1) { - if (!capable (CAP_SETPCAP)) { - new_permitted = cap_intersect (new_permitted, - current-> - cap_permitted); - } + if (must_not_trace_exec (current) && !capable (CAP_SETPCAP)) { + new_permitted = cap_intersect (new_permitted, + current-> + cap_permitted); } } @@ -315,7 +325,7 @@ int cap_vm_enough_memory(long pages) vm_acct_memory(pages); - /* + /* * Sometimes we want to use more memory than we have */ if (sysctl_overcommit_memory == 1) @@ -377,7 +387,7 @@ EXPORT_SYMBOL(cap_capget); EXPORT_SYMBOL(cap_capset_check); EXPORT_SYMBOL(cap_capset_set); EXPORT_SYMBOL(cap_bprm_set_security); -EXPORT_SYMBOL(cap_bprm_compute_creds); +EXPORT_SYMBOL(cap_bprm_apply_creds); EXPORT_SYMBOL(cap_bprm_secureexec); EXPORT_SYMBOL(cap_inode_setxattr); EXPORT_SYMBOL(cap_inode_removexattr); diff --git a/security/dummy.c b/security/dummy.c index 3bf46b0f5997..c34991da5d6e 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -26,6 +26,8 @@ #include <net/sock.h> #include <linux/xattr.h> #include <linux/hugetlb.h> +#include <linux/ptrace.h> +#include <linux/file.h> static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) { @@ -116,7 +118,7 @@ static int dummy_vm_enough_memory(long pages) vm_acct_memory(pages); - /* + /* * Sometimes we want to use more memory than we have */ if (sysctl_overcommit_memory == 1) @@ -169,9 +171,30 @@ static void dummy_bprm_free_security (struct linux_binprm *bprm) return; } -static void dummy_bprm_compute_creds (struct linux_binprm *bprm) +static inline int must_not_trace_exec (struct task_struct *p) { - return; + return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP)) + || atomic_read(&p->fs->count) > 1 + || atomic_read(&p->files->count) > 1 + || atomic_read(&p->sighand->count) > 1; +} + +static void dummy_bprm_apply_creds (struct linux_binprm *bprm) +{ + task_lock(current); + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { + current->mm->dumpable = 0; + + if (must_not_trace_exec(current) && !capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + } + + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + + task_unlock(current); } static int dummy_bprm_set_security (struct linux_binprm *bprm) @@ -887,7 +910,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, vm_enough_memory); set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); - set_to_dummy_if_null(ops, bprm_compute_creds); + set_to_dummy_if_null(ops, bprm_apply_creds); set_to_dummy_if_null(ops, bprm_set_security); set_to_dummy_if_null(ops, bprm_check_security); set_to_dummy_if_null(ops, bprm_secureexec); diff --git a/security/root_plug.c b/security/root_plug.c index c683d6133321..ec8955dcba29 100644 --- a/security/root_plug.c +++ b/security/root_plug.c @@ -90,7 +90,7 @@ static struct security_operations rootplug_security_ops = { .capset_set = cap_capset_set, .capable = cap_capable, - .bprm_compute_creds = cap_bprm_compute_creds, + .bprm_apply_creds = cap_bprm_apply_creds, .bprm_set_security = cap_bprm_set_security, .task_post_setuid = cap_task_post_setuid, diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 387729cc6a0a..be4d39864576 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -24,6 +24,21 @@ config SECURITY_SELINUX_BOOTPARAM If you are unsure how to answer this question, answer N. +config SECURITY_SELINUX_DISABLE + bool "NSA SELinux runtime disable" + depends on SECURITY_SELINUX + default n + help + This option enables writing to a selinuxfs node 'disable', which + allows SELinux to be disabled at runtime prior to the policy load. + SELinux will then remain disabled until the next boot. + This option is similar to the selinux=0 boot parameter, but is to + support runtime disabling of SELinux, e.g. from /sbin/init, for + portability across platforms where boot parameters are difficult + to employ. + + If you are unsure how to answer this question, answer N. + config SECURITY_SELINUX_DEVELOP bool "NSA SELinux Development Support" depends on SECURITY_SELINUX diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5e765cd7535b..2273c5f851b4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1745,7 +1745,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) spin_unlock(&files->file_lock); } -static void selinux_bprm_compute_creds(struct linux_binprm *bprm) +static void selinux_bprm_apply_creds(struct linux_binprm *bprm) { struct task_security_struct *tsec, *psec; struct bprm_security_struct *bsec; @@ -1755,7 +1755,7 @@ static void selinux_bprm_compute_creds(struct linux_binprm *bprm) struct rlimit *rlim, *initrlim; int rc, i; - secondary_ops->bprm_compute_creds(bprm); + secondary_ops->bprm_apply_creds(bprm); tsec = current->security; @@ -2560,7 +2560,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim /* Control the ability to change the hard limit (whether lowering or raising it), so that the hard limit can later be used as a safe reset point for the soft limit - upon context transitions. See selinux_bprm_compute_creds. */ + upon context transitions. See selinux_bprm_apply_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) return task_has_perm(current, current, PROCESS__SETRLIMIT); @@ -3971,7 +3971,7 @@ struct security_operations selinux_ops = { .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, - .bprm_compute_creds = selinux_bprm_compute_creds, + .bprm_apply_creds = selinux_bprm_apply_creds, .bprm_set_security = selinux_bprm_set_security, .bprm_check_security = selinux_bprm_check_security, .bprm_secureexec = selinux_bprm_secureexec, @@ -4216,4 +4216,57 @@ out: __initcall(selinux_nf_ip_init); +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +static void selinux_nf_ip_exit(void) +{ + printk(KERN_INFO "SELinux: Unregistering netfilter hooks\n"); + + nf_unregister_hook(&selinux_ipv4_op); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + nf_unregister_hook(&selinux_ipv6_op); +#endif /* IPV6 */ +} +#endif + +#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +#define selinux_nf_ip_exit() +#endif + #endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +int selinux_disable(void) +{ + extern void exit_sel_fs(void); + static int selinux_disabled = 0; + + if (ss_initialized) { + /* Not permitted after initial policy load. */ + return -EINVAL; + } + + if (selinux_disabled) { + /* Only do this once. */ + return -EINVAL; + } + + printk(KERN_INFO "SELinux: Disabled at runtime.\n"); + + selinux_disabled = 1; + + /* Reset security_ops to the secondary module, dummy or capability. */ + security_ops = secondary_ops; + + /* Unregister netfilter hooks. */ + selinux_nf_ip_exit(); + + /* Unregister selinuxfs. */ + exit_sel_fs(); + + return 0; +} +#endif + + diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index c944d72ecce4..1a589da54f1b 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -46,6 +46,8 @@ int task_has_security(struct task_struct *tsk, struct task_security_struct *tsec; tsec = tsk->security; + if (!tsec) + return -EACCES; return avc_has_perm(tsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY, perms, NULL, NULL); @@ -61,8 +63,9 @@ enum sel_inos { SEL_RELABEL, /* compute relabeling decision */ SEL_USER, /* compute reachable user contexts */ SEL_POLICYVERS, /* return policy version for this kernel */ - SEL_COMMIT_BOOLS, - SEL_MLS /* return if MLS policy is enabled */ + SEL_COMMIT_BOOLS, /* commit new boolean values */ + SEL_MLS, /* return if MLS policy is enabled */ + SEL_DISABLE /* disable SELinux until next reboot */ }; static ssize_t sel_read_enforce(struct file *filp, char *buf, @@ -151,6 +154,53 @@ static struct file_operations sel_enforce_ops = { .write = sel_write_enforce, }; +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +static ssize_t sel_write_disable(struct file * file, const char * buf, + size_t count, loff_t *ppos) + +{ + char *page; + ssize_t length; + int new_value; + extern int selinux_disable(void); + + if (count < 0 || count >= PAGE_SIZE) + return -ENOMEM; + if (*ppos != 0) { + /* No partial writes. */ + return -EINVAL; + } + page = (char*)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + memset(page, 0, PAGE_SIZE); + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + length = -EINVAL; + if (sscanf(page, "%d", &new_value) != 1) + goto out; + + if (new_value) { + length = selinux_disable(); + if (length < 0) + goto out; + } + + length = count; +out: + free_page((unsigned long) page); + return length; +} +#else +#define sel_write_disable NULL +#endif + +static struct file_operations sel_disable_ops = { + .write = sel_write_disable, +}; + static ssize_t sel_read_policyvers(struct file *filp, char *buf, size_t count, loff_t *ppos) { @@ -1005,6 +1055,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) [SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO}, [SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR}, [SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO}, + [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR}, /* last one */ {""} }; ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); @@ -1054,3 +1105,10 @@ static int __init init_sel_fs(void) } __initcall(init_sel_fs); + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +void exit_sel_fs(void) +{ + unregister_filesystem(&sel_fs_type); +} +#endif diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 7532053898a6..7d0fedf04179 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -456,9 +456,7 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) goto out; } } - printk(KERN_ERR "security_context_to_sid: called before " - "initial load_policy on unknown context %s\n", scontext); - rc = -EINVAL; + *sid = SECINITSID_KERNEL; goto out; } *sid = SECSID_NULL; @@ -1343,8 +1341,6 @@ int security_get_user_sids(u32 fromsid, if (!ebitmap_get_bit(&role->types, j)) continue; usercon.type = j+1; - if (usercon.type == fromcon->type) - continue; mls_for_user_ranges(user,usercon) { rc = context_struct_compute_av(fromcon, &usercon, SECCLASS_PROCESS, |
