Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b5da4c4 authored by Philippe Gerum's avatar Philippe Gerum Committed by Mike Frysinger
Browse files

Blackfin/ipipe: upgrade to I-pipe mainline



This patch introduces Blackfin-specific bits to support the current
tip of the interrupt pipeline development, mainly:

- 2/3-level interrupt maps (sparse IRQs)
- generic virq handling
- sysinfo v2 format for ipipe_get_sysinfo()

Signed-off-by: default avatarPhilippe Gerum <rpm@xenomai.org>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
parent 8944b5a2
Loading
Loading
Loading
Loading
+32 −63
Original line number Original line Diff line number Diff line
@@ -34,11 +34,12 @@
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
#include <asm/atomic.h>
#include <asm/traps.h>
#include <asm/traps.h>
#include <asm/bitsperlong.h>


#define IPIPE_ARCH_STRING     "1.12-00"
#define IPIPE_ARCH_STRING     "1.16-01"
#define IPIPE_MAJOR_NUMBER    1
#define IPIPE_MAJOR_NUMBER    1
#define IPIPE_MINOR_NUMBER    12
#define IPIPE_MINOR_NUMBER    16
#define IPIPE_PATCH_NUMBER    0
#define IPIPE_PATCH_NUMBER    1


#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
#error "I-pipe/blackfin: SMP not implemented"
#error "I-pipe/blackfin: SMP not implemented"
@@ -55,7 +56,6 @@ do { \
#define task_hijacked(p)						\
#define task_hijacked(p)						\
	({								\
	({								\
		int __x__ = __ipipe_root_domain_p;			\
		int __x__ = __ipipe_root_domain_p;			\
		__clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
		if (__x__)						\
		if (__x__)						\
			hard_local_irq_enable();			\
			hard_local_irq_enable();			\
		!__x__;							\
		!__x__;							\
@@ -64,16 +64,11 @@ do { \
struct ipipe_domain;
struct ipipe_domain;


struct ipipe_sysinfo {
struct ipipe_sysinfo {

	int sys_nr_cpus;	/* Number of CPUs on board */
	int ncpus;		/* Number of CPUs on board */
	int sys_hrtimer_irq;	/* hrtimer device IRQ */
	u64 cpufreq;		/* CPU frequency (in Hz) */
	u64 sys_hrtimer_freq;	/* hrtimer device frequency */

	u64 sys_hrclock_freq;	/* hrclock device frequency */
	/* Arch-dependent block */
	u64 sys_cpu_freq;	/* CPU frequency (Hz) */

	struct {
		unsigned tmirq;	/* Timer tick IRQ */
		u64 tmfreq;	/* Timer frequency */
	} archdep;
};
};


#define ipipe_read_tsc(t)					\
#define ipipe_read_tsc(t)					\
@@ -115,9 +110,19 @@ void __ipipe_enable_irqdesc(struct ipipe_domain *ipd,
void __ipipe_disable_irqdesc(struct ipipe_domain *ipd,
void __ipipe_disable_irqdesc(struct ipipe_domain *ipd,
			     unsigned irq);
			     unsigned irq);


#define __ipipe_enable_irq(irq)		(irq_desc[irq].chip->unmask(irq))
#define __ipipe_enable_irq(irq)						\
	do {								\
		struct irq_desc *desc = irq_to_desc(irq);		\
		struct irq_chip *chip = get_irq_desc_chip(desc);	\
		chip->irq_unmask(&desc->irq_data);			\
	} while (0)


#define __ipipe_disable_irq(irq)	(irq_desc[irq].chip->mask(irq))
#define __ipipe_disable_irq(irq)					\
	do {								\
		struct irq_desc *desc = irq_to_desc(irq);		\
		struct irq_chip *chip = get_irq_desc_chip(desc);	\
		chip->irq_mask(&desc->irq_data);			\
	} while (0)


static inline int __ipipe_check_tickdev(const char *devname)
static inline int __ipipe_check_tickdev(const char *devname)
{
{
@@ -128,12 +133,11 @@ void __ipipe_enable_pipeline(void);


#define __ipipe_hook_critical_ipi(ipd) do { } while (0)
#define __ipipe_hook_critical_ipi(ipd) do { } while (0)


#define __ipipe_sync_pipeline  ___ipipe_sync_pipeline
void ___ipipe_sync_pipeline(void);
void ___ipipe_sync_pipeline(unsigned long syncmask);


void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs);
void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs);


int __ipipe_get_irq_priority(unsigned irq);
int __ipipe_get_irq_priority(unsigned int irq);


void __ipipe_serial_debug(const char *fmt, ...);
void __ipipe_serial_debug(const char *fmt, ...);


@@ -152,7 +156,10 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
	return ffs(ul) - 1;
	return ffs(ul) - 1;
}
}


#define __ipipe_run_irqtail()  /* Must be a macro */			\
#define __ipipe_do_root_xirq(ipd, irq)					\
	((ipd)->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)))

#define __ipipe_run_irqtail(irq)  /* Must be a macro */			\
	do {								\
	do {								\
		unsigned long __pending;				\
		unsigned long __pending;				\
		CSYNC();						\
		CSYNC();						\
@@ -164,42 +171,8 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
		}							\
		}							\
	} while (0)
	} while (0)


#define __ipipe_run_isr(ipd, irq)					\
	do {								\
		if (!__ipipe_pipeline_head_p(ipd))			\
			hard_local_irq_enable();				\
		if (ipd == ipipe_root_domain) {				\
			if (unlikely(ipipe_virtual_irq_p(irq))) {	\
				irq_enter();				\
				ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
				irq_exit();				\
			} else 						\
				ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \
		} else {						\
			__clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
			ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
			/* Attempt to exit the outer interrupt level before \
			 * starting the deferred IRQ processing. */	\
			__ipipe_run_irqtail();				\
			__set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
		}							\
		hard_local_irq_disable();					\
	} while (0)

#define __ipipe_syscall_watched_p(p, sc)	\
#define __ipipe_syscall_watched_p(p, sc)	\
	(((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= NR_syscalls)
	(ipipe_notifier_enabled_p(p) || (unsigned long)sc >= NR_syscalls)

void ipipe_init_irq_threads(void);

int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);

#ifdef CONFIG_TICKSOURCE_CORETMR
#define IRQ_SYSTMR		IRQ_CORETMR
#define IRQ_PRIOTMR		IRQ_CORETMR
#else
#define IRQ_SYSTMR		IRQ_TIMER0
#define IRQ_PRIOTMR		CONFIG_IRQ_TIMER0
#endif


#ifdef CONFIG_BF561
#ifdef CONFIG_BF561
#define bfin_write_TIMER_DISABLE(val)	bfin_write_TMRS8_DISABLE(val)
#define bfin_write_TIMER_DISABLE(val)	bfin_write_TMRS8_DISABLE(val)
@@ -219,11 +192,11 @@ int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);


#define task_hijacked(p)		0
#define task_hijacked(p)		0
#define ipipe_trap_notify(t, r)  	0
#define ipipe_trap_notify(t, r)  	0
#define __ipipe_root_tick_p(regs)	1


#define ipipe_init_irq_threads()		do { } while (0)
#endif /* !CONFIG_IPIPE */
#define ipipe_start_irq_thread(irq, desc)	0


#ifndef CONFIG_TICKSOURCE_GPTMR0
#ifdef CONFIG_TICKSOURCE_CORETMR
#define IRQ_SYSTMR		IRQ_CORETMR
#define IRQ_SYSTMR		IRQ_CORETMR
#define IRQ_PRIOTMR		IRQ_CORETMR
#define IRQ_PRIOTMR		IRQ_CORETMR
#else
#else
@@ -231,10 +204,6 @@ int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);
#define IRQ_PRIOTMR		CONFIG_IRQ_TIMER0
#define IRQ_PRIOTMR		CONFIG_IRQ_TIMER0
#endif
#endif


#define __ipipe_root_tick_p(regs)	1

#endif /* !CONFIG_IPIPE */

#define ipipe_update_tick_evtdev(evtdev)	do { } while (0)
#define ipipe_update_tick_evtdev(evtdev)	do { } while (0)


#endif	/* !__ASM_BLACKFIN_IPIPE_H */
#endif	/* !__ASM_BLACKFIN_IPIPE_H */
+9 −2
Original line number Original line Diff line number Diff line
@@ -24,8 +24,10 @@


#ifdef CONFIG_IPIPE
#ifdef CONFIG_IPIPE


#include <asm/bitsperlong.h>
#include <mach/irq.h>

#define IPIPE_NR_XIRQS		NR_IRQS
#define IPIPE_NR_XIRQS		NR_IRQS
#define IPIPE_IRQ_ISHIFT	5	/* 2^5 for 32bits arch. */


/* Blackfin-specific, per-cpu pipeline status */
/* Blackfin-specific, per-cpu pipeline status */
#define IPIPE_SYNCDEFER_FLAG	15
#define IPIPE_SYNCDEFER_FLAG	15
@@ -42,11 +44,14 @@
#define IPIPE_EVENT_INIT	(IPIPE_FIRST_EVENT + 4)
#define IPIPE_EVENT_INIT	(IPIPE_FIRST_EVENT + 4)
#define IPIPE_EVENT_EXIT	(IPIPE_FIRST_EVENT + 5)
#define IPIPE_EVENT_EXIT	(IPIPE_FIRST_EVENT + 5)
#define IPIPE_EVENT_CLEANUP	(IPIPE_FIRST_EVENT + 6)
#define IPIPE_EVENT_CLEANUP	(IPIPE_FIRST_EVENT + 6)
#define IPIPE_LAST_EVENT	IPIPE_EVENT_CLEANUP
#define IPIPE_EVENT_RETURN	(IPIPE_FIRST_EVENT + 7)
#define IPIPE_LAST_EVENT	IPIPE_EVENT_RETURN
#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 1)
#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 1)


#define IPIPE_TIMER_IRQ		IRQ_CORETMR
#define IPIPE_TIMER_IRQ		IRQ_CORETMR


#define __IPIPE_FEATURE_SYSINFO_V2	1

#ifndef __ASSEMBLY__
#ifndef __ASSEMBLY__


extern unsigned long __ipipe_root_status; /* Alias to ipipe_root_cpudom_var(status) */
extern unsigned long __ipipe_root_status; /* Alias to ipipe_root_cpudom_var(status) */
@@ -63,6 +68,8 @@ void __ipipe_unlock_root(void);


#endif /* !__ASSEMBLY__ */
#endif /* !__ASSEMBLY__ */


#define __IPIPE_FEATURE_SYSINFO_V2	1

#endif /* CONFIG_IPIPE */
#endif /* CONFIG_IPIPE */


#endif /* !__ASM_BLACKFIN_IPIPE_BASE_H */
#endif /* !__ASM_BLACKFIN_IPIPE_BASE_H */
+39 −45
Original line number Original line Diff line number Diff line
@@ -154,7 +154,7 @@ void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs)
	 * pending for it.
	 * pending for it.
	 */
	 */
	if (test_bit(IPIPE_AHEAD_FLAG, &this_domain->flags) &&
	if (test_bit(IPIPE_AHEAD_FLAG, &this_domain->flags) &&
	    ipipe_head_cpudom_var(irqpend_himask) == 0)
	    !__ipipe_ipending_p(ipipe_head_cpudom_ptr()))
		goto out;
		goto out;


	__ipipe_walk_pipeline(head);
	__ipipe_walk_pipeline(head);
@@ -185,25 +185,21 @@ void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
}
}
EXPORT_SYMBOL(__ipipe_disable_irqdesc);
EXPORT_SYMBOL(__ipipe_disable_irqdesc);


int __ipipe_syscall_root(struct pt_regs *regs)
asmlinkage int __ipipe_syscall_root(struct pt_regs *regs)
{
{
	struct ipipe_percpu_domain_data *p;
	struct ipipe_percpu_domain_data *p;
	unsigned long flags;
	void (*hook)(void);
	int ret;
	int ret;


	WARN_ON_ONCE(irqs_disabled_hw());

	/*
	/*
	 * We need to run the IRQ tail hook whenever we don't
	 * We need to run the IRQ tail hook each time we intercept a
	 * propagate a syscall to higher domains, because we know that
	 * syscall, because we know that important operations might be
	 * important operations might be pending there (e.g. Xenomai
	 * pending there (e.g. Xenomai deferred rescheduling).
	 * deferred rescheduling).
	 */
	 */

	hook = (__typeof__(hook))__ipipe_irq_tail_hook;
	if (regs->orig_p0 < NR_syscalls) {
		void (*hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
	hook();
	hook();
		if ((current->flags & PF_EVNOTIFY) == 0)
			return 0;
	}


	/*
	/*
	 * This routine either returns:
	 * This routine either returns:
@@ -214,39 +210,34 @@ int __ipipe_syscall_root(struct pt_regs *regs)
	 * tail work has to be performed (for handling signals etc).
	 * tail work has to be performed (for handling signals etc).
	 */
	 */


	if (!__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
	if (!__ipipe_syscall_watched_p(current, regs->orig_p0) ||
	    !__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
		return 0;
		return 0;


	ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
	ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);


	flags = hard_local_irq_save();
	hard_local_irq_disable();


	if (!__ipipe_root_domain_p) {
	/*
		hard_local_irq_restore(flags);
	 * This is the end of the syscall path, so we may
		return 1;
	 * safely assume a valid Linux task stack here.
	 */
	if (current->ipipe_flags & PF_EVTRET) {
		current->ipipe_flags &= ~PF_EVTRET;
		__ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs);
	}
	}


	if (!__ipipe_root_domain_p)
		ret = -1;
	else {
		p = ipipe_root_cpudom_ptr();
		p = ipipe_root_cpudom_ptr();
	if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
		if (__ipipe_ipending_p(p))
		__ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
			__ipipe_sync_pipeline();

	hard_local_irq_restore(flags);

	return -ret;
	}
	}


unsigned long ipipe_critical_enter(void (*syncfn) (void))
	hard_local_irq_enable();
{
	unsigned long flags;


	flags = hard_local_irq_save();
	return -ret;

	return flags;
}

void ipipe_critical_exit(unsigned long flags)
{
	hard_local_irq_restore(flags);
}
}


static void __ipipe_no_irqtail(void)
static void __ipipe_no_irqtail(void)
@@ -255,10 +246,11 @@ static void __ipipe_no_irqtail(void)


int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
{
{
	info->ncpus = num_online_cpus();
	info->sys_nr_cpus = num_online_cpus();
	info->cpufreq = ipipe_cpu_freq();
	info->sys_cpu_freq = ipipe_cpu_freq();
	info->archdep.tmirq = IPIPE_TIMER_IRQ;
	info->sys_hrtimer_irq = IPIPE_TIMER_IRQ;
	info->archdep.tmfreq = info->cpufreq;
	info->sys_hrtimer_freq = __ipipe_core_clock;
	info->sys_hrclock_freq = __ipipe_core_clock;


	return 0;
	return 0;
}
}
@@ -289,6 +281,7 @@ int ipipe_trigger_irq(unsigned irq)
asmlinkage void __ipipe_sync_root(void)
asmlinkage void __ipipe_sync_root(void)
{
{
	void (*irq_tail_hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
	void (*irq_tail_hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
	struct ipipe_percpu_domain_data *p;
	unsigned long flags;
	unsigned long flags;


	BUG_ON(irqs_disabled());
	BUG_ON(irqs_disabled());
@@ -300,19 +293,20 @@ asmlinkage void __ipipe_sync_root(void)


	clear_thread_flag(TIF_IRQ_SYNC);
	clear_thread_flag(TIF_IRQ_SYNC);


	if (ipipe_root_cpudom_var(irqpend_himask) != 0)
	p = ipipe_root_cpudom_ptr();
		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
	if (__ipipe_ipending_p(p))
		__ipipe_sync_pipeline();


	hard_local_irq_restore(flags);
	hard_local_irq_restore(flags);
}
}


void ___ipipe_sync_pipeline(unsigned long syncmask)
void ___ipipe_sync_pipeline(void)
{
{
	if (__ipipe_root_domain_p &&
	if (__ipipe_root_domain_p &&
	    test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status)))
	    test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status)))
		return;
		return;


	__ipipe_sync_stage(syncmask);
	__ipipe_sync_stage();
}
}


void __ipipe_disable_root_irqs_hw(void)
void __ipipe_disable_root_irqs_hw(void)
+37 −4
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/kernel_stat.h>
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/irq.h>
#include <linux/sched.h>
#ifdef CONFIG_IPIPE
#ifdef CONFIG_IPIPE
#include <linux/ipipe.h>
#include <linux/ipipe.h>
#endif
#endif
@@ -556,10 +557,9 @@ static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
{
{
#ifdef CONFIG_IPIPE
#ifdef CONFIG_IPIPE
	_set_irq_handler(irq, handle_level_irq);
	handle = handle_level_irq;
#else
	__set_irq_handler_unlocked(irq, handle);
#endif
#endif
	__set_irq_handler_unlocked(irq, handle);
}
}


static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
@@ -1392,7 +1392,7 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
	struct ipipe_domain *this_domain = __ipipe_current_domain;
	struct ipipe_domain *this_domain = __ipipe_current_domain;
	struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
	struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
	struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
	struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
	int irq, s;
	int irq, s = 0;


	if (likely(vec == EVT_IVTMR_P))
	if (likely(vec == EVT_IVTMR_P))
		irq = IRQ_CORETMR;
		irq = IRQ_CORETMR;
@@ -1442,6 +1442,21 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
			__raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
			__raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
	}
	}


	/*
	 * We don't want Linux interrupt handlers to run at the
	 * current core priority level (i.e. < EVT15), since this
	 * might delay other interrupts handled by a high priority
	 * domain. Here is what we do instead:
	 *
	 * - we raise the SYNCDEFER bit to prevent
	 * __ipipe_handle_irq() to sync the pipeline for the root
	 * stage for the incoming interrupt. Upon return, that IRQ is
	 * pending in the interrupt log.
	 *
	 * - we raise the TIF_IRQ_SYNC bit for the current thread, so
	 * that _schedule_and_signal_from_int will eventually sync the
	 * pipeline from EVT15.
	 */
	if (this_domain == ipipe_root_domain) {
	if (this_domain == ipipe_root_domain) {
		s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
		s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
		barrier();
		barrier();
@@ -1451,6 +1466,24 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
	__ipipe_handle_irq(irq, regs);
	__ipipe_handle_irq(irq, regs);
	ipipe_trace_irq_exit(irq);
	ipipe_trace_irq_exit(irq);


	if (user_mode(regs) &&
	    !ipipe_test_foreign_stack() &&
	    (current->ipipe_flags & PF_EVTRET) != 0) {
		/*
		 * Testing for user_regs() does NOT fully eliminate
		 * foreign stack contexts, because of the forged
		 * interrupt returns we do through
		 * __ipipe_call_irqtail. In that case, we might have
		 * preempted a foreign stack context in a high
		 * priority domain, with a single interrupt level now
		 * pending after the irqtail unwinding is done. In
		 * which case user_mode() is now true, and the event
		 * gets dispatched spuriously.
		 */
		current->ipipe_flags &= ~PF_EVTRET;
		__ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs);
	}

	if (this_domain == ipipe_root_domain) {
	if (this_domain == ipipe_root_domain) {
		set_thread_flag(TIF_IRQ_SYNC);
		set_thread_flag(TIF_IRQ_SYNC);
		if (!s) {
		if (!s) {