diff options
Diffstat (limited to 'arch/arm/kernel')
31 files changed, 1097 insertions, 471 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5bcc22af1..557aa6fc5 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -9,8 +9,8 @@ HEAD_OBJ = head-$(PROCESSOR).o ENTRY_OBJ = entry-$(PROCESSOR).o O_TARGET := kernel.o -O_OBJS := $(ENTRY_OBJ) irq.o process.o ptrace.o setup.o \ - signal.o sys_arm.o time.o traps.o +O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o \ + semaphore.o setup.o signal.o sys_arm.o time.o traps.o ifeq ($(CONFIG_ISA_DMA),y) ISA_DMA_OBJS += dma-isa.o @@ -20,7 +20,7 @@ O_OBJS_arc = dma-arc.o iic.o fiq.o oldlatches.o O_OBJS_a5k = dma-a5k.o iic.o fiq.o O_OBJS_rpc = dma-rpc.o iic.o fiq.o O_OBJS_ebsa110 = dma-dummy.o -O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) +O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o O_OBJS_nexuspci = dma-dummy.o OX_OBJS_arc = dma.o @@ -30,7 +30,7 @@ OX_OBJS_ebsa110 = OX_OBJS_footbridge= dma.o hw-footbridge.o OX_OBJS_nexuspci = -all: lib kernel.o $(HEAD_OBJ) init_task.o +all: kernel.o $(HEAD_OBJ) init_task.o O_OBJS += $(O_OBJS_$(MACHINE)) @@ -48,7 +48,7 @@ ifeq ($(MACHINE),nexuspci) endif else ifdef CONFIG_PCI - O_OBJS += dec21285.o + O_OBJS += bios32.o dec21285.o endif endif @@ -80,11 +80,6 @@ include $(TOPDIR)/Rules.make $(ENTRY_OBJ): ../lib/constants.h -.PHONY: lib - -lib: - $(MAKE) -C ../lib constants.h - # Spell out some dependencies that `make dep' doesn't spot entry-armv.o: calls.S entry-armo.o: calls.S diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index c93421ba7..0905d55b5 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -12,6 +12,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <asm/pgtable.h> +#include <asm/proc-fns.h> #include <asm/semaphore.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -25,9 +26,6 @@ extern void outswb(unsigned int port, const void *to, int len); extern unsigned int local_bh_count[NR_CPUS]; extern unsigned int local_irq_count[NR_CPUS]; -extern void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags); -extern void iounmap(void *addr); - extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* @@ -36,7 +34,6 @@ extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); extern int sys_write(int, const char *, int); extern int sys_read(int, char *, int); extern int sys_lseek(int, off_t, int); -extern int sys_open(const char *, int, int); extern int sys_exit(int); extern int sys_wait4(int, int *, int, struct rusage *); @@ -93,7 +90,7 @@ EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); #ifdef CONFIG_CPU_32 EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(__iounmap); #endif EXPORT_SYMBOL(kernel_thread); @@ -101,11 +98,28 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); /* processor dependencies */ +#ifdef MULTI_CPU EXPORT_SYMBOL(processor); +#else +EXPORT_SYMBOL(cpu_flush_cache_all); +EXPORT_SYMBOL(cpu_flush_cache_area); +EXPORT_SYMBOL(cpu_flush_cache_entry); +EXPORT_SYMBOL(cpu_clean_cache_area); +EXPORT_SYMBOL(cpu_flush_ram_page); +EXPORT_SYMBOL(cpu_flush_tlb_all); +EXPORT_SYMBOL(cpu_flush_tlb_area); +EXPORT_SYMBOL(cpu_switch_mm); +EXPORT_SYMBOL(cpu_set_pmd); +EXPORT_SYMBOL(cpu_set_pte); +EXPORT_SYMBOL(cpu_flush_icache_area); +EXPORT_SYMBOL(cpu_cache_wback_area); +EXPORT_SYMBOL(cpu_cache_purge_area); +#endif EXPORT_SYMBOL(__machine_arch_type); /* networking */ EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(csum_partial_copy_nocheck); EXPORT_SYMBOL(__csum_ipv6_magic); /* io */ @@ -116,10 +130,6 @@ EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); -EXPORT_SYMBOL(_memcpy_fromio); -EXPORT_SYMBOL(_memcpy_toio); -EXPORT_SYMBOL(_memset_io); - /* address translation */ #ifndef __virt_to_phys__is_a_macro EXPORT_SYMBOL(__virt_to_phys); @@ -154,6 +164,7 @@ EXPORT_SYMBOL_NOVERS(strspn); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); @@ -202,9 +213,8 @@ EXPORT_SYMBOL(find_first_zero_bit); EXPORT_SYMBOL(find_next_zero_bit); /* elf */ -EXPORT_SYMBOL(armidlist); -EXPORT_SYMBOL(armidindex); EXPORT_SYMBOL(elf_platform); +EXPORT_SYMBOL(elf_hwcap); /* syscalls */ EXPORT_SYMBOL(sys_write); @@ -217,5 +227,5 @@ EXPORT_SYMBOL(sys_wait4); /* semaphores */ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); +EXPORT_SYMBOL_NOVERS(__down_trylock_failed); EXPORT_SYMBOL_NOVERS(__up_wakeup); - diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c new file mode 100644 index 000000000..35bb0a36a --- /dev/null +++ b/arch/arm/kernel/bios32.c @@ -0,0 +1,351 @@ +/* + * arch/arm/kernel/bios32.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/system.h> + +int have_isa_bridge; + +int (*pci_irq_fixup)(struct pci_dev *dev); + +extern struct pci_ops *dc21285_init(int pass); +extern void pcibios_fixup_ebsa285(struct pci_dev *dev); +extern void hw_init(void); + +void +pcibios_report_device_errors(void) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + + if (status & 0xf900) { + pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + printk(KERN_DEBUG "PCI: %02x:%02x status = %X\n", + dev->bus->number, dev->devfn, status); + } + } +} + +/* + * We don't use this to fix the device, but more our initialisation. + * It's not the correct use for this, but it works. The actions we + * take are: + * - enable only IO + * - set memory region to start at zero + * - (0x48) enable all memory requests from ISA to be channeled to PCI + * - (0x42) disable ping-pong (as per errata) + * - (0x40) enable PCI packet retry + * - (0x83) don't use CPU park enable, park on last master, disable GAT bit + * - (0x80) default rotating priorities + * - (0x81) rotate bank 4 + */ +static void __init pci_fixup_83c553(struct pci_dev *dev) +{ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_SPACE_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO); + + dev->resource[0].end -= dev->resource[0].start; + dev->resource[0].start = 0; + + pci_write_config_byte(dev, 0x48, 0xff); + pci_write_config_byte(dev, 0x42, 0x00); + pci_write_config_byte(dev, 0x40, 0x22); + pci_write_config_byte(dev, 0x83, 0x02); + pci_write_config_byte(dev, 0x80, 0xe0); + pci_write_config_byte(dev, 0x81, 0x01); +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 }, + { 0 } +}; + +/* + * Assign an address to an I/O range. + */ +static void __init pcibios_fixup_io_addr(struct pci_dev *dev, struct resource *r, int idx) +{ + unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + unsigned int size = r->end - r->start + 1; + u32 try; + + /* + * We need to avoid collisions with `mirrored' VGA ports and other strange + * ISA hardware, so we always want the addresses kilobyte aligned. + */ + if (!size || size > 256) { + printk(KERN_ERR "PCI: Cannot assign I/O space to %s, " + "%d bytes are too much.\n", dev->name, size); + return; + } + + if (allocate_resource(&ioport_resource, r, size, 0x9000, ~0, 1024)) { + printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O " + "space for %s.\n", size, dev->name); + return; + } + + printk("PCI: Assigning I/O space %04lx-%04lx to %s\n", + r->start, r->end, dev->name); + + pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO); + pci_read_config_dword(dev, reg, &try); + + if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { + r->start = 0; + pci_write_config_dword(dev, reg, 0); + printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try); + } +} + +/* + * Assign an address to an memory range. + */ +static void __init pcibios_fixup_mem_addr(struct pci_dev *dev, struct resource *r, int idx) +{ + unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + unsigned int size = r->end - r->start + 1; + u32 try; + + if (!size) { + printk(KERN_ERR "PCI: Cannot assign memory space to %s, " + "%d bytes are too much.\n", dev->name, size); + return; + } + + if (allocate_resource(&iomem_resource, r, size, + 0x00100000, 0x0fffffff, 1024)) { + printk(KERN_ERR "PCI: Unable to find free %d bytes of memory " + "space for %s.\n", size, dev->name); + return; + } + + printk("PCI: Assigning memory space %08lx-%08lx to %s\n", + r->start, r->end, dev->name); + + pci_write_config_dword(dev, reg, r->start); + pci_read_config_dword(dev, reg, &try); + + if (try != r->start) { + r->start = 0; + pci_write_config_dword(dev, reg, 0); + printk(KERN_ERR "PCI: memory address setup failed, " + "got %08x\n", try); + } +} + +#define _PCI_REGION_IO 1 +#define _PCI_REGION_MEM 2 + +/* + * Fix up one PCI devices regions, enables and interrupt lines + */ +static void __init pcibios_fixup_device(struct pci_dev *dev, u16 *cmd) +{ + int i, has_regions = 0; + + /* + * Fix up the regions. Any regions which aren't allocated + * are given a free region. + */ + for (i = 0; i < 6; i++) { + struct resource *r = dev->resource + i; + + if (r->flags & IORESOURCE_IO) { + has_regions |= _PCI_REGION_IO; + + if (!r->start || r->end == 0xffffffff) + pcibios_fixup_io_addr(dev, r, i); + } else if (r->end) { + has_regions |= _PCI_REGION_MEM; + + if (!r->start) + pcibios_fixup_mem_addr(dev, r, i); + } + } + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_ISA: + case PCI_CLASS_BRIDGE_EISA: + /* + * If this device is an ISA bridge, set the have_isa_bridge + * flag. We will then go looking for things like keyboard, + * etc + */ + have_isa_bridge = !0; + /* FALL THROUGH */ + + default: + /* + * Don't enable VGA-compatible cards since they have + * fixed I/O and memory space. + * + * Don't enabled disabled IDE interfaces either because + * some BIOSes may reallocate the same address when they + * find that no devices are attached. + */ + if (has_regions & _PCI_REGION_IO && + !((*cmd) & PCI_COMMAND_IO)) { + printk("PCI: Enabling I/O for %s\n", dev->name); + *cmd |= PCI_COMMAND_IO; + } + + if (has_regions & _PCI_REGION_MEM && + !((*cmd) & PCI_COMMAND_MEMORY)) { + printk("PCI: Enabling memory for %s\n", dev->name); + *cmd |= PCI_COMMAND_MEMORY; + } + } +} + +/* + * Fix base addresses, I/O and memory enables and IRQ's + */ +static void __init pcibios_fixup_devices(void) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + u16 cmd; + + /* + * architecture specific hacks. + * I don't really want this here, + * but I don't see any other place + * for it to live. + */ + if (machine_is_netwinder() && + dev->vendor == PCI_VENDOR_ID_DEC && + dev->device == PCI_DEVICE_ID_DEC_21142) + /* Put the chip to sleep in case the driver isn't loaded */ + pci_write_config_dword(dev, 0x40, 0x80000000); + + /* + * Set latency timer to 32, and a cache line size to 32 bytes. + * Also, set system error enable, parity error enable, and + * fast back to back transaction enable. Disable ROM. + */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + cmd |= PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | + PCI_COMMAND_PARITY; + + pcibios_fixup_device(dev, &cmd); + + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + + /* + * now fixup the IRQs, if required + */ + if (pci_irq_fixup) + dev->irq = pci_irq_fixup(dev); + + /* + * If any remaining IRQs are weird, fix it now. + */ + if (dev->irq >= NR_IRQS) + dev->irq = 0; + + /* + * catch any drivers still reading this from the + * device itself. This can be removed once + * all drivers are fixed. (are there any?) + */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } +} + +/* + * Allocate resources for all PCI devices that have been enabled. + * We need to do that before we try to fix up anything. + */ +static void __init pcibios_claim_resources(void) +{ + struct pci_dev *dev; + int idx; + + for (dev = pci_devices; dev; dev = dev->next) + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *a, *r = &dev->resource[idx]; + + /* + * Ignore regions that start at 0 or + * end at 0xffffffff + */ + if (!r->start || r->end == 0xffffffff) + continue; + + if (r->flags & IORESOURCE_IO) + a = &ioport_resource; + else + a = &iomem_resource; + + if (request_resource(a, r) < 0) + printk(KERN_ERR "PCI: Address space collision " + "on region %d of %s\n", + idx, dev->name); + /* We probably should disable the region, + * shouldn't we? + */ + } +} + +/* + * Called after each bus is probed, but before its children + * are examined. + * + * No fixup of bus required + */ +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ +} + +void __init pcibios_init(void) +{ + struct pci_ops *ops; + + /* + * Pre-initialisation. Set up the host bridge. + */ + ops = dc21285_init(0); + + printk("PCI: Probing PCI hardware\n"); + + pci_scan_bus(0, ops, NULL); + pcibios_claim_resources(); + pcibios_fixup_devices(); + + /* + * Now clear down any PCI error IRQs and + * register the error handler + */ + dc21285_init(1); + + /* + * Initialise any other hardware after we've + * got the PCI bus initialised. We may need + * the PCI bus to talk to this other hardware. + */ + hw_init(); +} + +char * __init pcibios_setup(char *str) +{ + return str; +} diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 154e3aeab..c95eeb1b0 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -119,9 +119,9 @@ .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) .long SYMBOL_NAME(sys_uname) -/* 110 */ .long SYMBOL_NAME(sys_ni_syscall) +/* 110 */ .long SYMBOL_NAME(sys_iopl) .long SYMBOL_NAME(sys_vhangup) - .long SYMBOL_NAME(sys_idle) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_syscall) /* call a syscall */ .long SYMBOL_NAME(sys_wait4) /* 115 */ .long SYMBOL_NAME(sys_swapoff) @@ -129,7 +129,7 @@ .long SYMBOL_NAME(sys_ipc) .long SYMBOL_NAME(sys_fsync) .long SYMBOL_NAME(sys_sigreturn_wrapper) - .long SYMBOL_NAME(sys_clone_wapper) +/* 120 */ .long SYMBOL_NAME(sys_clone_wapper) .long SYMBOL_NAME(sys_setdomainname) .long SYMBOL_NAME(sys_newuname) .long SYMBOL_NAME(sys_ni_syscall) /* .long SYMBOL_NAME(sys_modify_ldt) */ @@ -157,8 +157,8 @@ /* 145 */ .long SYMBOL_NAME(sys_readv) .long SYMBOL_NAME(sys_writev) .long SYMBOL_NAME(sys_getsid) - .long SYMBOL_NAME(sys_ni_syscall) - .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_fdatasync) + .long SYMBOL_NAME(sys_sysctl) /* 150 */ .long SYMBOL_NAME(sys_mlock) .long SYMBOL_NAME(sys_munlock) .long SYMBOL_NAME(sys_mlockall) diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index 80cef0b23..6a4988b15 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -1,7 +1,7 @@ /* - * arch/arm/kernel/dec21285.c: PCI functions for DEC 21285 + * arch/arm/kernel/dec21285.c: PCI functions for DC21285 * - * Copyright (C) 1998 Russell King, Phil Blundell + * Copyright (C) 1998-1999 Russell King, Phil Blundell */ #include <linux/config.h> #include <linux/sched.h> @@ -11,6 +11,7 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/ioport.h> #include <asm/irq.h> #include <asm/system.h> @@ -129,7 +130,7 @@ pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -__initfunc(void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set)) +void __init pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set) { unsigned short cmd; @@ -138,7 +139,7 @@ __initfunc(void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned pci_write_config_word(dev, PCI_COMMAND, cmd); } -__initfunc(void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr)) +void __init pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr) { int reg = PCI_BASE_ADDRESS_0 + (idx << 2); @@ -148,7 +149,7 @@ __initfunc(void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int add dev->base_address[idx] = addr; } -__initfunc(void pcibios_fixup(void)) +void __init pcibios_fixup(void) { struct pci_dev *dev; @@ -167,7 +168,7 @@ __initfunc(void pcibios_fixup(void)) hw_init(); } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; unsigned long cntl; @@ -242,11 +243,11 @@ __initfunc(void pcibios_init(void)) printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff); } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { return str; } diff --git a/arch/arm/kernel/dma-a5k.c b/arch/arm/kernel/dma-a5k.c index df02ea54e..84740b6d2 100644 --- a/arch/arm/kernel/dma-a5k.c +++ b/arch/arm/kernel/dma-a5k.c @@ -91,7 +91,7 @@ int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64; } diff --git a/arch/arm/kernel/dma-arc.c b/arch/arm/kernel/dma-arc.c index 9be27bdae..53ef12b1c 100644 --- a/arch/arm/kernel/dma-arc.c +++ b/arch/arm/kernel/dma-arc.c @@ -15,8 +15,11 @@ #include "dma.h" +#define DEBUG + int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id) { + printk("arch_request_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); if (channel == DMA_VIRTUAL_FLOPPY0 || channel == DMA_VIRTUAL_FLOPPY1) return 0; @@ -30,8 +33,9 @@ void arch_free_dma(dmach_t channel, dma_t *dma) void arch_enable_dma(dmach_t channel, dma_t *dma) { + printk("arch_enable_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); switch (channel) { -#ifdef CONFIG_BLK_DEV_FD +#ifdef CONFIG_BLK_DEV_FD1772 case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ switch (dma->dma_mode) { case DMA_MODE_READ: /* read */ @@ -100,7 +104,7 @@ void arch_enable_dma(dmach_t channel, dma_t *dma) int arch_get_dma_residue(dmach_t channel, dma_t *dma) { switch (channel) { -#ifdef CONFIG_BLK_DEV_FD +#ifdef CONFIG_BLK_DEV_FD1772 case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ extern unsigned int fdc1772_bytestogo; @@ -139,7 +143,7 @@ int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65; diff --git a/arch/arm/kernel/dma-dummy.c b/arch/arm/kernel/dma-dummy.c index db46ef1c3..7efc85363 100644 --- a/arch/arm/kernel/dma-dummy.c +++ b/arch/arm/kernel/dma-dummy.c @@ -8,8 +8,7 @@ */ #include <linux/errno.h> #include <linux/init.h> - -#include <asm/spinlock.h> +#include <linux/spinlock.h> spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; @@ -27,6 +26,6 @@ int get_dma_list(char *buf) return 0; } -__initfunc(void init_dma(void)) +void __init init_dma(void) { } diff --git a/arch/arm/kernel/dma-footbridge.c b/arch/arm/kernel/dma-footbridge.c index a355283dc..016b11c15 100644 --- a/arch/arm/kernel/dma-footbridge.c +++ b/arch/arm/kernel/dma-footbridge.c @@ -104,7 +104,7 @@ int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) return 0; } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { #ifdef CONFIG_ISA_DMA has_isa_dma = isa_init_dma(); diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c index 19be50433..f5f98bbac 100644 --- a/arch/arm/kernel/dma-isa.c +++ b/arch/arm/kernel/dma-isa.c @@ -11,6 +11,7 @@ * Copyright (C) 1998 Phil Blundell */ #include <linux/sched.h> +#include <linux/ioport.h> #include <linux/init.h> #include <asm/dma.h> @@ -125,7 +126,7 @@ void isa_disable_dma(int channel, dma_t *dma) outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); } -__initfunc(int isa_init_dma(void)) +int __init isa_init_dma(void) { int dmac_found; @@ -138,7 +139,7 @@ __initfunc(int isa_init_dma(void)) dmac_found = inb(0x00) == 0x55 && inb(0x00) == 0xaa; if (dmac_found) { - int channel; + int channel, i; for (channel = 0; channel < 8; channel++) isa_disable_dma(channel, NULL); @@ -173,6 +174,9 @@ __initfunc(int isa_init_dma(void)) outb(0x33, 0x4d6); request_dma(DMA_ISA_CASCADE, "cascade"); + + for (i = 0; i < sizeof(dma_resources) / sizeof(dma_resources[0]); i++) + request_resource(&ioport_resource, dma_resources + i); } return dmac_found; diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c index d3fcd9116..e27232255 100644 --- a/arch/arm/kernel/dma-rpc.c +++ b/arch/arm/kernel/dma-rpc.c @@ -359,7 +359,7 @@ int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) outb(tcr, IOMD_DMATCR); } -__initfunc(void arch_dma_init(dma_t *dma)) +void __init arch_dma_init(dma_t *dma) { outb(0, IOMD_IO0CR); outb(0, IOMD_IO1CR); diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 219e1f0f2..7d1a11cd5 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -19,13 +19,13 @@ #include <linux/malloc.h> #include <linux/mman.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <asm/page.h> #include <asm/irq.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/dma.h> -#include <asm/spinlock.h> /* A note on resource allocation: @@ -221,7 +221,7 @@ EXPORT_SYMBOL(get_dma_residue); EXPORT_SYMBOL(set_dma_sg); EXPORT_SYMBOL(set_dma_speed); -__initfunc(void init_dma(void)) +void __init init_dma(void) { arch_dma_init(dma_chan); } diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index dd4bf670c..c4b0efef8 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -44,6 +44,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/pgtable.h> +#include <asm/mmu_context.h> #ifdef CONFIG_ARCH_ARC #include <asm/arch/oldlatches.h> @@ -231,8 +232,42 @@ static wait_queue_head_t ecard_wait; static wait_queue_head_t ecard_done; static struct ecard_request *ecard_req; +/* to be removed when exec_mmap becomes extern */ +static int exec_mmap(void) +{ + struct mm_struct * mm, * old_mm; + + old_mm = current->mm; + if (old_mm && atomic_read(&old_mm->mm_users) == 1) { + flush_cache_mm(old_mm); + mm_release(); + exit_mmap(old_mm); + flush_tlb_mm(old_mm); + return 0; + } + + mm = mm_alloc(); + if (mm) { + struct mm_struct *active_mm = current->active_mm; + + current->mm = mm; + current->active_mm = mm; + activate_mm(active_mm, mm); + mm_release(); + if (old_mm) { + if (active_mm != old_mm) BUG(); + mmput(old_mm); + return 0; + } + mmdrop(active_mm); + return 0; + } + return -ENOMEM; +} + /* - * Set up the expansion card daemon's environment. + * Set up the expansion card + * daemon's environment. */ static void ecard_init_task(void) @@ -251,6 +286,8 @@ ecard_init_task(void) pgd_t *src_pgd, *dst_pgd; unsigned int dst_addr = IO_START; + exec_mmap(); + src_pgd = pgd_offset(current->mm, IO_BASE); dst_pgd = pgd_offset(current->mm, dst_addr); @@ -333,7 +370,7 @@ ecard_call(struct ecard_request *req) * call the loader. We can't schedule, or * sleep for this call. */ - if ((current == task[0] || in_interrupt()) && + if ((current == &init_task || in_interrupt()) && req->req == req_reset && req->ec == NULL) { ecard_init_task(); ecard_task_reset(req); @@ -721,8 +758,8 @@ again: printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -__initfunc(static void -ecard_probeirqhw(void)) +static void __init +ecard_probeirqhw(void) { ecard_t *ec; int found; @@ -798,8 +835,6 @@ unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) return address; } -static const char *unknown = "*unknown*"; - static int ecard_prints(char *buffer, ecard_t *ec) { char *start = buffer; @@ -818,7 +853,7 @@ static int ecard_prints(char *buffer, ecard_t *ec) ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); if (ec->card_desc) - strcpy(ec->card_desc, incd.d.string); + strcpy((char *)ec->card_desc, incd.d.string); } buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); @@ -872,8 +907,8 @@ static void ecard_proc_init(void) * If bit 1 of the first byte of the card is set, then the * card does not exist. */ -__initfunc(static int -ecard_probe(int slot, card_type_t type)) +static int __init +ecard_probe(int slot, card_type_t type) { ecard_t **ecp; ecard_t *ec; @@ -1009,7 +1044,7 @@ ecard_t *ecard_find(int cid, const card_ids *cids) return finding_pos; } -__initfunc(static void ecard_free_all(void)) +static void __init ecard_free_all(void) { ecard_t *ec, *ecn; @@ -1029,7 +1064,7 @@ __initfunc(static void ecard_free_all(void)) * Locate all hardware - interrupt management and * actual cards. */ -__initfunc(void ecard_init(void)) +void __init ecard_init(void) { int slot; diff --git a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S index 758163f07..5d9ce0ac6 100644 --- a/arch/arm/kernel/entry-armo.S +++ b/arch/arm/kernel/entry-armo.S @@ -650,6 +650,15 @@ Ldata_ldcstc_pre: b SYMBOL_NAME(do_DataAbort) /* + * Register switch for older 26-bit only ARMs + */ +ENTRY(__switch_to) + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack + str sp, [r0, #TSS_SAVE] @ Save sp_SVC + ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC + ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously + +/* *============================================================================= * Low-level interface code *----------------------------------------------------------------------------- diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 9456abe33..3e015d866 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -16,6 +16,7 @@ #include <asm/errno.h> #include <asm/hardware.h> #include <asm/arch/irqs.h> +#include <asm/proc-fns.h> #include "../lib/constants.h" @@ -244,6 +245,10 @@ irq_prio_ebsa110: movne \irqnr, #IRQ_PCI bne 1001f + tst \irqstat, #IRQ_MASK_DOORBELLHOST + movne \irqnr, #IRQ_DOORBELLHOST + bne 1001f + tst \irqstat, #IRQ_MASK_I2OINPOST movne \irqnr, #IRQ_I2OINPOST bne 1001f @@ -449,9 +454,13 @@ __dabt_svc: sub sp, sp, #S_FRAME_SIZE biceq r0, r0, #I_BIT @ previously msreq cpsr, r0 mov r0, r2 +#ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc - ldr pc, [r2, #8] @ call processor specific code + ldr pc, [r2] @ call processor specific code +#else + bl cpu_data_abort +#endif mov r3, sp bl SYMBOL_NAME(do_DataAbort) ldr r0, [sp, #S_PSR] @@ -503,7 +512,9 @@ __und_svc: sub sp, sp, #S_FRAME_SIZE .LCirq: .word __temp_irq .LCund: .word __temp_und .LCabt: .word __temp_abt +#ifdef MULTI_CPU .LCprocfns: .word SYMBOL_NAME(processor) +#endif .LCfp: .word SYMBOL_NAME(fp_enter) #ifdef CONFIG_ALIGNMENT_TRAP .LCswi: .word SYMBOL_NAME(cr_alignment) @@ -536,9 +547,13 @@ __dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go mrs r2, cpsr @ Enable interrupts if they were bic r2, r2, #I_BIT @ previously msr cpsr, r2 +#ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc - ldr pc, [r2, #8] @ call processor specific code + ldr pc, [r2] @ call processor specific code +#else + bl cpu_data_abort +#endif mov r3, sp adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_DataAbort) @@ -651,6 +666,23 @@ __pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go movs pc, lr #endif +/* + * Register switch for ARMv3 and ARMv4 processors + * r0 = previous, r1 = next, return previous. + * previous and next are guaranteed not to be the same. + */ +ENTRY(__switch_to) + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack + mrs ip, cpsr + stmfd sp!, {ip} @ Save cpsr_SVC + ldr r2, [r1, #TSS_DOMAIN] + str sp, [r0, #TSS_SAVE] @ Save sp_SVC + ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC + mcr p15, 0, r2, c3, c0 @ Set domain register + ldmfd sp!, {ip} + msr spsr, ip @ Save tasks CPSR into SPSR for this return + ldmfd sp!, {r4 - sl, fp, pc}^ @ Load all regs saved previously + .section ".text.init",#alloc,#execinstr /* * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary, diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 7dbc7ff95..bdf6de6b3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -2,6 +2,16 @@ /*============================================================================ * All exits to user mode from the kernel go through this code. */ + +/* + * Define to favour ARM8, ARM9 and StrongARM cpus. This says that it is + * cheaper to use two LDR instructions than a two-register LDM, if the + * latter would entail calculating an address specially. + */ +#if defined(CONFIG_CPU_SA110) +#define HARVARD_CACHE +#endif + .globl ret_from_sys_call .align 5 @@ -10,18 +20,23 @@ fast_syscall_return: slow_syscall_return: add sp, sp, #4 ret_from_sys_call: +#ifdef HARVARD_CACHE + ldr r0, bh_data + ldr r4, bh_data+4 +#else adr r0, bh_data ldmia r0, {r0, r4} +#endif ldr r0, [r0] ldr r1, [r4] tst r0, r1 blne SYMBOL_NAME(do_bottom_half) ret_with_reschedule: - get_current_task r1 @ check for scheduling - ldr r0, [r1, #TSK_NEED_RESCHED] + get_current_task r5 + ldr r0, [r5, #TSK_NEED_RESCHED] + ldr r1, [r5, #TSK_SIGPENDING] teq r0, #0 bne ret_reschedule - ldr r1, [r1, #TSK_SIGPENDING] teq r1, #0 @ check for signals bne ret_signal @@ -37,8 +52,13 @@ ret_reschedule: adrsvc al, lr, ret_with_reschedule .globl ret_from_exception ret_from_exception: +#ifdef HARVARD_CACHE + ldr r0, bh_data + ldr r1, bh_data + 4 +#else adr r0, bh_data ldmia r0, {r0, r1} +#endif ldr r0, [r0] ldr r1, [r1] mov r4, #0 @@ -132,7 +152,8 @@ ENTRY(sys_call_table) SYMBOL_NAME(sys_syscall): eor r6, r0, #OS_NUMBER << 20 cmp r6, #NR_syscalls @ check range - ldmleib sp, {r0 - r4} @ get our args + add ip, sp, #4 + ldmleib ip, {r0 - r4} @ get our args strle r4, [sp] @ Put our arg on the stack ldrle pc, [r5, r6, lsl #2] mov r0, #-ENOSYS diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index e3e87469f..7a16832c7 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -53,15 +53,12 @@ static unsigned long no_fiq_insn; #ifdef CONFIG_CPU_32 static inline void unprotect_page_0(void) { - __asm__ __volatile__("mcr p15, 0, %0, c3, c0" : - : "r" (DOMAIN_USER_MANAGER | - DOMAIN_KERNEL_CLIENT | - DOMAIN_IO_CLIENT)); + modify_domain(DOMAIN_USER, DOMAIN_MANAGER); } static inline void protect_page_0(void) { - set_fs(get_fs()); + modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } #else @@ -216,7 +213,7 @@ void release_fiq(struct fiq_handler *f) while (current_fiq->fiq_op(current_fiq->dev_id, 0)); } -__initfunc(void init_FIQ(void)) +void __init init_FIQ(void) { no_fiq_insn = *(unsigned long *)FIQ_VECTOR; set_fs(get_fs()); diff --git a/arch/arm/kernel/head-armv.S b/arch/arm/kernel/head-armv.S index 2e13f0818..e9a05aed6 100644 --- a/arch/arm/kernel/head-armv.S +++ b/arch/arm/kernel/head-armv.S @@ -72,6 +72,8 @@ ENTRY(_stext) * r1 = 6 -> CATS * r1 = 7 -> tbox * r1 = 8 -> SA110/21285 as co-processor + * r1 = 9 -> CL-PS7110 system + * r1 = 12 -> SA1100 based system */ __entry: teq r0, #0 @ check for illegal entry... @@ -162,9 +164,16 @@ __entry: teq r0, #0 @ check for illegal entry... addne r0, r4, #0x3600 @ d8000000 strne r3, [r0] #endif -@ -@ The following should work on both v3 and v4 implementations -@ + b aligned_call +/* + * The following should work on both v3 and v4 implementations + * Note: it seems that if the mov pc,lr is on the next cache + * line, it doesn't get fetched before the MMU starts + * translating, which prevents the kernel from booting. + * Ensure that this never happens. + */ + .align 5 +aligned_call: mov lr, pc mov pc, r10 @ Call processor flush (returns ctrl reg) adr r5, __entry @@ -178,7 +187,7 @@ __entry: teq r0, #0 @ check for illegal entry... #ifdef CONFIG_ARCH_RPC /* Turn the screen red on a error - RiscPC only. */ -1: mov r0, #0x02000000 + mov r0, #0x02000000 mov r3, #0x11 orr r3, r3, r3, lsl #8 orr r3, r3, r3, lsl #16 @@ -187,6 +196,7 @@ __entry: teq r0, #0 @ check for illegal entry... str r3, [r0], #4 str r3, [r0], #4 #endif +1: mov r0, r0 b 1b .Lbranch: .long .Lalready_done_mmap @ Real address of routine @@ -245,6 +255,12 @@ __entry: teq r0, #0 @ check for illegal entry... .long DC21285_ARMCSR_BASE @ Physical I/O base address .long 0x7cf00000 >> 18 @ Virtual I/O base address + @ SA1100 + .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0xc0000000 + .long 0xc0000000 + .long 0x80000000 @ IO mapping will change when kernel gets on its feet + .long 0x3800 + .LCProcTypes: @ ARM6 / 610 .long 0x41560600 .long 0xffffff00 @@ -266,9 +282,9 @@ __entry: teq r0, #0 @ check for illegal entry... b .Larmv3_flush_late @ arm v3 flush & ctrl late setup mov pc, lr - @ StrongARM - .long 0x4401a100 - .long 0xfffffff0 + @ StrongARM-110 and StrongARM-1100 + .long 0x4401a100 @ 4401a100 and 4401a110 + .long 0xffffffe0 .long 0x00000c02 b .Larmv4_flush_early b .Lsa_fastclock diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c index 857f120e1..54a64b811 100644 --- a/arch/arm/kernel/hw-footbridge.c +++ b/arch/arm/kernel/hw-footbridge.c @@ -44,7 +44,7 @@ extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; -__initfunc(static int ebsa_irqval(struct pci_dev *dev)) +static int __init ebsa_irqval(struct pci_dev *dev) { unsigned char pin; @@ -59,7 +59,7 @@ __initfunc(static int ebsa_irqval(struct pci_dev *dev)) #ifdef CONFIG_CATS static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; -__initfunc(static int cats_irqval(struct pci_dev *dev)) +static int __init cats_irqval(struct pci_dev *dev) { if (dev->irq >= 128) return 16 + (dev->irq & 0x1f); @@ -80,7 +80,7 @@ __initfunc(static int cats_irqval(struct pci_dev *dev)) } #endif -__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) +void __init pcibios_fixup_ebsa285(struct pci_dev *dev) { /* Latency timer of 32 */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); @@ -284,7 +284,7 @@ static struct irqaction irq_pci_error = { irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL }; -__initfunc(void pcibios_init_ebsa285(void)) +void __init pcibios_init_ebsa285(void) { setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error); } @@ -592,7 +592,7 @@ static inline void wb977_init_gpio(void) /* * Initialise the Winbond W83977F chip. */ -__initfunc(static void wb977_init(void)) +static void __init wb977_init(void) { request_region(0x370, 2, "W83977AF configuration"); @@ -642,7 +642,7 @@ void __netwinder_text cpld_modify(int mask, int set) gpio_modify_op(GPIO_IOLOAD, 0); } -__initfunc(static void cpld_init(void)) +static void __init cpld_init(void) { unsigned long flags; @@ -662,7 +662,7 @@ static unsigned char rwa_unlock[] __initdata = #define dprintk printk #endif -#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0) +#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) static inline void rwa010_unlock(void) { @@ -671,8 +671,10 @@ static inline void rwa010_unlock(void) WRITE_RWA(2, 2); mdelay(10); - for (i = 0; i < sizeof(rwa_unlock); i++) + for (i = 0; i < sizeof(rwa_unlock); i++) { outb(rwa_unlock[i], 0x279); + udelay(10); + } } static inline void rwa010_read_ident(void) @@ -685,22 +687,22 @@ static inline void rwa010_read_ident(void) outb(1, 0x279); - mdelay(10); + mdelay(1); dprintk("Identifier: "); for (i = 0; i < 9; i++) { si[i] = 0; for (j = 0; j < 8; j++) { int bit; - mdelay(1); + udelay(250); inb(0x203); - mdelay(1); + udelay(250); bit = inb(0x203); dprintk("%02X ", bit); + bit = (bit == 0xaa) ? 1 : 0; si[i] |= bit << j; } - mdelay(10); - dprintk("%02X ", si[i]); + dprintk("(%02X) ", si[i]); } dprintk("\n"); } @@ -842,7 +844,7 @@ static void rwa010_soundblaster_reset(void) outb(1, 0x38b); } -__initfunc(static void rwa010_init(void)) +static void __init rwa010_init(void) { rwa010_unlock(); rwa010_read_ident(); @@ -866,8 +868,63 @@ EXPORT_SYMBOL(cpld_modify); #define DEFAULT_LEDS GPIO_GREEN_LED #endif -__initfunc(void hw_init(void)) +/* + * CATS stuff + */ +#ifdef CONFIG_CATS + +#define CONFIG_PORT 0x370 +#define INDEX_PORT (CONFIG_PORT) +#define DATA_PORT (CONFIG_PORT + 1) + +static void __init cats_hw_init(void) { + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CONFIG_PORT); + outb(0x23, CONFIG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CONFIG_PORT); +} + +#endif + +void __init hw_init(void) +{ + extern void register_isa_ports(unsigned int, unsigned int, + unsigned int); + register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); #ifdef CONFIG_ARCH_NETWINDER /* * this ought to have a better home... @@ -888,6 +945,10 @@ __initfunc(void hw_init(void)) spin_unlock_irqrestore(&gpio_lock, flags); } #endif +#ifdef CONFIG_CATS + if (machine_is_cats()) + cats_hw_init(); +#endif leds_event(led_start); } diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c index 5d09ea540..e3853f3d5 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(init_mm); diff --git a/arch/arm/kernel/ioport.c b/arch/arm/kernel/ioport.c new file mode 100644 index 000000000..bae897747 --- /dev/null +++ b/arch/arm/kernel/ioport.c @@ -0,0 +1,27 @@ +/* + * linux/arch/arm/kernel/ioport.c + * + * IO permission support for ARM. + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/ioport.h> + +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +asmlinkage int sys_iopl(unsigned long turn_on) +{ + if (turn_on && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* + * We only support an on_off approach + */ + modify_domain(DOMAIN_IO, turn_on ? DOMAIN_MANAGER : DOMAIN_CLIENT); + + return 0; +} diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ee6e07c6c..41e2050e6 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -479,7 +479,7 @@ out: return irq_found; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { extern void init_dma(void); int irq; diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c new file mode 100644 index 000000000..a5424f8b6 --- /dev/null +++ b/arch/arm/kernel/isa.c @@ -0,0 +1,47 @@ +/* + * arch/arm/kernel/isa.c + * + * ISA shared memory and I/O port support + * + * Copyright (C) 1999 Phil Blundell + */ + +/* + * Nothing about this is actually ARM specific. One day we could move + * it into kernel/resource.c or some place like that. + */ + +#include <linux/stddef.h> +#include <linux/types.h> +#include <linux/linkage.h> +#include <linux/fs.h> +#include <linux/sysctl.h> +#include <linux/init.h> + +static unsigned int isa_membase, isa_portbase, isa_portshift; + +static ctl_table ctl_isa_vars[4] = { + {BUS_ISA_MEM_BASE, "membase", &isa_membase, + sizeof(isa_membase), 0444, NULL, &proc_dointvec}, + {BUS_ISA_PORT_BASE, "portbase", &isa_portbase, + sizeof(isa_portbase), 0444, NULL, &proc_dointvec}, + {BUS_ISA_PORT_SHIFT, "portshift", &isa_portshift, + sizeof(isa_portshift), 0444, NULL, &proc_dointvec}, + {0} +}; + +static struct ctl_table_header *isa_sysctl_header; + +static ctl_table ctl_isa[2] = {{BUS_ISA, "isa", NULL, 0, 0555, ctl_isa_vars}, + {0}}; +static ctl_table ctl_bus[2] = {{CTL_BUS, "bus", NULL, 0, 0555, ctl_isa}, + {0}}; + +void __init +register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift) +{ + isa_membase = membase; + isa_portbase = portbase; + isa_portshift = portshift; + isa_sysctl_header = register_sysctl_table(ctl_bus, 0); +} diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c index cb6c7f4b4..6b4cb001b 100644 --- a/arch/arm/kernel/leds-footbridge.c +++ b/arch/arm/kernel/leds-footbridge.c @@ -21,10 +21,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <asm/hardware.h> #include <asm/leds.h> -#include <asm/spinlock.h> #include <asm/system.h> #define LED_STATE_ENABLED 1 @@ -33,8 +33,9 @@ static char led_state; static char hw_led_state; static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; +extern spinlock_t gpio_lock; -#ifdef CONFIG_ARCH_EBSA285 +#ifdef CONFIG_FOOTBRIDGE static void __ebsa285_text ebsa285_leds_event(led_event_t evt) { @@ -222,12 +223,13 @@ static void dummy_leds_event(led_event_t evt) { } -__initfunc(void -init_leds_event(led_event_t evt)) +void __init +init_leds_event(led_event_t evt) { switch (machine_arch_type) { -#ifdef CONFIG_ARCH_EBSA285 +#ifdef CONFIG_FOOTBRIDGE case MACH_TYPE_EBSA285: + case MACH_TYPE_CO285: leds_event = ebsa285_leds_event; break; #endif diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index ff0c548b4..776dc9b88 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -9,7 +9,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ #include <stdarg.h> #include <linux/errno.h> @@ -54,16 +53,15 @@ void enable_hlt(void) /* * The idle loop on an ARM... */ -asmlinkage int sys_idle(void) +void cpu_idle(void) { - if (current->pid != 0) - return -EPERM; - /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; while (1) { if (!current->need_resched && !hlt_counter) proc_idle(); - current->policy = SCHED_YIELD; schedule(); #ifndef CONFIG_NO_PGT_CACHE check_pgt_cache(); @@ -73,7 +71,7 @@ asmlinkage int sys_idle(void) static char reboot_mode = 'h'; -__initfunc(void reboot_setup(char *str, int *ints)) +void __init reboot_setup(char *str, int *ints) { reboot_mode = str[0]; } @@ -207,10 +205,7 @@ void exit_thread(void) void flush_thread(void) { - int i; - - for (i = 0; i < NR_DEBUGS; i++) - current->tss.debug[i] = 0; + memset(¤t->thread.debug, 0, sizeof(current->thread.debug)); current->used_math = 0; current->flags &= ~PF_USEDFPU; } @@ -232,7 +227,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, save = ((struct context_save_struct *)(childregs)) - 1; init_thread_css(save); - p->tss.save = save; + p->thread.save = save; return 0; } @@ -245,7 +240,7 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) int fpvalid = 0; if (current->used_math) - memcpy (fp, ¤t->tss.fpstate.soft, sizeof (fp)); + memcpy (fp, ¤t->thread.fpstate.soft, sizeof (fp)); return fpvalid; } @@ -255,8 +250,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) */ void dump_thread(struct pt_regs * regs, struct user * dump) { - int i; - dump->magic = CMAGIC; dump->start_code = current->mm->start_code; dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); @@ -265,8 +258,11 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; dump->u_ssize = 0; - for (i = 0; i < NR_DEBUGS; i++) - dump->u_debugreg[i] = current->tss.debug[i]; + dump->u_debugreg[0] = current->thread.debug.bp[0].address; + dump->u_debugreg[1] = current->thread.debug.bp[1].address; + dump->u_debugreg[2] = current->thread.debug.bp[0].insn; + dump->u_debugreg[3] = current->thread.debug.bp[1].insn; + dump->u_debugreg[4] = current->thread.debug.nsaved; if (dump->start_stack < 0x04000000) dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; @@ -285,7 +281,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump) */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { - extern int sys_exit(int) __attribute__((noreturn)); pid_t __ret; __asm__ __volatile__( diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index fbc3a2187..6104b4dbe 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -28,7 +28,7 @@ /* * this routine will get a word off of the processes privileged stack. - * the offset is how far from the base addr as stored in the TSS. + * the offset is how far from the base addr as stored in the THREAD. * this routine assumes that all the privileged stacks are in our * data space. */ @@ -43,7 +43,7 @@ static inline long get_stack_long(struct task_struct *task, int offset) /* * this routine will put a word on the processes privileged stack. - * the offset is how far from the base addr as stored in the TSS. + * the offset is how far from the base addr as stored in the THREAD. * this routine assumes that all the privileged stacks are in our * data space. */ @@ -59,209 +59,24 @@ static inline long put_stack_long(struct task_struct *task, int offset, return 0; } -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) +static int +read_long(struct task_struct *child, unsigned long addr, unsigned long *res) { - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); - - if(MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - return *(unsigned long *)page; -} + int copied; -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of the page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, - unsigned long data) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - - if (MAP_NR(page) < max_mapnr) { - page += addr & ~PAGE_MASK; - - flush_cache_range(vma->vm_mm, addr, addr + sizeof(unsigned long)); - - *(unsigned long *)page = data; - - clean_cache_area(page, sizeof(unsigned long)); + copied = access_process_vm(child, addr, res, sizeof(*res), 0); - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, addr & PAGE_MASK); - } + return copied != sizeof(*res) ? -EIO : 0; } -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) +static int +write_long(struct task_struct *child, unsigned long addr, unsigned long val) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 1: - low >>= 8; - low |= high << 24; - break; - case 2: - low >>= 16; - low |= high << 16; - break; - case 3: - low >>= 24; - low |= high << 8; - break; - } - *result = low; - } else - *result = get_long(tsk, vma, addr); - return 0; -} + int copied; -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 0: /* shouldn't happen, but safety first */ - low = data; - break; - case 1: - low &= 0x000000ff; - low |= data << 8; - high &= ~0xff; - high |= data >> 24; - break; - case 2: - low &= 0x0000ffff; - low |= data << 16; - high &= ~0xffff; - high |= data >> 16; - break; - case 3: - low &= 0x00ffffff; - low |= data << 24; - high &= ~0xffffff; - high |= data >> 8; - break; - } - put_long(tsk, vma, addr & ~(sizeof(long)-1),low); - put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); - } else - put_long(tsk, vma, addr, data); - return 0; + copied = access_process_vm(child, addr, &val, sizeof(val), 1); + + return copied != sizeof(val) ? -EIO : 0; } /* @@ -315,7 +130,7 @@ printk ("sh%dx%d", type, shift); val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } printk ("=%08lX ", val); @@ -343,26 +158,19 @@ printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } printk ("=%08lX ", val); return val; } -int ptrace_set_bpt (struct task_struct *child) +static unsigned long +get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) { - unsigned long insn, pc, alt; - int i, nsaved = 0, res; - - pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); + unsigned long alt = 0; - res = read_long (child, pc, &insn); - if (res < 0) - return res; - - child->tss.debug[nsaved++] = alt = pc + 4; -printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); +printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); switch (insn & 0x0e100000) { case 0x00000000: case 0x00100000: @@ -423,7 +231,7 @@ printk ("ldr "); alt -= ptrace_getldrop2 (child, insn); } if (read_long (child, alt, &alt) < 0) - alt = pc + 4; /* not valid */ + alt = 0; /* not valid */ else alt = pc_pointer (alt); } @@ -440,7 +248,7 @@ printk ("ldrimm "); alt -= insn & 0xfff; } if (read_long (child, alt, &alt) < 0) - alt = pc + 4; /* not valid */ + alt = 0; /* not valid */ else alt = pc_pointer (alt); } @@ -473,7 +281,7 @@ printk ("ldm "); base = ptrace_getrn (child, insn); if (read_long (child, base + nr_regs, &alt) < 0) - alt = pc + 4; /* not valid */ + alt = 0; /* not valid */ else alt = pc_pointer (alt); break; @@ -499,22 +307,55 @@ printk ("b/bl "); break; } printk ("=%08lX\n", alt); - if (alt != pc + 4) - child->tss.debug[nsaved++] = alt; - for (i = 0; i < nsaved; i++) { - res = read_long (child, child->tss.debug[i], &insn); - if (res >= 0) { - child->tss.debug[i + 2] = insn; - res = write_long (child, child->tss.debug[i], BREAKINST); + return alt; +} + +static int +add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr) +{ + int nr = dbg->nsaved; + int res = -EINVAL; + + if (nr < 2) { + res = read_long(child, addr, &dbg->bp[nr].insn); + if (res == 0) + res = write_long(child, addr, BREAKINST); + + if (res == 0) { + dbg->bp[nr].address = addr; + dbg->nsaved += 1; } - if (res < 0) { - child->tss.debug[4] = 0; - return res; + } else + printk(KERN_DEBUG "add_breakpoint: too many breakpoints\n"); + + return res; +} + +int ptrace_set_bpt (struct task_struct *child) +{ + struct debug_info *dbg = &child->thread.debug; + unsigned long insn, pc, alt; + int res; + + pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); + + res = read_long(child, pc, &insn); + if (res >= 0) { + res = 0; + + dbg->nsaved = 0; + + res = add_breakpoint(child, dbg, pc + 4); + + if (res == 0) { + alt = get_branch_address(child, pc, insn); + if (alt) + res = add_breakpoint(child, dbg, alt); } } - child->tss.debug[4] = nsaved; - return 0; + + return res; } /* Ensure no single-step breakpoint is pending. Returns non-zero @@ -522,16 +363,24 @@ printk ("=%08lX\n", alt); */ int ptrace_cancel_bpt (struct task_struct *child) { - int i, nsaved = child->tss.debug[4]; + struct debug_info *dbg = &child->thread.debug; + unsigned long tmp; + int i, nsaved = dbg->nsaved; - child->tss.debug[4] = 0; + dbg->nsaved = 0; if (nsaved > 2) { printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } - for (i = 0; i < nsaved; i++) - write_long (child, child->tss.debug[i], child->tss.debug[i + 2]); + + for (i = 0; i < nsaved; i++) { + read_long(child, dbg->bp[i].address, &tmp); + if (tmp != BREAKINST) + printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); + write_long(child, dbg->bp[i].address, dbg->bp[i].insn); + } + return nsaved != 0; } @@ -598,8 +447,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) unsigned long tmp; ret = read_long(child, addr, &tmp); - if (ret >= 0) - ret = put_user(tmp, (unsigned long *)data); + if (ret) + put_user(tmp, (unsigned long *) data); goto out; } @@ -619,7 +468,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - ret = write_long(child,addr,data); + ret = write_long(child, addr, data); goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ @@ -665,7 +514,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->tss.debug[4] = -1; + child->thread.debug.nsaved = -1; child->flags &= ~PF_TRACESYS; wake_up_process(child); child->exit_code = data; diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c new file mode 100644 index 000000000..1bb21be3f --- /dev/null +++ b/arch/arm/kernel/semaphore.c @@ -0,0 +1,202 @@ +/* + * ARM semaphore implementation, taken from + * + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * + * Modified for ARM by Russell King + */ +#include <linux/sched.h> + +#include <asm/semaphore.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to aquire the semaphore, while the "sleeping" + * variable is a count of such aquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + wake_up(&sem->wait); + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + retval = -EINTR; + if (signal_pending(current)) { + sem->sleepers = 0; + if (atomic_add_negative(sleepers, &sem->count)) + break; + wake_up(&sem->wait); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + wake_up(&sem->wait); + retval = 0; + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +int __down_trylock(struct semaphore * sem) +{ + int sleepers; + + spin_lock_irq(&semaphore_lock); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irq(&semaphore_lock); + return 1; +} + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * r0 contains the semaphore pointer on entry. Save the C-clobbered + * registers (r0 to r3, ip and lr) except r0 in the cases where it + * is used as a return value.. + */ +asm(".align 5 + .globl __down_failed +__down_failed: + stmfd sp!, {r0 - r3, ip, lr} + bl __down + ldmfd sp!, {r0 - r3, ip, pc}"); + +asm(".align 5 + .globl __down_interruptible_failed +__down_interruptible_failed: + stmfd sp!, {r1 - r3, ip, lr} + bl __down_interruptible + ldmfd sp!, {r1 - r3, ip, pc}"); + +asm(".align 5 + .globl __down_trylock_failed +__down_trylock_failed: + stmfd sp!, {r1 - r3, ip, lr} + bl __down_trylock + ldmfd sp!, {r1 - r3, ip, pc}"); + +asm(".align 5 + .globl __up_wakeup +__up_wakeup: + stmfd sp!, {r0 - r3, ip, lr} + bl __up + ldmfd sp!, {r0 - r3, ip, pc}"); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0b0a70087..8258bd767 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/kernel/setup.c * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1999 Russell King */ /* @@ -38,24 +38,6 @@ #include <asm/setup.h> #include <asm/system.h> -/* Work out which CPUs to support */ -#ifdef CONFIG_ARCH_ACORN -#define SUPPORT_CPU_ARM6 -#define SUPPORT_CPU_ARM7 -#define SUPPORT_CPU_SA110 -#else -#define SUPPORT_CPU_SA110 -#endif -#ifdef CONFIG_CPU_ARM6 -#define SUPPORT_CPU_ARM6 -#endif -#ifdef CONFIG_CPU_ARM7 -#define SUPPORT_CPU_ARM7 -#endif -#ifdef CONFIG_CPU_SA110 -#define SUPPORT_CPU_SA110 -#endif - #define MEM_SIZE (16*1024*1024) #define COMMAND_LINE_SIZE 256 @@ -63,6 +45,10 @@ #define CONFIG_CMDLINE "" #endif +#ifndef PARAMS_BASE +#define PARAMS_BASE NULL +#endif + extern void reboot_setup(char *str, int *ints); extern void fpe_init(void); extern void disable_hlt(void); @@ -76,71 +62,32 @@ struct screen_info screen_info = { orig_video_isVGA: 1, orig_video_points: 8 }; -struct processor processor; + +extern int root_mountflags; +extern int _etext, _edata, _end; + unsigned char aux_device_present; -extern const struct processor arm2_processor_functions; -extern const struct processor arm250_processor_functions; -extern const struct processor arm3_processor_functions; -extern const struct processor arm6_processor_functions; -extern const struct processor arm7_processor_functions; -extern const struct processor sa110_processor_functions; - -char elf_platform[ELF_PLATFORM_SIZE]; - -const struct armversions armidlist[] = { - /*-- Match -- --- Mask -- -- Manu -- Processor uname -m --- ELF STUFF --- - --- processor asm funcs --- */ -#if defined(CONFIG_CPU_26) - /* ARM2 fake ident */ - { 0x41560200, 0xfffffff0, "ARM/VLSI", "arm2" , "armv1" , "v1", 0, - &arm2_processor_functions }, - /* ARM250 fake ident */ - { 0x41560250, 0xfffffff0, "ARM/VLSI", "arm250" , "armv2" , "v2", HWCAP_SWP, - &arm250_processor_functions }, - /* ARM3 processors */ - { 0x41560300, 0xfffffff0, "ARM/VLSI", "arm3" , "armv2" , "v2", HWCAP_SWP, - &arm3_processor_functions }, -#elif defined(CONFIG_CPU_32) -#ifdef SUPPORT_CPU_ARM6 - /* ARM6 */ - { 0x41560600, 0xfffffff0, "ARM/VLSI", "arm6" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, - /* ARM610 */ - { 0x41560610, 0xfffffff0, "ARM/VLSI", "arm610" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, -#endif -#ifdef SUPPORT_CPU_ARM7 - /* ARM7's have a strange numbering */ - { 0x41007000, 0xffffff00, "ARM/VLSI", "arm7" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, - /* ARM710 IDs are non-standard */ - { 0x41007100, 0xfff8ff00, "ARM/VLSI", "arm710" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, -#endif -#ifdef SUPPORT_CPU_SA110 -#ifdef CONFIG_ARCH_RPC - /* Acorn RiscPC's can't handle ARMv4 half-word instructions */ - { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP, - &sa110_processor_functions }, -#else - { 0x4401a100, 0xfffffff0, "Intel", "sa110" , "armv4" , "v4", HWCAP_SWP|HWCAP_HALF, - &sa110_processor_functions }, -#endif -#endif -#endif - { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL } -}; + char elf_platform[ELF_PLATFORM_SIZE]; +unsigned int elf_hwcap; /* * From head-armv.S */ unsigned int processor_id; unsigned int __machine_arch_type; -int armidindex; +#ifdef MULTI_CPU +struct processor processor; +#endif +#ifdef CONFIG_ARCH_ACORN +int memc_ctrl_reg; +int number_mfm_drives; +unsigned int vram_size; +#endif -extern int root_mountflags; -extern int _etext, _edata, _end; +static struct proc_info_item proc_info; +static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; +#define ENDIANNESS ((char)endian_test.l) /*------------------------------------------------------------------------- * Early initialisation routines for various configurable items in the @@ -152,8 +99,8 @@ extern int _etext, _edata, _end; * initial ram disk */ #ifdef CONFIG_BLK_DEV_INITRD -__initfunc(static void -check_initrd(unsigned long mem_start, unsigned long mem_end)) +static void __init +check_initrd(unsigned long mem_start, unsigned long mem_end) { if (initrd_end > mem_end) { printk ("initrd extends beyond end of memory " @@ -167,8 +114,8 @@ check_initrd(unsigned long mem_start, unsigned long mem_end)) #define check_initrd(ms,me) #endif -__initfunc(void -setup_processor(void)) +void __init +setup_processor(void) { armidindex = 0; @@ -187,8 +134,8 @@ static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; -__initfunc(static void -setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz)) +static void __init +setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz) { char c = ' ', *to = command_line; int len = 0; @@ -233,8 +180,8 @@ setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz)) *to = '\0'; } -__initfunc(static void -setup_ram(int doload, int prompt, int image_start)) +static void __init +setup_ram(int doload, int prompt, int image_start) { #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; @@ -250,8 +197,8 @@ setup_ram(int doload, int prompt, int image_start)) /* * initial ram disk */ -__initfunc(static void -setup_initrd(unsigned int start, unsigned int size)) +static void __init +setup_initrd(unsigned int start, unsigned int size) { #ifdef CONFIG_BLK_DEV_INITRD if (start) { @@ -277,8 +224,8 @@ unsigned int vram_size; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; #define ENDIANNESS ((char)endian_test.l) -__initfunc(void -setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { struct param_struct *params = (struct param_struct *)PARAMS_BASE; static unsigned char smptrap; @@ -297,10 +244,10 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem setup_processor(); - init_task.mm->start_code = TASK_SIZE; - init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; - init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; - init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + init_mm.start_code = TASK_SIZE; + init_mm.end_code = TASK_SIZE + (unsigned long) &_etext; + init_mm.end_data = TASK_SIZE + (unsigned long) &_edata; + init_mm.brk = TASK_SIZE + (unsigned long) &_end; /* * Add your machine dependencies here @@ -309,7 +256,13 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem case MACH_TYPE_EBSA110: /* EBSA110 locks if we execute 'wait for interrupt' */ disable_hlt(); - params = NULL; + if (params && params->u1.s.page_size != 4096) + params = NULL; + break; + + case MACH_TYPE_RISCPC: + /* RiscPC can't handle half-word loads and stores */ + elf_hwcap &= ~HWCAP_HALF; break; case MACH_TYPE_EBSA285: @@ -415,7 +368,7 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem from = params->commandline; } else { - ROOT_DEV = 0x00ff; + ROOT_DEV = to_kdev_t(0x00ff); setup_ram(1, 1, 0); setup_initrd(0, 0); @@ -441,9 +394,6 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem check_initrd(*memory_start_p, memory_end); - sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, ENDIANNESS); - sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, ENDIANNESS); - #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -462,7 +412,7 @@ static const char *machine_desc[] = { "unknown", "Nexus-FTV/PCI", "EBSA285", - "Corel-NetWinder", + "Rebel-NetWinder", "Chalice-CATS", "unknown-TBOX", "co-EBSA285", @@ -476,12 +426,13 @@ int get_cpuinfo(char * buffer) int len; len = sprintf(buffer, - "Processor\t: %s %s rev %d\n" + "Processor\t: %s %s rev %d (%s)\n" "BogoMips\t: %lu.%02lu\n" "Hardware\t: %s\n", - armidlist[armidindex].manu, - armidlist[armidindex].name, + proc_info.manufacturer, + proc_info.cpu_name, (int)processor_id & 15, + elf_platform, (loops_per_sec+2500) / 500000, ((loops_per_sec+2500) / 5000) % 100, machine_desc[machine_arch_type]); diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 5ec48f752..7b2f430c1 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -273,8 +273,8 @@ setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/ err |= __put_user (regs->ARM_cpsr, &sc->arm_cpsr); #endif - err |= __put_user (current->tss.trap_no, &sc->trap_no); - err |= __put_user (current->tss.error_code, &sc->error_code); + err |= __put_user (current->thread.trap_no, &sc->trap_no); + err |= __put_user (current->thread.error_code, &sc->error_code); err |= __put_user (mask, &sc->oldmask); return err; @@ -543,12 +543,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 4e49885b8..c48c62108 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -76,6 +76,25 @@ unsigned long mktime(unsigned int year, unsigned int mon, )*60 + sec; /* finally seconds */ } +/* + * Handle profile stuff... + */ +static void do_profile(unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + + pc -= (unsigned long)&_stext; + + pc >>= prof_shift; + + if (pc >= prof_len) + pc = prof_len - 1; + + prof_buffer[pc] += 1; + } +} + #include <asm/arch/time.h> static unsigned long do_gettimeoffset(void) @@ -130,7 +149,7 @@ void do_settimeofday(struct timeval *tv) sti(); } -__initfunc(void time_init(void)) +void __init time_init(void) { xtime.tv_usec = 0; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 9267fec09..9f9e6934f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -16,11 +16,11 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/spinlock.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> -#include <asm/spinlock.h> #include <asm/atomic.h> #include <asm/pgtable.h> @@ -198,8 +198,8 @@ void bad_user_access_alignment(const void *ptr) { printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, __builtin_return_address(0)); - current->tss.error_code = 0; - current->tss.trap_no = 11; + current->thread.error_code = 0; + current->thread.trap_no = 11; force_sig(SIGBUS, current); /* die_if_kernel("Oops - bad user access alignment", regs, mode);*/ } @@ -210,8 +210,8 @@ asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", current->comm, current->pid, instruction_pointer(regs)); #endif - current->tss.error_code = 0; - current->tss.trap_no = 6; + current->thread.error_code = 0; + current->thread.trap_no = 6; force_sig(SIGILL, current); die_if_kernel("Oops - undefined instruction", regs, mode); } @@ -222,8 +222,8 @@ asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", current->comm, current->pid, instruction_pointer(regs)); #endif - current->tss.error_code = 0; - current->tss.trap_no = 11; + current->thread.error_code = 0; + current->thread.trap_no = 11; force_sig(SIGBUS, current); die_if_kernel("Oops - address exception", regs, mode); } @@ -292,9 +292,7 @@ asmlinkage int arm_syscall (int no, struct pt_regs *regs) case 2: /* sys_cacheflush */ #ifdef CONFIG_CPU_32 /* r0 = start, r1 = length, r2 = flags */ - processor.u.armv3v4._flush_cache_area(regs->ARM_r0, - regs->ARM_r1, - 1); + cpu_flush_cache_area(regs->ARM_r0, regs->ARM_r1, 1); #endif break; @@ -367,7 +365,7 @@ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs { pgd_t *pgd; - printk ("current->tss.memmap = %08lX\n", current->tss.memmap); + printk ("current->thread.memmap = %08lX\n", current->thread.memmap); pgd = pgd_offset(current->mm, addr); printk ("*pgd = %08lx", pgd_val (*pgd)); if (!pgd_none (*pgd)) { @@ -387,3 +385,9 @@ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs code, regs->ARM_pc, instr, regs->ARM_lr, regs->ARM_sp); } #endif + +asmlinkage void __div0(void) +{ + printk("Awooga, division by zero in kernel.\n"); + __backtrace(); +} |