aboutsummaryrefslogtreecommitdiff
path: root/arch/cris/arch-v32/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris/arch-v32/kernel')
-rw-r--r--arch/cris/arch-v32/kernel/Makefile7
-rw-r--r--arch/cris/arch-v32/kernel/arbiter.c296
-rw-r--r--arch/cris/arch-v32/kernel/asm-offsets.c49
-rw-r--r--arch/cris/arch-v32/kernel/cache.c33
-rw-r--r--arch/cris/arch-v32/kernel/cacheflush.S99
-rw-r--r--arch/cris/arch-v32/kernel/crisksyms.c15
-rw-r--r--arch/cris/arch-v32/kernel/debugport.c343
-rw-r--r--arch/cris/arch-v32/kernel/dma.c224
-rw-r--r--arch/cris/arch-v32/kernel/entry.S222
-rw-r--r--arch/cris/arch-v32/kernel/fasttimer.c803
-rw-r--r--arch/cris/arch-v32/kernel/head.S261
-rw-r--r--arch/cris/arch-v32/kernel/io.c153
-rw-r--r--arch/cris/arch-v32/kernel/irq.c347
-rw-r--r--arch/cris/arch-v32/kernel/kgdb.c92
-rw-r--r--arch/cris/arch-v32/kernel/kgdb_asm.S2
-rw-r--r--arch/cris/arch-v32/kernel/pinmux.c229
-rw-r--r--arch/cris/arch-v32/kernel/process.c153
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c148
-rw-r--r--arch/cris/arch-v32/kernel/setup.c80
-rw-r--r--arch/cris/arch-v32/kernel/signal.c229
-rw-r--r--arch/cris/arch-v32/kernel/smp.c121
-rw-r--r--arch/cris/arch-v32/kernel/time.c327
-rw-r--r--arch/cris/arch-v32/kernel/traps.c196
-rw-r--r--arch/cris/arch-v32/kernel/vcs_hook.c96
-rw-r--r--arch/cris/arch-v32/kernel/vcs_hook.h42
25 files changed, 1551 insertions, 3016 deletions
diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile
index 5d5b613cde8..40358355d0c 100644
--- a/arch/cris/arch-v32/kernel/Makefile
+++ b/arch/cris/arch-v32/kernel/Makefile
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $
#
# Makefile for the linux kernel.
#
@@ -6,11 +5,9 @@
extra-y := head.o
-obj-y := entry.o traps.o irq.o debugport.o dma.o pinmux.o \
+obj-y := entry.o traps.o irq.o debugport.o \
process.o ptrace.o setup.o signal.o traps.o time.o \
- arbiter.o io.o
-
-obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o
+ cache.o cacheflush.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_ETRAX_KGDB) += kgdb.o kgdb_asm.o
diff --git a/arch/cris/arch-v32/kernel/arbiter.c b/arch/cris/arch-v32/kernel/arbiter.c
deleted file mode 100644
index 420a5312ed0..00000000000
--- a/arch/cris/arch-v32/kernel/arbiter.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Memory arbiter functions. Allocates bandwidth through the
- * arbiter and sets up arbiter breakpoints.
- *
- * The algorithm first assigns slots to the clients that has specified
- * bandwidth (e.g. ethernet) and then the remaining slots are divided
- * on all the active clients.
- *
- * Copyright (c) 2004, 2005 Axis Communications AB.
- */
-
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/marb_defs.h>
-#include <asm/arch/arbiter.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-struct crisv32_watch_entry
-{
- unsigned long instance;
- watch_callback* cb;
- unsigned long start;
- unsigned long end;
- int used;
-};
-
-#define NUMBER_OF_BP 4
-#define NBR_OF_CLIENTS 14
-#define NBR_OF_SLOTS 64
-#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */
-#define INTMEM_BANDWIDTH 400000000
-#define NBR_OF_REGIONS 2
-
-static struct crisv32_watch_entry watches[NUMBER_OF_BP] =
-{
- {regi_marb_bp0},
- {regi_marb_bp1},
- {regi_marb_bp2},
- {regi_marb_bp3}
-};
-
-static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
-static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
-static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
-
-DEFINE_SPINLOCK(arbiter_lock);
-
-static irqreturn_t
-crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs);
-
-static void crisv32_arbiter_config(int region)
-{
- int slot;
- int client;
- int interval = 0;
- int val[NBR_OF_SLOTS];
-
- for (slot = 0; slot < NBR_OF_SLOTS; slot++)
- val[slot] = NBR_OF_CLIENTS + 1;
-
- for (client = 0; client < NBR_OF_CLIENTS; client++)
- {
- int pos;
- if (!requested_slots[region][client])
- continue;
- interval = NBR_OF_SLOTS / requested_slots[region][client];
- pos = 0;
- while (pos < NBR_OF_SLOTS)
- {
- if (val[pos] != NBR_OF_CLIENTS + 1)
- pos++;
- else
- {
- val[pos] = client;
- pos += interval;
- }
- }
- }
-
- client = 0;
- for (slot = 0; slot < NBR_OF_SLOTS; slot++)
- {
- if (val[slot] == NBR_OF_CLIENTS + 1)
- {
- int first = client;
- while(!active_clients[region][client]) {
- client = (client + 1) % NBR_OF_CLIENTS;
- if (client == first)
- break;
- }
- val[slot] = client;
- client = (client + 1) % NBR_OF_CLIENTS;
- }
- if (region == EXT_REGION)
- REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, val[slot]);
- else if (region == INT_REGION)
- REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, val[slot]);
- }
-}
-
-extern char _stext, _etext;
-
-static void crisv32_arbiter_init(void)
-{
- static int initialized = 0;
-
- if (initialized)
- return;
-
- initialized = 1;
-
- /* CPU caches are active. */
- active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
- crisv32_arbiter_config(EXT_REGION);
- crisv32_arbiter_config(INT_REGION);
-
- if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
- "arbiter", NULL))
- printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
-
-#ifndef CONFIG_ETRAX_KGDB
- /* Global watch for writes to kernel text segment. */
- crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
- arbiter_all_clients, arbiter_all_write, NULL);
-#endif
-}
-
-
-
-int crisv32_arbiter_allocate_bandwidth(int client, int region,
- unsigned long bandwidth)
-{
- int i;
- int total_assigned = 0;
- int total_clients = 0;
- int req;
-
- crisv32_arbiter_init();
-
- for (i = 0; i < NBR_OF_CLIENTS; i++)
- {
- total_assigned += requested_slots[region][i];
- total_clients += active_clients[region][i];
- }
- req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
-
- if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS)
- return -ENOMEM;
-
- active_clients[region][client] = 1;
- requested_slots[region][client] = req;
- crisv32_arbiter_config(region);
-
- return 0;
-}
-
-int crisv32_arbiter_watch(unsigned long start, unsigned long size,
- unsigned long clients, unsigned long accesses,
- watch_callback* cb)
-{
- int i;
-
- crisv32_arbiter_init();
-
- if (start > 0x80000000) {
- printk("Arbiter: %lX doesn't look like a physical address", start);
- return -EFAULT;
- }
-
- spin_lock(&arbiter_lock);
-
- for (i = 0; i < NUMBER_OF_BP; i++) {
- if (!watches[i].used) {
- reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
-
- watches[i].used = 1;
- watches[i].start = start;
- watches[i].end = start + size;
- watches[i].cb = cb;
-
- REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, watches[i].start);
- REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, watches[i].end);
- REG_WR_INT(marb_bp, watches[i].instance, rw_op, accesses);
- REG_WR_INT(marb_bp, watches[i].instance, rw_clients, clients);
-
- if (i == 0)
- intr_mask.bp0 = regk_marb_yes;
- else if (i == 1)
- intr_mask.bp1 = regk_marb_yes;
- else if (i == 2)
- intr_mask.bp2 = regk_marb_yes;
- else if (i == 3)
- intr_mask.bp3 = regk_marb_yes;
-
- REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
- spin_unlock(&arbiter_lock);
-
- return i;
- }
- }
- spin_unlock(&arbiter_lock);
- return -ENOMEM;
-}
-
-int crisv32_arbiter_unwatch(int id)
-{
- reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
-
- crisv32_arbiter_init();
-
- spin_lock(&arbiter_lock);
-
- if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
- spin_unlock(&arbiter_lock);
- return -EINVAL;
- }
-
- memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
-
- if (id == 0)
- intr_mask.bp0 = regk_marb_no;
- else if (id == 1)
- intr_mask.bp2 = regk_marb_no;
- else if (id == 2)
- intr_mask.bp2 = regk_marb_no;
- else if (id == 3)
- intr_mask.bp3 = regk_marb_no;
-
- REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
-
- spin_unlock(&arbiter_lock);
- return 0;
-}
-
-extern void show_registers(struct pt_regs *regs);
-
-static irqreturn_t
-crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs)
-{
- reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, r_masked_intr);
- reg_marb_bp_r_brk_clients r_clients;
- reg_marb_bp_r_brk_addr r_addr;
- reg_marb_bp_r_brk_op r_op;
- reg_marb_bp_r_brk_first_client r_first;
- reg_marb_bp_r_brk_size r_size;
- reg_marb_bp_rw_ack ack = {0};
- reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1};
- struct crisv32_watch_entry* watch;
-
- if (masked_intr.bp0) {
- watch = &watches[0];
- ack_intr.bp0 = regk_marb_yes;
- } else if (masked_intr.bp1) {
- watch = &watches[1];
- ack_intr.bp1 = regk_marb_yes;
- } else if (masked_intr.bp2) {
- watch = &watches[2];
- ack_intr.bp2 = regk_marb_yes;
- } else if (masked_intr.bp3) {
- watch = &watches[3];
- ack_intr.bp3 = regk_marb_yes;
- } else {
- return IRQ_NONE;
- }
-
- /* Retrieve all useful information and print it. */
- r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
- r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
- r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
- r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
- r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
-
- printk("Arbiter IRQ\n");
- printk("Clients %X addr %X op %X first %X size %X\n",
- REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
- REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
- REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
- REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
- REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
-
- REG_WR(marb_bp, watch->instance, rw_ack, ack);
- REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
-
- printk("IRQ occured at %lX\n", regs->erp);
-
- if (watch->cb)
- watch->cb();
-
-
- return IRQ_HANDLED;
-}
diff --git a/arch/cris/arch-v32/kernel/asm-offsets.c b/arch/cris/arch-v32/kernel/asm-offsets.c
deleted file mode 100644
index 15b3d93a049..00000000000
--- a/arch/cris/arch-v32/kernel/asm-offsets.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <linux/sched.h>
-#include <asm/thread_info.h>
-
-/*
- * Generate definitions needed by assembly language modules.
- * This code generates raw asm output which is post-processed to extract
- * and format the required data.
- */
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-int main(void)
-{
-#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry))
- ENTRY(orig_r10);
- ENTRY(r13);
- ENTRY(r12);
- ENTRY(r11);
- ENTRY(r10);
- ENTRY(r9);
- ENTRY(acr);
- ENTRY(srs);
- ENTRY(mof);
- ENTRY(ccs);
- ENTRY(srp);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
- ENTRY(task);
- ENTRY(flags);
- ENTRY(preempt_count);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry))
- ENTRY(ksp);
- ENTRY(usp);
- ENTRY(ccs);
- BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry))
- ENTRY(pid);
- BLANK();
- DEFINE(LCLONE_VM, CLONE_VM);
- DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED);
- return 0;
-}
diff --git a/arch/cris/arch-v32/kernel/cache.c b/arch/cris/arch-v32/kernel/cache.c
new file mode 100644
index 00000000000..f38433b1f86
--- /dev/null
+++ b/arch/cris/arch-v32/kernel/cache.c
@@ -0,0 +1,33 @@
+#include <linux/module.h>
+#include <asm/io.h>
+#include <arch/cache.h>
+#include <arch/hwregs/dma.h>
+
+/* This file is used to workaround a cache bug, Guinness TR 106. */
+
+inline void flush_dma_descr(struct dma_descr_data *descr, int flush_buf)
+{
+ /* Flush descriptor to make sure we get correct in_eop and after. */
+ asm volatile ("ftagd [%0]" :: "r" (descr));
+ /* Flush buffer pointed out by descriptor. */
+ if (flush_buf)
+ cris_flush_cache_range(phys_to_virt((unsigned)descr->buf),
+ (unsigned)(descr->after - descr->buf));
+}
+EXPORT_SYMBOL(flush_dma_descr);
+
+void flush_dma_list(struct dma_descr_data *descr)
+{
+ while (1) {
+ flush_dma_descr(descr, 1);
+ if (descr->eol)
+ break;
+ descr = phys_to_virt((unsigned)descr->next);
+ }
+}
+EXPORT_SYMBOL(flush_dma_list);
+
+/* From cacheflush.S */
+EXPORT_SYMBOL(cris_flush_cache);
+/* From cacheflush.S */
+EXPORT_SYMBOL(cris_flush_cache_range);
diff --git a/arch/cris/arch-v32/kernel/cacheflush.S b/arch/cris/arch-v32/kernel/cacheflush.S
new file mode 100644
index 00000000000..6fc3d95d702
--- /dev/null
+++ b/arch/cris/arch-v32/kernel/cacheflush.S
@@ -0,0 +1,99 @@
+ .global cris_flush_cache_range
+ .type cris_flush_cache_range, @function
+cris_flush_cache_range:
+ move.d 1024, $r12
+ cmp.d $r11, $r12
+ bhi cris_flush_1KB
+ nop
+ add.d $r10, $r11
+ ftagd [$r10]
+cris_flush_last:
+ addq 32, $r10
+ cmp.d $r11, $r10
+ blt cris_flush_last
+ ftagd [$r10]
+ ret
+ nop
+cris_flush_1KB:
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ftagd [$r10]
+ addq 32, $r10
+ ba cris_flush_cache_range
+ sub.d $r12, $r11
+ .size cris_flush_cache_range, . - cris_flush_cache_range
+
+ .global cris_flush_cache
+ .type cris_flush_cache, @function
+cris_flush_cache:
+ moveq 0, $r10
+cris_flush_line:
+ move.d 16*1024, $r11
+ addq 16, $r10
+ cmp.d $r10, $r11
+ blt cris_flush_line
+ fidxd [$r10]
+ ret
+ nop
+ .size cris_flush_cache, . - cris_flush_cache
+
diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c
index e513da71124..bde8d1a10ca 100644
--- a/arch/cris/arch-v32/kernel/crisksyms.c
+++ b/arch/cris/arch-v32/kernel/crisksyms.c
@@ -1,8 +1,9 @@
#include <linux/module.h>
#include <linux/irq.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/intmem.h>
-#include <asm/arch/pinmux.h>
+#include <arch/dma.h>
+#include <arch/intmem.h>
+#include <mach/pinmux.h>
+#include <arch/io.h>
/* Functions for allocating DMA channels */
EXPORT_SYMBOL(crisv32_request_dma);
@@ -16,8 +17,12 @@ EXPORT_SYMBOL(crisv32_intmem_virt_to_phys);
/* Functions for handling pinmux */
EXPORT_SYMBOL(crisv32_pinmux_alloc);
+EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed);
EXPORT_SYMBOL(crisv32_pinmux_dealloc);
+EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed);
+EXPORT_SYMBOL(crisv32_io_get_name);
+EXPORT_SYMBOL(crisv32_io_get);
/* Functions masking/unmasking interrupts */
-EXPORT_SYMBOL(mask_irq);
-EXPORT_SYMBOL(unmask_irq);
+EXPORT_SYMBOL(crisv32_mask_irq);
+EXPORT_SYMBOL(crisv32_unmask_irq);
diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c
index d1272ad9215..610909b003f 100644
--- a/arch/cris/arch-v32/kernel/debugport.c
+++ b/arch/cris/arch-v32/kernel/debugport.c
@@ -4,17 +4,11 @@
#include <linux/console.h>
#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/arch/hwregs/ser_defs.h>
-#include <asm/arch/hwregs/dma_defs.h>
-#include <asm/arch/pinmux.h>
-
-#include <asm/irq.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/ser_defs.h>
+#include <hwregs/dma_defs.h>
+#include <mach/pinmux.h>
struct dbg_port
{
@@ -59,45 +53,50 @@ struct dbg_port ports[] =
115200,
'N',
8
- }
+ },
+#if CONFIG_ETRAX_SERIAL_PORTS == 5
+ {
+ 4,
+ regi_ser4,
+ 0,
+ 115200,
+ 'N',
+ 8
+ },
+#endif
};
static struct dbg_port *port =
#if defined(CONFIG_ETRAX_DEBUG_PORT0)
-&ports[0];
+ &ports[0];
#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
-&ports[1];
+ &ports[1];
#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
-&ports[2];
+ &ports[2];
#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
-&ports[3];
+ &ports[3];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT4)
+ &ports[4];
#else
-NULL;
+ NULL;
#endif
#ifdef CONFIG_ETRAX_KGDB
static struct dbg_port *kgdb_port =
#if defined(CONFIG_ETRAX_KGDB_PORT0)
-&ports[0];
+ &ports[0];
#elif defined(CONFIG_ETRAX_KGDB_PORT1)
-&ports[1];
+ &ports[1];
#elif defined(CONFIG_ETRAX_KGDB_PORT2)
-&ports[2];
+ &ports[2];
#elif defined(CONFIG_ETRAX_KGDB_PORT3)
-&ports[3];
+ &ports[3];
+#elif defined(CONFIG_ETRAX_KGDB_PORT4)
+ &ports[4];
#else
-NULL;
+ NULL;
#endif
#endif
-#ifdef CONFIG_ETRAXFS_SIM
-extern void print_str( const char *str );
-static char buffer[1024];
-static char msg[] = "Debug: ";
-static int buffer_pos = sizeof(msg) - 1;
-#endif
-
-extern struct tty_driver *serial_driver;
-
static void
start_port(struct dbg_port* p)
{
@@ -114,6 +113,10 @@ start_port(struct dbg_port* p)
crisv32_pinmux_alloc_fixed(pinmux_ser2);
else if (p->nbr == 3)
crisv32_pinmux_alloc_fixed(pinmux_ser3);
+#if CONFIG_ETRAX_SERIAL_PORTS == 5
+ else if (p->nbr == 4)
+ crisv32_pinmux_alloc_fixed(pinmux_ser4);
+#endif
/* Set up serial port registers */
reg_ser_rw_tr_ctrl tr_ctrl = {0};
@@ -156,124 +159,21 @@ start_port(struct dbg_port* p)
REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl);
}
-/* No debug */
-#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
- return;
-}
-
-/* Target debug */
-#elif !defined(CONFIG_ETRAXFS_SIM)
-
-static void
-console_write_direct(struct console *co, const char *buf, unsigned int len)
-{
- int i;
- reg_ser_r_stat_din stat;
- reg_ser_rw_tr_dma_en tr_dma_en, old;
-
- /* Switch to manual mode */
- tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en);
- if (tr_dma_en.en == regk_ser_yes) {
- tr_dma_en.en = regk_ser_no;
- REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en);
- }
-
- /* Send data */
- for (i = 0; i < len; i++) {
- /* LF -> CRLF */
- if (buf[i] == '\n') {
- do {
- stat = REG_RD (ser, port->instance, r_stat_din);
- } while (!stat.tr_rdy);
- REG_WR_INT (ser, port->instance, rw_dout, '\r');
- }
- /* Wait until transmitter is ready and send.*/
- do {
- stat = REG_RD (ser, port->instance, r_stat_din);
- } while (!stat.tr_rdy);
- REG_WR_INT (ser, port->instance, rw_dout, buf[i]);
- }
-
- /* Restore mode */
- if (tr_dma_en.en != old.en)
- REG_WR(ser, port->instance, rw_tr_dma_en, old);
-}
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
- if (!port)
- return;
- console_write_direct(co, buf, len);
-}
-
-
-
-#else
-
-/* VCS debug */
-
-static void
-console_write(struct console *co, const char *buf, unsigned int len)
-{
- char* pos;
- pos = memchr(buf, '\n', len);
- if (pos) {
- int l = ++pos - buf;
- memcpy(buffer + buffer_pos, buf, l);
- memcpy(buffer, msg, sizeof(msg) - 1);
- buffer[buffer_pos + l] = '\0';
- print_str(buffer);
- buffer_pos = sizeof(msg) - 1;
- if (pos - buf != len) {
- memcpy(buffer + buffer_pos, pos, len - l);
- buffer_pos += len - l;
- }
- } else {
- memcpy(buffer + buffer_pos, buf, len);
- buffer_pos += len;
- }
-}
-
-#endif
-
-int raw_printk(const char *fmt, ...)
-{
- static char buf[1024];
- int printed_len;
- va_list args;
- va_start(args, fmt);
- printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
- console_write(NULL, buf, strlen(buf));
- return printed_len;
-}
-
-void
-stupid_debug(char* buf)
-{
- console_write(NULL, buf, strlen(buf));
-}
-
#ifdef CONFIG_ETRAX_KGDB
/* Use polling to get a single character from the kernel debug port */
int
getDebugChar(void)
{
- reg_ser_rs_status_data stat;
+ reg_ser_rs_stat_din stat;
reg_ser_rw_ack_intr ack_intr = { 0 };
do {
- stat = REG_RD(ser, kgdb_instance, rs_status_data);
- } while (!stat.data_avail);
+ stat = REG_RD(ser, kgdb_port->instance, rs_stat_din);
+ } while (!stat.dav);
/* Ack the data_avail interrupt. */
- ack_intr.data_avail = 1;
- REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr);
+ ack_intr.dav = 1;
+ REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr);
return stat.data;
}
@@ -282,173 +182,18 @@ getDebugChar(void)
void
putDebugChar(int val)
{
- reg_ser_r_status_data stat;
+ reg_ser_r_stat_din stat;
do {
- stat = REG_RD (ser, kgdb_instance, r_status_data);
- } while (!stat.tr_ready);
- REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val));
+ stat = REG_RD(ser, kgdb_port->instance, r_stat_din);
+ } while (!stat.tr_rdy);
+ REG_WR_INT(ser, kgdb_port->instance, rw_dout, val);
}
#endif /* CONFIG_ETRAX_KGDB */
-static int __init
-console_setup(struct console *co, char *options)
-{
- char* s;
-
- if (options) {
- port = &ports[co->index];
- port->baudrate = 115200;
- port->parity = 'N';
- port->bits = 8;
- port->baudrate = simple_strtoul(options, NULL, 10);
- s = options;
- while(*s >= '0' && *s <= '9')
- s++;
- if (*s) port->parity = *s++;
- if (*s) port->bits = *s++ - '0';
- port->started = 0;
- start_port(port);
- }
- return 0;
-}
-
-/* This is a dummy serial device that throws away anything written to it.
- * This is used when no debug output is wanted.
- */
-static struct tty_driver dummy_driver;
-
-static int dummy_open(struct tty_struct *tty, struct file * filp)
-{
- return 0;
-}
-
-static void dummy_close(struct tty_struct *tty, struct file * filp)
-{
-}
-
-static int dummy_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- return count;
-}
-
-static int
-dummy_write_room(struct tty_struct *tty)
-{
- return 8192;
-}
-
-void __init
-init_dummy_console(void)
-{
- memset(&dummy_driver, 0, sizeof(struct tty_driver));
- dummy_driver.driver_name = "serial";
- dummy_driver.name = "ttyS";
- dummy_driver.major = TTY_MAJOR;
- dummy_driver.minor_start = 68;
- dummy_driver.num = 1; /* etrax100 has 4 serial ports */
- dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
- dummy_driver.subtype = SERIAL_TYPE_NORMAL;
- dummy_driver.init_termios = tty_std_termios;
- dummy_driver.init_termios.c_cflag =
- B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
- dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-
- dummy_driver.open = dummy_open;
- dummy_driver.close = dummy_close;
- dummy_driver.write = dummy_write;
- dummy_driver.write_room = dummy_write_room;
- if (tty_register_driver(&dummy_driver))
- panic("Couldn't register dummy serial driver\n");
-}
-
-static struct tty_driver*
-crisv32_console_device(struct console* co, int *index)
-{
- if (port)
- *index = port->nbr;
- return port ? serial_driver : &dummy_driver;
-}
-
-static struct console sercons = {
- name : "ttyS",
- write: console_write,
- read : NULL,
- device : crisv32_console_device,
- unblank : NULL,
- setup : console_setup,
- flags : CON_PRINTBUFFER,
- index : -1,
- cflag : 0,
- next : NULL
-};
-static struct console sercons0 = {
- name : "ttyS",
- write: console_write,
- read : NULL,
- device : crisv32_console_device,
- unblank : NULL,
- setup : console_setup,
- flags : CON_PRINTBUFFER,
- index : 0,
- cflag : 0,
- next : NULL
-};
-
-static struct console sercons1 = {
- name : "ttyS",
- write: console_write,
- read : NULL,
- device : crisv32_console_device,
- unblank : NULL,
- setup : console_setup,
- flags : CON_PRINTBUFFER,
- index : 1,
- cflag : 0,
- next : NULL
-};
-static struct console sercons2 = {
- name : "ttyS",
- write: console_write,
- read : NULL,
- device : crisv32_console_device,
- unblank : NULL,
- setup : console_setup,
- flags : CON_PRINTBUFFER,
- index : 2,
- cflag : 0,
- next : NULL
-};
-static struct console sercons3 = {
- name : "ttyS",
- write: console_write,
- read : NULL,
- device : crisv32_console_device,
- unblank : NULL,
- setup : console_setup,
- flags : CON_PRINTBUFFER,
- index : 3,
- cflag : 0,
- next : NULL
-};
-
/* Register console for printk's, etc. */
int __init
init_etrax_debug(void)
{
- static int first = 1;
-
- if (!first) {
- unregister_console(&sercons);
- register_console(&sercons0);
- register_console(&sercons1);
- register_console(&sercons2);
- register_console(&sercons3);
- init_dummy_console();
- return 0;
- }
- first = 0;
- register_console(&sercons);
start_port(port);
#ifdef CONFIG_ETRAX_KGDB
@@ -456,5 +201,3 @@ init_etrax_debug(void)
#endif /* CONFIG_ETRAX_KGDB */
return 0;
}
-
-__initcall(init_etrax_debug);
diff --git a/arch/cris/arch-v32/kernel/dma.c b/arch/cris/arch-v32/kernel/dma.c
deleted file mode 100644
index 570e19128ff..00000000000
--- a/arch/cris/arch-v32/kernel/dma.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Wrapper for DMA channel allocator that starts clocks etc */
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <asm/dma.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/marb_defs.h>
-#include <asm/arch/hwregs/config_defs.h>
-#include <asm/arch/hwregs/strmux_defs.h>
-#include <linux/errno.h>
-#include <asm/system.h>
-#include <asm/arch/arbiter.h>
-
-static char used_dma_channels[MAX_DMA_CHANNELS];
-static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
-
-static DEFINE_SPINLOCK(dma_lock);
-
-int crisv32_request_dma(unsigned int dmanr, const char * device_id,
- unsigned options, unsigned int bandwidth,
- enum dma_owner owner)
-{
- unsigned long flags;
- reg_config_rw_clk_ctrl clk_ctrl;
- reg_strmux_rw_cfg strmux_cfg;
-
- if (crisv32_arbiter_allocate_bandwidth(dmanr,
- options & DMA_INT_MEM ? INT_REGION : EXT_REGION,
- bandwidth))
- return -ENOMEM;
-
- spin_lock_irqsave(&dma_lock, flags);
-
- if (used_dma_channels[dmanr]) {
- spin_unlock_irqrestore(&dma_lock, flags);
- if (options & DMA_VERBOSE_ON_ERROR) {
- printk("Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
- }
- if (options & DMA_PANIC_ON_ERROR)
- panic("request_dma error!");
- return -EBUSY;
- }
- clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
- strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
-
- switch(dmanr)
- {
- case 0:
- case 1:
- clk_ctrl.dma01_eth0 = 1;
- break;
- case 2:
- case 3:
- clk_ctrl.dma23 = 1;
- break;
- case 4:
- case 5:
- clk_ctrl.dma45 = 1;
- break;
- case 6:
- case 7:
- clk_ctrl.dma67 = 1;
- break;
- case 8:
- case 9:
- clk_ctrl.dma89_strcop = 1;
- break;
-#if MAX_DMA_CHANNELS-1 != 9
-#error Check dma.c
-#endif
- default:
- spin_unlock_irqrestore(&dma_lock, flags);
- if (options & DMA_VERBOSE_ON_ERROR) {
- printk("Failed to request DMA %i for %s, only 0-%i valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1);
- }
-
- if (options & DMA_PANIC_ON_ERROR)
- panic("request_dma error!");
- return -EINVAL;
- }
-
- switch(owner)
- {
- case dma_eth0:
- if (dmanr == 0)
- strmux_cfg.dma0 = regk_strmux_eth0;
- else if (dmanr == 1)
- strmux_cfg.dma1 = regk_strmux_eth0;
- else
- panic("Invalid DMA channel for eth0\n");
- break;
- case dma_eth1:
- if (dmanr == 6)
- strmux_cfg.dma6 = regk_strmux_eth1;
- else if (dmanr == 7)
- strmux_cfg.dma7 = regk_strmux_eth1;
- else
- panic("Invalid DMA channel for eth1\n");
- break;
- case dma_iop0:
- if (dmanr == 2)
- strmux_cfg.dma2 = regk_strmux_iop0;
- else if (dmanr == 3)
- strmux_cfg.dma3 = regk_strmux_iop0;
- else
- panic("Invalid DMA channel for iop0\n");
- break;
- case dma_iop1:
- if (dmanr == 4)
- strmux_cfg.dma4 = regk_strmux_iop1;
- else if (dmanr == 5)
- strmux_cfg.dma5 = regk_strmux_iop1;
- else
- panic("Invalid DMA channel for iop1\n");
- break;
- case dma_ser0:
- if (dmanr == 6)
- strmux_cfg.dma6 = regk_strmux_ser0;
- else if (dmanr == 7)
- strmux_cfg.dma7 = regk_strmux_ser0;
- else
- panic("Invalid DMA channel for ser0\n");
- break;
- case dma_ser1:
- if (dmanr == 4)
- strmux_cfg.dma4 = regk_strmux_ser1;
- else if (dmanr == 5)
- strmux_cfg.dma5 = regk_strmux_ser1;
- else
- panic("Invalid DMA channel for ser1\n");
- break;
- case dma_ser2:
- if (dmanr == 2)
- strmux_cfg.dma2 = regk_strmux_ser2;
- else if (dmanr == 3)
- strmux_cfg.dma3 = regk_strmux_ser2;
- else
- panic("Invalid DMA channel for ser2\n");
- break;
- case dma_ser3:
- if (dmanr == 8)
- strmux_cfg.dma8 = regk_strmux_ser3;
- else if (dmanr == 9)
- strmux_cfg.dma9 = regk_strmux_ser3;
- else
- panic("Invalid DMA channel for ser3\n");
- break;
- case dma_sser0:
- if (dmanr == 4)
- strmux_cfg.dma4 = regk_strmux_sser0;
- else if (dmanr == 5)
- strmux_cfg.dma5 = regk_strmux_sser0;
- else
- panic("Invalid DMA channel for sser0\n");
- break;
- case dma_sser1:
- if (dmanr == 6)
- strmux_cfg.dma6 = regk_strmux_sser1;
- else if (dmanr == 7)
- strmux_cfg.dma7 = regk_strmux_sser1;
- else
- panic("Invalid DMA channel for sser1\n");
- break;
- case dma_ata:
- if (dmanr == 2)
- strmux_cfg.dma2 = regk_strmux_ata;
- else if (dmanr == 3)
- strmux_cfg.dma3 = regk_strmux_ata;
- else
- panic("Invalid DMA channel for ata\n");
- break;
- case dma_strp:
- if (dmanr == 8)
- strmux_cfg.dma8 = regk_strmux_strcop;
- else if (dmanr == 9)
- strmux_cfg.dma9 = regk_strmux_strcop;
- else
- panic("Invalid DMA channel for strp\n");
- break;
- case dma_ext0:
- if (dmanr == 6)
- strmux_cfg.dma6 = regk_strmux_ext0;
- else
- panic("Invalid DMA channel for ext0\n");
- break;
- case dma_ext1:
- if (dmanr == 7)
- strmux_cfg.dma7 = regk_strmux_ext1;
- else
- panic("Invalid DMA channel for ext1\n");
- break;
- case dma_ext2:
- if (dmanr == 2)
- strmux_cfg.dma2 = regk_strmux_ext2;
- else if (dmanr == 8)
- strmux_cfg.dma8 = regk_strmux_ext2;
- else
- panic("Invalid DMA channel for ext2\n");
- break;
- case dma_ext3:
- if (dmanr == 3)
- strmux_cfg.dma3 = regk_strmux_ext3;
- else if (dmanr == 9)
- strmux_cfg.dma9 = regk_strmux_ext2;
- else
- panic("Invalid DMA channel for ext2\n");
- break;
- }
-
- used_dma_channels[dmanr] = 1;
- used_dma_channels_users[dmanr] = device_id;
- REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
- REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
- spin_unlock_irqrestore(&dma_lock,flags);
- return 0;
-}
-
-void crisv32_free_dma(unsigned int dmanr)
-{
- spin_lock(&dma_lock);
- used_dma_channels[dmanr] = 0;
- spin_unlock(&dma_lock);
-}
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S
index f9d27807b91..2f19ac6217a 100644
--- a/arch/cris/arch-v32/kernel/entry.S
+++ b/arch/cris/arch-v32/kernel/entry.S
@@ -10,7 +10,7 @@
* after a timer-interrupt and after each system call.
*
* Stack layout in 'ret_from_system_call':
- * ptrace needs to have all regs on the stack.
+ * ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
* ptrace.c and ptrace.h
@@ -24,13 +24,14 @@
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/intr_vect_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <hwregs/asm/intr_vect_defs_asm.h>
;; Exported functions.
.globl system_call
.globl ret_from_intr
.globl ret_from_fork
+ .globl ret_from_kernel_thread
.globl resume
.globl multiple_interrupt
.globl nmi_interrupt
@@ -76,12 +77,27 @@ _need_resched:
; Called at exit from fork. schedule_tail must be called to drop
; spinlock if CONFIG_PREEMPT.
+ .type ret_from_fork,@function
ret_from_fork:
jsr schedule_tail
nop
ba ret_from_sys_call
nop
+ .size ret_from_fork, . - ret_from_fork
+ .type ret_from_kernel_thread,@function
+ret_from_kernel_thread:
+ jsr schedule_tail
+ nop
+ move.d $r2, $r10
+ jsr $r1
+ nop
+ moveq 0, $r9 ; no syscall restarts, TYVM...
+ ba ret_from_sys_call
+ nop
+ .size ret_from_kernel_thread, . - ret_from_kernel_thread
+
+ .type ret_from_intr,@function
ret_from_intr:
;; Check for resched if preemptive kernel, or if we're going back to
;; user-mode. This test matches the user_regs(regs) macro. Don't simply
@@ -91,9 +107,10 @@ ret_from_intr:
move.d [$acr], $r0
btstq 16, $r0 ; User-mode flag.
bpl _resume_kernel
+ .size ret_from_intr, . - ret_from_intr + 2 ; +2 includes the dslot.
; Note that di below is in delay slot.
-
+ .type _resume_userspace,@function
_resume_userspace:
di ; So need_resched and sigpending don't change.
@@ -107,6 +124,7 @@ _resume_userspace:
nop
ba _Rexit
nop
+ .size _resume_userspace, . - _resume_userspace
;; The system_call is called by a BREAK instruction, which looks pretty
;; much like any other exception.
@@ -122,30 +140,28 @@ _resume_userspace:
;; non-used instructions. Only the non-common cases cause the outlined code
;; to run..
+ .type system_call,@function
system_call:
;; Stack-frame similar to the irq heads, which is reversed in
;; ret_from_sys_call.
- subq 12, $sp ; Skip EXS, EDA.
- move $erp, [$sp]
- subq 4, $sp
- move $srp, [$sp]
- subq 4, $sp
- move $ccs, [$sp]
- subq 4, $sp
- ei ; Allow IRQs while handling system call
- move $spc, [$sp]
- subq 4, $sp
- move $mof, [$sp]
- subq 4, $sp
- move $srs, [$sp]
- subq 4, $sp
- move.d $acr, [$sp]
- subq 14*4, $sp ; Make room for R0-R13.
- movem $r13, [$sp] ; Push R0-R13
- subq 4, $sp
- move.d $r10, [$sp] ; Push orig_r10.
-; Set S-bit when kernel debugging to keep hardware breakpoints active.
+ sub.d 92, $sp ; Skip EXS and EDA.
+ movem $r13, [$sp]
+ move.d $sp, $r8
+ addq 14*4, $r8
+ move.d $acr, $r0
+ move $srs, $r1
+ move $mof, $r2
+ move $spc, $r3
+ move $ccs, $r4
+ move $srp, $r5
+ move $erp, $r6
+ subq 4, $sp
+ movem $r6, [$r8]
+ ei ; Enable interrupts while processing syscalls.
+ move.d $r10, [$sp]
+
+ ; Set S-bit when kernel debugging to keep hardware breakpoints active.
#ifdef CONFIG_ETRAX_KGDB
move $ccs, $r0
or.d (1<<9), $r0
@@ -179,7 +195,7 @@ _syscall_traced:
move.d $r0, [$sp]
;; The registers carrying parameters (R10-R13) are intact. The optional
- ;; fifth and sixth parameters is in MOF and SRP respectivly. Put them
+ ;; fifth and sixth parameters is in MOF and SRP respectively. Put them
;; back on the stack.
subq 4, $sp
move $srp, [$sp]
@@ -217,7 +233,9 @@ ret_from_sys_call:
and.d _TIF_ALLWORK_MASK, $r1
bne _syscall_exit_work
nop
+ .size system_call, . - system_call
+ .type _Rexit,@function
_Rexit:
;; This epilogue MUST match the prologues in multiple_interrupt, irq.h
;; and ptregs.h.
@@ -234,10 +252,12 @@ _Rexit:
addq 8, $sp ; Skip EXS, EDA.
jump $erp
rfe ; Restore condition code stack in delay-slot.
+ .size _Rexit, . - _Rexit
;; We get here after doing a syscall if extra work might need to be done
;; perform syscall exit tracing if needed.
+ .type _syscall_exit_work,@function
_syscall_exit_work:
;; R0 contains current at this point and irq's are disabled.
@@ -253,14 +273,18 @@ _syscall_exit_work:
move.d $r1, $r9
ba _resume_userspace
nop
+ .size _syscall_exit_work, . - _syscall_exit_work
+ .type _work_pending,@function
_work_pending:
addoq +TI_flags, $r0, $acr
move.d [$acr], $r10
btstq TIF_NEED_RESCHED, $r10 ; Need resched?
bpl _work_notifysig ; No, must be signal/notify.
nop
+ .size _work_pending, . - _work_pending
+ .type _work_resched,@function
_work_resched:
move.d $r9, $r1 ; Preserve R9.
jsr schedule
@@ -276,20 +300,21 @@ _work_resched:
btstq TIF_NEED_RESCHED, $r1
bmi _work_resched ; current->work.need_resched.
nop
+ .size _work_resched, . - _work_resched
+ .type _work_notifysig,@function
_work_notifysig:
;; Deal with pending signals and notify-resume requests.
addoq +TI_flags, $r0, $acr
- move.d [$acr], $r13 ; The thread_info_flags parameter.
- move.d $r9, $r10 ; do_notify_resume syscall/irq param.
- moveq 0, $r11 ; oldset param - 0 in this case.
- move.d $sp, $r12 ; The regs param.
+ move.d [$acr], $r12 ; The thread_info_flags parameter.
+ move.d $sp, $r11 ; The regs param.
jsr do_notify_resume
- nop
+ move.d $r9, $r10 ; do_notify_resume syscall/irq param.
ba _Rexit
nop
+ .size _work_notifysig, . - _work_notifysig
;; We get here as a sidetrack when we've entered a syscall with the
;; trace-bit set. We need to call do_syscall_trace and then continue
@@ -331,41 +356,43 @@ _syscall_trace_entry:
;;
;; Returns old current in R10.
+ .type resume,@function
resume:
- subq 4, $sp
- move $srp, [$sp] ; Keep old/new PC on the stack.
+ subq 4, $sp ; Make space for srp.
+
add.d $r12, $r10 ; R10 = current tasks tss.
addoq +THREAD_ccs, $r10, $acr
+ move $srp, [$sp] ; Keep old/new PC on the stack.
move $ccs, [$acr] ; Save IRQ enable state.
di
addoq +THREAD_usp, $r10, $acr
+ subq 10*4, $sp ; Make room for R9.
move $usp, [$acr] ; Save user-mode stackpointer.
;; See copy_thread for the reason why register R9 is saved.
- subq 10*4, $sp
movem $r9, [$sp] ; Save non-scratch registers and R9.
addoq +THREAD_ksp, $r10, $acr
+ move.d $sp, $r10 ; Return last running task in R10.
move.d $sp, [$acr] ; Save kernel SP for old task.
- move.d $sp, $r10 ; Return last running task in R10.
and.d -8192, $r10 ; Get thread_info from stackpointer.
addoq +TI_task, $r10, $acr
- move.d [$acr], $r10 ; Get task.
add.d $r12, $r11 ; Find the new tasks tss.
+ move.d [$acr], $r10 ; Get task.
addoq +THREAD_ksp, $r11, $acr
move.d [$acr], $sp ; Switch to new stackframe.
+ addoq +THREAD_usp, $r11, $acr
movem [$sp+], $r9 ; Restore non-scratch registers and R9.
- addoq +THREAD_usp, $r11, $acr
move [$acr], $usp ; Restore user-mode stackpointer.
addoq +THREAD_ccs, $r11, $acr
+ move.d [$sp+], $r11
+ jump $r11 ; Restore PC.
move [$acr], $ccs ; Restore IRQ enable status.
- move.d [$sp+], $acr
- jump $acr ; Restore PC.
- nop
+ .size resume, . - resume
nmi_interrupt:
@@ -396,8 +423,8 @@ nmi_interrupt:
btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0
bpl 1f
nop
- jsr handle_watchdog_bite ; In time.c.
- move.d $sp, $r10 ; Pointer to registers
+ jsr handle_watchdog_bite ; In time.c.
+ move.d $sp, $r10 ; Pointer to registers
1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0
bpl 1f
nop
@@ -425,9 +452,10 @@ spurious_interrupt:
nop
;; This handles the case when multiple interrupts arrive at the same
- ;; time. Jump to the first set interrupt bit in a priotiry fashion. The
+ ;; time. Jump to the first set interrupt bit in a priority fashion. The
;; hardware will call the unserved interrupts after the handler
;; finishes.
+ .type multiple_interrupt, @function
multiple_interrupt:
;; This prologue MUST match the one in irq.h and the struct in ptregs.h!
subq 12, $sp ; Skip EXS, EDA.
@@ -460,6 +488,7 @@ multiple_interrupt:
move.d $sp, $r10
jump ret_from_intr
nop
+ .size multiple_interrupt, . - multiple_interrupt
do_sigtrap:
;; Sigtraps the process that executed the BREAK instruction. Creates a
@@ -609,8 +638,8 @@ sys_call_table:
.long sys_uselib
.long sys_swapon
.long sys_reboot
- .long old_readdir
- .long old_mmap /* 90 */
+ .long sys_old_readdir
+ .long sys_old_mmap /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
@@ -689,7 +718,7 @@ sys_call_table:
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
@@ -778,21 +807,21 @@ sys_call_table:
.long sys_epoll_ctl /* 255 */
.long sys_epoll_wait
.long sys_remap_file_pages
- .long sys_set_tid_address
- .long sys_timer_create
- .long sys_timer_settime /* 260 */
- .long sys_timer_gettime
- .long sys_timer_getoverrun
- .long sys_timer_delete
- .long sys_clock_settime
- .long sys_clock_gettime /* 265 */
- .long sys_clock_getres
- .long sys_clock_nanosleep
+ .long sys_set_tid_address
+ .long sys_timer_create
+ .long sys_timer_settime /* 260 */
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun
+ .long sys_timer_delete
+ .long sys_clock_settime
+ .long sys_clock_gettime /* 265 */
+ .long sys_clock_getres
+ .long sys_clock_nanosleep
.long sys_statfs64
.long sys_fstatfs64
.long sys_tgkill /* 270 */
.long sys_utimes
- .long sys_fadvise64_64
+ .long sys_fadvise64_64
.long sys_ni_syscall /* sys_vserver */
.long sys_ni_syscall /* sys_mbind */
.long sys_ni_syscall /* 275 sys_get_mempolicy */
@@ -805,13 +834,80 @@ sys_call_table:
.long sys_mq_getsetattr
.long sys_ni_syscall /* reserved for kexec */
.long sys_waitid
-
- /*
- * NOTE!! This doesn't have to be exact - we just have
- * to make sure we have _enough_ of the "sys_ni_syscall"
- * entries. Don't panic if you notice that this hasn't
- * been shrunk every time we add a new system call.
- */
+ .long sys_ni_syscall /* 285 */ /* available */
+ .long sys_add_key
+ .long sys_request_key
+ .long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get /* 290 */
+ .long sys_inotify_init
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch
+ .long sys_migrate_pages
+ .long sys_openat /* 295 */
+ .long sys_mkdirat
+ .long sys_mknodat
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64 /* 300 */
+ .long sys_unlinkat
+ .long sys_renameat
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat /* 305 */
+ .long sys_fchmodat
+ .long sys_faccessat
+ .long sys_pselect6
+ .long sys_ppoll
+ .long sys_unshare /* 310 */
+ .long sys_set_robust_list
+ .long sys_get_robust_list
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee /* 315 */
+ .long sys_vmsplice
+ .long sys_move_pages
+ .long sys_getcpu
+ .long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
+ .long sys_signalfd
+ .long sys_timerfd_create
+ .long sys_eventfd
+ .long sys_fallocate
+ .long sys_timerfd_settime /* 325 */
+ .long sys_timerfd_gettime
+ .long sys_signalfd4
+ .long sys_eventfd2
+ .long sys_epoll_create1
+ .long sys_dup3 /* 330 */
+ .long sys_pipe2
+ .long sys_inotify_init1
+ .long sys_preadv
+ .long sys_pwritev
+ .long sys_setns /* 335 */
+ .long sys_name_to_handle_at
+ .long sys_open_by_handle_at
+ .long sys_rt_tgsigqueueinfo
+ .long sys_perf_event_open
+ .long sys_recvmmsg /* 340 */
+ .long sys_accept4
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
+ .long sys_prlimit64
+ .long sys_clock_adjtime /* 345 */
+ .long sys_syncfs
+ .long sys_sendmmsg
+ .long sys_process_vm_readv
+ .long sys_process_vm_writev
+ .long sys_kcmp /* 350 */
+ .long sys_finit_module
+
+ /*
+ * NOTE!! This doesn't have to be exact - we just have
+ * to make sure we have _enough_ of the "sys_ni_syscall"
+ * entries. Don't panic if you notice that this hasn't
+ * been shrunk every time we add a new system call.
+ */
.rept NR_syscalls - (.-sys_call_table) / 4
.long sys_ni_syscall
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index 5daeb6f7f3b..b130c2c5fdd 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -1,110 +1,9 @@
-/* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $
+/*
* linux/arch/cris/kernel/fasttimer.c
*
* Fast timers for ETRAX FS
- * This may be useful in other OS than Linux so use 2 space indentation...
- *
- * $Log: fasttimer.c,v $
- * Revision 1.11 2005/01/04 11:15:46 starvik
- * Don't share timer IRQ.
- *
- * Revision 1.10 2004/12/07 09:19:38 starvik
- * Corrected includes.
- * Use correct interrupt macros.
- *
- * Revision 1.9 2004/05/14 10:18:58 starvik
- * Export fast_timer_list
- *
- * Revision 1.8 2004/05/14 07:58:03 starvik
- * Merge of changes from 2.4
- *
- * Revision 1.7 2003/07/10 12:06:14 starvik
- * Return IRQ_NONE if irq wasn't handled
- *
- * Revision 1.6 2003/07/04 08:27:49 starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.5 2003/06/05 10:16:22 johana
- * New INTR_VECT macros.
- *
- * Revision 1.4 2003/06/03 08:49:45 johana
- * Fixed typo.
- *
- * Revision 1.3 2003/06/02 12:51:27 johana
- * Now compiles.
- * Commented some include files that probably can be removed.
- *
- * Revision 1.2 2003/06/02 12:09:41 johana
- * Ported to ETRAX FS using the trig interrupt instead of timer1.
- *
- * Revision 1.3 2002/12/12 08:26:32 starvik
- * Don't use C-comments inside CVS comments
- *
- * Revision 1.2 2002/12/11 15:42:02 starvik
- * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
- *
- * Revision 1.1 2002/11/18 07:58:06 starvik
- * Fast timers (from Linux 2.4)
- *
- * Revision 1.5 2002/10/15 06:21:39 starvik
- * Added call to init_waitqueue_head
- *
- * Revision 1.4 2002/05/28 17:47:59 johana
- * Added del_fast_timer()
- *
- * Revision 1.3 2002/05/28 16:16:07 johana
- * Handle empty fast_timer_list
- *
- * Revision 1.2 2002/05/27 15:38:42 johana
- * Made it compile without warnings on Linux 2.4.
- * (includes, wait_queue, PROC_FS and snprintf)
*
- * Revision 1.1 2002/05/27 15:32:25 johana
- * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
- *
- * Revision 1.8 2001/11/27 13:50:40 pkj
- * Disable interrupts while stopping the timer and while modifying the
- * list of active timers in timer1_handler() as it may be interrupted
- * by other interrupts (e.g., the serial interrupt) which may add fast
- * timers.
- *
- * Revision 1.7 2001/11/22 11:50:32 pkj
- * * Only store information about the last 16 timers.
- * * proc_fasttimer_read() now uses an allocated buffer, since it
- * requires more space than just a page even for only writing the
- * last 16 timers. The buffer is only allocated on request, so
- * unless /proc/fasttimer is read, it is never allocated.
- * * Renamed fast_timer_started to fast_timers_started to match
- * fast_timers_added and fast_timers_expired.
- * * Some clean-up.
- *
- * Revision 1.6 2000/12/13 14:02:08 johana
- * Removed volatile for fast_timer_list
- *
- * Revision 1.5 2000/12/13 13:55:35 johana
- * Added DEBUG_LOG, added som cli() and cleanup
- *
- * Revision 1.4 2000/12/05 13:48:50 johana
- * Added range check when writing proc file, modified timer int handling
- *
- * Revision 1.3 2000/11/23 10:10:20 johana
- * More debug/logging possibilities.
- * Moved GET_JIFFIES_USEC() to timex.h and time.c
- *
- * Revision 1.2 2000/11/01 13:41:04 johana
- * Clean up and bugfixes.
- * Created new do_gettimeofday_fast() that gets a timeval struct
- * with time based on jiffies and *R_TIMER0_DATA, uses a table
- * for fast conversion of timer value to microseconds.
- * (Much faster the standard do_gettimeofday() and we don't really
- * wan't to use the true time - we wan't the "uptime" so timers don't screw up
- * when we change the time.
- * TODO: Add efficient support for continuous timers as well.
- *
- * Revision 1.1 2000/10/26 15:49:16 johana
- * Added fasttimer, highresolution timers.
- *
- * Copyright (C) 2000,2001 2002, 2003 Axis Communications AB, Lund, Sweden
+ * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden
*/
#include <linux/errno.h>
@@ -118,15 +17,13 @@
#include <linux/delay.h>
#include <asm/irq.h>
-#include <asm/system.h>
-#include <linux/version.h>
-
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/timer_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/timer_defs.h>
#include <asm/fasttimer.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
/*
* timer0 is running at 100MHz and generating jiffies timer ticks
@@ -140,30 +37,25 @@
#define DEBUG_LOG_INCLUDED
#define FAST_TIMER_LOG
-//#define FAST_TIMER_TEST
+/* #define FAST_TIMER_TEST */
#define FAST_TIMER_SANITY_CHECKS
#ifdef FAST_TIMER_SANITY_CHECKS
-#define SANITYCHECK(x) x
-static int sanity_failed = 0;
-#else
-#define SANITYCHECK(x)
+static int sanity_failed;
#endif
#define D1(x)
#define D2(x)
#define DP(x)
-#define __INLINE__ inline
-
-static int fast_timer_running = 0;
-static int fast_timers_added = 0;
-static int fast_timers_started = 0;
-static int fast_timers_expired = 0;
-static int fast_timers_deleted = 0;
-static int fast_timer_is_init = 0;
-static int fast_timer_ints = 0;
+static unsigned int fast_timer_running;
+static unsigned int fast_timers_added;
+static unsigned int fast_timers_started;
+static unsigned int fast_timers_expired;
+static unsigned int fast_timers_deleted;
+static unsigned int fast_timer_is_init;
+static unsigned int fast_timer_ints;
struct fast_timer *fast_timer_list = NULL;
@@ -171,8 +63,8 @@ struct fast_timer *fast_timer_list = NULL;
#define DEBUG_LOG_MAX 128
static const char * debug_log_string[DEBUG_LOG_MAX];
static unsigned long debug_log_value[DEBUG_LOG_MAX];
-static int debug_log_cnt = 0;
-static int debug_log_cnt_wrapped = 0;
+static unsigned int debug_log_cnt;
+static unsigned int debug_log_cnt_wrapped;
#define DEBUG_LOG(string, value) \
{ \
@@ -202,103 +94,92 @@ struct fast_timer timer_expired_log[NUM_TIMER_STATS];
int timer_div_settings[NUM_TIMER_STATS];
int timer_delay_settings[NUM_TIMER_STATS];
+struct work_struct fast_work;
static void
-timer_trig_handler(void);
+timer_trig_handler(struct work_struct *work);
/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
-void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+inline void do_gettimeofday_fast(struct fasttime_t *tv)
{
- unsigned long sec = jiffies;
- unsigned long usec = GET_JIFFIES_USEC();
-
- usec += (sec % HZ) * (1000000 / HZ);
- sec = sec / HZ;
-
- if (usec > 1000000)
- {
- usec -= 1000000;
- sec++;
- }
- tv->tv_sec = sec;
- tv->tv_usec = usec;
+ tv->tv_jiff = jiffies;
+ tv->tv_usec = GET_JIFFIES_USEC();
}
-int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)
{
- if (t0->tv_sec < t1->tv_sec)
- {
- return -1;
- }
- else if (t0->tv_sec > t1->tv_sec)
- {
- return 1;
- }
- if (t0->tv_usec < t1->tv_usec)
- {
- return -1;
- }
- else if (t0->tv_usec > t1->tv_usec)
- {
- return 1;
- }
- return 0;
+ /* Compare jiffies. Takes care of wrapping */
+ if (time_before(t0->tv_jiff, t1->tv_jiff))
+ return -1;
+ else if (time_after(t0->tv_jiff, t1->tv_jiff))
+ return 1;
+
+ /* Compare us */
+ if (t0->tv_usec < t1->tv_usec)
+ return -1;
+ else if (t0->tv_usec > t1->tv_usec)
+ return 1;
+ return 0;
}
/* Called with ints off */
-void __INLINE__ start_timer_trig(unsigned long delay_us)
+inline void start_timer_trig(unsigned long delay_us)
{
reg_timer_rw_ack_intr ack_intr = { 0 };
reg_timer_rw_intr_mask intr_mask;
reg_timer_rw_trig trig;
reg_timer_rw_trig_cfg trig_cfg = { 0 };
- reg_timer_r_time r_time;
+ reg_timer_r_time r_time0;
+ reg_timer_r_time r_time1;
+ unsigned char trig_wrap;
+ unsigned char time_wrap;
- r_time = REG_RD(timer, regi_timer, r_time);
+ r_time0 = REG_RD(timer, regi_timer0, r_time);
D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
delay_us, freq_index, div));
/* Clear trig irq */
- intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+ intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
intr_mask.trig = 0;
- REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+ REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
- /* Set timer values */
- /* r_time is 100MHz (10 ns resolution) */
- trig = r_time + delay_us*(1000/10);
+ /* Set timer values and check if trigger wraps. */
+ /* r_time is 100MHz (10 ns resolution) */
+ trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;
timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
/* Ack interrupt */
ack_intr.trig = 1;
- REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+ REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
/* Start timer */
- REG_WR(timer, regi_timer, rw_trig, trig);
+ REG_WR(timer, regi_timer0, rw_trig, trig);
trig_cfg.tmr = regk_timer_time;
- REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+ REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
/* Check if we have already passed the trig time */
- r_time = REG_RD(timer, regi_timer, r_time);
- if (r_time < trig) {
+ r_time1 = REG_RD(timer, regi_timer0, r_time);
+ time_wrap = r_time1 < r_time0;
+
+ if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {
/* No, Enable trig irq */
- intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+ intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
intr_mask.trig = 1;
- REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+ REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
fast_timers_started++;
fast_timer_running = 1;
- }
- else
- {
+ } else {
/* We have passed the time, disable trig point, ack intr */
trig_cfg.tmr = regk_timer_off;
- REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
- REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
- /* call the int routine directly */
- timer_trig_handler();
+ REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
+ REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
+ /* call the int routine */
+ INIT_WORK(&fast_work, timer_trig_handler);
+ schedule_work(&fast_work);
}
}
@@ -320,22 +201,20 @@ void start_one_shot_timer(struct fast_timer *t,
do_gettimeofday_fast(&t->tv_set);
tmp = fast_timer_list;
- SANITYCHECK({ /* Check so this is not in the list already... */
- while (tmp != NULL)
- {
- if (tmp == t)
- {
- printk("timer name: %s data: 0x%08lX already in list!\n", name, data);
- sanity_failed++;
- return;
- }
- else
- {
- tmp = tmp->next;
- }
- }
- tmp = fast_timer_list;
- });
+#ifdef FAST_TIMER_SANITY_CHECKS
+ /* Check so this is not in the list already... */
+ while (tmp != NULL) {
+ if (tmp == t) {
+ printk(KERN_DEBUG
+ "timer name: %s data: 0x%08lX already "
+ "in list!\n", name, data);
+ sanity_failed++;
+ goto done;
+ } else
+ tmp = tmp->next;
+ }
+ tmp = fast_timer_list;
+#endif
t->delay_us = delay_us;
t->function = function;
@@ -343,11 +222,10 @@ void start_one_shot_timer(struct fast_timer *t,
t->name = name;
t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
- t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000;
- if (t->tv_expires.tv_usec > 1000000)
- {
+ t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
+ if (t->tv_expires.tv_usec > 1000000) {
t->tv_expires.tv_usec -= 1000000;
- t->tv_expires.tv_sec++;
+ t->tv_expires.tv_jiff += HZ;
}
#ifdef FAST_TIMER_LOG
timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
@@ -355,15 +233,12 @@ void start_one_shot_timer(struct fast_timer *t,
fast_timers_added++;
/* Check if this should timeout before anything else */
- if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
- {
+ if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) {
/* Put first in list and modify the timer value */
t->prev = NULL;
t->next = fast_timer_list;
if (fast_timer_list)
- {
fast_timer_list->prev = t;
- }
fast_timer_list = t;
#ifdef FAST_TIMER_LOG
timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
@@ -372,10 +247,8 @@ void start_one_shot_timer(struct fast_timer *t,
} else {
/* Put in correct place in list */
while (tmp->next &&
- timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
- {
+ fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
tmp = tmp->next;
- }
/* Insert t after tmp */
t->prev = tmp;
t->next = tmp->next;
@@ -388,6 +261,7 @@ void start_one_shot_timer(struct fast_timer *t,
D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+done:
local_irq_restore(flags);
} /* start_one_shot_timer */
@@ -431,19 +305,18 @@ int del_fast_timer(struct fast_timer * t)
/* Timer interrupt handler for trig interrupts */
static irqreturn_t
-timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+timer_trig_interrupt(int irq, void *dev_id)
{
reg_timer_r_masked_intr masked_intr;
-
/* Check if the timer interrupt is for us (a trig int) */
- masked_intr = REG_RD(timer, regi_timer, r_masked_intr);
+ masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);
if (!masked_intr.trig)
return IRQ_NONE;
- timer_trig_handler();
+ timer_trig_handler(NULL);
return IRQ_HANDLED;
}
-static void timer_trig_handler(void)
+static void timer_trig_handler(struct work_struct *work)
{
reg_timer_rw_ack_intr ack_intr = { 0 };
reg_timer_rw_intr_mask intr_mask;
@@ -451,38 +324,45 @@ static void timer_trig_handler(void)
struct fast_timer *t;
unsigned long flags;
+ /* We keep interrupts disabled not only when we modify the
+ * fast timer list, but any time we hold a reference to a
+ * timer in the list, since del_fast_timer may be called
+ * from (another) interrupt context. Thus, the only time
+ * when interrupts are enabled is when calling the timer
+ * callback function.
+ */
local_irq_save(flags);
/* Clear timer trig interrupt */
- intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+ intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
intr_mask.trig = 0;
- REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+ REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
/* First stop timer, then ack interrupt */
/* Stop timer */
trig_cfg.tmr = regk_timer_off;
- REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+ REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
/* Ack interrupt */
ack_intr.trig = 1;
- REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+ REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
fast_timer_running = 0;
fast_timer_ints++;
- local_irq_restore(flags);
+ fast_timer_function_type *f;
+ unsigned long d;
t = fast_timer_list;
- while (t)
- {
- struct timeval tv;
+ while (t) {
+ struct fasttime_t tv;
/* Has it really expired? */
do_gettimeofday_fast(&tv);
- D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+ D1(printk(KERN_DEBUG
+ "t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));
- if (timeval_cmp(&t->tv_expires, &tv) <= 0)
- {
+ if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {
/* Yes it has expired */
#ifdef FAST_TIMER_LOG
timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
@@ -490,84 +370,77 @@ static void timer_trig_handler(void)
fast_timers_expired++;
/* Remove this timer before call, since it may reuse the timer */
- local_irq_save(flags);
if (t->prev)
- {
t->prev->next = t->next;
- }
else
- {
fast_timer_list = t->next;
- }
if (t->next)
- {
t->next->prev = t->prev;
- }
t->prev = NULL;
t->next = NULL;
- local_irq_restore(flags);
- if (t->function != NULL)
- {
- t->function(t->data);
- }
- else
- {
+ /* Save function callback data before enabling
+ * interrupts, since the timer may be removed and we
+ * don't know how it was allocated (e.g. ->function
+ * and ->data may become overwritten after deletion
+ * if the timer was stack-allocated).
+ */
+ f = t->function;
+ d = t->data;
+
+ if (f != NULL) {
+ /* Run the callback function with interrupts
+ * enabled. */
+ local_irq_restore(flags);
+ f(d);
+ local_irq_save(flags);
+ } else
DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
- }
- }
- else
- {
+ } else {
/* Timer is to early, let's set it again using the normal routines */
D1(printk(".\n"));
}
- local_irq_save(flags);
- if ((t = fast_timer_list) != NULL)
- {
+ t = fast_timer_list;
+ if (t != NULL) {
/* Start next timer.. */
- long us;
- struct timeval tv;
+ long us = 0;
+ struct fasttime_t tv;
do_gettimeofday_fast(&tv);
- us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
- t->tv_expires.tv_usec - tv.tv_usec);
- if (us > 0)
- {
- if (!fast_timer_running)
- {
+
+ /* time_after_eq takes care of wrapping */
+ if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
+ us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
+ 1000000 / HZ + t->tv_expires.tv_usec -
+ tv.tv_usec);
+
+ if (us > 0) {
+ if (!fast_timer_running) {
#ifdef FAST_TIMER_LOG
timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
#endif
start_timer_trig(us);
}
- local_irq_restore(flags);
break;
- }
- else
- {
+ } else {
/* Timer already expired, let's handle it better late than never.
* The normal loop handles it
*/
D1(printk("e! %d\n", us));
}
}
- local_irq_restore(flags);
}
- if (!t)
- {
+ local_irq_restore(flags);
+
+ if (!t)
D1(printk("ttrig stop!\n"));
- }
}
static void wake_up_func(unsigned long data)
{
-#ifdef DECLARE_WAITQUEUE
wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data;
-#else
- struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
-#endif
wake_up(sleep_wait_p);
}
@@ -577,243 +450,175 @@ static void wake_up_func(unsigned long data)
void schedule_usleep(unsigned long us)
{
struct fast_timer t;
-#ifdef DECLARE_WAITQUEUE
wait_queue_head_t sleep_wait;
init_waitqueue_head(&sleep_wait);
- {
- DECLARE_WAITQUEUE(wait, current);
-#else
- struct wait_queue *sleep_wait = NULL;
- struct wait_queue wait = { current, NULL };
-#endif
D1(printk("schedule_usleep(%d)\n", us));
- add_wait_queue(&sleep_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
"usleep");
- schedule();
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&sleep_wait, &wait);
+ /* Uninterruptible sleep on the fast timer. (The condition is
+ * somewhat redundant since the timer is what wakes us up.) */
+ wait_event(sleep_wait, !fast_timer_pending(&t));
+
D1(printk("done schedule_usleep(%d)\n", us));
-#ifdef DECLARE_WAITQUEUE
- }
-#endif
}
#ifdef CONFIG_PROC_FS
-static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-#else
- ,int unused
-#endif
- );
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-static struct proc_dir_entry *fasttimer_proc_entry;
-#else
-static struct proc_dir_entry fasttimer_proc_entry =
-{
- 0, 9, "fasttimer",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL /* ops -- default to array */,
- &proc_fasttimer_read /* get_info */,
-};
-#endif
-#endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_PROC_FS
-
/* This value is very much based on testing */
#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
-static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-#else
- ,int unused
-#endif
- )
+static int proc_fasttimer_show(struct seq_file *m, void *v)
{
- unsigned long flags;
- int i = 0;
- int num_to_show;
- struct timeval tv;
- struct fast_timer *t, *nextt;
- static char *bigbuf = NULL;
- static unsigned long used;
-
- if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
- {
- used = 0;
- bigbuf[0] = '\0';
- return 0;
- }
-
- if (!offset || !used)
- {
- do_gettimeofday_fast(&tv);
-
- used = 0;
- used += sprintf(bigbuf + used, "Fast timers added: %i\n",
- fast_timers_added);
- used += sprintf(bigbuf + used, "Fast timers started: %i\n",
- fast_timers_started);
- used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
- fast_timer_ints);
- used += sprintf(bigbuf + used, "Fast timers expired: %i\n",
- fast_timers_expired);
- used += sprintf(bigbuf + used, "Fast timers deleted: %i\n",
- fast_timers_deleted);
- used += sprintf(bigbuf + used, "Fast timer running: %s\n",
- fast_timer_running ? "yes" : "no");
- used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n",
- (unsigned long)tv.tv_sec,
- (unsigned long)tv.tv_usec);
+ unsigned long flags;
+ int i = 0;
+ int num_to_show;
+ struct fasttime_t tv;
+ struct fast_timer *t, *nextt;
+
+ do_gettimeofday_fast(&tv);
+
+ seq_printf(m, "Fast timers added: %i\n", fast_timers_added);
+ seq_printf(m, "Fast timers started: %i\n", fast_timers_started);
+ seq_printf(m, "Fast timer interrupts: %i\n", fast_timer_ints);
+ seq_printf(m, "Fast timers expired: %i\n", fast_timers_expired);
+ seq_printf(m, "Fast timers deleted: %i\n", fast_timers_deleted);
+ seq_printf(m, "Fast timer running: %s\n",
+ fast_timer_running ? "yes" : "no");
+ seq_printf(m, "Current time: %lu.%06lu\n",
+ (unsigned long)tv.tv_jiff,
+ (unsigned long)tv.tv_usec);
#ifdef FAST_TIMER_SANITY_CHECKS
- used += sprintf(bigbuf + used, "Sanity failed: %i\n",
- sanity_failed);
+ seq_printf(m, "Sanity failed: %i\n", sanity_failed);
#endif
- used += sprintf(bigbuf + used, "\n");
+ seq_putc(m, '\n');
#ifdef DEBUG_LOG_INCLUDED
- {
- int end_i = debug_log_cnt;
- i = 0;
-
- if (debug_log_cnt_wrapped)
- {
- i = debug_log_cnt;
- }
-
- while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
- used+100 < BIG_BUF_SIZE)
- {
- used += sprintf(bigbuf + used, debug_log_string[i],
- debug_log_value[i]);
- i = (i+1) % DEBUG_LOG_MAX;
- }
- }
- used += sprintf(bigbuf + used, "\n");
+ {
+ int end_i = debug_log_cnt;
+ i = 0;
+
+ if (debug_log_cnt_wrapped)
+ i = debug_log_cnt;
+
+ while ((i != end_i || debug_log_cnt_wrapped)) {
+ if (seq_printf(m, debug_log_string[i], debug_log_value[i]) < 0)
+ return 0;
+ i = (i+1) % DEBUG_LOG_MAX;
+ }
+ }
+ seq_putc(m, '\n');
#endif
- num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
- {
- int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+ num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers started: %i\n", fast_timers_started);
+ for (i = 0; i < num_to_show; i++) {
+ int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
#if 1 //ndef FAST_TIMER_LOG
- used += sprintf(bigbuf + used, "div: %i delay: %i"
- "\n",
- timer_div_settings[cur],
- timer_delay_settings[cur]
- );
+ seq_printf(m, "div: %i delay: %i"
+ "\n",
+ timer_div_settings[cur],
+ timer_delay_settings[cur]);
#endif
#ifdef FAST_TIMER_LOG
- t = &timer_started_log[cur];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
+ t = &timer_started_log[cur];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
#endif
- }
- used += sprintf(bigbuf + used, "\n");
+ }
+ seq_putc(m, '\n');
#ifdef FAST_TIMER_LOG
- num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
- {
- t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
- }
- used += sprintf(bigbuf + used, "\n");
-
- num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
- NUM_TIMER_STATS);
- used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired);
- for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
- {
- t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
- );
- }
- used += sprintf(bigbuf + used, "\n");
+ num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers added: %i\n", fast_timers_added);
+ for (i = 0; i < num_to_show; i++) {
+ t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
+ }
+ seq_putc(m, '\n');
+
+ num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+ NUM_TIMER_STATS);
+ seq_printf(m, "Timers expired: %i\n", fast_timers_expired);
+ for (i = 0; i < num_to_show; i++){
+ t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data) < 0)
+ return 0;
+ }
+ seq_putc(m, '\n');
#endif
- used += sprintf(bigbuf + used, "Active timers:\n");
- local_irq_save(flags);
- local_irq_save(flags);
- t = fast_timer_list;
- while (t != NULL && (used+100 < BIG_BUF_SIZE))
- {
- nextt = t->next;
- local_irq_restore(flags);
- used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
- "d: %6li us data: 0x%08lX"
-/* " func: 0x%08lX" */
- "\n",
- t->name,
- (unsigned long)t->tv_set.tv_sec,
- (unsigned long)t->tv_set.tv_usec,
- (unsigned long)t->tv_expires.tv_sec,
- (unsigned long)t->tv_expires.tv_usec,
- t->delay_us,
- t->data
+ seq_puts(m, "Active timers:\n");
+ local_irq_save(flags);
+ t = fast_timer_list;
+ while (t != NULL){
+ nextt = t->next;
+ local_irq_restore(flags);
+ if (seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+ "d: %6li us data: 0x%08lX"
+/* " func: 0x%08lX" */
+ "\n",
+ t->name,
+ (unsigned long)t->tv_set.tv_jiff,
+ (unsigned long)t->tv_set.tv_usec,
+ (unsigned long)t->tv_expires.tv_jiff,
+ (unsigned long)t->tv_expires.tv_usec,
+ t->delay_us,
+ t->data
/* , t->function */
- );
- local_irq_disable();
- if (t->next != nextt)
- {
- printk("timer removed!\n");
- }
- t = nextt;
- }
- local_irq_restore(flags);
- }
+ ) < 0)
+ return 0;
+ local_irq_save(flags);
+ if (t->next != nextt)
+ printk("timer removed!\n");
+ t = nextt;
+ }
+ local_irq_restore(flags);
+ return 0;
+}
- if (used - offset < len)
- {
- len = used - offset;
- }
+static int proc_fasttimer_open(struct inode *inode, struct file *file)
+{
+ return single_open_size(file, proc_fasttimer_show, PDE_DATA(inode), BIG_BUF_SIZE);
+}
- memcpy(buf, bigbuf + offset, len);
- *start = buf;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- *eof = 1;
-#endif
+static const struct file_operations proc_fasttimer_fops = {
+ .open = proc_fasttimer_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
- return len;
-}
#endif /* PROC_FS */
#ifdef FAST_TIMER_TEST
@@ -822,7 +627,7 @@ static volatile int num_test_timeout = 0;
static struct fast_timer tr[10];
static int exp_num[10];
-static struct timeval tv_exp[100];
+static struct fasttime_t tv_exp[100];
static void test_timeout(unsigned long data)
{
@@ -860,7 +665,7 @@ static void fast_timer_test(void)
int prev_num;
int j;
- struct timeval tv, tv0, tv1, tv2;
+ struct fasttime_t tv, tv0, tv1, tv2;
printk("fast_timer_test() start\n");
do_gettimeofday_fast(&tv);
@@ -873,21 +678,22 @@ static void fast_timer_test(void)
{
do_gettimeofday_fast(&tv_exp[j]);
}
- printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+ printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec);
for (j = 0; j < 1000; j++)
{
- printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+ printk(KERN_DEBUG "%i %i %i %i %i\n",
+ j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
j += 4;
}
for (j = 0; j < 100; j++)
{
- printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
- tv_exp[j].tv_sec,tv_exp[j].tv_usec,
- tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
- tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
- tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
- tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+ printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+ tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
+ tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
+ tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
+ tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
+ tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
j += 4;
}
do_gettimeofday_fast(&tv0);
@@ -914,14 +720,15 @@ static void fast_timer_test(void)
while (num_test_timeout < i)
{
if (num_test_timeout != prev_num)
- {
prev_num = num_test_timeout;
- }
}
do_gettimeofday_fast(&tv2);
- printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec);
- printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
- printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+ printk(KERN_INFO "Timers started %is %06i\n",
+ tv0.tv_jiff, tv0.tv_usec);
+ printk(KERN_INFO "Timers started at %is %06i\n",
+ tv1.tv_jiff, tv1.tv_usec);
+ printk(KERN_INFO "Timers done %is %06i\n",
+ tv2.tv_jiff, tv2.tv_usec);
DP(printk("buf0:\n");
printk(buf0);
printk("buf1:\n");
@@ -943,9 +750,9 @@ static void fast_timer_test(void)
printk("%-10s set: %6is %06ius exp: %6is %06ius "
"data: 0x%08X func: 0x%08X\n",
t->name,
- t->tv_set.tv_sec,
+ t->tv_set.tv_jiff,
t->tv_set.tv_usec,
- t->tv_expires.tv_sec,
+ t->tv_expires.tv_jiff,
t->tv_expires.tv_usec,
t->data,
t->function
@@ -953,10 +760,12 @@ static void fast_timer_test(void)
printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",
t->delay_us,
- tv_exp[j].tv_sec,
+ tv_exp[j].tv_jiff,
tv_exp[j].tv_usec,
exp_num[j],
- (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+ (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
+ 1000000 + tv_exp[j].tv_usec -
+ t->tv_expires.tv_usec);
}
proc_fasttimer_read(buf5, NULL, 0, 0, 0);
printk("buf5 after all done:\n");
@@ -966,7 +775,7 @@ static void fast_timer_test(void)
#endif
-void fast_timer_init(void)
+int fast_timer_init(void)
{
/* For some reason, request_irq() hangs when called froom time_init() */
if (!fast_timer_is_init)
@@ -974,22 +783,18 @@ void fast_timer_init(void)
printk("fast_timer_init()\n");
#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
- fasttimer_proc_entry->read_proc = proc_fasttimer_read;
-#else
- proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
-#endif
+ proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops);
#endif /* PROC_FS */
- if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED,
- "fast timer int", NULL))
- {
- printk("err: timer1 irq\n");
- }
+ if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
+ IRQF_SHARED,
+ "fast timer int", &fast_timer_list))
+ printk(KERN_ERR "err: fasttimer irq\n");
fast_timer_is_init = 1;
#ifdef FAST_TIMER_TEST
printk("do test\n");
fast_timer_test();
#endif
}
+ return 0;
}
+__initcall(fast_timer_init);
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S
index 20bd80a84e4..51e34165ece 100644
--- a/arch/cris/arch-v32/kernel/head.S
+++ b/arch/cris/arch-v32/kernel/head.S
@@ -4,22 +4,25 @@
* Copyright (C) 2003, Axis Communications AB
*/
-
#define ASSEMBLER_MACROS_ONLY
/*
* The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
* -traditional must not be used when assembling this file.
*/
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
-#include <asm/arch/hwregs/asm/reg_map_asm.h>
-#include <asm/arch/hwregs/asm/config_defs_asm.h>
-#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+#include <arch/memmap.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/asm/mmu_defs_asm.h>
+#include <hwregs/asm/reg_map_asm.h>
+#include <mach/startup.inc>
#define CRAMFS_MAGIC 0x28cd3d45
+#define JHEAD_MAGIC 0x1FF528A6
+#define JHEAD_SIZE 8
#define RAM_INIT_MAGIC 0x56902387
#define COMMAND_LINE_MAGIC 0x87109563
+#define NAND_BOOT_MAGIC 0x9a9db001
;; NOTE: R8 and R9 carry information from the decompressor (if the
;; kernel was compressed). They must not be used in the code below
@@ -30,16 +33,8 @@
.global romfs_start
.global romfs_length
.global romfs_in_flash
+ .global nand_boot
.global swapper_pg_dir
- .global crisv32_nand_boot
- .global crisv32_nand_cramfs_offset
-
- ;; Dummy section to make it bootable with current VCS simulator
-#ifdef CONFIG_ETRAXFS_SIM
- .section ".boot", "ax"
- ba tstart
- nop
-#endif
.text
tstart:
@@ -51,33 +46,15 @@ tstart:
;;
di
- ;; Start clocks for used blocks.
- move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
- move.d [$r1], $r0
- or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
- REG_STATE(config, rw_clk_ctrl, bif, yes) | \
- REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
- move.d $r0, [$r1]
-
- ;; Set up waitstates etc
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0
- move.d CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1
- move.d $r1, [$r0]
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0
- move.d CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1
- move.d $r1, [$r0]
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0
- move.d CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1
- move.d $r1, [$r0]
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
- move.d CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
- move.d $r1, [$r0]
-
-#ifdef CONFIG_ETRAXFS_SIM
- ;; Set up minimal flash waitstates
- move.d 0, $r10
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
- move.d $r10, [$r11]
+ START_CLOCKS
+
+ SETUP_WAIT_STATES
+
+ GIO_INIT
+
+#ifdef CONFIG_SMP
+secondary_cpu_entry: /* Entry point for secondary CPUs */
+ di
#endif
;; Setup and enable the MMU. Use same configuration for both the data
@@ -85,17 +62,16 @@ tstart:
;;
;; Note; 3 cycles is needed for a bank-select to take effect. Further;
;; bank 1 is the instruction MMU, bank 2 is the data MMU.
-#ifndef CONFIG_ETRAXFS_SIM
+
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \
| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \
+ | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5) \
| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
#else
- ;; Map the virtual DRAM to the RW eprom area at address 0.
- ;; Also map 0xa for the hook calls,
move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \
- | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0) \
- | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \
- | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
+ | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \
+ | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
#endif
;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
@@ -104,14 +80,25 @@ tstart:
;; Enable certain page protections and setup linear mapping
;; for f,e,c,b,4,0.
-#ifndef CONFIG_ETRAXFS_SIM
+
+ ;; ARTPEC-3:
+ ;; c,d used for linear kernel mapping, up to 512 MB
+ ;; e used for vmalloc
+ ;; f unused, but page mapped to get page faults
+
+ ;; ETRAX FS:
+ ;; c used for linear kernel mapping, up to 256 MB
+ ;; d used for vmalloc
+ ;; e,f used for memory-mapped NOR flash
+
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
move.d REG_STATE(mmu, rw_mm_cfg, we, on) \
| REG_STATE(mmu, rw_mm_cfg, acc, on) \
| REG_STATE(mmu, rw_mm_cfg, ex, on) \
- | REG_STATE(mmu, rw_mm_cfg, inv, on) \
- | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \
- | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \
- | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \
+ | REG_STATE(mmu, rw_mm_cfg, inv, on) \
+ | REG_STATE(mmu, rw_mm_cfg, seg_f, page) \
+ | REG_STATE(mmu, rw_mm_cfg, seg_e, page) \
+ | REG_STATE(mmu, rw_mm_cfg, seg_d, linear) \
| REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \
| REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \
| REG_STATE(mmu, rw_mm_cfg, seg_a, page) \
@@ -135,7 +122,7 @@ tstart:
| REG_STATE(mmu, rw_mm_cfg, seg_d, page) \
| REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \
| REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \
- | REG_STATE(mmu, rw_mm_cfg, seg_a, linear) \
+ | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \
| REG_STATE(mmu, rw_mm_cfg, seg_9, page) \
| REG_STATE(mmu, rw_mm_cfg, seg_8, page) \
| REG_STATE(mmu, rw_mm_cfg, seg_7, page) \
@@ -183,17 +170,11 @@ tstart:
nop
nop
nop
- move $s10, $r0
+ move $s12, $r0
cmpq 0, $r0
beq master_cpu
nop
slave_cpu:
- ; A slave waits for cpu_now_booting to be equal to CPU ID.
- move.d cpu_now_booting, $r1
-slave_wait:
- cmp.d [$r1], $r0
- bne slave_wait
- nop
; Time to boot-up. Get stack location provided by master CPU.
move.d smp_init_current_idle_thread, $r1
move.d [$r1], $sp
@@ -203,15 +184,20 @@ slave_wait:
jsr smp_callin
nop
master_cpu:
+ /* Set up entry point for secondary CPUs. The boot ROM has set up
+ * EBP at start of internal memory. The CPU will get there
+ * later when we issue an IPI to them... */
+ move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0
+ move.d secondary_cpu_entry, $r1
+ move.d $r1, [$r0]
#endif
-#ifndef CONFIG_ETRAXFS_SIM
- ;; Check if starting from DRAM or flash.
+ ; Check if starting from DRAM (network->RAM boot or unpacked
+ ; compressed kernel), or directly from flash.
lapcq ., $r0
and.d 0x7fffffff, $r0 ; Mask off the non-cache bit.
cmp.d 0x10000, $r0 ; Arbitrary, something above this code.
blo _inflash0
nop
-#endif
jump _inram ; Jump to cached RAM.
nop
@@ -232,12 +218,20 @@ _inflash:
beq _dram_initialized
nop
-#include "../lib/dram_init.S"
+#if defined CONFIG_ETRAXFS
+#include "../mach-fs/dram_init.S"
+#elif defined CONFIG_CRIS_MACH_ARTPEC3
+#include "../mach-a3/dram_init.S"
+#else
+#error Only ETRAXFS and ARTPEC-3 supported!
+#endif
+
_dram_initialized:
;; Copy the text and data section to DRAM. This depends on that the
;; variables used below are correctly set up by the linker script.
;; The calculated value stored in R4 is used below.
+ ;; Leave the cramfs file system (piggybacked after the kernel) in flash.
moveq 0, $r0 ; Source.
move.d text_start, $r1 ; Destination.
move.d __vmlinux_end, $r2
@@ -249,7 +243,7 @@ _dram_initialized:
blo 1b
nop
- ;; Keep CRAMFS in flash.
+ ;; Check for cramfs.
moveq 0, $r0
move.d romfs_length, $r1
move.d $r0, [$r1]
@@ -258,6 +252,7 @@ _dram_initialized:
bne 1f
nop
+ ;; Set length and start of cramfs, set romfs_in_flash flag
addoq +4, $r4, $acr
move.d [$acr], $r0
move.d romfs_length, $r1
@@ -273,48 +268,42 @@ _dram_initialized:
nop
_inram:
- ;; Check if booting from NAND flash (in that case we just remember the offset
- ;; into the flash where cramfs should be).
- move.d REG_ADDR(config, regi_config, r_bootsel), $r0
- move.d [$r0], $r0
- and.d REG_MASK(config, r_bootsel, boot_mode), $r0
- cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0
- bne move_cramfs
- moveq 1,$r0
- move.d crisv32_nand_boot, $r1
- move.d $r0, [$r1]
- move.d crisv32_nand_cramfs_offset, $r1
- move.d $r9, [$r1]
+ ;; Check if booting from NAND flash; if so, set appropriate flags
+ ;; and move on.
+ cmp.d NAND_BOOT_MAGIC, $r12
+ bne move_cramfs ; not nand, jump
moveq 1, $r0
- move.d romfs_in_flash, $r1
+ move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND
move.d $r0, [$r1]
- jump _start_it
+ moveq 0, $r0 ; tell axisflashmap romfs is not in
+ move.d romfs_in_flash, $r1 ; (directly accessed) flash
+ move.d $r0, [$r1]
+ jump _start_it ; continue with boot
nop
move_cramfs:
- ;; Move the cramfs after BSS.
+ ;; kernel is in DRAM.
+ ;; Must figure out if there is a piggybacked rootfs image or not.
+ ;; Set romfs_length to 0 => no rootfs image available by default.
moveq 0, $r0
move.d romfs_length, $r1
move.d $r0, [$r1]
-#ifndef CONFIG_ETRAXFS_SIM
;; The kernel could have been unpacked to DRAM by the loader, but
- ;; the cramfs image could still be inte the flash immediately
- ;; following the compressed kernel image. The loaded passes the address
- ;; of the bute succeeding the last compressed byte in the flash in
+ ;; the cramfs image could still be in the flash immediately
+ ;; following the compressed kernel image. The loader passes the address
+ ;; of the byte succeeding the last compressed byte in the flash in
;; register R9 when starting the kernel.
cmp.d 0x0ffffff8, $r9
bhs _no_romfs_in_flash ; R9 points outside the flash area.
nop
-#else
- ba _no_romfs_in_flash
- nop
-#endif
+ ;; cramfs rootfs might to be in flash. Check for it.
move.d [$r9], $r0 ; cramfs_super.magic
cmp.d CRAMFS_MAGIC, $r0
bne _no_romfs_in_flash
nop
+ ;; found cramfs in flash. set address and size, and romfs_in_flash flag.
addoq +4, $r9, $acr
move.d [$acr], $r0
move.d romfs_length, $r1
@@ -330,27 +319,42 @@ move_cramfs:
nop
_no_romfs_in_flash:
- ;; Look for cramfs.
+ ;; No romfs in flash, so look for cramfs, or jffs2 with jhead,
+ ;; after kernel in RAM, as is the case with network->RAM boot.
+ ;; For cramfs, partition starts with magic and length.
+ ;; For jffs2, a jhead is prepended which contains with magic and length.
+ ;; The jhead is not part of the jffs2 partition however.
#ifndef CONFIG_ETRAXFS_SIM
- move.d __vmlinux_end, $r0
+ move.d __bss_start, $r0
#else
move.d __end, $r0
#endif
move.d [$r0], $r1
- cmp.d CRAMFS_MAGIC, $r1
- bne 2f
+ cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic?
+ beq 2f ; yes, jump
+ nop
+ cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic?
+ bne 4f ; no, skip copy
+ nop
+ addq 4, $r0 ; location of jffs2 size
+ move.d [$r0+], $r2 ; fetch jffs2 size -> r2
+ ; r0 now points to start of jffs2
+ ba 3f
nop
+2:
+ addoq +4, $r0, $acr ; location of cramfs size
+ move.d [$acr], $r2 ; fetch cramfs size -> r2
+ ; r0 still points to start of cramfs
+3:
+ ;; Now, move the root fs to after kernel's BSS
- addoq +4, $r0, $acr
- move.d [$acr], $r2
- move.d _end, $r1
+ move.d _end, $r1 ; start of cramfs -> r1
move.d romfs_start, $r3
- move.d $r1, [$r3]
+ move.d $r1, [$r3] ; store at romfs_start (for axisflashmap)
move.d romfs_length, $r3
- move.d $r2, [$r3]
+ move.d $r2, [$r3] ; store size at romfs_length
-#ifndef CONFIG_ETRAXFS_SIM
- add.d $r2, $r0
+ add.d $r2, $r0 ; copy from end and downwards
add.d $r2, $r1
lsrq 1, $r2 ; Size is in bytes, we copy words.
@@ -363,12 +367,18 @@ _no_romfs_in_flash:
subq 1, $r2
bne 1b
nop
-#endif
-2:
+4:
+ ;; BSS move done.
+ ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM
+ ;; Also clear nand_boot flag; if we got here, we know we've not
+ ;; booted from NAND flash.
moveq 0, $r0
move.d romfs_in_flash, $r1
move.d $r0, [$r1]
+ moveq 0, $r0
+ move.d nand_boot, $r1
+ move.d $r0, [$r1]
jump _start_it ; Jump to cached code.
nop
@@ -384,8 +394,8 @@ _start_it:
move.d cris_command_line, $r10
or.d 0x80000000, $r11 ; Make it virtual
1:
- move.b [$r11+], $r12
- move.b $r12, [$r10+]
+ move.b [$r11+], $r1
+ move.b $r1, [$r10+]
subq 1, $r13
bne 1b
nop
@@ -401,7 +411,6 @@ no_command_line:
move.d etrax_irv, $r1 ; Set the exception base register and pointer.
move.d $r0, [$r1]
-#ifndef CONFIG_ETRAXFS_SIM
;; Clear the BSS region from _bss_start to _end.
move.d __bss_start, $r0
move.d _end, $r1
@@ -409,39 +418,55 @@ no_command_line:
cmp.d $r1, $r0
blo 1b
nop
-#endif
-
-#ifdef CONFIG_ETRAXFS_SIM
- /* Set the watchdog timeout to something big. Will be removed when */
- /* watchdog can be disabled with command line option */
- move.d 0x7fffffff, $r10
- jsr CPU_WATCHDOG_TIMEOUT
- nop
-#endif
; Initialize registers to increase determinism
move.d __bss_start, $r0
movem [$r0], $r13
+#ifdef CONFIG_ETRAX_L2CACHE
+ jsr l2cache_init
+ nop
+#endif
+
jump start_kernel ; Jump to start_kernel() in init/main.c.
nop
.data
etrax_irv:
.dword 0
+
+; Variables for communication with the Axis flash map driver (axisflashmap),
+; and for setting up memory in arch/cris/kernel/setup.c .
+
+; romfs_start is set to the start of the root file system, if it exists
+; in directly accessible memory (i.e. NOR Flash when booting from Flash,
+; or RAM when booting directly from a network-downloaded RAM image)
romfs_start:
.dword 0
+
+; romfs_length is set to the size of the root file system image, if it exists
+; in directly accessible memory (see romfs_start). Otherwise it is set to 0.
romfs_length:
.dword 0
+
+; romfs_in_flash is set to 1 if the root file system resides in directly
+; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot
+; or NAND flash boot.
romfs_in_flash:
.dword 0
-crisv32_nand_boot:
- .dword 0
-crisv32_nand_cramfs_offset:
+
+; nand_boot is set to 1 when the kernel has been booted from NAND flash
+nand_boot:
.dword 0
swapper_pg_dir = 0xc0002000
.section ".init.data", "aw"
-#include "../lib/hw_settings.S"
+#if defined CONFIG_ETRAXFS
+#include "../mach-fs/hw_settings.S"
+#elif defined CONFIG_CRIS_MACH_ARTPEC3
+#include "../mach-a3/hw_settings.S"
+#else
+#error Only ETRAXFS and ARTPEC-3 supported!
+#endif
diff --git a/arch/cris/arch-v32/kernel/io.c b/arch/cris/arch-v32/kernel/io.c
deleted file mode 100644
index dfbfcb8d258..00000000000
--- a/arch/cris/arch-v32/kernel/io.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Helper functions for I/O pins.
- *
- * Copyright (c) 2004 Axis Communications AB.
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/hwregs/gio_defs.h>
-
-struct crisv32_ioport crisv32_ioports[] =
-{
- {
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe),
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout),
- (unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din),
- 8
- },
- {
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe),
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout),
- (unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din),
- 18
- },
- {
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe),
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout),
- (unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din),
- 18
- },
- {
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe),
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout),
- (unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din),
- 18
- },
- {
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe),
- (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout),
- (unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din),
- 18
- }
-};
-
-#define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport)
-
-struct crisv32_iopin crisv32_led1_green;
-struct crisv32_iopin crisv32_led1_red;
-struct crisv32_iopin crisv32_led2_green;
-struct crisv32_iopin crisv32_led2_red;
-struct crisv32_iopin crisv32_led3_green;
-struct crisv32_iopin crisv32_led3_red;
-
-/* Dummy port used when green LED and red LED is on the same bit */
-static unsigned long io_dummy;
-static struct crisv32_ioport dummy_port =
-{
- &io_dummy,
- &io_dummy,
- &io_dummy,
- 18
-};
-static struct crisv32_iopin dummy_led =
-{
- &dummy_port,
- 0
-};
-
-static int __init crisv32_io_init(void)
-{
- int ret = 0;
- /* Initialize LEDs */
- ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G);
- ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R);
- ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G);
- ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R);
- ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G);
- ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R);
- crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out);
- crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out);
- crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
- crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
- crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
- crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
-
- if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R))
- crisv32_led1_red = dummy_led;
- if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R))
- crisv32_led2_red = dummy_led;
-
- return ret;
-}
-
-__initcall(crisv32_io_init);
-
-int crisv32_io_get(struct crisv32_iopin* iopin,
- unsigned int port, unsigned int pin)
-{
- if (port > NBR_OF_PORTS)
- return -EINVAL;
- if (port > crisv32_ioports[port].pin_count)
- return -EINVAL;
-
- iopin->bit = 1 << pin;
- iopin->port = &crisv32_ioports[port];
-
- if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
- return -EIO;
-
- return 0;
-}
-
-int crisv32_io_get_name(struct crisv32_iopin* iopin,
- char* name)
-{
- int port;
- int pin;
-
- if (toupper(*name) == 'P')
- name++;
-
- if (toupper(*name) < 'A' || toupper(*name) > 'E')
- return -EINVAL;
-
- port = toupper(*name) - 'A';
- name++;
- pin = simple_strtoul(name, NULL, 10);
-
- if (pin < 0 || pin > crisv32_ioports[port].pin_count)
- return -EINVAL;
-
- iopin->bit = 1 << pin;
- iopin->port = &crisv32_ioports[port];
-
- if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
- return -EIO;
-
- return 0;
-}
-
-#ifdef CONFIG_PCI
-/* PCI I/O access stuff */
-struct cris_io_operations* cris_iops = NULL;
-EXPORT_SYMBOL(cris_iops);
-#endif
-
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index cc361bf578a..25437ae2812 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -15,15 +15,21 @@
#include <linux/threads.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/intr_vect_defs.h>
#define CPU_FIXED -1
/* IRQ masks (refer to comment for crisv32_do_multiple) */
-#define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ))
+#if TIMER0_INTR_VECT - FIRST_IRQ < 32
+#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ))
+#undef TIMER_VECT1
+#else
+#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32))
+#define TIMER_VECT1
+#endif
#ifdef CONFIG_ETRAX_KGDB
#if defined(CONFIG_ETRAX_KGDB_PORT0)
#define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ))
@@ -44,8 +50,8 @@ struct cris_irq_allocation
cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */
};
-struct cris_irq_allocation irq_allocations[NR_IRQS] =
- {[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}};
+struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] =
+ { [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} };
static unsigned long irq_regs[NR_CPUS] =
{
@@ -55,6 +61,12 @@ static unsigned long irq_regs[NR_CPUS] =
#endif
};
+#if NR_REAL_IRQS > 32
+#define NBR_REGS 2
+#else
+#define NBR_REGS 1
+#endif
+
unsigned long cpu_irq_counters[NR_CPUS];
unsigned long irq_counters[NR_REAL_IRQS];
@@ -79,45 +91,89 @@ extern void d_mmu_write(void);
extern void kgdb_init(void);
extern void breakpoint(void);
+/* From traps.c. */
+extern void breakh_BUG(void);
+
/*
- * Build the IRQ handler stubs using macros from irq.h. First argument is the
- * IRQ number, the second argument is the corresponding bit in
- * intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h.
+ * Build the IRQ handler stubs using macros from irq.h.
*/
-BUILD_IRQ(0x31, (1 << 0)) /* memarb */
-BUILD_IRQ(0x32, (1 << 1)) /* gen_io */
-BUILD_IRQ(0x33, (1 << 2)) /* iop0 */
-BUILD_IRQ(0x34, (1 << 3)) /* iop1 */
-BUILD_IRQ(0x35, (1 << 4)) /* iop2 */
-BUILD_IRQ(0x36, (1 << 5)) /* iop3 */
-BUILD_IRQ(0x37, (1 << 6)) /* dma0 */
-BUILD_IRQ(0x38, (1 << 7)) /* dma1 */
-BUILD_IRQ(0x39, (1 << 8)) /* dma2 */
-BUILD_IRQ(0x3a, (1 << 9)) /* dma3 */
-BUILD_IRQ(0x3b, (1 << 10)) /* dma4 */
-BUILD_IRQ(0x3c, (1 << 11)) /* dma5 */
-BUILD_IRQ(0x3d, (1 << 12)) /* dma6 */
-BUILD_IRQ(0x3e, (1 << 13)) /* dma7 */
-BUILD_IRQ(0x3f, (1 << 14)) /* dma8 */
-BUILD_IRQ(0x40, (1 << 15)) /* dma9 */
-BUILD_IRQ(0x41, (1 << 16)) /* ata */
-BUILD_IRQ(0x42, (1 << 17)) /* sser0 */
-BUILD_IRQ(0x43, (1 << 18)) /* sser1 */
-BUILD_IRQ(0x44, (1 << 19)) /* ser0 */
-BUILD_IRQ(0x45, (1 << 20)) /* ser1 */
-BUILD_IRQ(0x46, (1 << 21)) /* ser2 */
-BUILD_IRQ(0x47, (1 << 22)) /* ser3 */
-BUILD_IRQ(0x48, (1 << 23))
-BUILD_IRQ(0x49, (1 << 24)) /* eth0 */
-BUILD_IRQ(0x4a, (1 << 25)) /* eth1 */
-BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */
-BUILD_IRQ(0x4c, (1 << 27)) /* bif_arb */
-BUILD_IRQ(0x4d, (1 << 28)) /* bif_dma */
-BUILD_IRQ(0x4e, (1 << 29)) /* ext */
-BUILD_IRQ(0x4f, (1 << 29)) /* ipi */
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+BUILD_TIMER_IRQ(0x31, 0)
+#else
+BUILD_IRQ(0x31)
+#endif
+BUILD_IRQ(0x32)
+BUILD_IRQ(0x33)
+BUILD_IRQ(0x34)
+BUILD_IRQ(0x35)
+BUILD_IRQ(0x36)
+BUILD_IRQ(0x37)
+BUILD_IRQ(0x38)
+BUILD_IRQ(0x39)
+BUILD_IRQ(0x3a)
+BUILD_IRQ(0x3b)
+BUILD_IRQ(0x3c)
+BUILD_IRQ(0x3d)
+BUILD_IRQ(0x3e)
+BUILD_IRQ(0x3f)
+BUILD_IRQ(0x40)
+BUILD_IRQ(0x41)
+BUILD_IRQ(0x42)
+BUILD_IRQ(0x43)
+BUILD_IRQ(0x44)
+BUILD_IRQ(0x45)
+BUILD_IRQ(0x46)
+BUILD_IRQ(0x47)
+BUILD_IRQ(0x48)
+BUILD_IRQ(0x49)
+BUILD_IRQ(0x4a)
+#ifdef CONFIG_ETRAXFS
+BUILD_TIMER_IRQ(0x4b, 0)
+#else
+BUILD_IRQ(0x4b)
+#endif
+BUILD_IRQ(0x4c)
+BUILD_IRQ(0x4d)
+BUILD_IRQ(0x4e)
+BUILD_IRQ(0x4f)
+BUILD_IRQ(0x50)
+#if MACH_IRQS > 32
+BUILD_IRQ(0x51)
+BUILD_IRQ(0x52)
+BUILD_IRQ(0x53)
+BUILD_IRQ(0x54)
+BUILD_IRQ(0x55)
+BUILD_IRQ(0x56)
+BUILD_IRQ(0x57)
+BUILD_IRQ(0x58)
+BUILD_IRQ(0x59)
+BUILD_IRQ(0x5a)
+BUILD_IRQ(0x5b)
+BUILD_IRQ(0x5c)
+BUILD_IRQ(0x5d)
+BUILD_IRQ(0x5e)
+BUILD_IRQ(0x5f)
+BUILD_IRQ(0x60)
+BUILD_IRQ(0x61)
+BUILD_IRQ(0x62)
+BUILD_IRQ(0x63)
+BUILD_IRQ(0x64)
+BUILD_IRQ(0x65)
+BUILD_IRQ(0x66)
+BUILD_IRQ(0x67)
+BUILD_IRQ(0x68)
+BUILD_IRQ(0x69)
+BUILD_IRQ(0x6a)
+BUILD_IRQ(0x6b)
+BUILD_IRQ(0x6c)
+BUILD_IRQ(0x6d)
+BUILD_IRQ(0x6e)
+BUILD_IRQ(0x6f)
+BUILD_IRQ(0x70)
+#endif
/* Pointers to the low-level handlers. */
-static void (*interrupt[NR_IRQS])(void) = {
+static void (*interrupt[MACH_IRQS])(void) = {
IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt,
IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt,
IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt,
@@ -128,7 +184,20 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt,
IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt,
IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt,
- IRQ0x4f_interrupt
+ IRQ0x4f_interrupt, IRQ0x50_interrupt,
+#if MACH_IRQS > 32
+ IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt,
+ IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt,
+ IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt,
+ IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt,
+ IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt,
+ IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt,
+ IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt,
+ IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt,
+ IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt,
+ IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt,
+ IRQ0x6f_interrupt, IRQ0x70_interrupt,
+#endif
};
void
@@ -137,13 +206,21 @@ block_irq(int irq, int cpu)
int intr_mask;
unsigned long flags;
- spin_lock_irqsave(&irq_lock, flags);
- intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-
- /* Remember; 1 let thru, 0 block. */
- intr_mask &= ~(1 << (irq - FIRST_IRQ));
-
- REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
+ spin_lock_irqsave(&irq_lock, flags);
+ /* Remember, 1 let thru, 0 block. */
+ if (irq - FIRST_IRQ < 32) {
+ intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+ rw_mask, 0);
+ intr_mask &= ~(1 << (irq - FIRST_IRQ));
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+ 0, intr_mask);
+ } else {
+ intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+ rw_mask, 1);
+ intr_mask &= ~(1 << (irq - FIRST_IRQ - 32));
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+ 1, intr_mask);
+ }
spin_unlock_irqrestore(&irq_lock, flags);
}
@@ -154,12 +231,20 @@ unblock_irq(int irq, int cpu)
unsigned long flags;
spin_lock_irqsave(&irq_lock, flags);
- intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
-
- /* Remember; 1 let thru, 0 block. */
- intr_mask |= (1 << (irq - FIRST_IRQ));
-
- REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
+ /* Remember, 1 let thru, 0 block. */
+ if (irq - FIRST_IRQ < 32) {
+ intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+ rw_mask, 0);
+ intr_mask |= (1 << (irq - FIRST_IRQ));
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+ 0, intr_mask);
+ } else {
+ intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+ rw_mask, 1);
+ intr_mask |= (1 << (irq - FIRST_IRQ - 32));
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
+ 1, intr_mask);
+ }
spin_unlock_irqrestore(&irq_lock, flags);
}
@@ -181,19 +266,18 @@ static int irq_cpu(int irq)
/* Let the interrupt stay if possible */
- if (cpu_isset(cpu, irq_allocations[irq - FIRST_IRQ].mask))
+ if (cpumask_test_cpu(cpu, &irq_allocations[irq - FIRST_IRQ].mask))
goto out;
/* IRQ must be moved to another CPU. */
- cpu = first_cpu(irq_allocations[irq - FIRST_IRQ].mask);
+ cpu = cpumask_first(&irq_allocations[irq - FIRST_IRQ].mask);
irq_allocations[irq - FIRST_IRQ].cpu = cpu;
out:
spin_unlock_irqrestore(&irq_lock, flags);
return cpu;
}
-void
-mask_irq(int irq)
+void crisv32_mask_irq(int irq)
{
int cpu;
@@ -201,59 +285,39 @@ mask_irq(int irq)
block_irq(irq, cpu);
}
-void
-unmask_irq(int irq)
+void crisv32_unmask_irq(int irq)
{
unblock_irq(irq, irq_cpu(irq));
}
-static unsigned int startup_crisv32_irq(unsigned int irq)
+static void enable_crisv32_irq(struct irq_data *data)
{
- unmask_irq(irq);
- return 0;
+ crisv32_unmask_irq(data->irq);
}
-static void shutdown_crisv32_irq(unsigned int irq)
+static void disable_crisv32_irq(struct irq_data *data)
{
- mask_irq(irq);
+ crisv32_mask_irq(data->irq);
}
-static void enable_crisv32_irq(unsigned int irq)
-{
- unmask_irq(irq);
-}
-
-static void disable_crisv32_irq(unsigned int irq)
-{
- mask_irq(irq);
-}
-
-static void ack_crisv32_irq(unsigned int irq)
-{
-}
-
-static void end_crisv32_irq(unsigned int irq)
-{
-}
-
-void set_affinity_crisv32_irq(unsigned int irq, cpumask_t dest)
+static int set_affinity_crisv32_irq(struct irq_data *data,
+ const struct cpumask *dest, bool force)
{
unsigned long flags;
+
spin_lock_irqsave(&irq_lock, flags);
- irq_allocations[irq - FIRST_IRQ].mask = dest;
+ irq_allocations[data->irq - FIRST_IRQ].mask = *dest;
spin_unlock_irqrestore(&irq_lock, flags);
+ return 0;
}
-static struct hw_interrupt_type crisv32_irq_type = {
- .typename = "CRISv32",
- .startup = startup_crisv32_irq,
- .shutdown = shutdown_crisv32_irq,
- .enable = enable_crisv32_irq,
- .disable = disable_crisv32_irq,
- .ack = ack_crisv32_irq,
- .end = end_crisv32_irq,
- .set_affinity = set_affinity_crisv32_irq
+static struct irq_chip crisv32_irq_type = {
+ .name = "CRISv32",
+ .irq_shutdown = disable_crisv32_irq,
+ .irq_enable = enable_crisv32_irq,
+ .irq_disable = disable_crisv32_irq,
+ .irq_set_affinity = set_affinity_crisv32_irq,
};
void
@@ -267,11 +331,11 @@ extern void do_IRQ(int irq, struct pt_regs * regs);
void
crisv32_do_IRQ(int irq, int block, struct pt_regs* regs)
{
- /* Interrupts that may not be moved to another CPU and
- * are IRQF_DISABLED may skip blocking. This is currently
- * only valid for the timer IRQ and the IPI and is used
- * for the timer interrupt to avoid watchdog starvation.
- */
+ /* Interrupts that may not be moved to another CPU may
+ * skip blocking. This is currently only valid for the
+ * timer IRQ and the IPI and is used for the timer
+ * interrupt to avoid watchdog starvation.
+ */
if (!block) {
do_IRQ(irq, regs);
return;
@@ -298,8 +362,9 @@ crisv32_do_multiple(struct pt_regs* regs)
{
int cpu;
int mask;
- int masked;
+ int masked[NBR_REGS];
int bit;
+ int i;
cpu = smp_processor_id();
@@ -308,42 +373,59 @@ crisv32_do_multiple(struct pt_regs* regs)
*/
irq_enter();
- /* Get which IRQs that happend. */
- masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect);
+ for (i = 0; i < NBR_REGS; i++) {
+ /* Get which IRQs that happened. */
+ masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
+ r_masked_vect, i);
- /* Calculate new IRQ mask with these IRQs disabled. */
- mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
- mask &= ~masked;
+ /* Calculate new IRQ mask with these IRQs disabled. */
+ mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
+ mask &= ~masked[i];
/* Timer IRQ is never masked */
- if (masked & TIMER_MASK)
- mask |= TIMER_MASK;
-
- /* Block all the IRQs */
- REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+#ifdef TIMER_VECT1
+ if ((i == 1) && (masked[0] & TIMER_MASK))
+ mask |= TIMER_MASK;
+#else
+ if ((i == 0) && (masked[0] & TIMER_MASK))
+ mask |= TIMER_MASK;
+#endif
+ /* Block all the IRQs */
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
/* Check for timer IRQ and handle it special. */
- if (masked & TIMER_MASK) {
- masked &= ~TIMER_MASK;
- do_IRQ(TIMER_INTR_VECT, regs);
+#ifdef TIMER_VECT1
+ if ((i == 1) && (masked[i] & TIMER_MASK)) {
+ masked[i] &= ~TIMER_MASK;
+ do_IRQ(TIMER0_INTR_VECT, regs);
+ }
+#else
+ if ((i == 0) && (masked[i] & TIMER_MASK)) {
+ masked[i] &= ~TIMER_MASK;
+ do_IRQ(TIMER0_INTR_VECT, regs);
+ }
+#endif
}
#ifdef IGNORE_MASK
/* Remove IRQs that can't be handled as multiple. */
- masked &= ~IGNORE_MASK;
+ masked[0] &= ~IGNORE_MASK;
#endif
/* Handle the rest of the IRQs. */
- for (bit = 0; bit < 32; bit++)
- {
- if (masked & (1 << bit))
- do_IRQ(bit + FIRST_IRQ, regs);
+ for (i = 0; i < NBR_REGS; i++) {
+ for (bit = 0; bit < 32; bit++) {
+ if (masked[i] & (1 << bit))
+ do_IRQ(bit + FIRST_IRQ + i*32, regs);
+ }
}
/* Unblock all the IRQs. */
- mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
- mask |= masked;
- REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+ for (i = 0; i < NBR_REGS; i++) {
+ mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
+ mask |= masked[i];
+ REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
+ }
/* This irq_exit() will trigger the soft IRQs. */
irq_exit();
@@ -361,22 +443,24 @@ init_IRQ(void)
reg_intr_vect_rw_mask vect_mask = {0};
/* Clear all interrupts masks. */
- REG_WR(intr_vect, regi_irq, rw_mask, vect_mask);
+ for (i = 0; i < NBR_REGS; i++)
+ REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask);
for (i = 0; i < 256; i++)
etrax_irv->v[i] = weird_irq;
/* Point all IRQ's to bad handlers. */
for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
- irq_desc[j].chip = &crisv32_irq_type;
+ irq_set_chip_and_handler(j, &crisv32_irq_type,
+ handle_simple_irq);
set_exception_vector(i, interrupt[j]);
}
- /* Mark Timer and IPI IRQs as CPU local */
- irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
- irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU;
+ /* Mark Timer and IPI IRQs as CPU local */
+ irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
+ irq_set_status_flags(TIMER0_INTR_VECT, IRQ_PER_CPU);
irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
- irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU;
+ irq_set_status_flags(IPI_INTR_VECT, IRQ_PER_CPU);
set_exception_vector(0x00, nmi_interrupt);
set_exception_vector(0x30, multiple_interrupt);
@@ -391,6 +475,11 @@ init_IRQ(void)
set_exception_vector(0x0a, d_mmu_access);
set_exception_vector(0x0b, d_mmu_write);
+#ifdef CONFIG_BUG
+ /* Break 14 handler, used to implement cheap BUG(). */
+ set_exception_vector(0x1e, breakh_BUG);
+#endif
+
/* The system-call trap is reached by "break 13". */
set_exception_vector(0x1d, system_call);
diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c
index 480e56348be..b06813aeb12 100644
--- a/arch/cris/arch-v32/kernel/kgdb.c
+++ b/arch/cris/arch-v32/kernel/kgdb.c
@@ -174,10 +174,10 @@
#include <asm/ptrace.h>
#include <asm/irq.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
-#include <asm/arch/hwregs/ser_defs.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/intr_vect_defs.h>
+#include <hwregs/ser_defs.h>
/* From entry.S. */
extern void gdb_handle_exception(void);
@@ -381,31 +381,9 @@ static int read_register(char regno, unsigned int *valptr);
/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
int getDebugChar(void);
-#ifdef CONFIG_ETRAXFS_SIM
-int getDebugChar(void)
-{
- return socketread();
-}
-#endif
-
/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
void putDebugChar(int val);
-#ifdef CONFIG_ETRAXFS_SIM
-void putDebugChar(int val)
-{
- socketwrite((char *)&val, 1);
-}
-#endif
-
-/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
- represented by int x. */
-static char highhex(int x);
-
-/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
- represented by int x. */
-static char lowhex(int x);
-
/* Returns the integer equivalent of a hexadecimal character. */
static int hex(char ch);
@@ -464,9 +442,6 @@ void breakpoint(void);
/* Run-length encoding maximum length. Send 64 at most. */
#define RUNLENMAX 64
-/* Definition of all valid hexadecimal characters */
-static const char hexchars[] = "0123456789abcdef";
-
/* The inbound/outbound buffers used in packet I/O */
static char input_buffer[BUFMAX];
static char output_buffer[BUFMAX];
@@ -550,8 +525,8 @@ gdb_cris_strtol(const char *s, char **endptr, int base)
char *sd;
int x = 0;
- for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1)
- x = x * base + (sd - hexchars);
+ for (s1 = (char*)s; (sd = gdb_cris_memchr(hex_asc, *s1, base)) != NULL; ++s1)
+ x = x * base + (sd - hex_asc);
if (endptr) {
/* Unconverted suffix is stored in endptr unless endptr is NULL. */
@@ -655,22 +630,6 @@ read_register(char regno, unsigned int *valptr)
}
/********************************** Packet I/O ******************************/
-/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
- represented by int x. */
-static inline char
-highhex(int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
- represented by int x. */
-static inline char
-lowhex(int x)
-{
- return hexchars[x & 0xf];
-}
-
/* Returns the integer equivalent of a hexadecimal character. */
static int
hex(char ch)
@@ -704,8 +663,7 @@ mem2hex(char *buf, unsigned char *mem, int count)
/* Valid mem address. */
for (i = 0; i < count; i++) {
ch = *mem++;
- *buf++ = highhex (ch);
- *buf++ = lowhex (ch);
+ buf = hex_byte_pack(buf, ch);
}
}
/* Terminate properly. */
@@ -723,8 +681,7 @@ mem2hex_nbo(char *buf, unsigned char *mem, int count)
mem += count - 1;
for (i = 0; i < count; i++) {
ch = *mem--;
- *buf++ = highhex (ch);
- *buf++ = lowhex (ch);
+ buf = hex_byte_pack(buf, ch);
}
/* Terminate properly. */
@@ -862,8 +819,8 @@ putpacket(char *buffer)
}
}
putDebugChar('#');
- putDebugChar(highhex (checksum));
- putDebugChar(lowhex (checksum));
+ putDebugChar(hex_asc_hi(checksum));
+ putDebugChar(hex_asc_lo(checksum));
} while(kgdb_started && (getDebugChar() != '+'));
}
@@ -909,8 +866,7 @@ stub_is_stopped(int sigval)
/* Send trap type (converted to signal) */
*ptr++ = 'T';
- *ptr++ = highhex(sigval);
- *ptr++ = lowhex(sigval);
+ ptr = hex_byte_pack(ptr, sigval);
if (((reg.exs & 0xff00) >> 8) == 0xc) {
@@ -955,7 +911,7 @@ stub_is_stopped(int sigval)
if (reg.eda >= bp_d_regs[bp * 2] &&
reg.eda <= bp_d_regs[bp * 2 + 1]) {
- /* EDA withing range for this BP; it must be the one
+ /* EDA within range for this BP; it must be the one
we're looking for. */
stopped_data_address = reg.eda;
break;
@@ -1018,30 +974,26 @@ stub_is_stopped(int sigval)
}
/* Only send PC, frame and stack pointer. */
read_register(PC, &reg_cont);
- *ptr++ = highhex(PC);
- *ptr++ = lowhex(PC);
+ ptr = hex_byte_pack(ptr, PC);
*ptr++ = ':';
ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[PC]);
*ptr++ = ';';
read_register(R8, &reg_cont);
- *ptr++ = highhex(R8);
- *ptr++ = lowhex(R8);
+ ptr = hex_byte_pack(ptr, R8);
*ptr++ = ':';
ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[R8]);
*ptr++ = ';';
read_register(SP, &reg_cont);
- *ptr++ = highhex(SP);
- *ptr++ = lowhex(SP);
+ ptr = hex_byte_pack(ptr, SP);
*ptr++ = ':';
ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[SP]);
*ptr++ = ';';
/* Send ERP as well; this will save us an entire register fetch in some cases. */
read_register(ERP, &reg_cont);
- *ptr++ = highhex(ERP);
- *ptr++ = lowhex(ERP);
+ ptr = hex_byte_pack(ptr, ERP);
*ptr++ = ':';
ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[ERP]);
*ptr++ = ';';
@@ -1533,8 +1485,8 @@ handle_exception(int sigval)
Success: SAA, where AA is the signal number.
Failure: void. */
output_buffer[0] = 'S';
- output_buffer[1] = highhex(sigval);
- output_buffer[2] = lowhex(sigval);
+ output_buffer[1] = hex_asc_hi(sigval);
+ output_buffer[2] = hex_asc_lo(sigval);
output_buffer[3] = 0;
break;
@@ -1599,7 +1551,7 @@ kgdb_init(void)
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask);
- ser_intr_mask.data_avail = regk_ser_yes;
+ ser_intr_mask.dav = regk_ser_yes;
REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask);
#elif defined(CONFIG_ETRAX_KGDB_PORT1)
/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1611,7 +1563,7 @@ kgdb_init(void)
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask);
- ser_intr_mask.data_avail = regk_ser_yes;
+ ser_intr_mask.dav = regk_ser_yes;
REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask);
#elif defined(CONFIG_ETRAX_KGDB_PORT2)
/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1623,7 +1575,7 @@ kgdb_init(void)
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask);
- ser_intr_mask.data_avail = regk_ser_yes;
+ ser_intr_mask.dav = regk_ser_yes;
REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask);
#elif defined(CONFIG_ETRAX_KGDB_PORT3)
/* Note: no shortcut registered (not handled by multiple_interrupt).
@@ -1635,7 +1587,7 @@ kgdb_init(void)
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask);
- ser_intr_mask.data_avail = regk_ser_yes;
+ ser_intr_mask.dav = regk_ser_yes;
REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask);
#endif
diff --git a/arch/cris/arch-v32/kernel/kgdb_asm.S b/arch/cris/arch-v32/kernel/kgdb_asm.S
index 3e7fa9ef851..f3a47605902 100644
--- a/arch/cris/arch-v32/kernel/kgdb_asm.S
+++ b/arch/cris/arch-v32/kernel/kgdb_asm.S
@@ -5,7 +5,7 @@
* port exceptions for kernel debugging purposes.
*/
-#include <asm/arch/hwregs/intr_vect.h>
+#include <hwregs/intr_vect.h>
;; Exported functions.
.globl kgdb_handle_exception
diff --git a/arch/cris/arch-v32/kernel/pinmux.c b/arch/cris/arch-v32/kernel/pinmux.c
deleted file mode 100644
index a2b8aa37c1b..00000000000
--- a/arch/cris/arch-v32/kernel/pinmux.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
- * Unassigned pins and GPIO pins can be allocated to a fixed interface
- * or the I/O processor instead.
- *
- * Copyright (c) 2004 Axis Communications AB.
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch/hwregs/pinmux_defs.h>
-
-#undef DEBUG
-
-#define PORT_PINS 18
-#define PORTS 4
-
-static char pins[PORTS][PORT_PINS];
-static DEFINE_SPINLOCK(pinmux_lock);
-
-static void crisv32_pinmux_set(int port);
-
-int
-crisv32_pinmux_init(void)
-{
- static int initialized = 0;
-
- if (!initialized) {
- reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);
- initialized = 1;
- pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
- pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
- REG_WR(pinmux, regi_pinmux, rw_pa, pa);
- crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
- crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
- crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
- crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
- }
-
- return 0;
-}
-
-int
-crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
-{
- int i;
- unsigned long flags;
-
- crisv32_pinmux_init();
-
- if (port > PORTS)
- return -EINVAL;
-
- spin_lock_irqsave(&pinmux_lock, flags);
-
- for (i = first_pin; i <= last_pin; i++)
- {
- if ((pins[port][i] != pinmux_none) && (pins[port][i] != pinmux_gpio) &&
- (pins[port][i] != mode))
- {
- spin_unlock_irqrestore(&pinmux_lock, flags);
-#ifdef DEBUG
- panic("Pinmux alloc failed!\n");
-#endif
- return -EPERM;
- }
- }
-
- for (i = first_pin; i <= last_pin; i++)
- pins[port][i] = mode;
-
- crisv32_pinmux_set(port);
-
- spin_unlock_irqrestore(&pinmux_lock, flags);
-
- return 0;
-}
-
-int
-crisv32_pinmux_alloc_fixed(enum fixed_function function)
-{
- int ret = -EINVAL;
- char saved[sizeof pins];
- unsigned long flags;
-
- spin_lock_irqsave(&pinmux_lock, flags);
-
- /* Save internal data for recovery */
- memcpy(saved, pins, sizeof pins);
-
- reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
-
- switch(function)
- {
- case pinmux_ser1:
- ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
- hwprot.ser1 = regk_pinmux_yes;
- break;
- case pinmux_ser2:
- ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
- hwprot.ser2 = regk_pinmux_yes;
- break;
- case pinmux_ser3:
- ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
- hwprot.ser3 = regk_pinmux_yes;
- break;
- case pinmux_sser0:
- ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
- hwprot.sser0 = regk_pinmux_yes;
- break;
- case pinmux_sser1:
- ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
- hwprot.sser1 = regk_pinmux_yes;
- break;
- case pinmux_ata0:
- ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
- hwprot.ata0 = regk_pinmux_yes;
- break;
- case pinmux_ata1:
- ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
- hwprot.ata1 = regk_pinmux_yes;
- break;
- case pinmux_ata2:
- ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
- hwprot.ata2 = regk_pinmux_yes;
- break;
- case pinmux_ata3:
- ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
- hwprot.ata2 = regk_pinmux_yes;
- break;
- case pinmux_ata:
- ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
- ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
- hwprot.ata = regk_pinmux_yes;
- break;
- case pinmux_eth1:
- ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
- hwprot.eth1 = regk_pinmux_yes;
- hwprot.eth1_mgm = regk_pinmux_yes;
- break;
- case pinmux_timer:
- ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
- hwprot.timer = regk_pinmux_yes;
- spin_unlock_irqrestore(&pinmux_lock, flags);
- return ret;
- }
-
- if (!ret)
- REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
- else
- memcpy(pins, saved, sizeof pins);
-
- spin_unlock_irqrestore(&pinmux_lock, flags);
-
- return ret;
-}
-
-void
-crisv32_pinmux_set(int port)
-{
- int i;
- int gpio_val = 0;
- int iop_val = 0;
-
- for (i = 0; i < PORT_PINS; i++)
- {
- if (pins[port][i] == pinmux_gpio)
- gpio_val |= (1 << i);
- else if (pins[port][i] == pinmux_iop)
- iop_val |= (1 << i);
- }
-
- REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8*port, gpio_val);
- REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8*port, iop_val);
-
-#ifdef DEBUG
- crisv32_pinmux_dump();
-#endif
-}
-
-int
-crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
-{
- int i;
- unsigned long flags;
-
- crisv32_pinmux_init();
-
- if (port > PORTS)
- return -EINVAL;
-
- spin_lock_irqsave(&pinmux_lock, flags);
-
- for (i = first_pin; i <= last_pin; i++)
- pins[port][i] = pinmux_none;
-
- crisv32_pinmux_set(port);
- spin_unlock_irqrestore(&pinmux_lock, flags);
-
- return 0;
-}
-
-void
-crisv32_pinmux_dump(void)
-{
- int i, j;
-
- crisv32_pinmux_init();
-
- for (i = 0; i < PORTS; i++)
- {
- printk("Port %c\n", 'B'+i);
- for (j = 0; j < PORT_PINS; j++)
- printk(" Pin %d = %d\n", j, pins[i][j]);
- }
-}
-
-__initcall(crisv32_pinmux_init);
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index 6326351af25..cebd32e2a8f 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -9,32 +9,23 @@
*/
#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/fs.h>
-#include <linux/slab.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/timer_defs.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/reg_map.h>
+#include <hwregs/timer_defs.h>
+#include <hwregs/intr_vect_defs.h>
+#include <linux/ptrace.h>
extern void stop_watchdog(void);
-#ifdef CONFIG_ETRAX_GPIO
-extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */
-#endif
-
-extern int cris_hlt_counter;
-
/* We use this if we don't have any better idle routine. */
void default_idle(void)
{
- local_irq_disable();
- if (!need_resched() && !cris_hlt_counter) {
- /* Halt until exception. */
- __asm__ volatile("ei \n\t"
- "halt ");
- }
- local_irq_enable();
+ /* Halt until exception. */
+ __asm__ volatile("ei \n\t"
+ "halt ");
}
/*
@@ -82,7 +73,7 @@ hard_reset_now(void)
wd_ctrl.cmd = regk_timer_start;
arch_enable_nmi();
- REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+ REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
}
#endif
@@ -98,31 +89,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
return task_pt_regs(t)->erp;
}
-static void
-kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
-{
- fn(arg);
- do_exit(-1); /* Should never be called, return bad exit value. */
-}
-
-/* Create a kernel thread. */
-int
-kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- /* Don't use r10 since that is set to 0 in copy_thread. */
- regs.r11 = (unsigned long) fn;
- regs.r12 = (unsigned long) arg;
- regs.erp = (unsigned long) kernel_thread_helper;
- regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
-
- /* Create the new process. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
/*
* Setup the child's kernel stack with a pt_regs and call switch_stack() on it.
* It will be unnested during _resume and _ret_from_sys_call when the new thread
@@ -133,36 +99,44 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
*/
extern asmlinkage void ret_from_fork(void);
+extern asmlinkage void ret_from_kernel_thread(void);
int
-copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
- struct task_struct *p, struct pt_regs *regs)
+copy_thread(unsigned long clone_flags, unsigned long usp,
+ unsigned long arg, struct task_struct *p)
{
- struct pt_regs *childregs;
- struct switch_stack *swstack;
+ struct pt_regs *childregs = task_pt_regs(p);
+ struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1;
/*
* Put the pt_regs structure at the end of the new kernel stack page and
* fix it up. Note: the task_struct doubles as the kernel stack for the
* task.
*/
- childregs = task_pt_regs(p);
- *childregs = *regs; /* Struct copy of pt_regs. */
- p->set_child_tid = p->clear_child_tid = NULL;
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(swstack, 0,
+ sizeof(struct switch_stack) + sizeof(struct pt_regs));
+ swstack->r1 = usp;
+ swstack->r2 = arg;
+ childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
+ swstack->return_ip = (unsigned long) ret_from_kernel_thread;
+ p->thread.ksp = (unsigned long) swstack;
+ p->thread.usp = 0;
+ return 0;
+ }
+ *childregs = *current_pt_regs(); /* Struct copy of pt_regs. */
childregs->r10 = 0; /* Child returns 0 after a fork/clone. */
/* Set a new TLS ?
- * The TLS is in $mof beacuse it is the 5th argument to sys_clone.
+ * The TLS is in $mof because it is the 5th argument to sys_clone.
*/
if (p->mm && (clone_flags & CLONE_SETTLS)) {
- task_thread_info(p)->tls = regs->mof;
+ task_thread_info(p)->tls = childregs->mof;
}
/* Put the switch stack right below the pt_regs. */
- swstack = ((struct switch_stack *) childregs) - 1;
- /* Paramater to ret_from_sys_call. 0 is don't restart the syscall. */
+ /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */
swstack->r9 = 0;
/*
@@ -172,74 +146,12 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
swstack->return_ip = (unsigned long) ret_from_fork;
/* Fix the user-mode and kernel-mode stackpointer. */
- p->thread.usp = usp;
+ p->thread.usp = usp ?: rdusp();
p->thread.ksp = (unsigned long) swstack;
return 0;
}
-/*
- * Be aware of the "magic" 7th argument in the four system-calls below.
- * They need the latest stackframe, which is put as the 7th argument by
- * entry.S. The previous arguments are dummies or actually used, but need
- * to be defined to reach the 7th argument.
- *
- * N.B.: Another method to get the stackframe is to use current_regs(). But
- * it returns the latest stack-frame stacked when going from _user mode_ and
- * some of these (at least sys_clone) are called from kernel-mode sometimes
- * (for example during kernel_thread, above) and thus cannot use it. Thus,
- * to be sure not to get any surprises, we use the method for the other calls
- * as well.
- */
-asmlinkage int
-sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
-asmlinkage int
-sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid,
- unsigned long tls, long srp, struct pt_regs *regs)
-{
- if (!newusp)
- newusp = rdusp();
-
- return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
-}
-
-/*
- * vfork is a system call in i386 because of register-pressure - maybe
- * we can remove it and handle it in libc but we put it here until then.
- */
-asmlinkage int
-sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* sys_execve() executes a new program. */
-asmlinkage int
-sys_execve(const char *fname, char **argv, char **envp, long r13, long mof, long srp,
- struct pt_regs *regs)
-{
- int error;
- char *filename;
-
- filename = getname(fname);
- error = PTR_ERR(filename);
-
- if (IS_ERR(filename))
- goto out;
-
- error = do_execve(filename, argv, envp, regs);
- putname(filename);
- out:
- return error;
-}
-
unsigned long
get_wchan(struct task_struct *p)
{
@@ -252,6 +164,9 @@ get_wchan(struct task_struct *p)
void show_regs(struct pt_regs * regs)
{
unsigned long usp = rdusp();
+
+ show_regs_print_info(KERN_DEFAULT);
+
printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
regs->erp, regs->srp, regs->ccs, usp, regs->mof);
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 82cf2e3624a..f085229cf87 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -1,12 +1,11 @@
/*
- * Copyright (C) 2000-2003, Axis Communications AB.
+ * Copyright (C) 2000-2007, Axis Communications AB.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -16,9 +15,8 @@
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
#include <asm/processor.h>
-#include <asm/arch/hwregs/supp_reg.h>
+#include <arch/hwregs/supp_reg.h>
/*
* Determines which bits in CCS the user has access to.
@@ -79,6 +77,35 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
return 0;
}
+void user_enable_single_step(struct task_struct *child)
+{
+ unsigned long tmp;
+
+ /*
+ * Set up SPC if not set already (in which case we have no other
+ * choice but to trust it).
+ */
+ if (!get_reg(child, PT_SPC)) {
+ /* In case we're stopped in a delay slot. */
+ tmp = get_reg(child, PT_ERP) & ~1;
+ put_reg(child, PT_SPC, tmp);
+ }
+ tmp = get_reg(child, PT_CCS) | SBIT_USER;
+ put_reg(child, PT_CCS, tmp);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ put_reg(child, PT_SPC, 0);
+
+ if (!get_debugreg(child->pid, PT_BP_CTRL)) {
+ unsigned long tmp;
+ /* If no h/w bp configured, disable S bit. */
+ tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
+ put_reg(child, PT_CCS, tmp);
+ }
+}
+
/*
* Called by kernel/ptrace.c when detaching.
*
@@ -87,11 +114,8 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
void
ptrace_disable(struct task_struct *child)
{
- unsigned long tmp;
-
/* Deconfigure SPC and S-bit. */
- tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
- put_reg(child, PT_CCS, tmp);
+ user_disable_single_step(child);
put_reg(child, PT_SPC, 0);
/* Deconfigure any watchpoints associated with the child. */
@@ -99,9 +123,11 @@ ptrace_disable(struct task_struct *child)
}
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int ret;
+ unsigned int regno = addr >> 2;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
@@ -136,10 +162,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- tmp = get_reg(child, addr >> 2);
+ tmp = get_reg(child, regno);
ret = put_user(tmp, datap);
break;
}
@@ -147,117 +173,30 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = 0;
-
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
-
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
- /* Write the word at location address in the USER area. */
+ /* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+ if ((addr & 3) || regno > PT_MAX)
break;
- addr >>= 2;
-
- if (addr == PT_CCS) {
+ if (regno == PT_CCS) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= CCS_MASK;
data |= get_reg(child, PT_CCS) & ~CCS_MASK;
}
- if (put_reg(child, addr, data))
- break;
- ret = 0;
- break;
-
- case PTRACE_SYSCALL:
- case PTRACE_CONT:
- ret = -EIO;
-
- if (!valid_signal(data))
- break;
-
- /* Continue means no single-step. */
- put_reg(child, PT_SPC, 0);
-
- if (!get_debugreg(child->pid, PT_BP_CTRL)) {
- unsigned long tmp;
- /* If no h/w bp configured, disable S bit. */
- tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
- put_reg(child, PT_CCS, tmp);
- }
-
- if (request == PTRACE_SYSCALL) {
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- else {
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
-
- child->exit_code = data;
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- ret = 0;
-
- break;
-
- /* Make the child exit by sending it a sigkill. */
- case PTRACE_KILL:
- ret = 0;
-
- if (child->exit_state == EXIT_ZOMBIE)
- break;
-
- child->exit_code = SIGKILL;
-
- /* Deconfigure single-step and h/w bp. */
- ptrace_disable(child);
-
- /* TODO: make sure any pending breakpoint is killed */
- wake_up_process(child);
- break;
-
- /* Set the trap flag. */
- case PTRACE_SINGLESTEP: {
- unsigned long tmp;
- ret = -EIO;
-
- /* Set up SPC if not set already (in which case we have
- no other choice but to trust it). */
- if (!get_reg(child, PT_SPC)) {
- /* In case we're stopped in a delay slot. */
- tmp = get_reg(child, PT_ERP) & ~1;
- put_reg(child, PT_SPC, tmp);
- }
- tmp = get_reg(child, PT_CCS) | SBIT_USER;
- put_reg(child, PT_CCS, tmp);
-
- if (!valid_signal(data))
+ if (put_reg(child, regno, data))
break;
-
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
- /* TODO: set some clever breakpoint mechanism... */
-
- child->exit_code = data;
- wake_up_process(child);
ret = 0;
break;
- }
- case PTRACE_DETACH:
- ret = ptrace_detach(child, data);
- break;
-
/* Get all GP registers from the child. */
case PTRACE_GETREGS: {
- int i;
+ int i;
unsigned long tmp;
for (i = 0; i <= PT_MAX; i++) {
@@ -304,6 +243,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
+out_tsk:
return ret;
}
diff --git a/arch/cris/arch-v32/kernel/setup.c b/arch/cris/arch-v32/kernel/setup.c
index 4662f363df6..61e10ae6529 100644
--- a/arch/cris/arch-v32/kernel/setup.c
+++ b/arch/cris/arch-v32/kernel/setup.c
@@ -9,6 +9,9 @@
#include <linux/delay.h>
#include <linux/param.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+
#ifdef CONFIG_PROC_FS
#define HAS_FPU 0x0001
@@ -43,23 +46,22 @@ static struct cpu_info cpinfo[] = {
{"ETRAX 100LX v2", 11, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB
| HAS_MMU},
-
+#ifdef CONFIG_ETRAXFS
{"ETRAX FS", 32, 32, HAS_ETHERNET100 | HAS_ATA | HAS_MMU},
-
+#else
+ {"ARTPEC-3", 32, 32, HAS_ETHERNET100 | HAS_MMU},
+#endif
{"Unknown", 0, 0, 0}
};
-int
-show_cpuinfo(struct seq_file *m, void *v)
+int show_cpuinfo(struct seq_file *m, void *v)
{
int i;
int cpu = (int)v - 1;
- int entries;
unsigned long revision;
struct cpu_info *info;
- entries = sizeof cpinfo / sizeof(struct cpu_info);
- info = &cpinfo[entries - 1];
+ info = &cpinfo[ARRAY_SIZE(cpinfo) - 1];
#ifdef CONFIG_SMP
if (!cpu_online(cpu))
@@ -68,7 +70,7 @@ show_cpuinfo(struct seq_file *m, void *v)
revision = rdvr();
- for (i = 0; i < entries; i++) {
+ for (i = 0; i < ARRAY_SIZE(cpinfo); i++) {
if (cpinfo[i].rev == revision) {
info = &cpinfo[i];
break;
@@ -109,9 +111,63 @@ show_cpuinfo(struct seq_file *m, void *v)
#endif /* CONFIG_PROC_FS */
-void
-show_etrax_copyright(void)
+void show_etrax_copyright(void)
+{
+#ifdef CONFIG_ETRAXFS
+ printk(KERN_INFO "Linux/CRISv32 port on ETRAX FS "
+ "(C) 2003, 2004 Axis Communications AB\n");
+#else
+ printk(KERN_INFO "Linux/CRISv32 port on ARTPEC-3 "
+ "(C) 2003-2009 Axis Communications AB\n");
+#endif
+}
+
+static struct i2c_board_info __initdata i2c_info[] = {
+ {I2C_BOARD_INFO("camblock", 0x43)},
+ {I2C_BOARD_INFO("tmp100", 0x48)},
+ {I2C_BOARD_INFO("tmp100", 0x4A)},
+ {I2C_BOARD_INFO("tmp100", 0x4C)},
+ {I2C_BOARD_INFO("tmp100", 0x4D)},
+ {I2C_BOARD_INFO("tmp100", 0x4E)},
+#ifdef CONFIG_RTC_DRV_PCF8563
+ {I2C_BOARD_INFO("pcf8563", 0x51)},
+#endif
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+ {I2C_BOARD_INFO("vgpio", 0x20)},
+ {I2C_BOARD_INFO("vgpio", 0x21)},
+#endif
+ {I2C_BOARD_INFO("pca9536", 0x41)},
+ {I2C_BOARD_INFO("fnp300", 0x40)},
+ {I2C_BOARD_INFO("fnp300", 0x42)},
+ {I2C_BOARD_INFO("adc101", 0x54)},
+};
+
+static struct i2c_board_info __initdata i2c_info2[] = {
+ {I2C_BOARD_INFO("camblock", 0x43)},
+ {I2C_BOARD_INFO("tmp100", 0x48)},
+ {I2C_BOARD_INFO("tmp100", 0x4A)},
+ {I2C_BOARD_INFO("tmp100", 0x4C)},
+ {I2C_BOARD_INFO("tmp100", 0x4D)},
+ {I2C_BOARD_INFO("tmp100", 0x4E)},
+#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
+ {I2C_BOARD_INFO("vgpio", 0x20)},
+ {I2C_BOARD_INFO("vgpio", 0x21)},
+#endif
+ {I2C_BOARD_INFO("pca9536", 0x41)},
+ {I2C_BOARD_INFO("fnp300", 0x40)},
+ {I2C_BOARD_INFO("fnp300", 0x42)},
+ {I2C_BOARD_INFO("adc101", 0x54)},
+};
+
+static struct i2c_board_info __initdata i2c_info3[] = {
+ {I2C_BOARD_INFO("adc101", 0x54)},
+};
+
+static int __init etrax_init(void)
{
- printk(KERN_INFO
- "Linux/CRISv32 port on ETRAX FS (C) 2003, 2004 Axis Communications AB\n");
+ i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
+ i2c_register_board_info(1, i2c_info2, ARRAY_SIZE(i2c_info2));
+ i2c_register_board_info(2, i2c_info3, ARRAY_SIZE(i2c_info3));
+ return 0;
}
+arch_initcall(etrax_init);
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index 99e59b3eacf..01d1375c900 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
@@ -18,14 +19,11 @@
#include <asm/processor.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
-#include <asm/arch/ptrace.h>
-#include <asm/arch/hwregs/cpu_vect.h>
+#include <arch/ptrace.h>
+#include <arch/hwregs/cpu_vect.h>
extern unsigned long cris_signal_return_page;
-/* Flag to check if a signal is blockable. */
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
/*
* A syscall in CRIS is really a "break 13" instruction, which is 2
* bytes. The registers is manipulated so upon return the instruction
@@ -50,128 +48,9 @@ struct rt_signal_frame {
unsigned char retcode[8]; /* Trampoline code. */
};
-int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs);
+void do_signal(int restart, struct pt_regs *regs);
void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
struct pt_regs *regs);
-/*
- * Swap in the new signal mask, and wait for a signal. Define some
- * dummy arguments to be able to reach the regs argument.
- */
-int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
-{
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
-
- spin_lock_irq(&current->sighand->siglock);
-
- saveset = current->blocked;
-
- siginitset(&current->blocked, mask);
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->r10 = -EINTR;
-
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- if (do_signal(0, &saveset, regs)) {
- /*
- * This point is reached twice: once to call
- * the signal handler, then again to return
- * from the sigsuspend system call. When
- * calling the signal handler, R10 hold the
- * signal number as set by do_signal(). The
- * sigsuspend call will always return with
- * the restored value above; -EINTR.
- */
- return regs->r10;
- }
- }
-}
-
-/* Define some dummy arguments to be able to reach the regs argument. */
-int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13,
- long mof, long srp, struct pt_regs *regs)
-{
- sigset_t saveset;
- sigset_t newset;
-
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
-
- sigdelsetmask(&newset, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
-
- saveset = current->blocked;
- current->blocked = newset;
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->r10 = -EINTR;
-
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- if (do_signal(0, &saveset, regs)) {
- /* See comment in function above. */
- return regs->r10;
- }
- }
-}
-
-int
-sys_sigaction(int signal, const struct old_sigaction *act,
- struct old_sigaction *oact)
-{
- int retval;
- struct k_sigaction newk;
- struct k_sigaction oldk;
-
- if (act) {
- old_sigset_t mask;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(newk.sa.sa_handler, &act->sa_handler) ||
- __get_user(newk.sa.sa_restorer, &act->sa_restorer))
- return -EFAULT;
-
- __get_user(newk.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
- siginitset(&newk.sa.sa_mask, mask);
- }
-
- retval = do_sigaction(signal, act ? &newk : NULL, oact ? &oldk : NULL);
-
- if (!retval && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
- __put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
- return -EFAULT;
-
- __put_user(oldk.sa.sa_flags, &oact->sa_flags);
- __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
- }
-
- return retval;
-}
-
-int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
@@ -203,11 +82,9 @@ badframe:
return 1;
}
-/* Define some dummy arguments to be able to reach the regs argument. */
-asmlinkage int
-sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
+asmlinkage int sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
sigset_t set;
struct signal_frame __user *frame;
unsigned long oldspc = regs->spc;
@@ -232,13 +109,7 @@ sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
sizeof(frame->extramask))))
goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
@@ -252,11 +123,9 @@ badframe:
return 0;
}
-/* Define some dummy variables to be able to reach the regs argument. */
-asmlinkage int
-sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
+asmlinkage int sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
sigset_t set;
struct rt_signal_frame __user *frame;
unsigned long oldspc = regs->spc;
@@ -278,19 +147,13 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
- goto badframe;
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
keep_debug_flags(oldccs, oldspc, regs);
@@ -351,7 +214,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
* which performs the syscall sigreturn(), or a provided user-mode
* trampoline.
*/
-static void
+static int
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
struct pt_regs * regs)
{
@@ -417,16 +280,14 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
/* Actually move the USP to reflect the stacked frame. */
wrusp((unsigned long)frame);
- return;
+ return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void
+static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs)
{
@@ -453,6 +314,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
if (err)
goto give_sigsegv;
@@ -503,21 +365,22 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Actually move the usp to reflect the stacked frame. */
wrusp((unsigned long)frame);
- return;
+ return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
+ return -EFAULT;
}
-/* Invoke a singal handler to, well, handle the signal. */
+/* Invoke a signal handler to, well, handle the signal. */
static inline void
handle_signal(int canrestart, unsigned long sig,
siginfo_t *info, struct k_sigaction *ka,
- sigset_t *oldset, struct pt_regs * regs)
+ struct pt_regs * regs)
{
+ sigset_t *oldset = sigmask_to_save();
+ int ret;
+
/* Check if this got called from a system call. */
if (canrestart) {
/* If so, check system call restarting. */
@@ -561,19 +424,12 @@ handle_signal(int canrestart, unsigned long sig,
/* Set up the stack frame. */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+ ret = setup_frame(sig, ka, oldset, regs);
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ if (ret == 0)
+ signal_delivered(sig, info, ka, regs, 0);
}
/*
@@ -587,8 +443,8 @@ handle_signal(int canrestart, unsigned long sig,
* we can use user_mode(regs) to see if we came directly from kernel or user
* mode below.
*/
-int
-do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+void
+do_signal(int canrestart, struct pt_regs *regs)
{
int signr;
siginfo_t info;
@@ -600,17 +456,14 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
* without doing anything.
*/
if (!user_mode(regs))
- return 1;
-
- if (!oldset)
- oldset = &current->blocked;
+ return;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
- /* Deliver the signal. */
- handle_signal(canrestart, signr, &info, &ka, oldset, regs);
- return 1;
+ /* Whee! Actually deliver the signal. */
+ handle_signal(canrestart, signr, &info, &ka, regs);
+ return;
}
/* Got here from a system call? */
@@ -623,12 +476,14 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
}
if (regs->r10 == -ERESTART_RESTARTBLOCK){
- regs->r10 = __NR_restart_syscall;
+ regs->r9 = __NR_restart_syscall;
regs->erp -= 2;
}
}
- return 0;
+ /* if there's no signal to deliver, we just put the saved sigmask
+ * back */
+ restore_saved_sigmask();
}
asmlinkage void
@@ -641,7 +496,7 @@ ugdb_trap_user(struct thread_info *ti, int sig)
user_regs(ti)->spc = 0;
}
/* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
- not withing any configured h/w breakpoint range). Synchronize with
+ not within any configured h/w breakpoint range). Synchronize with
what already exists for kernel debugging. */
if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
/* Break 8: subtract 2 from ERP unless in a delay slot. */
@@ -686,7 +541,7 @@ keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
int __init
cris_init_signal(void)
{
- u16* data = (u16*)kmalloc(PAGE_SIZE, GFP_KERNEL);
+ u16* data = kmalloc(PAGE_SIZE, GFP_KERNEL);
/* This is movu.w __NR_sigreturn, r9; break 13; */
data[0] = 0x9c5f;
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 464ecaec3bc..0698582467c 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -1,12 +1,13 @@
+#include <linux/types.h>
#include <asm/delay.h>
-#include <asm/arch/irq.h>
-#include <asm/arch/hwregs/intr_vect.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <irq.h>
+#include <hwregs/intr_vect.h>
+#include <hwregs/intr_vect_defs.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
-#include <asm/arch/hwregs/mmu_defs_asm.h>
-#include <asm/arch/hwregs/supp_reg.h>
-#include <asm/atomic.h>
+#include <hwregs/asm/mmu_defs_asm.h>
+#include <hwregs/supp_reg.h>
+#include <linux/atomic.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -20,14 +21,16 @@
#define IPI_SCHEDULE 1
#define IPI_CALL 2
#define IPI_FLUSH_TLB 4
+#define IPI_BOOT 8
#define FLUSH_ALL (void*)0xffffffff
/* Vector of locks used for various atomic operations */
-spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED};
+spinlock_t cris_atomic_locks[] = {
+ [0 ... LOCK_COUNT - 1] = __SPIN_LOCK_UNLOCKED(cris_atomic_locks)
+};
/* CPU masks */
-cpumask_t cpu_online_map = CPU_MASK_NONE;
cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
EXPORT_SYMBOL(phys_cpu_present_map);
@@ -51,19 +54,19 @@ static struct mm_struct* flush_mm;
static struct vm_area_struct* flush_vma;
static unsigned long flush_addr;
-extern int setup_irq(int, struct irqaction *);
-
/* Mode registers */
-static unsigned long irq_regs[NR_CPUS] =
-{
+static unsigned long irq_regs[NR_CPUS] = {
regi_irq,
regi_irq2
};
-static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id);
static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
-static struct irqaction irq_ipi = { crisv32_ipi_interrupt, IRQF_DISABLED,
- CPU_MASK_NONE, "ipi", NULL, NULL};
+static struct irqaction irq_ipi = {
+ .handler = crisv32_ipi_interrupt,
+ .flags = 0,
+ .name = "ipi",
+};
extern void cris_mmu_init(void);
extern void cris_timer_init(void);
@@ -78,10 +81,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
/* Mark all possible CPUs as present */
for (i = 0; i < max_cpus; i++)
- cpu_set(i, phys_cpu_present_map);
+ cpumask_set_cpu(i, &phys_cpu_present_map);
}
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
{
/* PGD pointer has moved after per_cpu initialization so
* update the MMU.
@@ -94,8 +97,9 @@ void __devinit smp_prepare_boot_cpu(void)
SUPP_BANK_SEL(2);
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
- cpu_set(0, cpu_online_map);
- cpu_set(0, phys_cpu_present_map);
+ set_cpu_online(0, true);
+ cpumask_set_cpu(0, &phys_cpu_present_map);
+ set_cpu_possible(0, true);
}
void __init smp_cpus_done(unsigned int max_cpus)
@@ -104,21 +108,24 @@ void __init smp_cpus_done(unsigned int max_cpus)
/* Bring one cpu online.*/
static int __init
-smp_boot_one_cpu(int cpuid)
+smp_boot_one_cpu(int cpuid, struct task_struct idle)
{
unsigned timeout;
- struct task_struct *idle;
-
- idle = fork_idle(cpuid);
- if (IS_ERR(idle))
- panic("SMP: fork failed for CPU:%d", cpuid);
+ cpumask_t cpu_mask;
+ cpumask_clear(&cpu_mask);
task_thread_info(idle)->cpu = cpuid;
/* Information to the CPU that is about to boot */
smp_init_current_idle_thread = task_thread_info(idle);
cpu_now_booting = cpuid;
+ /* Kick it */
+ set_cpu_online(cpuid, true);
+ cpumask_set_cpu(cpuid, &cpu_mask);
+ send_ipi(IPI_BOOT, 0, cpu_mask);
+ set_cpu_online(cpuid, false);
+
/* Wait for CPU to come online */
for (timeout = 0; timeout < 10000; timeout++) {
if(cpu_online(cpuid)) {
@@ -130,19 +137,14 @@ smp_boot_one_cpu(int cpuid)
barrier();
}
- put_task_struct(idle);
- idle = NULL;
-
printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
return -1;
}
-/* Secondary CPUs starts uing C here. Here we need to setup CPU
+/* Secondary CPUs starts using C here. Here we need to setup CPU
* specific stuff such as the local timer and the MMU. */
void __init smp_callin(void)
{
- extern void cpu_idle(void);
-
int cpu = cpu_now_booting;
reg_intr_vect_rw_mask vect_mask = {0};
@@ -159,13 +161,14 @@ void __init smp_callin(void)
/* Enable IRQ and idle */
REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
- unmask_irq(IPI_INTR_VECT);
- unmask_irq(TIMER_INTR_VECT);
+ crisv32_unmask_irq(IPI_INTR_VECT);
+ crisv32_unmask_irq(TIMER0_INTR_VECT);
preempt_disable();
+ notify_cpu_starting(cpu);
local_irq_enable();
- cpu_set(cpu, cpu_online_map);
- cpu_idle();
+ set_cpu_online(cpu, true);
+ cpu_startup_entry(CPUHP_ONLINE);
}
/* Stop execution on this CPU.*/
@@ -178,7 +181,7 @@ void stop_this_cpu(void* dummy)
/* Other calls */
void smp_send_stop(void)
{
- smp_call_function(stop_this_cpu, NULL, 1, 0);
+ smp_call_function(stop_this_cpu, NULL, 0);
}
int setup_profiling_timer(unsigned int multiplier)
@@ -194,16 +197,17 @@ int setup_profiling_timer(unsigned int multiplier)
*/
unsigned long cache_decay_ticks = 1;
-int __devinit __cpu_up(unsigned int cpu)
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
- smp_boot_one_cpu(cpu);
+ smp_boot_one_cpu(cpu, tidle);
return cpu_online(cpu) ? 0 : -ENOSYS;
}
void smp_send_reschedule(int cpu)
{
- cpumask_t cpu_mask = CPU_MASK_NONE;
- cpu_set(cpu, cpu_mask);
+ cpumask_t cpu_mask;
+ cpumask_clear(&cpu_mask);
+ cpumask_set_cpu(cpu, &cpu_mask);
send_ipi(IPI_SCHEDULE, 0, cpu_mask);
}
@@ -219,8 +223,8 @@ void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, unsigned
cpumask_t cpu_mask;
spin_lock_irqsave(&tlbstate_lock, flags);
- cpu_mask = (mm == FLUSH_ALL ? CPU_MASK_ALL : mm->cpu_vm_mask);
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpu_mask = (mm == FLUSH_ALL ? cpu_all_mask : *mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
flush_mm = mm;
flush_vma = vma;
flush_addr = addr;
@@ -239,8 +243,8 @@ void flush_tlb_mm(struct mm_struct *mm)
__flush_tlb_mm(mm);
flush_tlb_common(mm, FLUSH_ALL, 0);
/* No more mappings in other CPUs */
- cpus_clear(mm->cpu_vm_mask);
- cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+ cpumask_clear(mm_cpumask(mm));
+ cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
}
void flush_tlb_page(struct vm_area_struct *vma,
@@ -265,10 +269,10 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
int ret = 0;
/* Calculate CPUs to send to. */
- cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+ cpumask_and(&cpu_mask, &cpu_mask, cpu_online_mask);
/* Send the IPI. */
- for_each_cpu_mask(i, cpu_mask)
+ for_each_cpu(i, &cpu_mask)
{
ipi.vector |= vector;
REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
@@ -276,7 +280,7 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
/* Wait for IPI to finish on other CPUS */
if (wait) {
- for_each_cpu_mask(i, cpu_mask) {
+ for_each_cpu(i, &cpu_mask) {
int j;
for (j = 0 ; j < 1000; j++) {
ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
@@ -300,14 +304,14 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
-int smp_call_function(void (*func)(void *info), void *info,
- int nonatomic, int wait)
+int smp_call_function(void (*func)(void *info), void *info, int wait)
{
- cpumask_t cpu_mask = CPU_MASK_ALL;
+ cpumask_t cpu_mask;
struct call_data_struct data;
int ret;
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_setall(&cpu_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
WARN_ON(irqs_disabled());
@@ -323,7 +327,7 @@ int smp_call_function(void (*func)(void *info), void *info,
return ret;
}
-irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id)
{
void (*func) (void *info) = call_data->func;
void *info = call_data->info;
@@ -331,15 +335,18 @@ irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi);
+ if (ipi.vector & IPI_SCHEDULE) {
+ scheduler_ipi();
+ }
if (ipi.vector & IPI_CALL) {
- func(info);
+ func(info);
}
if (ipi.vector & IPI_FLUSH_TLB) {
- if (flush_mm == FLUSH_ALL)
- __flush_tlb_all();
- else if (flush_vma == FLUSH_ALL)
+ if (flush_mm == FLUSH_ALL)
+ __flush_tlb_all();
+ else if (flush_vma == FLUSH_ALL)
__flush_tlb_mm(flush_mm);
- else
+ else
__flush_tlb_page(flush_vma, flush_addr);
}
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index 50f3f93293d..ee66866538f 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -1,146 +1,135 @@
-/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $
- *
+/*
* linux/arch/cris/arch-v32/kernel/time.c
*
- * Copyright (C) 2003 Axis Communications AB
+ * Copyright (C) 2003-2010 Axis Communications AB
*
*/
#include <linux/timex.h>
#include <linux/time.h>
-#include <linux/jiffies.h>
+#include <linux/clocksource.h>
#include <linux/interrupt.h>
#include <linux/swap.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/threads.h>
+#include <linux/cpufreq.h>
#include <asm/types.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/delay.h>
-#include <asm/rtc.h>
#include <asm/irq.h>
-
-#include <asm/arch/hwregs/reg_map.h>
-#include <asm/arch/hwregs/reg_rdwr.h>
-#include <asm/arch/hwregs/timer_defs.h>
-#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/irq_regs.h>
+
+#include <hwregs/reg_map.h>
+#include <hwregs/reg_rdwr.h>
+#include <hwregs/timer_defs.h>
+#include <hwregs/intr_vect_defs.h>
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+#include <hwregs/clkgen_defs.h>
+#endif
/* Watchdog defines */
-#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
-#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */
-#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */
+#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
+#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */
+/* Number of 763 counts before watchdog bites */
+#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1)
+
+/* Register the continuos readonly timer available in FS and ARTPEC-3. */
+static cycle_t read_cont_rotime(struct clocksource *cs)
+{
+ return (u32)REG_RD(timer, regi_timer0, r_time);
+}
+
+static struct clocksource cont_rotime = {
+ .name = "crisv32_rotime",
+ .rating = 300,
+ .read = read_cont_rotime,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init etrax_init_cont_rotime(void)
+{
+ clocksource_register_khz(&cont_rotime, 100000);
+ return 0;
+}
+arch_initcall(etrax_init_cont_rotime);
+
unsigned long timer_regs[NR_CPUS] =
{
- regi_timer,
+ regi_timer0,
#ifdef CONFIG_SMP
- regi_timer2
+ regi_timer2
#endif
};
-extern void update_xtime_from_cmos(void);
extern int set_rtc_mmss(unsigned long nowtime);
-extern int setup_irq(int, struct irqaction *);
-extern int have_rtc;
+
+#ifdef CONFIG_CPU_FREQ
+static int
+cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
+ void *data);
+
+static struct notifier_block cris_time_freq_notifier_block = {
+ .notifier_call = cris_time_freq_notifier,
+};
+#endif
unsigned long get_ns_in_jiffie(void)
{
reg_timer_r_tmr0_data data;
unsigned long ns;
- data = REG_RD(timer, regi_timer, r_tmr0_data);
+ data = REG_RD(timer, regi_timer0, r_tmr0_data);
ns = (TIMER0_DIV - data) * 10;
return ns;
}
-unsigned long do_slow_gettimeoffset(void)
-{
- unsigned long count;
- unsigned long usec_count = 0;
-
- static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
- static unsigned long jiffies_p = 0;
-
- /*
- * cache volatile jiffies temporarily; we have IRQs turned off.
- */
- unsigned long jiffies_t;
-
- /* The timer interrupt comes from Etrax timer 0. In order to get
- * better precision, we check the current value. It might have
- * underflowed already though.
- */
-
- count = REG_RD(timer, regi_timer, r_tmr0_data);
- jiffies_t = jiffies;
-
- /*
- * avoiding timer inconsistencies (they are rare, but they happen)...
- * there are one problem that must be avoided here:
- * 1. the timer counter underflows
- */
- if( jiffies_t == jiffies_p ) {
- if( count > count_p ) {
- /* Timer wrapped, use new count and prescale
- * increase the time corresponding to one jiffie
- */
- usec_count = 1000000/HZ;
- }
- } else
- jiffies_p = jiffies_t;
- count_p = count;
- /* Convert timer value to usec */
- /* 100 MHz timer, divide by 100 to get usec */
- usec_count += (TIMER0_DIV - count) / 100;
- return usec_count;
-}
/* From timer MDS describing the hardware watchdog:
* 4.3.1 Watchdog Operation
* The watchdog timer is an 8-bit timer with a configurable start value.
- * Once started the whatchdog counts downwards with a frequency of 763 Hz
+ * Once started the watchdog counts downwards with a frequency of 763 Hz
* (100/131072 MHz). When the watchdog counts down to 1, it generates an
* NMI (Non Maskable Interrupt), and when it counts down to 0, it resets the
* chip.
*/
/* This gives us 1.3 ms to do something useful when the NMI comes */
-/* right now, starting the watchdog is the same as resetting it */
+/* Right now, starting the watchdog is the same as resetting it */
#define start_watchdog reset_watchdog
#if defined(CONFIG_ETRAX_WATCHDOG)
static short int watchdog_key = 42; /* arbitrary 7 bit number */
#endif
-/* number of pages to consider "out of memory". it is normal that the memory
- * is used though, so put this really low.
- */
-
+/* Number of pages to consider "out of memory". It is normal that the memory
+ * is used though, so set this really low. */
#define WATCHDOG_MIN_FREE_PAGES 8
-void
-reset_watchdog(void)
+void reset_watchdog(void)
{
#if defined(CONFIG_ETRAX_WATCHDOG)
reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
- /* only keep watchdog happy as long as we have memory left! */
+ /* Only keep watchdog happy as long as we have memory left! */
if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
- /* reset the watchdog with the inverse of the old key */
- watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */
+ /* Reset the watchdog with the inverse of the old key */
+ /* Invert key, which is 7 bits */
+ watchdog_key ^= ETRAX_WD_KEY_MASK;
wd_ctrl.cnt = ETRAX_WD_CNT;
wd_ctrl.cmd = regk_timer_start;
wd_ctrl.key = watchdog_key;
- REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+ REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
}
#endif
}
/* stop the watchdog - we still need the correct key */
-void
-stop_watchdog(void)
+void stop_watchdog(void)
{
#if defined(CONFIG_ETRAX_WATCHDOG)
reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
@@ -148,29 +137,39 @@ stop_watchdog(void)
wd_ctrl.cnt = ETRAX_WD_CNT;
wd_ctrl.cmd = regk_timer_stop;
wd_ctrl.key = watchdog_key;
- REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+ REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
#endif
}
extern void show_registers(struct pt_regs *regs);
-void
-handle_watchdog_bite(struct pt_regs* regs)
+void handle_watchdog_bite(struct pt_regs *regs)
{
#if defined(CONFIG_ETRAX_WATCHDOG)
extern int cause_of_death;
- raw_printk("Watchdog bite\n");
+ oops_in_progress = 1;
+ printk(KERN_WARNING "Watchdog bite\n");
/* Check if forced restart or unexpected watchdog */
if (cause_of_death == 0xbedead) {
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+ /* There is a bug in Artpec-3 (voodoo TR 78) that requires
+ * us to go to lower frequency for the reset to be reliable
+ */
+ reg_clkgen_rw_clk_ctrl ctrl =
+ REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
+ ctrl.pll = 0;
+ REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl);
+#endif
while(1);
}
- /* Unexpected watchdog, stop the watchdog and dump registers*/
+ /* Unexpected watchdog, stop the watchdog and dump registers. */
stop_watchdog();
- raw_printk("Oops: bitten by watchdog\n");
- show_registers(regs);
+ printk(KERN_WARNING "Oops: bitten by watchdog\n");
+ show_registers(regs);
+ oops_in_progress = 0;
#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog();
#endif
@@ -178,21 +177,15 @@ handle_watchdog_bite(struct pt_regs* regs)
#endif
}
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-
/*
* timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick.
*/
-
-//static unsigned short myjiff; /* used by our debug routine print_timestamp */
-
extern void cris_do_profile(struct pt_regs *regs);
-static inline irqreturn_t
-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
{
+ struct pt_regs *regs = get_irq_regs();
int cpu = smp_processor_id();
reg_timer_r_masked_intr masked_intr;
reg_timer_rw_ack_intr ack_intr = { 0 };
@@ -202,11 +195,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (!masked_intr.tmr0)
return IRQ_NONE;
- /* acknowledge the timer irq */
+ /* Acknowledge the timer irq. */
ack_intr.tmr0 = 1;
REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
- /* reset watchdog otherwise it resets us! */
+ /* Reset watchdog otherwise it resets us! */
reset_watchdog();
/* Update statistics. */
@@ -218,73 +211,49 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (cpu != 0)
return IRQ_HANDLED;
- /* call the real timer interrupt handler */
- do_timer(regs);
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- *
- * The division here is not time critical since it will run once in
- * 11 minutes
- */
- if ((time_status & STA_UNSYNC) == 0 &&
- xtime.tv_sec > last_rtc_update + 660 &&
- (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
- (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
- }
+ /* Call the real timer interrupt handler */
+ xtime_update(1);
return IRQ_HANDLED;
}
-/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain
- * it needs to be IRQF_DISABLED to make the jiffies update work properly
- */
-
-static struct irqaction irq_timer = {
- .mask = timer_interrupt,
- .flags = IRQF_SHARED | IRQF_DISABLED,
- .mask = CPU_MASK_NONE,
+/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */
+static struct irqaction irq_timer = {
+ .handler = timer_interrupt,
+ .flags = IRQF_SHARED,
.name = "timer"
};
-void __init
-cris_timer_init(void)
+void __init cris_timer_init(void)
{
int cpu = smp_processor_id();
- reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
- reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
+ reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
+ reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
reg_timer_rw_intr_mask timer_intr_mask;
- /* Setup the etrax timers
+ /* Setup the etrax timers.
* Base frequency is 100MHz, divider 1000000 -> 100 HZ
* We use timer0, so timer1 is free.
* The trig timer is used by the fasttimer API if enabled.
*/
- tmr0_ctrl.op = regk_timer_ld;
+ tmr0_ctrl.op = regk_timer_ld;
tmr0_ctrl.freq = regk_timer_f100;
- REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
- REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
- tmr0_ctrl.op = regk_timer_run;
- REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
-
- /* enable the timer irq */
- timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
- timer_intr_mask.tmr0 = 1;
- REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
+ REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
+ REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
+ tmr0_ctrl.op = regk_timer_run;
+ REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
+
+ /* Enable the timer irq. */
+ timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
+ timer_intr_mask.tmr0 = 1;
+ REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
}
-void __init
-time_init(void)
+void __init time_init(void)
{
reg_intr_vect_rw_mask intr_mask;
- /* probe for the RTC and read it if it exists
+ /* Probe for the RTC and read it if it exists.
* Before the RTC can be probed the loops_per_usec variable needs
* to be initialized to make usleep work. A better value for
* loops_per_usec is calculated by the kernel later once the
@@ -292,53 +261,57 @@ time_init(void)
*/
loops_per_usec = 50;
- if(RTC_INIT() < 0) {
- /* no RTC, start at 1980 */
- xtime.tv_sec = 0;
- xtime.tv_nsec = 0;
- have_rtc = 0;
- } else {
- /* get the current time */
- have_rtc = 1;
- update_xtime_from_cmos();
- }
-
- /*
- * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
- * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
- */
- set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
-
- /* Start CPU local timer */
+ /* Start CPU local timer. */
cris_timer_init();
- /* enable the timer irq in global config */
- intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
- intr_mask.timer = 1;
- REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+ /* Enable the timer irq in global config. */
+ intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1);
+ intr_mask.timer0 = 1;
+ REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask);
- /* now actually register the timer irq handler that calls timer_interrupt() */
+ /* Now actually register the timer irq handler that calls
+ * timer_interrupt(). */
+ setup_irq(TIMER0_INTR_VECT, &irq_timer);
- setup_irq(TIMER_INTR_VECT, &irq_timer);
-
- /* enable watchdog if we should use one */
+ /* Enable watchdog if we should use one. */
#if defined(CONFIG_ETRAX_WATCHDOG)
- printk("Enabling watchdog...\n");
+ printk(KERN_INFO "Enabling watchdog...\n");
start_watchdog();
/* If we use the hardware watchdog, we want to trap it as an NMI
- and dump registers before it resets us. For this to happen, we
- must set the "m" NMI enable flag (which once set, is unset only
- when an NMI is taken).
-
- The same goes for the external NMI, but that doesn't have any
- driver or infrastructure support yet. */
- {
- unsigned long flags;
- local_save_flags(flags);
- flags |= (1<<30); /* NMI M flag is at bit 30 */
- local_irq_restore(flags);
- }
+ * and dump registers before it resets us. For this to happen, we
+ * must set the "m" NMI enable flag (which once set, is unset only
+ * when an NMI is taken). */
+ {
+ unsigned long flags;
+ local_save_flags(flags);
+ flags |= (1<<30); /* NMI M flag is at bit 30 */
+ local_irq_restore(flags);
+ }
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_register_notifier(&cris_time_freq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
#endif
}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct cpufreq_freqs *freqs = data;
+ if (val == CPUFREQ_POSTCHANGE) {
+ reg_timer_r_tmr0_data data;
+ reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ;
+ do {
+ data = REG_RD(timer, timer_regs[freqs->cpu],
+ r_tmr0_data);
+ } while (data > 20);
+ REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div);
+ }
+ return 0;
+}
+#endif
diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c
index 2462b1ef1fb..8bbe09c9313 100644
--- a/arch/cris/arch-v32/kernel/traps.c
+++ b/arch/cris/arch-v32/kernel/traps.c
@@ -1,50 +1,44 @@
/*
- * Copyright (C) 2003, Axis Communications AB.
+ * Copyright (C) 2003-2006, Axis Communications AB.
*/
#include <linux/ptrace.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
+#include <hwregs/supp_reg.h>
+#include <hwregs/intr_vect_defs.h>
+#include <asm/irq.h>
-#include <asm/arch/hwregs/supp_reg.h>
-
-extern void reset_watchdog(void);
-extern void stop_watchdog(void);
-
-extern int raw_printk(const char *fmt, ...);
-
-void
-show_registers(struct pt_regs *regs)
+void show_registers(struct pt_regs *regs)
{
/*
* It's possible to use either the USP register or current->thread.usp.
- * USP might not correspond to the current proccess for all cases this
+ * USP might not correspond to the current process for all cases this
* function is called, and current->thread.usp isn't up to date for the
- * current proccess. Experience shows that using USP is the way to go.
+ * current process. Experience shows that using USP is the way to go.
*/
- unsigned long usp;
+ unsigned long usp = rdusp();
unsigned long d_mmu_cause;
unsigned long i_mmu_cause;
- usp = rdusp();
-
- raw_printk("CPU: %d\n", smp_processor_id());
+ printk("CPU: %d\n", smp_processor_id());
- raw_printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
- regs->erp, regs->srp, regs->ccs, usp, regs->mof);
+ printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
+ regs->erp, regs->srp, regs->ccs, usp, regs->mof);
- raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
- regs->r0, regs->r1, regs->r2, regs->r3);
+ printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
+ regs->r0, regs->r1, regs->r2, regs->r3);
- raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
- regs->r4, regs->r5, regs->r6, regs->r7);
+ printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
+ regs->r4, regs->r5, regs->r6, regs->r7);
- raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
- regs->r8, regs->r9, regs->r10, regs->r11);
+ printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
+ regs->r8, regs->r9, regs->r10, regs->r11);
- raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
- regs->r12, regs->r13, regs->orig_r10, regs->acr);
+ printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
+ regs->r12, regs->r13, regs->orig_r10, regs->acr);
- raw_printk("sp: %08lx\n", regs);
+ printk(" sp: %08lx\n", (unsigned long)regs);
SUPP_BANK_SEL(BANK_IM);
SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause);
@@ -52,18 +46,20 @@ show_registers(struct pt_regs *regs)
SUPP_BANK_SEL(BANK_DM);
SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause);
- raw_printk(" Data MMU Cause: %08lx\n", d_mmu_cause);
- raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
+ printk(" Data MMU Cause: %08lx\n", d_mmu_cause);
+ printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
- raw_printk("Process %s (pid: %d, stackpage: %08lx)\n",
- current->comm, current->pid, (unsigned long) current);
+ printk("Process %s (pid: %d, stackpage=%08lx)\n",
+ current->comm, current->pid, (unsigned long)current);
- /* Show additional info if in kernel-mode. */
+ /*
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
if (!user_mode(regs)) {
int i;
- unsigned char c;
- show_stack(NULL, (unsigned long *) usp);
+ show_stack(NULL, (unsigned long *)usp);
/*
* If the previous stack-dump wasn't a kernel one, dump the
@@ -72,7 +68,7 @@ show_registers(struct pt_regs *regs)
if (usp != 0)
show_stack(NULL, NULL);
- raw_printk("\nCode: ");
+ printk("\nCode: ");
if (regs->erp < PAGE_OFFSET)
goto bad_value;
@@ -84,76 +80,114 @@ show_registers(struct pt_regs *regs)
* instruction decoding should be in sync at the interesting
* point, but small enough to fit on a row. The regs->erp
* location is pointed out in a ksymoops-friendly way by
- * wrapping the byte for that address in parenthesis.
+ * wrapping the byte for that address in parenthesises.
*/
for (i = -12; i < 12; i++) {
- if (__get_user(c, &((unsigned char *) regs->erp)[i])) {
+ unsigned char c;
+
+ if (__get_user(c, &((unsigned char *)regs->erp)[i])) {
bad_value:
- raw_printk(" Bad IP value.");
+ printk(" Bad IP value.");
break;
}
if (i == 0)
- raw_printk("(%02x) ", c);
+ printk("(%02x) ", c);
else
- raw_printk("%02x ", c);
+ printk("%02x ", c);
}
-
- raw_printk("\n");
+ printk("\n");
}
}
-/*
- * This gets called from entry.S when the watchdog has bitten. Show something
- * similiar to an Oops dump, and if the kernel if configured to be a nice doggy;
- * halt instead of reboot.
- */
-void
-watchdog_bite_hook(struct pt_regs *regs)
+void arch_enable_nmi(void)
{
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- local_irq_disable();
- stop_watchdog();
- show_registers(regs);
+ unsigned long flags;
- while (1)
- ; /* Do nothing. */
-#else
- show_registers(regs);
-#endif
+ local_save_flags(flags);
+ flags |= (1 << 30); /* NMI M flag is at bit 30 */
+ local_irq_restore(flags);
}
-/* This is normally the Oops function. */
-void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
+extern void (*nmi_handler)(struct pt_regs *);
+void handle_nmi(struct pt_regs *regs)
{
- if (user_mode(regs))
- return;
+#ifdef CONFIG_ETRAXFS
+ reg_intr_vect_r_nmi r;
+#endif
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- /*
- * This printout might take too long and could trigger
- * the watchdog normally. If NICE_DOGGY is set, simply
- * stop the watchdog during the printout.
- */
- stop_watchdog();
+ if (nmi_handler)
+ nmi_handler(regs);
+
+#ifdef CONFIG_ETRAXFS
+ /* Wait until nmi is no longer active. */
+ do {
+ r = REG_RD(intr_vect, regi_irq, r_nmi);
+ } while (r.ext == regk_intr_vect_on);
#endif
+}
- raw_printk("%s: %04lx\n", str, err & 0xffff);
- show_registers(regs);
+#ifdef CONFIG_BUG
+extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
-#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
- reset_watchdog();
-#endif
+/* Copy of the regs at BUG() time. */
+struct pt_regs BUG_regs;
- do_exit(SIGSEGV);
+void do_BUG(char *file, unsigned int line)
+{
+ printk("kernel BUG at %s:%d!\n", file, line);
+ die_if_kernel("Oops", &BUG_regs, 0);
}
+EXPORT_SYMBOL(do_BUG);
-void arch_enable_nmi(void)
+void fixup_BUG(struct pt_regs *regs)
+{
+ BUG_regs = *regs;
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ /*
+ * Fixup the BUG arguments through exception handlers.
+ */
+ {
+ const struct exception_table_entry *fixup;
+
+ /*
+ * ERP points at the "break 14" + 2, compensate for the 2
+ * bytes.
+ */
+ fixup = search_exception_tables(instruction_pointer(regs) - 2);
+ if (fixup) {
+ /* Adjust the instruction pointer in the stackframe. */
+ instruction_pointer(regs) = fixup->fixup;
+ arch_fixup(regs);
+ }
+ }
+#else
+ /* Dont try to lookup the filename + line, just dump regs. */
+ do_BUG("unknown", 0);
+#endif
+}
+
+/*
+ * Break 14 handler. Save regs and jump into the fixup_BUG.
+ */
+__asm__ ( ".text\n\t"
+ ".global breakh_BUG\n\t"
+ "breakh_BUG:\n\t"
+ SAVE_ALL
+ KGDB_FIXUP
+ "move.d $sp, $r10\n\t"
+ "jsr fixup_BUG\n\t"
+ "nop\n\t"
+ "jump ret_from_intr\n\t"
+ "nop\n\t");
+
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void
+handle_BUG(struct pt_regs *regs)
{
- unsigned long flags;
- local_save_flags(flags);
- flags |= (1<<30); /* NMI M flag is at bit 30 */
- local_irq_restore(flags);
}
+#endif
+#endif
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.c b/arch/cris/arch-v32/kernel/vcs_hook.c
deleted file mode 100644
index 64d71c54c22..00000000000
--- a/arch/cris/arch-v32/kernel/vcs_hook.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $
-//
-// Call simulator hook. This is the part running in the
-// simulated program.
-//
-
-#include "vcs_hook.h"
-#include <stdarg.h>
-#include <asm/arch-v32/hwregs/reg_map.h>
-#include <asm/arch-v32/hwregs/intr_vect_defs.h>
-
-#define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */
-#define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */
-
-#define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset]
-#define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset]
-#define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } while(0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset]
-
-
-// ------------------------------------------------------------------ hook_call
-int hook_call( unsigned id, unsigned pcnt, ...) {
- va_list ap;
- unsigned i;
- unsigned ret;
-#ifdef USING_SOS
- PREEMPT_OFF_SAVE();
-#endif
-
- // pass parameters
- HOOK_DATA(0) = id;
-
- /* Have to make hook_print_str a special case since we call with a
- parameter of byte type. Should perhaps be a separate
- hook_call. */
-
- if (id == hook_print_str) {
- int i;
- char *str;
-
- HOOK_DATA(1) = pcnt;
-
- va_start(ap, pcnt);
- str = (char*)va_arg(ap,unsigned);
-
- for (i=0; i!=pcnt; i++) {
- HOOK_DATA_BYTE(8+i) = str[i];
- }
- HOOK_DATA_BYTE(8+i) = 0; /* null byte */
- }
- else {
- va_start(ap, pcnt);
- for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned);
- va_end(ap);
- }
-
- // read from mem to make sure data has propagated to memory before trigging
- *((volatile unsigned*) HOOK_MEM_BASE_ADDR);
-
- // trigger hook
- HOOK_TRIG(id);
-
- // wait for call to finish
- while( VHOOK_DATA(0) > 0 ) {}
-
- // extract return value
-
- ret = VHOOK_DATA(1);
-
-#ifdef USING_SOS
- PREEMPT_RESTORE();
-#endif
- return ret;
-}
-
-unsigned
-hook_buf(unsigned i)
-{
- return (HOOK_DATA(i));
-}
-
-void print_str( const char *str ) {
- int i;
- for (i=1; str[i]; i++); /* find null at end of string */
- hook_call(hook_print_str, i, str);
-}
-
-// --------------------------------------------------------------- CPU_KICK_DOG
-void CPU_KICK_DOG(void) {
- (void) hook_call( hook_kick_dog, 0 );
-}
-
-// ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT
-void CPU_WATCHDOG_TIMEOUT( unsigned t ) {
- (void) hook_call( hook_dog_timeout, 1, t );
-}
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.h b/arch/cris/arch-v32/kernel/vcs_hook.h
deleted file mode 100644
index 7d73709e3cc..00000000000
--- a/arch/cris/arch-v32/kernel/vcs_hook.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// $Id: vcs_hook.h,v 1.1 2003/08/12 12:01:06 starvik Exp $
-//
-// Call simulator hook functions
-
-#ifndef HOOK_H
-#define HOOK_H
-
-int hook_call( unsigned id, unsigned pcnt, ...);
-
-enum hook_ids {
- hook_debug_on = 1,
- hook_debug_off,
- hook_stop_sim_ok,
- hook_stop_sim_fail,
- hook_alloc_shared,
- hook_ptr_shared,
- hook_free_shared,
- hook_file2shared,
- hook_cmp_shared,
- hook_print_params,
- hook_sim_time,
- hook_stop_sim,
- hook_kick_dog,
- hook_dog_timeout,
- hook_rand,
- hook_srand,
- hook_rand_range,
- hook_print_str,
- hook_print_hex,
- hook_cmp_offset_shared,
- hook_fill_random_shared,
- hook_alloc_random_data,
- hook_calloc_random_data,
- hook_print_int,
- hook_print_uint,
- hook_fputc,
- hook_init_fd,
- hook_sbrk
-
-};
-
-#endif