diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-02-15 02:15:32 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-02-15 02:15:32 +0000 |
commit | 86464aed71025541805e7b1515541aee89879e33 (patch) | |
tree | e01a457a4912a8553bc65524aa3125d51f29f810 /arch/arm | |
parent | 88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff) |
Merge with Linux 2.2.1.
Diffstat (limited to 'arch/arm')
34 files changed, 1014 insertions, 511 deletions
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 5ef8ea75e..967ee6766 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -120,6 +120,7 @@ COMPRESSED_HEAD = head-nexuspci.o endif ifeq ($(CONFIG_ARCH_VNC),y) +TEXTADDR = 0xC000C000 MACHINE = vnc ARCHDIR = vnc endif @@ -141,7 +142,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S OBJDUMP = $(CROSS_COMPILE)objdump CPP = $(CC) -E ARCHCC := $(word 1,$(CC)) -GCCLIB := `$(ARCHCC) $(CFLAGS_PROC) --print-libgcc-file-name` +GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name` #GCCARCH := -B/usr/bin/arm-linuxelf- HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=) ifeq ($(CONFIG_FRAME_POINTER),y) @@ -160,10 +161,10 @@ LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) BLOCK_DRIVERS := drivers/block/block.a CDROM_DRIVERS := drivers/cdrom/cdrom.a ifeq ($(CONFIG_FB),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char.a +CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a else ifeq ($(CONFIG_VGA_CONSOLE),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char.a +CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a else CHAR_DRIVERS := arch/arm/drivers/char/char.a endif diff --git a/arch/arm/config.in b/arch/arm/config.in index 2b59a964c..467218db7 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -38,15 +38,22 @@ if [ "$CONFIG_ARCH_TBOX" = "y" ]; then define_bool CONFIG_BUS_I2C y fi -# These machines have PCI/may have PCI +# These machines always have PCI if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ "$CONFIG_ARCH_VNC" = "y" ]; then define_bool CONFIG_PCI y +fi +if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then + bool "PCI support" CONFIG_PCI +fi + +# These machines have ISA-DMA +if [ "$CONFIG_CATS" = "y" -o \ + "$CONFIG_ARCH_VNC" = "y" ]; then + define_bool CONFIG_ISA_DMA y else - if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then - bool "PCI support" CONFIG_PCI - fi + define_bool CONFIG_ISA_DMA n fi # Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has @@ -122,6 +129,11 @@ if [ "$CONFIG_PARPORT" != "n" ]; then fi fi fi +if [ "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_VNC" = "y" ]; then + string 'Initial kernel command string' CONFIG_CMDLINE +fi endmenu source drivers/pnp/Config.in @@ -132,16 +144,20 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then source drivers/acorn/block/Config.in fi -source arch/arm/drivers/char/Config.in +if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then + source arch/arm/drivers/char/Config.in +else + source drivers/char/Config.in +fi +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + source drivers/acorn/char/Config.in +fi if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then bool 'VGA text console' CONFIG_VGA_CONSOLE - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Video mode selection support' CONFIG_VIDEO_SELECT - fi fi bool 'Support Frame buffer devices' CONFIG_FB source drivers/video/Config.in @@ -195,8 +211,6 @@ fi source fs/Config.in -source fs/nls/Config.in - mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 542ca995a..23b2c1267 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -10,44 +10,54 @@ ENTRY_OBJ = entry-$(PROCESSOR).o O_TARGET := kernel.o O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \ - signal.o sys_arm.o time.o traps.o fiq.o + signal.o sys_arm.o time.o traps.o + +DMA_OBJS_arc = dma-arc.o +DMA_OBJS_a5k = dma-a5k.o +DMA_OBJS_rpc = dma-rpc.o +DMA_OBJS_ebsa110 = dma-dummy.o +DMA_OBJS_ebsa285 = dma-ebsa285.o +DMA_OBJS_nexuspci = +DMA_OBJS_vnc = dma-vnc.o + +O_OBJS_arc = ecard.o iic.o fiq.o oldlatches.o +O_OBJS_a5k = ecard.o iic.o fiq.o +O_OBJS_rpc = ecard.o iic.o fiq.o +O_OBJS_ebsa110 = leds-ebsa110.o +O_OBJS_ebsa285 = leds-ebsa285.o hw-ebsa285.o +O_OBJS_nexuspci = +O_OBJS_vnc = leds-ebsa285.o hw-vnc.o all: lib kernel.o $(HEAD_OBJ) init_task.o ifeq ($(CONFIG_MODULES),y) -OX_OBJS = armksyms.o + OX_OBJS = armksyms.o else -O_OBJS += armksyms.o + O_OBJS += armksyms.o endif -ifdef CONFIG_ARCH_ACORN - O_OBJS += ecard.o iic.o - ifdef CONFIG_ARCH_ARC - O_OBJS += oldlatches.o +ifeq ($(MACHINE),nexuspci) + ifdef CONFIG_PCI + O_OBJS += plx9080.o endif - O_OBJS += dma-$(MACHINE).o - OX_OBJS += dma.o -endif - -ifeq ($(MACHINE),ebsa110) - O_OBJS += dma-dummy.o leds-ebsa110.o -endif - -ifeq ($(MACHINE),ebsa285) - OX_OBJS += dma.o - O_OBJS += dma-ebsa285.o leds-ebsa285.o +else ifdef CONFIG_PCI O_OBJS += dec21285.o endif endif -ifeq ($(MACHINE),nexuspci) - O_OBJS += dma-dummy.o - ifdef CONFIG_PCI - O_OBJS += plx9080.o +ifneq ($(DMA_OBJS_$(MACHINE)),) + OX_OBJS += dma.o + O_OBJS += $(DMA_OBJS_$(MACHINE)) + ifeq ($(CONFIG_ISA_DMA),y) + O_OBJS += dma-isa.o endif +else + O_OBJS += dma-dummy.o endif +O_OBJS += $(O_OBJS_$(MACHINE)) + $(HEAD_OBJ): $(HEAD_OBJ:.o=.S) $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 751f9616a..46f71fa92 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -9,7 +9,7 @@ #define NR_syscalls 256 #else -/* 0 */ .long SYMBOL_NAME(sys_setup) +/* 0 */ .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork_wrapper) .long SYMBOL_NAME(sys_read) diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index de4861b82..aa66ee04a 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -3,14 +3,23 @@ * * Copyright (C) 1998 Russell King, Phil Blundell */ +#include <linux/sched.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/ptrace.h> +#include <linux/interrupt.h> #include <linux/init.h> +#include <asm/irq.h> #include <asm/system.h> #define MAX_SLOTS 20 +extern void pcibios_fixup_ebsa285(struct pci_dev *dev); +extern void pcibios_init_ebsa285(void); +extern void pcibios_fixup_vnc(struct pci_dev *dev); +extern void pcibios_init_vnc(void); + int pcibios_present(void) { @@ -24,12 +33,11 @@ pcibios_base_address(unsigned char bus, unsigned char dev_fn) int slot = PCI_SLOT(dev_fn); if (slot < MAX_SLOTS) - return 0xf8c00000 + (slot << 11); + return 0xf8c00000 + (slot << 11) + (PCI_FUNC(dev_fn) << 8); else return 0; - } else { + } else return 0xf9000000 | (bus << 16) | (dev_fn << 8); - } } int @@ -119,56 +127,35 @@ pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 }; -static int irqmap_cats[] __initdata = { 18, 8, 9, 11 }; - -__initfunc(static int ebsa_irqval(struct pci_dev *dev)) +__initfunc(void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set)) { - unsigned char pin; - - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_PIN, - &pin); - - return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; + unsigned short cmd; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd = (cmd & ~clear) | set; + pci_write_config_word(dev, PCI_COMMAND, cmd); } -__initfunc(static int cats_irqval(struct pci_dev *dev)) +__initfunc(void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr)) { - if (dev->irq >= 128) - return 32 + (dev->irq & 0x1f); - - switch (dev->irq) { - case 1: - case 2: - case 3: - case 4: - return irqmap_cats[dev->irq - 1]; - case 0: - return 0; - } + int reg = PCI_BASE_ADDRESS_0 + (idx << 2); - printk("PCI: device %02x:%02x has unknown irq line %x\n", - dev->bus->number, dev->devfn, dev->irq); - return 0; + pci_write_config_dword(dev, reg, addr); + pci_read_config_dword(dev, reg, &addr); + + dev->base_address[idx] = addr; } __initfunc(void pcibios_fixup(void)) { struct pci_dev *dev; - unsigned char cmd; for (dev = pci_devices; dev; dev = dev->next) { - /* sort out the irq mapping for this device */ - switch (machine_type) { - case MACH_TYPE_EBSA285: - dev->irq = ebsa_irqval(dev); - break; - case MACH_TYPE_CATS: - dev->irq = cats_irqval(dev); - break; - } + if (machine_is_ebsa285() || machine_is_cats()) + pcibios_fixup_ebsa285(dev); + if (machine_is_netwinder()) + pcibios_fixup_vnc(dev); + pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); @@ -176,34 +163,19 @@ __initfunc(void pcibios_fixup(void)) "PCI: %02x:%02x [%04x/%04x] on irq %d\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->irq); - - /* Turn on bus mastering - boot loader doesn't - * - perhaps it should! - dag - */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_COMMAND, cmd); } + if (machine_is_netwinder()) + hw_init(); } __initfunc(void pcibios_init(void)) { - int rev; - - rev = *(unsigned char *)0xfe000008; - printk("DEC21285 PCI revision %02X\n", rev); - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is slightly - * bizarre but apparently necessary to avoid problems with some - * video cards. - * - * We should really only do this if we are the configuration master. - */ - *((unsigned long *)0xfe000018) = 0x10000000; + if (machine_is_ebsa285() || machine_is_cats()) + pcibios_init_ebsa285(); + if (machine_is_netwinder()) + pcibios_init_vnc(); + + printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008); } __initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) diff --git a/arch/arm/kernel/dma-a5k.c b/arch/arm/kernel/dma-a5k.c index 50ee42435..18bbf0c9c 100644 --- a/arch/arm/kernel/dma-a5k.c +++ b/arch/arm/kernel/dma-a5k.c @@ -16,7 +16,7 @@ #include "dma.h" -static struct fiq_handler fh = { "floppydma", NULL }; +static struct fiq_handler fh = { NULL, "floppydma", NULL, NULL }; int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id) { diff --git a/arch/arm/kernel/dma-ebsa285.c b/arch/arm/kernel/dma-ebsa285.c index 74af95584..f1c42dac2 100644 --- a/arch/arm/kernel/dma-ebsa285.c +++ b/arch/arm/kernel/dma-ebsa285.c @@ -4,6 +4,9 @@ * Copyright (C) 1998 Phil Blundell * * DMA functions specific to EBSA-285/CATS architectures + * + * Changelog: + * 09/11/1998 RMK Split out ISA DMA functions to dma-isa.c */ #include <linux/config.h> @@ -19,44 +22,19 @@ #include <asm/hardware.h> #include "dma.h" - -/* 8237 DMA controllers */ -#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ -#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ - -/* 8237 DMA controller registers */ -#define DMA1_CMD_REG 0x08 /* command register (w) */ -#define DMA1_STAT_REG 0x08 /* status register (r) */ -#define DMA1_REQ_REG 0x09 /* request register (w) */ -#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ -#define DMA1_MODE_REG 0x0B /* mode register (w) */ -#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ -#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ -#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ - -#define DMA2_CMD_REG 0xD0 /* command register (w) */ -#define DMA2_STAT_REG 0xD0 /* status register (r) */ -#define DMA2_REQ_REG 0xD2 /* request register (w) */ -#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ -#define DMA2_MODE_REG 0xD6 /* mode register (w) */ -#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ -#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ -#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ +#include "dma-isa.h" int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) { - /* 21285 internal channels */ - if (channel == 0 || channel == 1) + switch (channel) { + case 0: + case 1: /* 21285 internal channels */ return 0; - /* ISA channels */ -// if (machine_is_cats() && ((channel >= 2 && channel <= 5) || -// (channel >= 7 && channel <= 9))) -// return 0; + case 2 ... 9: + if (machine_is_cats()) + return isa_request_dma(channel - 2, dma, dev_name); + } return -EINVAL; } @@ -75,14 +53,9 @@ int arch_get_dma_residue(dmach_t channel, dma_t *dma) case 1: break; #ifdef CONFIG_CATS - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: + case 2 ... 9: + if (machine_is_cats()) + residue = isa_get_dma_residue(channel - 2); #endif } return residue; @@ -98,56 +71,9 @@ void arch_enable_dma(dmach_t channel, dma_t *dma) */ break; #ifdef CONFIG_CATS - case 2: - case 3: - case 4: - case 5: - case 7: - case 8: - case 9: - if (dma->invalid) { - static unsigned char dma_page[] = { 0x87, 0x83, 0x81, 0x82, - 0x00, 0x8b, 0x89, 0x8a }; - unsigned long int address = dma->buf.address, - length = dma->buf.length - 1; - outb(address >> 24, dma_page[channel - DMA_ISA_BASE] | 0x400); - outb(address >> 16, dma_page[channel - DMA_ISA_BASE]); - if (channel >= DMA_ISA_BASE + 5) { - outb(0, DMA2_CLEAR_FF_REG); - outb(address >> 1, - IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2)); - outb(address >> 9, - IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2)); - outb((length >> 1) & 0xfe, - IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2)); - outb(length >> 9, - IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2)); - outb(dma->dma_mode | (channel - DMA_ISA_BASE - 4), DMA2_MODE_REG); - } else { - outb(0, DMA1_CLEAR_FF_REG); - outb(address >> 0, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1)); - outb(address >> 8, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1)); - outb(length >> 0, - IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1)); - outb(length >> 8, - IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1)); - outb(dma->dma_mode | (channel - DMA_ISA_BASE), DMA1_MODE_REG); - } - switch (dma->dma_mode) { - case DMA_MODE_READ: - dma_cache_inv(__bus_to_virt(address), length + 1); - break; - case DMA_MODE_WRITE: - dma_cache_wback(__bus_to_virt(address), length + 1); - break; - } - dma->invalid = 0; - } - - if (channel >= DMA_ISA_BASE + 5) - outb(channel - DMA_ISA_BASE - 4, DMA2_MASK_REG); - else - outb(channel - DMA_ISA_BASE, DMA1_MASK_REG); + case 2 ... 9: + if (machine_is_cats()) + isa_enable_dma(channel - 2, dma); #endif } } @@ -162,18 +88,9 @@ void arch_disable_dma(dmach_t channel, dma_t *dma) */ break; #ifdef CONFIG_CATS - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - if (channel >= DMA_ISA_BASE + 5) - outb(channel - DMA_ISA_BASE, DMA2_MASK_REG); - else - outb((channel - DMA_ISA_BASE) | 4, DMA1_MASK_REG); + case 2 ... 9: + if (machine_is_cats()) + isa_disable_dma(channel - 2, dma); #endif } } diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c new file mode 100644 index 000000000..bdf7c6147 --- /dev/null +++ b/arch/arm/kernel/dma-isa.c @@ -0,0 +1,107 @@ +/* + * arch/arm/kernel/dma-isa.c: ISA DMA primitives + * + * Copyright (C) Russell King + * + * Taken from various sources, including: + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen and John Boyd, Nov. 1992. + * arch/arm/kernel/dma-ebsa285.c + * Copyright (C) 1998 Phil Blundell + */ +#include <linux/sched.h> + +#include <asm/dma.h> +#include <asm/io.h> + +#include "dma.h" +#include "dma-isa.h" + +#define ISA_DMA_MASK 0 +#define ISA_DMA_MODE 1 +#define ISA_DMA_CLRFF 2 +#define ISA_DMA_PGHI 3 +#define ISA_DMA_PGLO 4 +#define ISA_DMA_ADDR 5 +#define ISA_DMA_COUNT 6 + +static unsigned int isa_dma_port[8][7] = { + /* MASK MODE CLRFF PAGE_HI PAGE_LO ADDR COUNT */ + { 0x0a, 0x0b, 0x0c, 0x487, 0x087, 0x00, 0x01 }, + { 0x0a, 0x0b, 0x0c, 0x483, 0x083, 0x02, 0x03 }, + { 0x0a, 0x0b, 0x0c, 0x481, 0x081, 0x04, 0x05 }, + { 0x0a, 0x0b, 0x0c, 0x482, 0x082, 0x06, 0x07 }, + { 0xd4, 0xd6, 0xd8, 0x000, 0x000, 0xc0, 0xc2 }, + { 0xd4, 0xd6, 0xd8, 0x48b, 0x08b, 0xc4, 0xc6 }, + { 0xd4, 0xd6, 0xd8, 0x489, 0x089, 0xc8, 0xca }, + { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce } +}; + +int isa_request_dma(int channel, dma_t *dma, const char *dev_name) +{ + if (channel != 4) + return 0; + + return -EINVAL; +} + +void isa_free_dma(int channel, dma_t *dma) +{ + /* nothing to do */ +} + +int isa_get_dma_residue(int channel, dma_t *dma) +{ + unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; + int count; + + count = 1 + inb(io_port) + (inb(io_port) << 8); + + return channel < 4 ? count : (count << 1); +} + +void isa_enable_dma(int channel, dma_t *dma) +{ + unsigned long address, length; + + if (dma->invalid) { + address = dma->buf.address; + length = dma->buf.length - 1; + + outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); + outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); + + if (channel >= 4) { + address >>= 1; + length = (length >> 1) & 0xfe; /* why &0xfe? */ + } + + outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); + + outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); + outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); + + outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); + outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); + + outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]); + + switch (dma->dma_mode) { + case DMA_MODE_READ: + dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length); + break; + + case DMA_MODE_WRITE: + dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length); + break; + } + dma->invalid = 0; + } + outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); +} + +void isa_disable_dma(int channel, dma_t *dma) +{ + outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); +} diff --git a/arch/arm/kernel/dma-isa.h b/arch/arm/kernel/dma-isa.h new file mode 100644 index 000000000..3fcbdb3c7 --- /dev/null +++ b/arch/arm/kernel/dma-isa.h @@ -0,0 +1,25 @@ +/* + * Request an ISA DMA channel + */ +int isa_request_dma(int channel, dma_t *dma, const char *dev_name); + +/* + * Free an ISA DMA channel + */ +void isa_free_dma(int channel, dma_t *dma); + +/* + * Get ISA DMA channel residue + */ +int isa_get_dma_residue(int channel, dma_t *dma); + +/* + * Enable (and set up) an ISA DMA channel + */ +void isa_enable_dma(int channel, dma_t *dma); + +/* + * Disable an ISA DMA channel + */ +void isa_disable_dma(int channel, dma_t *dma); + diff --git a/arch/arm/kernel/dma-vnc.c b/arch/arm/kernel/dma-vnc.c new file mode 100644 index 000000000..132fa627a --- /dev/null +++ b/arch/arm/kernel/dma-vnc.c @@ -0,0 +1,51 @@ +/* + * arch/arm/kernel/dma-vnc.c + * + * Copyright (C) 1998 Russell King + */ +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/mman.h> +#include <linux/init.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/hardware.h> + +#include "dma.h" +#include "dma-isa.h" + +int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) +{ + if (channel < 8) + return isa_request_dma(channel, dma, dev_name); + return -EINVAL; +} + +void arch_free_dma(dmach_t channel, dma_t *dma) +{ + isa_free_dma(channel, dma); +} + +int arch_get_dma_residue(dmach_t channel, dma_t *dma) +{ + return isa_get_dma_residue(channel, dma); +} + +void arch_enable_dma(dmach_t channel, dma_t *dma) +{ + isa_enable_dma(channel, dma); +} + +void arch_disable_dma(dmach_t channel, dma_t *dma) +{ + isa_disable_dma(channel, dma); +} + +__initfunc(void arch_dma_init(dma_t *dma)) +{ + /* Nothing to do */ +} + diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 592cc979c..a164073ae 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -26,6 +26,26 @@ #include <asm/hardware.h> #include <asm/io.h> #include <asm/dma.h> +#include <asm/spinlock.h> + + +/* A note on resource allocation: + * + * All drivers needing DMA channels, should allocate and release them + * through the public routines `request_dma()' and `free_dma()'. + * + * In order to avoid problems, all processes should allocate resources in + * the same sequence and release them in the reverse order. + * + * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA. + * When releasing them, first release the DMA, then release the IRQ. + * If you don't, you may cause allocation requests to fail unnecessarily. + * This doesn't really matter now, but it will once we get real semaphores + * in the kernel. + */ + + +spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; #include "dma.h" diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index f7d204787..fe1c75f5c 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -3,7 +3,7 @@ * * Find all installed expansion cards, and handle interrupts from them. * - * Copyright 1995,1996,1997 Russell King + * Copyright 1995-1998 Russell King * * Created from information from Acorns RiscOS3 PRMs * @@ -14,6 +14,7 @@ * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from * Linux. (Caused cards not to respond under RiscOS without hard reset). * 15-Feb-1998 RMK Added DMA support + * 12-Sep-1998 RMK Added EASI support */ #define ECARD_C @@ -79,7 +80,7 @@ static signed char irqno_to_expcard[16]; static unsigned int ecard_numcards, ecard_numirqcards; static unsigned int have_expmask; -static void ecard_def_irq_enable (ecard_t *ec, int irqnr) +static void ecard_def_irq_enable(ecard_t *ec, int irqnr) { #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { @@ -89,7 +90,7 @@ static void ecard_def_irq_enable (ecard_t *ec, int irqnr) #endif } -static void ecard_def_irq_disable (ecard_t *ec, int irqnr) +static void ecard_def_irq_disable(ecard_t *ec, int irqnr) { #ifdef HAS_EXPMASK if (irqnr < 4 && have_expmask) { @@ -99,14 +100,14 @@ static void ecard_def_irq_disable (ecard_t *ec, int irqnr) #endif } -static void ecard_def_fiq_enable (ecard_t *ec, int fiqnr) +static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) { - panic ("ecard_def_fiq_enable called - impossible"); + panic("ecard_def_fiq_enable called - impossible"); } -static void ecard_def_fiq_disable (ecard_t *ec, int fiqnr) +static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) { - panic ("ecard_def_fiq_disable called - impossible"); + panic("ecard_def_fiq_disable called - impossible"); } static expansioncard_ops_t ecard_default_ops = { @@ -122,7 +123,7 @@ static expansioncard_ops_t ecard_default_ops = { * * They are not meant to be called directly, but via enable/disable_irq. */ -void ecard_enableirq (unsigned int irqnr) +void ecard_enableirq(unsigned int irqnr) { irqnr &= 7; if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { @@ -132,14 +133,14 @@ void ecard_enableirq (unsigned int irqnr) ec->ops = &ecard_default_ops; if (ec->claimed && ec->ops->irqenable) - ec->ops->irqenable (ec, irqnr); + ec->ops->irqenable(ec, irqnr); else - printk (KERN_ERR "ecard: rejecting request to " + printk(KERN_ERR "ecard: rejecting request to " "enable IRQs for %d\n", irqnr); } } -void ecard_disableirq (unsigned int irqnr) +void ecard_disableirq(unsigned int irqnr) { irqnr &= 7; if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { @@ -149,11 +150,11 @@ void ecard_disableirq (unsigned int irqnr) ec->ops = &ecard_default_ops; if (ec->ops && ec->ops->irqdisable) - ec->ops->irqdisable (ec, irqnr); + ec->ops->irqdisable(ec, irqnr); } } -void ecard_enablefiq (unsigned int fiqnr) +void ecard_enablefiq(unsigned int fiqnr) { fiqnr &= 7; if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { @@ -163,14 +164,14 @@ void ecard_enablefiq (unsigned int fiqnr) ec->ops = &ecard_default_ops; if (ec->claimed && ec->ops->fiqenable) - ec->ops->fiqenable (ec, fiqnr); + ec->ops->fiqenable(ec, fiqnr); else - printk (KERN_ERR "ecard: rejecting request to " + printk(KERN_ERR "ecard: rejecting request to " "enable FIQs for %d\n", fiqnr); } } -void ecard_disablefiq (unsigned int fiqnr) +void ecard_disablefiq(unsigned int fiqnr) { fiqnr &= 7; if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { @@ -180,7 +181,7 @@ void ecard_disablefiq (unsigned int fiqnr) ec->ops = &ecard_default_ops; if (ec->ops->fiqdisable) - ec->ops->fiqdisable (ec, fiqnr); + ec->ops->fiqdisable(ec, fiqnr); } } @@ -198,8 +199,27 @@ static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) } } cli(); - if (called == 0) - printk (KERN_WARNING "Wild interrupt from backplane?\n"); + if (called == 0) { + static int last, lockup; + + if (last == jiffies) { + lockup += 1; + if (lockup > 1000000) { + printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n"); + disable_irq(intr_no); + printk("Expansion card IRQ state:\n"); + for (i = 0; i < num_cards; i++) + printk(" %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32, + expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr); + } + } else + lockup = 0; + + if (!last || time_after(jiffies, last + 5*HZ)) { + last = jiffies; + printk(KERN_ERR "\nUnrecognised interrupt from backplane\n"); + } + } } #ifdef HAS_EXPMASK @@ -214,7 +234,7 @@ static unsigned char first_set[] = 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 }; -static void ecard_irq_expmask (int intr_no, void *dev_id, struct pt_regs *regs) +static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) { const unsigned int statusmask = 15; unsigned int status; @@ -239,22 +259,22 @@ again: */ oldexpmask = have_expmask; EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]); - sti (); - do_ecard_IRQ (ec->irq, regs); - cli (); + sti(); + do_ecard_IRQ(ec->irq, regs); + cli(); EXPMASK_ENABLE = have_expmask = oldexpmask; status = EXPMASK_STATUS & statusmask; if (status) goto again; } else { - printk (KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno); + printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno); EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno)); } } else - printk (KERN_WARNING "Wild interrupt from backplane (masks)\n"); + printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -static int ecard_checkirqhw (void) +static int ecard_checkirqhw(void) { int found; @@ -267,7 +287,7 @@ static int ecard_checkirqhw (void) } #endif -static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int useld) +static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) { extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader); unsigned char *a = (unsigned char *)addr; @@ -287,7 +307,7 @@ static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int usel * If we require a low address or address 0, then reset, and start again... */ if (!off || lowaddress > laddr) { - outb (0, ec->podaddr); + outb(0, ec->podaddr); lowaddress = 0; } while (lowaddress <= laddr) { @@ -314,15 +334,136 @@ static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int usel } } +static int ecard_prints(char *buffer, ecard_t *ec) +{ + char *start = buffer; + + buffer += sprintf(buffer, "\n %d: ", ec->slot_no); + + if (ec->cid.id == 0) { + struct in_chunk_dir incd; + + buffer += sprintf(buffer, "[%04X:%04X] ", + ec->cid.manufacturer, ec->cid.product); + + if (!ec->card_desc && ec->cid.is && ec->cid.cd && + ecard_readchunk(&incd, ec, 0xf5, 0)) + ec->card_desc = incd.d.string; + + if (!ec->card_desc) + ec->card_desc = "*unknown*"; + + buffer += sprintf(buffer, "%s", ec->card_desc); + } else + buffer += sprintf(buffer, "Simple card %d", ec->cid.id); + + return buffer - start; +} + +static inline unsigned short ecard_getu16(unsigned char *v) +{ + return v[0] | v[1] << 8; +} + +static inline signed long ecard_gets24(unsigned char *v) +{ + return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); +} + +/* + * Probe for an expansion card. + * + * If bit 1 of the first byte of the card is set, then the + * card does not exist. + */ +__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type)) +{ + ecard_t *ec = expcard + freeslot; + struct ex_ecid cid; + char buffer[200]; + int i; + + irqno_to_expcard[card] = -1; + + ec->slot_no = card; + ec->irq = NO_IRQ; + ec->fiq = NO_IRQ; + ec->dma = NO_DMA; + ec->card_desc = NULL; + ec->ops = &ecard_default_ops; + + if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) + return 0; + + cid.r_zero = 1; + ecard_readbytes(&cid, ec, 0, 16, 0); + if (cid.r_zero) + return 0; + + irqno_to_expcard[card] = freeslot; + + ec->type = type; + ec->cid.id = cid.r_id; + ec->cid.cd = cid.r_cd; + ec->cid.is = cid.r_is; + ec->cid.w = cid.r_w; + ec->cid.manufacturer = ecard_getu16(cid.r_manu); + ec->cid.product = ecard_getu16(cid.r_prod); + ec->cid.country = cid.r_country; + ec->cid.irqmask = cid.r_irqmask; + ec->cid.irqoff = ecard_gets24(cid.r_irqoff); + ec->cid.fiqmask = cid.r_fiqmask; + ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); + ec->fiqaddr = + ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr); + + if (ec->cid.cd && ec->cid.is) { + ec->irqmask = ec->cid.irqmask; + ec->irqaddr += ec->cid.irqoff; + ec->fiqmask = ec->cid.fiqmask; + ec->fiqaddr += ec->cid.fiqoff; + } else { + ec->irqmask = 1; + ec->fiqmask = 4; + } + + for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) + if (blacklist[i].manufacturer == ec->cid.manufacturer && + blacklist[i].product == ec->cid.product) { + ec->loader = blacklist[i].loader; + ec->card_desc = blacklist[i].type; + break; + } + + ecard_prints(buffer, ec); + printk("%s", buffer); + + ec->irq = 32 + card; +#ifdef IO_EC_MEMC8_BASE + if (card == 8) + ec->irq = 11; +#endif +#ifdef CONFIG_ARCH_RPC + /* On RiscPC, only first two slots have DMA capability */ + if (card < 2) + ec->dma = 2 + card; +#endif +#if 0 /* We don't support FIQs on expansion cards at the moment */ + ec->fiq = 96 + card; +#endif + + return 1; +} + /* * This is called to reset the loaders for each expansion card on reboot. * * This is required to make sure that the card is in the correct state * that RiscOS expects it to be. */ -void ecard_reset (int card) +void ecard_reset(int card) { - extern int ecard_loader_reset (volatile unsigned int pa, loader_t loader); + extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader); if (card >= ecard_numcards) return; @@ -330,11 +471,11 @@ void ecard_reset (int card) if (card < 0) { for (card = 0; card < ecard_numcards; card++) if (expcard[card].loader) - ecard_loader_reset (BUS_ADDR(expcard[card].podaddr), + ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), expcard[card].loader); } else if (expcard[card].loader) - ecard_loader_reset (BUS_ADDR(expcard[card].podaddr), + ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), expcard[card].loader); #ifdef HAS_EXPMASK @@ -347,18 +488,19 @@ void ecard_reset (int card) static unsigned int ecard_startcard; -void ecard_startfind (void) +void ecard_startfind(void) { ecard_startcard = 0; } -ecard_t *ecard_find (int cld, const card_ids *cids) +ecard_t *ecard_find(int cid, const card_ids *cids) { int card; + if (!cids) { for (card = ecard_startcard; card < ecard_numcards; card++) if (!expcard[card].claimed && - ((expcard[card].cld.ecld ^ cld) & 0x78) == 0) + (expcard[card].cid.id ^ cid) == 0) break; } else { for (card = ecard_startcard; card < ecard_numcards; card++) { @@ -368,8 +510,8 @@ ecard_t *ecard_find (int cld, const card_ids *cids) if (expcard[card].claimed) continue; - manufacturer = expcard[card].cld.manufacturer; - product = expcard[card].cld.product; + manufacturer = expcard[card].cid.manufacturer; + product = expcard[card].cid.product; for (i = 0; cids[i].manufacturer != 65535; i++) if (manufacturer == cids[i].manufacturer && @@ -380,16 +522,21 @@ ecard_t *ecard_find (int cld, const card_ids *cids) break; } } + ecard_startcard = card + 1; + return card < ecard_numcards ? &expcard[card] : NULL; } -int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) { struct ex_chunk_dir excd; int index = 16; int useld = 0; + if (!ec->cid.is || !ec->cid.cd) + return 0; + while(1) { ecard_readbytes(&excd, ec, index, 8, useld); index += 8; @@ -427,124 +574,49 @@ int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num) } } cd->start_offset = c_start(&excd); - memcpy (cd->d.string, excd.d.string, 256); + memcpy(cd->d.string, excd.d.string, 256); return 1; } -unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed) +unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { switch (ec->slot_no) { case 0 ... 3: switch (type) { case ECARD_MEMC: - return MEMCECIO_BASE + (ec->slot_no << 12); + return IO_EC_MEMC_BASE + (ec->slot_no << 12); case ECARD_IOC: - return IOCECIO_BASE + (speed << 17) + (ec->slot_no << 12); + return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12); - default: - return 0; +#ifdef IO_EC_EASI_BASE + case ECARD_EASI: + return IO_EC_EASI_BASE + (ec->slot_no << 22); +#endif } + break; -#ifdef IOCEC4IO_BASE case 4 ... 7: - if (type != ECARD_IOC) - return 0; - - return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12); + switch (type) { +#ifdef IO_EC_IOC4_BASE + case ECARD_IOC: + return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12); #endif -#ifdef MEMCEC8IO_BASE - case 8: - return MEMCEC8IO_BASE; +#ifdef IO_EC_EASI_BASE + case ECARD_EASI: + return IO_EC_EASI_BASE + (ec->slot_no << 22); #endif - } - return 0; -} - -/* - * Probe for an expansion card. - * - * If bit 1 of the first byte of the card is set, - * then the card does not exist. - */ -__initfunc(static int ecard_probe (int card, int freeslot)) -{ - ecard_t *ec = expcard + freeslot; - struct ex_ecld excld; - const char *card_desc = NULL; - int i; - - irqno_to_expcard[card] = -1; - - ec->slot_no = card; - if ((ec->podaddr = ecard_address (ec, ECARD_IOC, ECARD_SYNC)) == 0) - return 0; - - excld.r_ecld = 2; - ecard_readbytes (&excld, ec, 0, 16, 0); - if (excld.r_ecld & 2) - return 0; - - irqno_to_expcard[card] = freeslot; - - ec->irq = NO_IRQ; - ec->fiq = NO_IRQ; - ec->dma = NO_DMA; - ec->cld.ecld = e_ecld(&excld); - ec->cld.manufacturer = e_manu(&excld); - ec->cld.product = e_prod(&excld); - ec->cld.country = e_country(&excld); - ec->cld.fiqmask = e_fiqmask(&excld); - ec->cld.irqmask = e_irqmask(&excld); - ec->cld.fiqaddr = e_fiqaddr(&excld); - ec->cld.irqaddr = e_irqaddr(&excld); - ec->fiqaddr = - ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr); - ec->fiqmask = 4; - ec->irqmask = 1; - ec->ops = &ecard_default_ops; - - for (i = 0; i < sizeof (blacklist) / sizeof (*blacklist); i++) - if (blacklist[i].manufacturer == ec->cld.manufacturer && - blacklist[i].product == ec->cld.product) { - ec->loader = blacklist[i].loader; - card_desc = blacklist[i].type; + default: break; } + break; - ec->irq = 32 + card; -#if 0 - /* We don't support FIQs on expansion cards at the moment */ - ec->fiq = 96 + card; -#endif -#ifdef CONFIG_ARCH_RPC - if (card != 8) { - /* On RiscPC, only first two slots have DMA capability - */ - if (card < 2) - ec->dma = 2 + card; - } else - ec->irq = 11; +#ifdef IO_EC_MEMC8_BASE + case 8: + return IO_EC_MEMC8_BASE; #endif - - if ((ec->cld.ecld & 0x78) == 0) { - struct in_chunk_dir incd; - printk ("\n %d: [%04X:%04X] ", card, ec->cld.manufacturer, ec->cld.product); - if (e_is (&excld)) { - ec->fiqmask = e_fiqmask (&excld); - ec->irqmask = e_irqmask (&excld); - ec->fiqaddr += e_fiqaddr (&excld); - ec->irqaddr += e_irqaddr (&excld); - } - if (!card_desc && e_cd (&excld) && ecard_readchunk (&incd, ec, 0xf5, 0)) - card_desc = incd.d.string; - if (card_desc) - printk ("%s", card_desc); - else - printk ("*Unknown*"); - } else - printk("\n %d: Simple card %d\n", card, (ec->cld.ecld >> 3) & 15); - return 1; + } + return 0; } static struct irqaction irqexpansioncard = { @@ -565,11 +637,11 @@ __initfunc(void ecard_init(void)) { int i, nc = 0; - memset (expcard, 0, sizeof (expcard)); + memset(expcard, 0, sizeof(expcard)); #ifdef HAS_EXPMASK if (ecard_checkirqhw()) { - printk (KERN_DEBUG "Expansion card interrupt management hardware found\n"); + printk(KERN_DEBUG "Expansion card interrupt management hardware found\n"); irqexpansioncard.handler = ecard_irq_expmask; irqexpansioncard.flags |= SA_IRQNOMASK; have_expmask = -1; @@ -581,8 +653,8 @@ __initfunc(void ecard_init(void)) /* * First of all, probe all cards on the expansion card interrupt line */ - for (i = 0; i < 4; i++) - if (ecard_probe (i, nc)) + for (i = 0; i < 8; i++) + if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI)) nc += 1; else have_expmask &= ~(1<<i); @@ -591,8 +663,8 @@ __initfunc(void ecard_init(void)) /* Now probe other cards with different interrupt lines */ -#ifdef MEMCEC8IO_BASE - if (ecard_probe (8, nc)) +#ifdef IO_EC_MEMC8_BASE + if (ecard_probe(8, nc, ECARD_IOC)) nc += 1; #endif @@ -600,7 +672,7 @@ __initfunc(void ecard_init(void)) ecard_numcards = nc; if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) { - printk ("Could not allocate interrupt for expansion cards\n"); + printk("Could not allocate interrupt for expansion cards\n"); return; } @@ -609,5 +681,5 @@ __initfunc(void ecard_init(void)) EXPMASK_ENABLE = have_expmask; #endif - oldlatch_init (); + oldlatch_init(); } diff --git a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S index 4c65fc892..3ca29cd2c 100644 --- a/arch/arm/kernel/entry-armo.S +++ b/arch/arm/kernel/entry-armo.S @@ -271,26 +271,18 @@ vector_undefinstr: mov fp, #0 teqp pc, #I_BIT | MODE_SVC .Lbug_undef: - adr r1, .LC2 - ldmia r1, {r1, r4} - ldr r1, [r1] - get_current_task r2 - teq r1, r2 - stmnefd sp!, {ip, lr} - blne SYMBOL_NAME(math_state_restore) - ldmnefd sp!, {ip, lr} + ldr r4, .LC2 ldr pc, [r4] @ Call FP module USR entry point .globl SYMBOL_NAME(fpundefinstr) SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr -SYMBOL_NAME(fpundefinstrsvc): mov r0, lr mov r1, sp teqp pc, #MODE_SVC bl SYMBOL_NAME(do_undefinstr) b ret_from_exception @ Normal FP exit -__und_svc: SVC_SAVE_ALL @ Non-user mode +__und_svc: SVC_SAVE_ALL @ Non-user mode mask_pc r0, lr and r2, lr, #3 sub r0, r0, #4 @@ -298,8 +290,44 @@ __und_svc: SVC_SAVE_ALL @ Non-user mode bl SYMBOL_NAME(do_undefinstr) SVC_RESTORE_ALL -.LC2: .word SYMBOL_NAME(last_task_used_math) - .word SYMBOL_NAME(fp_enter) +/* We get here if an undefined instruction happens and the floating + * point emulator is not present. If the offending instruction was + * a WFS, we just perform a normal return as if we had emulated the + * operation. This is a hack to allow some basic userland binaries + * to run so that the emulator module proper can be loaded. --philb + */ +fpe_not_present: + adr r10, wfs_mask_data + ldmia r10, {r4, r5, r6, r7, r8} + ldr r10, [sp, #S_PC] @ Load PC + sub r10, r10, #4 + mask_pc r10, r10 + ldrt r10, [r10] @ get instruction + and r5, r10, r5 + teq r5, r4 @ Is it WFS? + beq ret_from_exception + and r5, r10, r8 + teq r5, r6 @ Is it LDF/STF on sp or fp? + teqne r5, r7 + bne fpundefinstr + tst r10, #0x00200000 @ Does it have WB + beq ret_from_exception + and r4, r10, #255 @ get offset + and r6, r10, #0x000f0000 + tst r10, #0x00800000 @ +/- + rsbeq r4, r4, #0 + ldr r5, [sp, r6, lsr #14] @ Load reg + add r5, r5, r4, lsl #2 + str r5, [sp, r6, lsr #14] @ Save reg + b ret_from_exception + +wfs_mask_data: .word 0x0e200110 @ WFS + .word 0x0fff0fff + .word 0x0d0d0100 @ LDF [sp]/STF [sp] + .word 0x0d0b0100 @ LDF [fp]/STF [fp] + .word 0x0f0f0f00 + +.LC2: .word SYMBOL_NAME(fp_enter) /*============================================================================= * Prefetch abort handler diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7ecf1d59a..bcc938b32 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -231,60 +231,68 @@ irq_prio_ebsa110: .macro disable_fiq .endm + .equ pci_iack_high, PCI_IACK & 0xff000000 + .equ pci_iack_low, PCI_IACK & 0x00ff0000 + .macro get_irqnr_and_base, irqnr, irqstat, base mov r4, #IO_BASE_ARM_CSR - ldr \irqstat, [r4, #IRQ_STATUS] @ just show us the unmasked ones + ldr \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones @ run through hard priorities @ timer tst \irqstat, #IRQ_MASK_TIMER0 movne \irqnr, #IRQ_TIMER0 - bne 1f + bne 1001f @ ether10 tst \irqstat, #IRQ_MASK_ETHER10 movne \irqnr, #IRQ_ETHER10 - bne 1f + bne 1001f @ ether100 tst \irqstat, #IRQ_MASK_ETHER100 movne \irqnr, #IRQ_ETHER100 - bne 1f + bne 1001f @ video compressor - tst \irqstat, #IRQ_VIDCOMP_MASK + tst \irqstat, #IRQ_MASK_VIDCOMP movne \irqnr, #IRQ_VIDCOMP - bne 1f + bne 1001f @ now try all the PIC sources @ determine whether we have an irq tst \irqstat, #IRQ_MASK_EXTERN_IRQ - beq 3f - mov r4, #(IO_BASE_PCI_IACK & 0xff000000) - orr r4, r4, #(IO_BASE_PCI_IACK & 0x00ff0000) + beq 1002f + mov r4, #pci_iack_high + orr r4, r4, #pci_iack_low ldrb \irqnr, [r4] @ get the IACK byte - b 1f + b 1001f -3: @ PCI errors +1002: @ PCI errors tst \irqstat, #IRQ_MASK_PCI_ERR movne \irqnr, #IRQ_PCI_ERR - bne 1f + bne 1001f @ softint - tst \irqstat, #IRQ_MASK_SOFT_IRQ - movne \irqnr, #IRQ_SOFT_IRQ - bne 1f + tst \irqstat, #IRQ_MASK_SOFTIRQ + movne \irqnr, #IRQ_SOFTIRQ + bne 1001f @ debug uart tst \irqstat, #IRQ_MASK_UART_DEBUG - movne \irqnr, #IRQ_UART_DEBUG - bne 1f + movne \irqnr, #IRQ_CONRX + bne 1001f @ watchdog - tst \irqstat, #IRQ_WATCHDOG_MASK + tst \irqstat, #IRQ_MASK_WATCHDOG movne \irqnr, #IRQ_WATCHDOG -1: @ If Z is set, then we will not enter an interrupt +1001: @ If Z is set, then we will not enter an interrupt + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif @@ -696,8 +704,8 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go adrsvc al, lr, fpundefinstr @ lr = undefined instr return 1: get_current_task r10 - mov lr, #1 - strb lr, [r10, #TSK_USED_MATH] @ set current->used_math + mov r8, #1 + strb r8, [r10, #TSK_USED_MATH] @ set current->used_math add r10, r10, #TSS_FPESAVE @ r10 = workspace ldr r4, .LC2 ldr pc, [r4] @ Call FP module USR entry point @@ -742,6 +750,43 @@ __und_invalid: sub sp, sp, #S_FRAME_SIZE and r2, r6, #31 @ int mode b SYMBOL_NAME(bad_mode) @ Does not ever return... +/* We get here if an undefined instruction happens and the floating + * point emulator is not present. If the offending instruction was + * a WFS, we just perform a normal return as if we had emulated the + * operation. This is a hack to allow some basic userland binaries + * to run so that the emulator module proper can be loaded. --philb + */ +fpe_not_present: + adr r10, wfs_mask_data + ldmia r10, {r4, r5, r6, r7, r8} + ldr r10, [sp, #S_PC] @ Load PC + sub r10, r10, #4 + mask_pc r10, r10 + ldrt r10, [r10] @ get instruction + and r5, r10, r5 + teq r5, r4 @ Is it WFS? + moveq pc, r9 + and r5, r10, r8 + teq r5, r6 @ Is it LDF/STF on sp or fp? + teqne r5, r7 + movne pc, lr + tst r10, #0x00200000 @ Does it have WB + moveq pc, r9 + and r4, r10, #255 @ get offset + and r6, r10, #0x000f0000 + tst r10, #0x00800000 @ +/- + rsbeq r4, r4, #0 + ldr r5, [sp, r6, lsr #14] @ Load reg + add r5, r5, r4, lsl #2 + str r5, [sp, r6, lsr #14] @ Save reg + mov pc, r9 + +wfs_mask_data: .word 0x0e200110 @ WFS + .word 0x0fff0fff + .word 0x0d0d0100 @ LDF [sp]/STF [sp] + .word 0x0d0b0100 @ LDF [fp]/STF [fp] + .word 0x0f0f0f00 + #include "entry-common.S" .data diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 6e0e9e38c..c77c0ea51 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -288,4 +288,4 @@ ENTRY(trap_init) .data ENTRY(fp_enter) - .word fpundefinstr + .word fpe_not_present diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index c32fef3c8..a5da15c7f 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -106,14 +106,7 @@ void set_fiq_handler(void *start, unsigned int length) memcpy((void *)FIQ_VECTOR, start, length); protect_page_0(); -#if 0 - /* This doesn'w work correctly. Ok, it's a misuse - * of the DMA flushing code, but it ought to work. - * More investigation required. Maybe it really - * needs the cache flushed. - */ - dma_cache_wback(FIQ_VECTOR, length); -#else +#ifdef CONFIG_CPU_32 processor.u.armv3v4._flush_cache_area(FIQ_VECTOR, FIQ_VECTOR + length, 1); #endif } diff --git a/arch/arm/kernel/head-armo.S b/arch/arm/kernel/head-armo.S index 1dc4fde13..d6b2b79e6 100644 --- a/arch/arm/kernel/head-armo.S +++ b/arch/arm/kernel/head-armo.S @@ -58,6 +58,3 @@ Loldparams: mov r4, #0x02000000 cmp r4, r3 blt 1b movs pc, lr - - .align 13 -ENTRY(this_must_match_init_task) diff --git a/arch/arm/kernel/head-armv.S b/arch/arm/kernel/head-armv.S index 88e71adab..cd4be86cb 100644 --- a/arch/arm/kernel/head-armv.S +++ b/arch/arm/kernel/head-armv.S @@ -8,9 +8,23 @@ #include <linux/config.h> #include <linux/linkage.h> +#ifndef CONFIG_ARCH_VNC #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 #endif +#else + .text + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, #0 + mov r1, #5 +#endif #define DEBUG @@ -97,6 +111,15 @@ __entry: teq r0, #0 @ check for illegal entry... add r3, r3, #1 << 20 teq r0, r2 bne 1b +#ifdef CONFIG_ARCH_VNC + add r0, r4, #0x3f00 + add r0, r0, #0x00f8 + mov r3, #0x7c000000 + orr r3, r3, r8 + str r3, [r0], #4 + add r3, r3, #1 << 20 + str r3, [r0], #4 +#endif #endif #ifdef CONFIG_ARCH_RPC /* Map in screen at 0x02000000 & SCREEN2_BASE @@ -339,7 +362,7 @@ __entry: teq r0, #0 @ check for illegal entry... beq 1001b .endm -#elif defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_VNC) +#elif defined(CONFIG_ARCH_EBSA285) .macro addruart,rx mov \rx, #0xfe000000 .endm @@ -374,6 +397,30 @@ __entry: teq r0, #0 @ check for illegal entry... .macro waituart,rd,rx .endm + +#elif defined(CONFIG_ARCH_VNC) + .macro addruart,rx + mov \rx, #0xff000000 + orr \rx, \rx, #0x00e00000 + orr \rx, \rx, #0x000003f8 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b + .endm #else #error Unknown architecture #endif diff --git a/arch/arm/kernel/hw-ebsa285.c b/arch/arm/kernel/hw-ebsa285.c new file mode 100644 index 000000000..e3385696b --- /dev/null +++ b/arch/arm/kernel/hw-ebsa285.c @@ -0,0 +1,161 @@ +/* + * arch/arm/kernel/hw-ebsa286.c + * + * EBSA285 hardware specific functions + * + * Copyright (C) 1998 Russell King, Phil Blundel + */ +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/ptrace.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/system.h> + +extern int setup_arm_irq(int, struct irqaction *); + +extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set); +extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr); +extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq); + +static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 }; +static int irqmap_cats[] __initdata = { 18, 8, 9, 11 }; + +__initfunc(static int ebsa_irqval(struct pci_dev *dev)) +{ + unsigned char pin; + + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_PIN, + &pin); + + return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; +} + +__initfunc(static int cats_irqval(struct pci_dev *dev)) +{ + if (dev->irq >= 128) + return 32 + (dev->irq & 0x1f); + + switch (dev->irq) { + case 1: + case 2: + case 3: + case 4: + return irqmap_cats[dev->irq - 1]; + case 0: + return 0; + } + + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + return 0; +} + +__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) +{ + char cmd; + + /* sort out the irq mapping for this device */ + switch (machine_type) { + case MACH_TYPE_EBSA285: + dev->irq = ebsa_irqval(dev); + break; + case MACH_TYPE_CATS: + dev->irq = cats_irqval(dev); + break; + } + + /* Turn on bus mastering - boot loader doesn't + * - perhaps it should! - dag + */ + pci_read_config_byte(dev, PCI_COMMAND, &cmd); + pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); +} + +static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) +{ + const char *err = "unknown"; + unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff; + unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07; + static unsigned long next_warn[7]; + int idx = 6; + + switch(irq) { + case IRQ_PCIPARITY: + *(unsigned long *)0xfe000004 = cmd | 1 << 31; + idx = 0; + err = "parity"; + break; + + case IRQ_PCITARGETABORT: + *(unsigned long *)0xfe000004 = cmd | 1 << 28; + idx = 1; + err = "target abort"; + break; + + case IRQ_PCIMASTERABORT: + *(unsigned long *)0xfe000004 = cmd | 1 << 29; + idx = 2; + err = "master abort"; + break; + + case IRQ_PCIDATAPARITY: + *(unsigned long *)0xfe000004 = cmd | 1 << 24; + idx = 3; + err = "data parity"; + break; + + case IRQ_DISCARDTIMER: + *(unsigned long *)0xfe00013c = ctrl | 1 << 8; + idx = 4; + err = "discard timer"; + break; + + case IRQ_SERR: + *(unsigned long *)0xfe00013c = ctrl | 1 << 3; + idx = 5; + err = "system"; + break; + } + if (time_after_eq(jiffies, next_warn[idx])) { + next_warn[idx] = jiffies + 3 * HZ / 100; + printk(KERN_ERR "PCI %s error detected\n", err); + } +} + +static struct irqaction irq_pci_error = { + irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL +}; + +__initfunc(void pcibios_init_ebsa285(void)) +{ + setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error); + setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error); + setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error); + setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error); + setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error); + setup_arm_irq(IRQ_SERR, &irq_pci_error); + + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is slightly + * bizarre but apparently necessary to avoid problems with some + * video cards. + * + * We should really only do this if the central function is enabled. + */ + *(unsigned long *)0xfe000010 = 0; + *(unsigned long *)0xfe000018 = 0xe0000000; + *(unsigned long *)0xfe0000f8 = 0; + *(unsigned long *)0xfe0000fc = 0; + *(unsigned long *)0xfe000100 = 0x01fc0000; + *(unsigned long *)0xfe000104 = 0; + *(unsigned long *)0xfe000108 = 0x80000000; + *(unsigned long *)0xfe000004 = 0x17; +} diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c index 689c43589..99577f1b7 100644 --- a/arch/arm/kernel/init_task.c +++ b/arch/arm/kernel/init_task.c @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index b4950ace2..332e8940d 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -119,7 +119,9 @@ int get_irq_list(char *buf) *p++ = '\n'; } +#ifdef CONFIG_ACORN p += get_fiq_list(p); +#endif return p - buf; } @@ -354,7 +356,7 @@ unsigned long probe_irq_on(void) /* * wait for spurious interrupts to mask themselves out again */ - for (delay = jiffies + HZ/10; delay > jiffies; ) + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) /* min 100ms delay */; /* @@ -424,6 +426,8 @@ __initfunc(void init_IRQ(void)) } irq_init_irq(); +#ifdef CONFIG_ARCH_ACORN init_FIQ(); +#endif init_dma(); } diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 767faff9e..cddc3fab3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -57,13 +57,15 @@ #endif #ifndef CONFIG_CMDLINE -#define CONFIG_CMDLINE "root=nfs rw console=ttyS1,38400n8" +#define CONFIG_CMDLINE "root=/dev/nfs rw" #endif #define MEM_SIZE (16*1024*1024) #define COMMAND_LINE_SIZE 256 struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info = { + orig_video_lines: 30, + orig_video_cols: 80, orig_video_mode: 0, orig_video_ega_bx: 0, orig_video_isVGA: 1, @@ -210,6 +212,8 @@ setup_params(unsigned long *mem_end_p)) #ifdef CONFIG_ARCH_ACORN *mem_end_p = GET_MEMORY_END(params); +#elif defined(CONFIG_ARCH_EBSA285) + *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages; #else *mem_end_p = PAGE_OFFSET + MEM_SIZE; #endif @@ -305,18 +309,18 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; __initfunc(static void setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end)) { - char c = ' ', *to = command_line; + char c, *to = command_line; int len = 0; *mem_start = (unsigned long)&_end; for (;;) { - if (c == ' ' && - cmd_line[0] == 'm' && - cmd_line[1] == 'e' && - cmd_line[2] == 'm' && - cmd_line[3] == '=') { - *mem_end = simple_strtoul(cmd_line+4, &cmd_line, 0); + if (cmd_line[0] == ' ' && + cmd_line[1] == 'm' && + cmd_line[2] == 'e' && + cmd_line[3] == 'm' && + cmd_line[4] == '=') { + *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0); switch(*cmd_line) { case 'M': case 'm': @@ -336,7 +340,7 @@ setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end)) *to++ = c; } - *to = '\0'; + *to = '\0'; } __initfunc(void @@ -381,33 +385,27 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem conswitchp = &dummy_con; #endif #endif -printascii("setup_arch done\n"); } +static const struct { + char *machine_name; + char *bus_name; +} machine_desc[] = { + { "DEC-EBSA110", "DEC" }, + { "Acorn-RiscPC", "Acorn" }, + { "Nexus-NexusPCI", "PCI" }, + { "DEC-EBSA285", "PCI" }, + { "Corel-Netwinder", "PCI/ISA" }, + { "Chalice-CATS", "PCI" }, + { "unknown-TBOX", "PCI" } +}; + #if defined(CONFIG_ARCH_ARC) #define HARDWARE "Acorn-Archimedes" #define IO_BUS "Acorn" #elif defined(CONFIG_ARCH_A5K) #define HARDWARE "Acorn-A5000" #define IO_BUS "Acorn" -#elif defined(CONFIG_ARCH_RPC) -#define HARDWARE "Acorn-RiscPC" -#define IO_BUS "Acorn" -#elif defined(CONFIG_ARCH_EBSA110) -#define HARDWARE "DEC-EBSA110" -#define IO_BUS "DEC" -#elif defined(CONFIG_ARCH_EBSA285) -#define HARDWARE "DEC-EBSA285" -#define IO_BUS "PCI" -#elif defined(CONFIG_ARCH_NEXUSPCI) -#define HARDWARE "Nexus-NexusPCI" -#define IO_BUS "PCI" -#elif defined(CONFIG_ARCH_VNC) -#define HARDWARE "Corel-VNC" -#define IO_BUS "PCI" -#else -#define HARDWARE "unknown" -#define IO_BUS "unknown" #endif #if defined(CONFIG_CPU_ARM2) @@ -439,8 +437,17 @@ int get_cpuinfo(char * buffer) (int)processor_id & 15, (loops_per_sec+2500) / 500000, ((loops_per_sec+2500) / 5000) % 100, +#ifdef HARDWARE HARDWARE, +#else + machine_desc[machine_type].machine_name, +#endif OPTIMISATION, - IO_BUS); +#ifdef IO_BUS + IO_BUS +#else + machine_desc[machine_type].bus_name +#endif + ); return len; } diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 56ada1dc7..5996398f8 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -77,7 +77,8 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) goto out; if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; - if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) + if (a.fd >= current->files->max_fds || + !(file = current->files->fd[a.fd])) goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 7445921d9..22c3639da 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -9,7 +9,7 @@ * * 1994-07-02 Alan Modra * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include <linux/errno.h> @@ -125,9 +125,11 @@ void do_settimeofday(struct timeval *tv) } xtime = *tv; - time_state = TIME_BAD; - time_maxerror = MAXPHASE; - time_esterror = MAXPHASE; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_state = TIME_ERROR; /* p. 24, (a) */ + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; sti (); } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6da813aa2..5d04f325b 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -51,7 +51,7 @@ static int verify_stack_pointer (unsigned long stackptr, int size) if (stackptr < 0x02048000 || stackptr + size > 0x03000000) return -EFAULT; #else - if (stackptr < 0xc0000000 || stackptr + size > (unsigned long)high_memory) + if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory) return -EFAULT; #endif return 0; @@ -175,7 +175,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret) printk("(sp underflow)"); printk("\n"); - dump_mem(cstack, sstack + 4096); + dump_mem(cstack - 16, sstack + 4096); frameptr = regs->ARM_fp; if (frameptr) { diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index d47a092cb..684db2a47 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -26,6 +26,10 @@ ifeq ($(MACHINE),ebsa110) L_OBJS += io-ebsa110.o endif +ifeq ($(MACHINE),vnc) + L_OBJS += io-ebsa285.o +endif + ifeq ($(MACHINE),ebsa285) L_OBJS += io-ebsa285.o endif diff --git a/arch/arm/lib/io-ebsa285.S b/arch/arm/lib/io-ebsa285.S index 0ee1e37fc..a86983d43 100644 --- a/arch/arm/lib/io-ebsa285.S +++ b/arch/arm/lib/io-ebsa285.S @@ -104,24 +104,75 @@ ENTRY(outswb) ENTRY(outsw) add r0, r0, #0xff000000 add r0, r0, #0x00e00000 -1: teq r2, #0 - ldrneh r3, [r1], #2 - strneh r3, [r0] - subne r2, r2, #1 - bne 1b +1: subs r2, r2, #1 + ldrgeh r3, [r1], #2 + strgeh r3, [r0] + bgt 1b mov pc, lr ENTRY(inswb) mov r2, r2, lsr #1 ENTRY(insw) + stmfd sp!, {r4, r5, lr} add r0, r0, #0xff000000 add r0, r0, #0x00e00000 -1: teq r2, #0 + @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 + subs ip, r2, #8 + blo too_little + @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + ands lr, r1, #3 @ check alignment + beq 1f + + ldrh r3, [r0] + strh r3, [r1], #2 + sub ip, ip, #1 + cmn ip, #8 + blo too_little + +1: ldrh r2, [r0] + ldrh r3, [r0] + orr r2, r2, r3, lsl #16 + ldrh r3, [r0] + ldrh r4, [r0] + orr r3, r3, r4, lsl #16 + ldrh r4, [r0] + ldrh r5, [r0] + orr r4, r4, r5, lsl #16 + ldrh r5, [r0] + ldrh lr, [r0] + orr r5, r5, lr, lsl #16 + stmia r1!, {r2, r3, r4, r5} + subs ip, ip, #8 + @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1 + bhs 1b + @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7 + cmn ip, #4 + ldrhsh r2, [r0] @ ... ... ... ... - 4 - 3 - 2 - 1 ... ... + ldrhsh r3, [r0] + orrhs r2, r2, r3, lsl #16 + ldrhsh r3, [r0] + ldrhsh r4, [r0] + orrhs r3, r3, r4, lsl #16 + stmhsia r1!, {r2, r3} + + tst ip, #2 + ldrneh r2, [r0] @ ... ... - 6 - 5 ... ... - 2 - 1 ... ... ldrneh r3, [r0] - strneh r3, [r1], #2 - subne r2, r2, #1 - bne 1b - mov pc, lr + orrne r2, r2, r3, lsl #16 + strne r2, [r1], #4 + + tst ip, #1 + ldrneh r2, [r0] + strneh r2, [r1], #2 + + ldmfd sp!, {r4, r5, pc} + +too_little: subs r2, r2, #1 + ldrgeh r3, [r0] + strgeh r3, [r1], #2 + bgt too_little + + ldmfd sp!, {r4, r5, pc} ENTRY(insb) diff --git a/arch/arm/mm/fault-armo.c b/arch/arm/mm/fault-armo.c index 4e244a297..6fe1f30ff 100644 --- a/arch/arm/mm/fault-armo.c +++ b/arch/arm/mm/fault-armo.c @@ -174,7 +174,7 @@ bad_area: } /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->ARM_pc)) != 0) { + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", tsk->comm, regs->ARM_pc, addr, fixup); regs->ARM_pc = fixup; diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 98134abac..f090c5f2c 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -208,7 +208,7 @@ bad_area: } /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->ARM_pc)) != 0) { + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", tsk->comm, regs->ARM_pc, addr, fixup); regs->ARM_pc = fixup; diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 613fefce1..b3b0ecf56 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -192,6 +192,15 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); + +#ifdef CONFIG_CPU_26 + if (max_mapnr <= 128) { + extern int sysctl_overcommit_memory; + /* On a machine this small we won't get anywhere without + overcommit, so turn it on by default. */ + sysctl_overcommit_memory = 1; + } +#endif } void free_initmem (void) diff --git a/arch/arm/mm/mm-ebsa285.c b/arch/arm/mm/mm-ebsa285.c index 82bbce899..a5b17c6b9 100644 --- a/arch/arm/mm/mm-ebsa285.c +++ b/arch/arm/mm/mm-ebsa285.c @@ -5,7 +5,6 @@ * * Copyright (C) 1998 Russell King, Dave Gilbert. */ -#include <linux/config.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/init.h> @@ -14,46 +13,7 @@ #include <asm/page.h> #include <asm/io.h> #include <asm/proc/mm-init.h> - -/* - * These two functions convert PCI bus addresses to virtual addresses - * and back again. - */ -unsigned long __virt_to_bus(unsigned long res) -{ - if (res < PAGE_OFFSET || res >= 0xD0000000) { - printk("__virt_to_bus: invalid address 0x%08lx\n", res); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - } else - res = (res - PAGE_OFFSET) + 0x10000000; - - return res; -} - -unsigned long __bus_to_virt(unsigned long res) -{ - if (res < 0x10000000 || res >= 0x20000000) { - printk("__bus_to_virt: invalid address 0x%08lx\n", res); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - } else - res = (res - 0x10000000) + PAGE_OFFSET; - - return res; -} - -/* Logical Physical - * 0xfff00000 0x40000000 X-Bus - * 0xffe00000 0x7c000000 PCI I/O space - * 0xfe000000 0x42000000 CSR - * 0xfd000000 0x78000000 Outbound write flush - * 0xfc000000 0x79000000 PCI IACK/special space - * 0xf9000000 0x7a000000 PCI Config type 1 - * 0xf8000000 0x7b000000 PCI Config type 0 - */ +#include <asm/dec21285.h> /* * This is to allow us to fiddle with the EEPROM @@ -65,15 +25,15 @@ unsigned long __bus_to_virt(unsigned long res) * until we're happy with them... */ #define MAPPING \ - { 0xd8000000, 0x41000000, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \ - { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \ - { 0xe0000000, 0x80000000, 0x10000000, DOMAIN_USER, 1, 1 }, /* VGA */ \ - { 0xf8000000, 0x7b000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ - { 0xf9000000, 0x7a000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ - { 0xfc000000, 0x79000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ - { 0xfd000000, 0x78000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Outbound wflsh*/ \ - { 0xfe000000, 0x42000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ - { 0xffe00000, 0x7c000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ - { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */ + { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \ + { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \ + { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \ + { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ + { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ + { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ + { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ + { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ + { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ + { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */ #include "mm-armv.c" diff --git a/arch/arm/mm/mm-rpc.c b/arch/arm/mm/mm-rpc.c index 18ebe4a47..1c755faaf 100644 --- a/arch/arm/mm/mm-rpc.c +++ b/arch/arm/mm/mm-rpc.c @@ -91,7 +91,8 @@ init_dram_banks(struct param_struct *params)) #define MAPPING \ { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1 }, /* VRAM */ \ - { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 } /* IO space */ + { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ \ + { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1 } /* EASI space */ /* * Include common routine to set up page tables */ diff --git a/arch/arm/mm/mm-vnc.c b/arch/arm/mm/mm-vnc.c index eed49eb29..94e037485 100644 --- a/arch/arm/mm/mm-vnc.c +++ b/arch/arm/mm/mm-vnc.c @@ -13,20 +13,19 @@ #include <asm/page.h> #include <asm/io.h> #include <asm/proc/mm-init.h> +#include <asm/dec21285.h> /* Table describing the MMU translation mapping * mainly used to set up the I/O mappings. */ #define MAPPING \ - { 0xe0000000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO, 0, 1 }, /* PCI I/O */ \ - { 0xe0100000, DC21285_PCI_TYPE_0_CONFIG, 0x00f00000, DOMAIN_IO, 0, 1 }, /* Type 0 Config */ \ - { 0xe1000000, DC21285_ARMCSR_BASE, 0x00100000, DOMAIN_IO, 0, 1 }, /* ARM CSR */ \ - { 0xe1100000, DC21285_PCI_IACK, 0x00100000, DOMAIN_IO, 0, 1 }, /* PCI IACK */ \ - { 0xe1300000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \ - { 0xe1400000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \ - { 0xe1500000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \ - { 0xe1600000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \ - { 0xe1700000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \ - { 0xe1800000, DC21285_FLASH, 0x00800000, DOMAIN_IO, 0, 1 } /* Flash */ + { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \ + { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \ + { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ + { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ + { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ + { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ + { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ + { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ #include "mm-armv.c" diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index d077ab1d2..221797862 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -10,6 +10,11 @@ #include <asm/assembler.h> #include "../lib/constants.h" +/* This is the maximum size of an area which will be flushed. If the area + * is larger than this, then we flush the whole cache + */ +#define MAX_AREA_SIZE 32768 + .data Lclean_switch: .long 0 .text @@ -52,7 +57,7 @@ _sa110_flush_cache_all_r2: .align 5 _sa110_flush_cache_area: sub r3, r1, r0 - cmp r3, #32768 + cmp r3, #MAX_AREA_SIZE bgt _sa110_flush_cache_all_r2 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c6, 1 @ flush D entry @@ -79,16 +84,17 @@ _sa110_flush_cache_area: .align 5 _sa110_cache_wback_area: sub r3, r1, r0 - cmp r3, #32768 - movgt r2, #0 - bgt _sa110_flush_cache_all + cmp r3, #MAX_AREA_SIZE + mov r2, #0 + bgt _sa110_flush_cache_all_r2 + bic r0, r0, #31 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #32 mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #32 cmp r0, r1 blt 1b - mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r2, c7, c10, 4 @ drain WB mov pc, lr /* |