summaryrefslogtreecommitdiff
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/Makefile2
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c100
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c8
-rw-r--r--arch/blackfin/kernel/entry.S4
-rw-r--r--arch/blackfin/kernel/ipipe.c428
-rw-r--r--arch/blackfin/kernel/irqchip.c5
-rw-r--r--arch/blackfin/kernel/mcount.S70
-rw-r--r--arch/blackfin/kernel/process.c7
-rw-r--r--arch/blackfin/kernel/time.c15
-rw-r--r--arch/blackfin/kernel/traps.c13
10 files changed, 586 insertions, 66 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index f0902c120dc2..38a233374f07 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -15,6 +15,8 @@ else
obj-y += time.o
endif
+obj-$(CONFIG_IPIPE) += ipipe.o
+obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o
obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o
obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index 2c72b15b71b0..4c14331978f6 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -422,13 +422,13 @@ arch_initcall(bfin_gpio_init);
void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
{ \
unsigned long flags; \
- local_irq_save(flags); \
+ local_irq_save_hw(flags); \
if (arg) \
gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
else \
gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
AWA_DUMMY_READ(name); \
- local_irq_restore(flags); \
+ local_irq_restore_hw(flags); \
} \
EXPORT_SYMBOL(set_gpio_ ## name);
@@ -444,13 +444,13 @@ SET_GPIO(both)
void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
{ \
unsigned long flags; \
- local_irq_save(flags); \
+ local_irq_save_hw(flags); \
if (arg) \
gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
else \
gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
AWA_DUMMY_READ(name); \
- local_irq_restore(flags); \
+ local_irq_restore_hw(flags); \
} \
EXPORT_SYMBOL(set_gpio_ ## name);
#else
@@ -473,10 +473,10 @@ SET_GPIO_SC(data)
void set_gpio_toggle(unsigned gpio)
{
unsigned long flags;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
AWA_DUMMY_READ(toggle);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
#else
void set_gpio_toggle(unsigned gpio)
@@ -494,10 +494,10 @@ EXPORT_SYMBOL(set_gpio_toggle);
void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
{ \
unsigned long flags; \
- local_irq_save(flags); \
+ local_irq_save_hw(flags); \
gpio_bankb[gpio_bank(gpio)]->name = arg; \
AWA_DUMMY_READ(name); \
- local_irq_restore(flags); \
+ local_irq_restore_hw(flags); \
} \
EXPORT_SYMBOL(set_gpiop_ ## name);
#else
@@ -525,10 +525,10 @@ unsigned short get_gpio_ ## name(unsigned gpio) \
{ \
unsigned long flags; \
unsigned short ret; \
- local_irq_save(flags); \
+ local_irq_save_hw(flags); \
ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \
AWA_DUMMY_READ(name); \
- local_irq_restore(flags); \
+ local_irq_restore_hw(flags); \
return ret; \
} \
EXPORT_SYMBOL(get_gpio_ ## name);
@@ -558,10 +558,10 @@ unsigned short get_gpiop_ ## name(unsigned gpio) \
{ \
unsigned long flags; \
unsigned short ret; \
- local_irq_save(flags); \
+ local_irq_save_hw(flags); \
ret = (gpio_bankb[gpio_bank(gpio)]->name); \
AWA_DUMMY_READ(name); \
- local_irq_restore(flags); \
+ local_irq_restore_hw(flags); \
return ret; \
} \
EXPORT_SYMBOL(get_gpiop_ ## name);
@@ -611,10 +611,10 @@ int gpio_pm_wakeup_request(unsigned gpio, unsigned char type)
if ((check_gpio(gpio) < 0) || !type)
return -EINVAL;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
wakeup_flags_map[gpio] = type;
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -627,11 +627,11 @@ void gpio_pm_wakeup_free(unsigned gpio)
if (check_gpio(gpio) < 0)
return;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
EXPORT_SYMBOL(gpio_pm_wakeup_free);
@@ -882,7 +882,7 @@ int peripheral_request(unsigned short per, const char *label)
if (!(per & P_DEFINED))
return -ENODEV;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
/* If a pin can be muxed as either GPIO or peripheral, make
* sure it is not already a GPIO pin when we request it.
@@ -893,7 +893,7 @@ int peripheral_request(unsigned short per, const char *label)
printk(KERN_ERR
"%s: Peripheral %d is already reserved as GPIO by %s !\n",
__func__, ident, get_label(ident));
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
@@ -923,7 +923,7 @@ int peripheral_request(unsigned short per, const char *label)
printk(KERN_ERR
"%s: Peripheral %d function %d is already reserved by %s !\n",
__func__, ident, P_FUNCT2MUX(per), get_label(ident));
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
}
@@ -938,7 +938,7 @@ int peripheral_request(unsigned short per, const char *label)
#endif
port_setup(ident, PERIPHERAL_USAGE);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
set_label(ident, label);
return 0;
@@ -980,10 +980,10 @@ void peripheral_free(unsigned short per)
if (check_gpio(ident) < 0)
return;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) {
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return;
}
@@ -994,7 +994,7 @@ void peripheral_free(unsigned short per)
set_label(ident, "free");
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
EXPORT_SYMBOL(peripheral_free);
@@ -1028,7 +1028,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
if (check_gpio(gpio) < 0)
return -EINVAL;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
/*
* Allow that the identical GPIO can
@@ -1037,7 +1037,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
*/
if (cmp_label(gpio, label) == 0) {
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -1045,7 +1045,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
dump_stack();
printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
gpio, get_label(gpio));
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
@@ -1053,7 +1053,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
printk(KERN_ERR
"bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
gpio, get_label(gpio));
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio)))
@@ -1063,7 +1063,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
set_label(gpio, label);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
port_setup(gpio, GPIO_USAGE);
@@ -1078,12 +1078,12 @@ void bfin_gpio_free(unsigned gpio)
if (check_gpio(gpio) < 0)
return;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
dump_stack();
gpio_error(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return;
}
@@ -1091,7 +1091,7 @@ void bfin_gpio_free(unsigned gpio)
set_label(gpio, "free");
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
EXPORT_SYMBOL(bfin_gpio_free);
@@ -1102,14 +1102,14 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
if (check_gpio(gpio) < 0)
return -EINVAL;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
dump_stack();
printk(KERN_ERR
"bfin-gpio: GPIO %d is already reserved as gpio-irq !\n",
gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
@@ -1117,7 +1117,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
printk(KERN_ERR
"bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
gpio, get_label(gpio));
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return -EBUSY;
}
if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))
@@ -1128,7 +1128,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
reserved_gpio_irq_map[gpio_bank(gpio)] |= gpio_bit(gpio);
set_label(gpio, label);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
port_setup(gpio, GPIO_USAGE);
@@ -1142,12 +1142,12 @@ void bfin_gpio_irq_free(unsigned gpio)
if (check_gpio(gpio) < 0)
return;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
if (unlikely(!(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
dump_stack();
gpio_error(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return;
}
@@ -1155,7 +1155,7 @@ void bfin_gpio_irq_free(unsigned gpio)
set_label(gpio, "free");
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
@@ -1169,10 +1169,10 @@ int bfin_gpio_direction_input(unsigned gpio)
return -EINVAL;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -1187,11 +1187,11 @@ int bfin_gpio_direction_output(unsigned gpio, int value)
return -EINVAL;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
gpio_set_value(gpio, value);
gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -1218,10 +1218,10 @@ void bfin_gpio_irq_prepare(unsigned gpio)
port_setup(gpio, GPIO_USAGE);
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
#else
@@ -1232,11 +1232,11 @@ int bfin_gpio_get_value(unsigned gpio)
int ret;
if (unlikely(get_gpio_edge(gpio))) {
- local_irq_save(flags);
+ local_irq_save_hw(flags);
set_gpio_edge(gpio, 0);
ret = get_gpio_data(gpio);
set_gpio_edge(gpio, 1);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return ret;
} else
@@ -1254,11 +1254,11 @@ int bfin_gpio_direction_input(unsigned gpio)
return -EINVAL;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
AWA_DUMMY_READ(inen);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -1273,7 +1273,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value)
return -EINVAL;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
if (value)
@@ -1283,7 +1283,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value)
gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
AWA_DUMMY_READ(dir);
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 5ef5d1a787fc..87463ce87f5a 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -332,7 +332,7 @@ void flush_switched_cplbs(unsigned int cpu)
nr_cplb_flush[cpu]++;
- local_irq_save(flags);
+ local_irq_save_hw(flags);
disable_icplb();
for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
icplb_tbl[cpu][i].data = 0;
@@ -346,7 +346,7 @@ void flush_switched_cplbs(unsigned int cpu)
bfin_write32(DCPLB_DATA0 + i * 4, 0);
}
enable_dcplb();
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
@@ -362,7 +362,7 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
return;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
current_rwx_mask[cpu] = masks;
d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
@@ -382,5 +382,5 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
addr += PAGE_SIZE;
}
enable_dcplb();
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
index c0c3fe811228..a9cfba9946b5 100644
--- a/arch/blackfin/kernel/entry.S
+++ b/arch/blackfin/kernel/entry.S
@@ -42,6 +42,10 @@
#endif
ENTRY(_ret_from_fork)
+#ifdef CONFIG_IPIPE
+ [--sp] = reti; /* IRQs on. */
+ SP += 4;
+#endif /* CONFIG_IPIPE */
SP += -12;
call _schedule_tail;
SP += 12;
diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c
new file mode 100644
index 000000000000..339be5a3ae6a
--- /dev/null
+++ b/arch/blackfin/kernel/ipipe.c
@@ -0,0 +1,428 @@
+/* -*- linux-c -*-
+ * linux/arch/blackfin/kernel/ipipe.c
+ *
+ * Copyright (C) 2005-2007 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-dependent I-pipe support for the Blackfin.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kthread.h>
+#include <asm/unistd.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+static int create_irq_threads;
+
+DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
+
+static DEFINE_PER_CPU(unsigned long, pending_irqthread_mask);
+
+static DEFINE_PER_CPU(int [IVG13 + 1], pending_irq_count);
+
+asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+
+static void __ipipe_no_irqtail(void);
+
+unsigned long __ipipe_irq_tail_hook = (unsigned long)&__ipipe_no_irqtail;
+EXPORT_SYMBOL(__ipipe_irq_tail_hook);
+
+unsigned long __ipipe_core_clock;
+EXPORT_SYMBOL(__ipipe_core_clock);
+
+unsigned long __ipipe_freq_scale;
+EXPORT_SYMBOL(__ipipe_freq_scale);
+
+atomic_t __ipipe_irq_lvdepth[IVG15 + 1];
+
+unsigned long __ipipe_irq_lvmask = __all_masked_irq_flags;
+EXPORT_SYMBOL(__ipipe_irq_lvmask);
+
+static void __ipipe_ack_irq(unsigned irq, struct irq_desc *desc)
+{
+ desc->ipipe_ack(irq, desc);
+}
+
+/*
+ * __ipipe_enable_pipeline() -- We are running on the boot CPU, hw
+ * interrupts are off, and secondary CPUs are still lost in space.
+ */
+void __ipipe_enable_pipeline(void)
+{
+ unsigned irq;
+
+ __ipipe_core_clock = get_cclk(); /* Fetch this once. */
+ __ipipe_freq_scale = 1000000000UL / __ipipe_core_clock;
+
+ for (irq = 0; irq < NR_IRQS; ++irq)
+ ipipe_virtualize_irq(ipipe_root_domain,
+ irq,
+ (ipipe_irq_handler_t)&asm_do_IRQ,
+ NULL,
+ &__ipipe_ack_irq,
+ IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+}
+
+/*
+ * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+ * interrupt protection log is maintained here for each domain. Hw
+ * interrupts are masked on entry.
+ */
+void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs)
+{
+ struct ipipe_domain *this_domain, *next_domain;
+ struct list_head *head, *pos;
+ int m_ack, s = -1;
+
+ /*
+ * Software-triggered IRQs do not need any ack. The contents
+ * of the register frame should only be used when processing
+ * the timer interrupt, but not for handling any other
+ * interrupt.
+ */
+ m_ack = (regs == NULL || irq == IRQ_SYSTMR || irq == IRQ_CORETMR);
+
+ this_domain = ipipe_current_domain;
+
+ if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control)))
+ head = &this_domain->p_link;
+ else {
+ head = __ipipe_pipeline.next;
+ next_domain = list_entry(head, struct ipipe_domain, p_link);
+ if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) {
+ if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+ next_domain->irqs[irq].acknowledge(irq, irq_desc + irq);
+ if (test_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags))
+ s = __test_and_set_bit(IPIPE_STALL_FLAG,
+ &ipipe_root_cpudom_var(status));
+ __ipipe_dispatch_wired(next_domain, irq);
+ goto finalize;
+ return;
+ }
+ }
+
+ /* Ack the interrupt. */
+
+ pos = head;
+
+ while (pos != &__ipipe_pipeline) {
+ next_domain = list_entry(pos, struct ipipe_domain, p_link);
+ /*
+ * For each domain handling the incoming IRQ, mark it
+ * as pending in its log.
+ */
+ if (test_bit(IPIPE_HANDLE_FLAG, &next_domain->irqs[irq].control)) {
+ /*
+ * Domains that handle this IRQ are polled for
+ * acknowledging it by decreasing priority
+ * order. The interrupt must be made pending
+ * _first_ in the domain's status flags before
+ * the PIC is unlocked.
+ */
+ __ipipe_set_irq_pending(next_domain, irq);
+
+ if (!m_ack && next_domain->irqs[irq].acknowledge != NULL) {
+ next_domain->irqs[irq].acknowledge(irq, irq_desc + irq);
+ m_ack = 1;
+ }
+ }
+
+ /*
+ * If the domain does not want the IRQ to be passed
+ * down the interrupt pipe, exit the loop now.
+ */
+ if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+ break;
+
+ pos = next_domain->p_link.next;
+ }
+
+ /*
+ * Now walk the pipeline, yielding control to the highest
+ * priority domain that has pending interrupt(s) or
+ * immediately to the current domain if the interrupt has been
+ * marked as 'sticky'. This search does not go beyond the
+ * current domain in the pipeline. We also enforce the
+ * additional root stage lock (blackfin-specific). */
+
+ if (test_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags))
+ s = __test_and_set_bit(IPIPE_STALL_FLAG,
+ &ipipe_root_cpudom_var(status));
+finalize:
+
+ __ipipe_walk_pipeline(head);
+
+ if (!s)
+ __clear_bit(IPIPE_STALL_FLAG,
+ &ipipe_root_cpudom_var(status));
+}
+
+int __ipipe_check_root(void)
+{
+ return ipipe_root_domain_p;
+}
+
+void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ int prio = desc->ic_prio;
+
+ desc->depth = 0;
+ if (ipd != &ipipe_root &&
+ atomic_inc_return(&__ipipe_irq_lvdepth[prio]) == 1)
+ __set_bit(prio, &__ipipe_irq_lvmask);
+}
+EXPORT_SYMBOL(__ipipe_enable_irqdesc);
+
+void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ int prio = desc->ic_prio;
+
+ if (ipd != &ipipe_root &&
+ atomic_dec_and_test(&__ipipe_irq_lvdepth[prio]))
+ __clear_bit(prio, &__ipipe_irq_lvmask);
+}
+EXPORT_SYMBOL(__ipipe_disable_irqdesc);
+
+void __ipipe_stall_root_raw(void)
+{
+ /*
+ * This code is called by the ins{bwl} routines (see
+ * arch/blackfin/lib/ins.S), which are heavily used by the
+ * network stack. It masks all interrupts but those handled by
+ * non-root domains, so that we keep decent network transfer
+ * rates for Linux without inducing pathological jitter for
+ * the real-time domain.
+ */
+ __asm__ __volatile__ ("sti %0;" : : "d"(__ipipe_irq_lvmask));
+
+ __set_bit(IPIPE_STALL_FLAG,
+ &ipipe_root_cpudom_var(status));
+}
+
+void __ipipe_unstall_root_raw(void)
+{
+ __clear_bit(IPIPE_STALL_FLAG,
+ &ipipe_root_cpudom_var(status));
+
+ __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags));
+}
+
+int __ipipe_syscall_root(struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ /* We need to run the IRQ tail hook whenever we don't
+ * propagate a syscall to higher domains, because we know that
+ * important operations might be pending there (e.g. Xenomai
+ * deferred rescheduling). */
+
+ if (!__ipipe_syscall_watched_p(current, regs->orig_p0)) {
+ void (*hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
+ hook();
+ return 0;
+ }
+
+ /*
+ * This routine either returns:
+ * 0 -- if the syscall is to be passed to Linux;
+ * 1 -- if the syscall should not be passed to Linux, and no
+ * tail work should be performed;
+ * -1 -- if the syscall should not be passed to Linux but the
+ * tail work has to be performed (for handling signals etc).
+ */
+
+ if (__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
+ __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) {
+ if (ipipe_root_domain_p && !in_atomic()) {
+ /*
+ * Sync pending VIRQs before _TIF_NEED_RESCHED
+ * is tested.
+ */
+ local_irq_save_hw(flags);
+ if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0)
+ __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+ local_irq_restore_hw(flags);
+ return -1;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+ unsigned long flags;
+
+ local_irq_save_hw(flags);
+
+ return flags;
+}
+
+void ipipe_critical_exit(unsigned long flags)
+{
+ local_irq_restore_hw(flags);
+}
+
+static void __ipipe_no_irqtail(void)
+{
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+ info->ncpus = num_online_cpus();
+ info->cpufreq = ipipe_cpu_freq();
+ info->archdep.tmirq = IPIPE_TIMER_IRQ;
+ info->archdep.tmfreq = info->cpufreq;
+
+ return 0;
+}
+
+/*
+ * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+ * just like if it has been actually received from a hw source. Also
+ * works for virtual interrupts.
+ */
+int ipipe_trigger_irq(unsigned irq)
+{
+ unsigned long flags;
+
+ if (irq >= IPIPE_NR_IRQS ||
+ (ipipe_virtual_irq_p(irq)
+ && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+ return -EINVAL;
+
+ local_irq_save_hw(flags);
+
+ __ipipe_handle_irq(irq, NULL);
+
+ local_irq_restore_hw(flags);
+
+ return 1;
+}
+
+/* Move Linux IRQ to threads. */
+
+static int do_irqd(void *__desc)
+{
+ struct irq_desc *desc = __desc;
+ unsigned irq = desc - irq_desc;
+ int thrprio = desc->thr_prio;
+ int thrmask = 1 << thrprio;
+ int cpu = smp_processor_id();
+ cpumask_t cpumask;
+
+ sigfillset(&current->blocked);
+ current->flags |= PF_NOFREEZE;
+ cpumask = cpumask_of_cpu(cpu);
+ set_cpus_allowed(current, cpumask);
+ ipipe_setscheduler_root(current, SCHED_FIFO, 50 + thrprio);
+
+ while (!kthread_should_stop()) {
+ local_irq_disable();
+ if (!(desc->status & IRQ_SCHEDULED)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+resched:
+ local_irq_enable();
+ schedule();
+ local_irq_disable();
+ }
+ __set_current_state(TASK_RUNNING);
+ /*
+ * If higher priority interrupt servers are ready to
+ * run, reschedule immediately. We need this for the
+ * GPIO demux IRQ handler to unmask the interrupt line
+ * _last_, after all GPIO IRQs have run.
+ */
+ if (per_cpu(pending_irqthread_mask, cpu) & ~(thrmask|(thrmask-1)))
+ goto resched;
+ if (--per_cpu(pending_irq_count[thrprio], cpu) == 0)
+ per_cpu(pending_irqthread_mask, cpu) &= ~thrmask;
+ desc->status &= ~IRQ_SCHEDULED;
+ desc->thr_handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs));
+ local_irq_enable();
+ }
+ __set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+static void kick_irqd(unsigned irq, void *cookie)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ int thrprio = desc->thr_prio;
+ int thrmask = 1 << thrprio;
+ int cpu = smp_processor_id();
+
+ if (!(desc->status & IRQ_SCHEDULED)) {
+ desc->status |= IRQ_SCHEDULED;
+ per_cpu(pending_irqthread_mask, cpu) |= thrmask;
+ ++per_cpu(pending_irq_count[thrprio], cpu);
+ wake_up_process(desc->thread);
+ }
+}
+
+int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc)
+{
+ if (desc->thread || !create_irq_threads)
+ return 0;
+
+ desc->thread = kthread_create(do_irqd, desc, "IRQ %d", irq);
+ if (desc->thread == NULL) {
+ printk(KERN_ERR "irqd: could not create IRQ thread %d!\n", irq);
+ return -ENOMEM;
+ }
+
+ wake_up_process(desc->thread);
+
+ desc->thr_handler = ipipe_root_domain->irqs[irq].handler;
+ ipipe_root_domain->irqs[irq].handler = &kick_irqd;
+
+ return 0;
+}
+
+void __init ipipe_init_irq_threads(void)
+{
+ unsigned irq;
+ struct irq_desc *desc;
+
+ create_irq_threads = 1;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ desc = irq_desc + irq;
+ if (desc->action != NULL ||
+ (desc->status & IRQ_NOREQUEST) != 0)
+ ipipe_start_irq_thread(irq, desc);
+ }
+}
+
+EXPORT_SYMBOL(show_stack);
+
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+void notrace _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif /* CONFIG_IPIPE_TRACE_MCOUNT */
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 1624e1129681..ab8209cbbad0 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -108,8 +108,9 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs;
struct irq_desc *desc = irq_desc + irq;
+#ifndef CONFIG_IPIPE
unsigned short pending, other_ints;
-
+#endif
old_regs = set_irq_regs(regs);
/*
@@ -137,6 +138,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
#endif
generic_handle_irq(irq);
+#ifndef CONFIG_IPIPE /* Useless and bugous over the I-pipe: IRQs are threaded. */
/* If we're the only interrupt running (ignoring IRQ15 which is for
syscalls), lower our priority to IRQ14 so that softirqs run at
that level. If there's another, lower-level interrupt, irq_exit
@@ -146,6 +148,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
other_ints = pending & (pending - 1);
if (other_ints == 0)
lower_to_irq14();
+#endif /* !CONFIG_IPIPE */
irq_exit();
set_irq_regs(old_regs);
diff --git a/arch/blackfin/kernel/mcount.S b/arch/blackfin/kernel/mcount.S
new file mode 100644
index 000000000000..edcfb3865f46
--- /dev/null
+++ b/arch/blackfin/kernel/mcount.S
@@ -0,0 +1,70 @@
+/*
+ * linux/arch/blackfin/mcount.S
+ *
+ * Copyright (C) 2006 Analog Devices Inc.
+ *
+ * 2007/04/12 Save index, length, modify and base registers. --rpm
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+.text
+
+.align 4 /* just in case */
+
+ENTRY(__mcount)
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = ( r7:0, p5:0 );
+ [--sp] = ASTAT;
+
+ p1.L = _ipipe_trace_enable;
+ p1.H = _ipipe_trace_enable;
+ r7 = [p1];
+ CC = r7 == 0;
+ if CC jump out;
+ link 0x10;
+ r0 = 0x0;
+ [sp + 0xc] = r0; /* v */
+ r0 = 0x0; /* type: IPIPE_TRACE_FN */
+ r1 = rets;
+ p0 = [fp]; /* p0: Prior FP */
+ r2 = [p0 + 4]; /* r2: Prior RETS */
+ call ___ipipe_trace;
+ unlink;
+out:
+ ASTAT = [sp++];
+ ( r7:0, p5:0 ) = [sp++];
+ b3 = [sp++];
+ b2 = [sp++];
+ b1 = [sp++];
+ b0 = [sp++];
+ m3 = [sp++];
+ m2 = [sp++];
+ m1 = [sp++];
+ m0 = [sp++];
+ l3 = [sp++];
+ l2 = [sp++];
+ l1 = [sp++];
+ l0 = [sp++];
+ i3 = [sp++];
+ i2 = [sp++];
+ i1 = [sp++];
+ i0 = [sp++];
+ rts;
+ENDPROC(__mcount)
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 1ec0faa8c68d..33e2e8993f7f 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -82,11 +82,14 @@ void cpu_idle(void)__attribute__((l1_text));
*/
static void default_idle(void)
{
- local_irq_disable();
+#ifdef CONFIG_IPIPE
+ ipipe_suspend_domain();
+#endif
+ local_irq_disable_hw();
if (!need_resched())
idle_with_irq_disabled();
- local_irq_enable();
+ local_irq_enable_hw();
}
/*
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index ec4dfa38eb0a..172b4c588467 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -31,7 +31,7 @@ static struct irqaction bfin_timer_irq = {
#endif
};
-#ifdef CONFIG_TICK_SOURCE_SYSTMR0
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
void __init setup_system_timer0(void)
{
/* Power down the core timer, just to play safe. */
@@ -74,7 +74,7 @@ void __init setup_core_timer(void)
static void __init
time_sched_init(irqreturn_t(*timer_routine) (int, void *))
{
-#ifdef CONFIG_TICK_SOURCE_SYSTMR0
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
setup_system_timer0();
bfin_timer_irq.handler = timer_routine;
setup_irq(IRQ_TIMER0, &bfin_timer_irq);
@@ -94,7 +94,7 @@ static unsigned long gettimeoffset(void)
unsigned long offset;
unsigned long clocks_per_jiffy;
-#ifdef CONFIG_TICK_SOURCE_SYSTMR0
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
clocks_per_jiffy = bfin_read_TIMER0_PERIOD();
offset = bfin_read_TIMER0_COUNTER() / \
(((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
@@ -133,7 +133,8 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
static long last_rtc_update;
write_seqlock(&xtime_lock);
-#ifdef CONFIG_TICK_SOURCE_SYSTMR0
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
+/* FIXME: Here TIMIL0 is not set when IPIPE enabled, why? */
if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) {
#endif
do_timer(1);
@@ -155,13 +156,17 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
/* Do it again in 60s. */
last_rtc_update = xtime.tv_sec - 600;
}
-#ifdef CONFIG_TICK_SOURCE_SYSTMR0
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
set_gptimer_status(0, TIMER_STATUS_TIMIL0);
}
#endif
write_sequnlock(&xtime_lock);
+#ifdef CONFIG_IPIPE
+ update_root_process_times(get_irq_regs());
+#else
update_process_times(user_mode(get_irq_regs()));
+#endif
profile_tick(CPU_PROFILING);
return IRQ_HANDLED;
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 950cc822fb75..956aefb84687 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -577,10 +577,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
}
}
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_addr = (void __user *)fp->pc;
- force_sig_info(sig, &info, current);
+#ifdef CONFIG_IPIPE
+ if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp))
+#endif
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_addr = (void __user *)fp->pc;
+ force_sig_info(sig, &info, current);
+ }
trace_buffer_restore(j);
return;