diff options
80 files changed, 4491 insertions, 478 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index debde0128cd..1e6b6bdf634 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4448,7 +4448,7 @@ L:	platform-driver-x86@vger.kernel.org  S:	Maintained  F:	drivers/platform/x86/panasonic-laptop.c -PANASONIC MN10300/AM33 PORT +PANASONIC MN10300/AM33/AM34 PORT  M:	David Howells <dhowells@redhat.com>  M:	Koichi Yasutake <yasutake.koichi@jp.panasonic.com>  L:	linux-am33-list@redhat.com (moderated for non-subscribers) diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index a0a16e6e4a4..81e27816aaf 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -48,7 +48,7 @@ config GENERIC_CALIBRATE_DELAY  	def_bool y  config GENERIC_CMOS_UPDATE -        def_bool y +        def_bool n  config GENERIC_FIND_NEXT_BIT  	def_bool y @@ -72,10 +72,6 @@ config GENERIC_HARDIRQS  config HOTPLUG_CPU  	def_bool n -config HZ -	int -	default 1000 -  mainmenu "Matsushita MN10300/AM33 Kernel Configuration"  source "init/Kconfig" @@ -98,6 +94,9 @@ config MN10300_UNIT_ASB2303  config MN10300_UNIT_ASB2305  	bool "ASB2305" +config MN10300_UNIT_ASB2364 +	bool "ASB2364" +  endchoice  choice @@ -115,17 +114,13 @@ config MN10300_PROC_MN103E010  	select MN10300_PROC_HAS_TTYSM1  	select MN10300_PROC_HAS_TTYSM2 -endchoice - -choice -	prompt "Processor core support" -	default MN10300_CPU_AM33V2 -	help -	  This option specifies the processor core for which the kernel will be -	  compiled. It affects the instruction set used. - -config MN10300_CPU_AM33V2 -	bool "AM33v2" +config MN10300_PROC_MN2WS0050 +	bool "MN2WS0050" +	depends on MN10300_UNIT_ASB2364 +	select AM34_2 +	select MN10300_PROC_HAS_TTYSM0 +	select MN10300_PROC_HAS_TTYSM1 +	select MN10300_PROC_HAS_TTYSM2  endchoice @@ -138,7 +133,7 @@ config MN10300_HAS_ATOMIC_OPS_UNIT  config FPU  	bool "FPU present"  	default y -	depends on MN10300_PROC_MN103E010 +	depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050  config LAZY_SAVE_FPU  	bool "Save FPU state lazily" @@ -179,24 +174,55 @@ config KERNEL_TEXT_ADDRESS  config KERNEL_ZIMAGE_BASE_ADDRESS  	hex "Base address of compressed vmlinux image" -	default "0x90700000" +	default "0x50700000" + +config BOOT_STACK_OFFSET +	hex +	default	"0xF00"	if SMP +	default	"0xFF0" if !SMP +config BOOT_STACK_SIZE +	hex +	depends on SMP +	default	"0x100"  endmenu -config PREEMPT -	bool "Preemptible Kernel" -	help -	  This option reduces the latency of the kernel when reacting to -	  real-time or interactive events by allowing a low priority process to -	  be preempted even if it is in kernel mode executing a system call. -	  This allows applications to run more reliably even when the system is -	  under load. +config SMP +	bool "Symmetric multi-processing support" +	default y +	depends on MN10300_PROC_MN2WS0038 || MN10300_PROC_MN2WS0050 +	---help--- +	  This enables support for systems with more than one CPU. If you have +	  a system with only one CPU, like most personal computers, say N. If +	  you have a system with more than one CPU, say Y. + +	  If you say N here, the kernel will run on single and multiprocessor +	  machines, but will use only one CPU of a multiprocessor machine. If +	  you say Y here, the kernel will run on many, but not all, +	  singleprocessor machines. On a singleprocessor machine, the kernel +	  will run faster if you say N here. + +	  See also <file:Documentation/i386/IO-APIC.txt>, +	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at +	  <http://www.tldp.org/docs.html#howto>. -	  Say Y here if you are building a kernel for a desktop, embedded -	  or real-time system.  Say N if you are unsure. +	  If you don't know what to do here, say N. + +config NR_CPUS +	int +	depends on SMP +	default "2" + +config USE_GENERIC_SMP_HELPERS +	bool +	depends on SMP +	default y + +source "kernel/Kconfig.preempt"  config MN10300_CURRENT_IN_E2  	bool "Hold current task address in E2 register" +	depends on !SMP  	default y  	help  	  This option removes the E2/R2 register from the set available to gcc @@ -218,12 +244,14 @@ config MN10300_USING_JTAG  	  suppresses the use of certain hardware debugging features, such as  	  single-stepping, which are taken over completely by the JTAG unit. +source "kernel/Kconfig.hz" +  config MN10300_RTC  	bool "Using MN10300 RTC" -	depends on MN10300_PROC_MN103E010 +	depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050 +	select GENERIC_CMOS_UPDATE  	default n  	help -  	  This option enables support for the RTC, thus enabling time to be  	  tracked, even when system is powered down. This is available on-chip  	  on the MN103E010. @@ -315,14 +343,23 @@ config MN10300_TTYSM1  choice  	prompt "Select the timer to supply the clock for SIF1" -	default MN10300_TTYSM0_TIMER9 +	default MN10300_TTYSM1_TIMER12 \ +		if !(AM33_2 || AM33_3) +	default MN10300_TTYSM1_TIMER9 \ +		if AM33_2 || AM33_3  	depends on MN10300_TTYSM1 +config MN10300_TTYSM1_TIMER12 +	bool "Use timer 12 (16-bit)" +	depends on !(AM33_2 || AM33_3) +  config MN10300_TTYSM1_TIMER9  	bool "Use timer 9 (16-bit)" +	depends on AM33_2 || AM33_3  config MN10300_TTYSM1_TIMER3  	bool "Use timer 3 (8-bit)" +	depends on AM33_2 || AM33_3  endchoice @@ -337,17 +374,33 @@ config MN10300_TTYSM2  choice  	prompt "Select the timer to supply the clock for SIF2" -	default MN10300_TTYSM0_TIMER10 +	default MN10300_TTYSM2_TIMER3 \ +		if !(AM33_2 || AM33_3) +	default MN10300_TTYSM2_TIMER10 \ +		if AM33_2 || AM33_3  	depends on MN10300_TTYSM2 +config MN10300_TTYSM2_TIMER9 +	bool "Use timer 9 (16-bit)" +	depends on !(AM33_2 || AM33_3) + +config MN10300_TTYSM2_TIMER1 +	bool "Use timer 1 (8-bit)" +	depends on !(AM33_2 || AM33_3) + +config MN10300_TTYSM2_TIMER3 +	bool "Use timer 3 (8-bit)" +	depends on !(AM33_2 || AM33_3) +  config MN10300_TTYSM2_TIMER10  	bool "Use timer 10 (16-bit)" +	depends on AM33_2 || AM33_3  endchoice  config MN10300_TTYSM2_CTS  	bool "Enable the use of the CTS line /dev/ttySM2" -	depends on MN10300_TTYSM2 +	depends on MN10300_TTYSM2 && AM33_2  endmenu diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile index ac5c6bdb2f0..7120282bf0d 100644 --- a/arch/mn10300/Makefile +++ b/arch/mn10300/Makefile @@ -36,6 +36,9 @@ endif  ifeq ($(CONFIG_MN10300_PROC_MN103E010),y)  PROCESSOR	:= mn103e010  endif +ifeq ($(CONFIG_MN10300_PROC_MN2WS0050),y) +PROCESSOR	:= mn2ws0050 +endif  ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y)  UNIT		:= asb2303 @@ -43,6 +46,9 @@ endif  ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y)  UNIT		:= asb2305  endif +ifeq ($(CONFIG_MN10300_UNIT_ASB2364),y) +UNIT		:= asb2364 +endif  head-y		:= arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o diff --git a/arch/mn10300/boot/compressed/head.S b/arch/mn10300/boot/compressed/head.S index 4ef608a6241..7b50345b9e8 100644 --- a/arch/mn10300/boot/compressed/head.S +++ b/arch/mn10300/boot/compressed/head.S @@ -15,10 +15,28 @@  #include <linux/linkage.h>  #include <asm/cpu-regs.h>  #include <asm/cache.h> +#ifdef CONFIG_SMP +#include <proc/smp-regs.h> +#endif  	.globl startup_32  startup_32: -	# first save off parameters from bootloader +#ifdef CONFIG_SMP +	# +	# Secondary CPUs jump directly to the kernel entry point +	# +	# Must save primary CPU's D0-D2 registers as they hold boot parameters +	# +	mov	(CPUID), d3 +	and	CPUID_MASK,d3 +	beq	startup_primary +	mov	CONFIG_KERNEL_TEXT_ADDRESS,a0 +	jmp	(a0) + +startup_primary: +#endif /* CONFIG_SMP */ + +	# first save parameters from bootloader  	mov	param_save_area,a0  	mov	d0,(a0)  	mov	d1,(4,a0) diff --git a/arch/mn10300/include/asm/exceptions.h b/arch/mn10300/include/asm/exceptions.h index 7d8080bc659..ca3e20508c7 100644 --- a/arch/mn10300/include/asm/exceptions.h +++ b/arch/mn10300/include/asm/exceptions.h @@ -114,6 +114,8 @@ extern void die(const char *, struct pt_regs *, enum exception_code)  extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code); +#define NUM2EXCEP_IRQ_LEVEL(num)	(EXCEP_IRQ_LEVEL0 + (num) * 8) +  #endif /* __ASSEMBLY__ */  #endif /* _ASM_EXCEPTIONS_H */ diff --git a/arch/mn10300/include/asm/frame.inc b/arch/mn10300/include/asm/frame.inc index 5b1949bdf03..406060e5e1c 100644 --- a/arch/mn10300/include/asm/frame.inc +++ b/arch/mn10300/include/asm/frame.inc @@ -18,6 +18,9 @@  #ifndef __ASM_OFFSETS_H__  #include <asm/asm-offsets.h>  #endif +#ifdef CONFIG_SMP +#include <proc/smp-regs.h> +#endif  #define pi break @@ -37,9 +40,25 @@  	movm	[d2,d3,a2,a3,exreg0,exreg1,exother],(sp)  	mov	sp,fp				# FRAME pointer in A3  	add	-12,sp				# allow for calls to be made +#ifdef CONFIG_SMP +#ifdef CONFIG_PREEMPT /* FIXME */ +	mov	epsw,d2 +	and	~EPSW_IE,epsw +#endif +	mov	(CPUID),a0 +	add	a0,a0 +	add	a0,a0 +	mov	(___frame,a0),a1 +	mov	a1,(REG_NEXT,fp) +	mov	fp,(___frame,a0) +#ifdef CONFIG_PREEMPT /* FIXME */ +	mov	d2,epsw +#endif +#else  /* CONFIG_SMP */  	mov	(__frame),a1  	mov	a1,(REG_NEXT,fp)  	mov	fp,(__frame) +#endif /* CONFIG_SMP */  	and	~EPSW_FE,epsw			# disable the FPU inside the kernel @@ -57,10 +76,27 @@  .macro RESTORE_ALL  	# peel back the stack to the calling frame  	# - this permits execve() to discard extra frames due to kernel syscalls +#ifdef  CONFIG_SMP +#ifdef CONFIG_PREEMPT /* FIXME */ +	mov	epsw,d2 +	and	~EPSW_IE,epsw +#endif +	mov	(CPUID),a0 +	add	a0,a0 +	add	a0,a0 +	mov	(___frame,a0),fp +	mov	fp,sp +	mov	(REG_NEXT,fp),d0                # userspace has regs->next == 0 +	mov	d0,(___frame,a0) +#ifdef CONFIG_PREEMPT /* FIXME */ +	mov	d2,epsw +#endif +#else   /* CONFIG_SMP */  	mov	(__frame),fp  	mov	fp,sp  	mov	(REG_NEXT,fp),d0                # userspace has regs->next == 0  	mov	d0,(__frame) +#endif  /* CONFIG_SMP */  #ifndef CONFIG_MN10300_USING_JTAG  	mov	(REG_EPSW,fp),d0 diff --git a/arch/mn10300/include/asm/hardirq.h b/arch/mn10300/include/asm/hardirq.h index 7bd9b7cc245..0000d650b55 100644 --- a/arch/mn10300/include/asm/hardirq.h +++ b/arch/mn10300/include/asm/hardirq.h @@ -19,8 +19,10 @@  /* assembly code in softirq.h is sensitive to the offsets of these fields */  typedef struct {  	unsigned int	__softirq_pending; +#ifdef CONFIG_MN10300_WD_TIMER  	unsigned int	__nmi_count;	/* arch dependent */  	unsigned int	__irq_count;	/* arch dependent */ +#endif  } ____cacheline_aligned irq_cpustat_t;  #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */ diff --git a/arch/mn10300/include/asm/intctl-regs.h b/arch/mn10300/include/asm/intctl-regs.h index ba544c796c5..585b708c2bc 100644 --- a/arch/mn10300/include/asm/intctl-regs.h +++ b/arch/mn10300/include/asm/intctl-regs.h @@ -15,24 +15,19 @@  #ifdef __KERNEL__ -/* interrupt controller registers */ -#define GxICR(X)		__SYSREG(0xd4000000 + (X) * 4, u16)	/* group irq ctrl regs */ - -#define IAGR			__SYSREG(0xd4000100, u16)	/* intr acceptance group reg */ -#define IAGR_GN			0x00fc		/* group number register -						 * (documentation _has_ to be wrong) -						 */ +/* + * Interrupt controller registers + * - Registers 64-191 are at addresses offset from the main array + */ +#define GxICR(X)						\ +	__SYSREG(0xd4000000 + (X) * 4 +				\ +		 (((X) >= 64) && ((X) < 192)) * 0xf00, u16) -#define EXTMD			__SYSREG(0xd4000200, u16)	/* external pin intr spec reg */ -#define GET_XIRQ_TRIGGER(X) ((EXTMD >> ((X) * 2)) & 3) +#define GxICR_u8(X)							\ +	__SYSREG(0xd4000000 + (X) * 4 +					\ +		 (((X) >= 64) && ((X) < 192)) * 0xf00, u8) -#define SET_XIRQ_TRIGGER(X,Y)			\ -do {						\ -	u16 x = EXTMD;				\ -	x &= ~(3 << ((X) * 2));			\ -	x |= ((Y) & 3) << ((X) * 2);		\ -	EXTMD = x;				\ -} while (0) +#include <proc/intctl-regs.h>  #define XIRQ_TRIGGER_LOWLEVEL	0  #define XIRQ_TRIGGER_HILEVEL	1 @@ -59,10 +54,18 @@ do {						\  #define GxICR_LEVEL_5		0x5000		/* - level 5 */  #define GxICR_LEVEL_6		0x6000		/* - level 6 */  #define GxICR_LEVEL_SHIFT	12 +#define GxICR_NMI		0x8000		/* nmi request flag */ + +#define NUM2GxICR_LEVEL(num)	((num) << GxICR_LEVEL_SHIFT)  #ifndef __ASSEMBLY__  extern void set_intr_level(int irq, u16 level); -extern void set_intr_postackable(int irq); +extern void mn10300_intc_set_level(unsigned int irq, unsigned int level); +extern void mn10300_intc_clear(unsigned int irq); +extern void mn10300_intc_set(unsigned int irq); +extern void mn10300_intc_enable(unsigned int irq); +extern void mn10300_intc_disable(unsigned int irq); +extern void mn10300_set_lateack_irq_type(int irq);  #endif  /* external interrupts */ diff --git a/arch/mn10300/include/asm/irq.h b/arch/mn10300/include/asm/irq.h index 25c045d16d1..b7b8e175b16 100644 --- a/arch/mn10300/include/asm/irq.h +++ b/arch/mn10300/include/asm/irq.h @@ -22,7 +22,11 @@  #define NO_IRQ		INT_MAX  /* hardware irq numbers */ +#ifdef CONFIG_SMP +#define NR_IRQS		GxICR_NUM_EXT_IRQS +#else  #define NR_IRQS		GxICR_NUM_IRQS +#endif  /* external hardware irq numbers */  #define NR_XIRQS	GxICR_NUM_XIRQS diff --git a/arch/mn10300/include/asm/irqflags.h b/arch/mn10300/include/asm/irqflags.h index b3ab2071354..7a7ae12c711 100644 --- a/arch/mn10300/include/asm/irqflags.h +++ b/arch/mn10300/include/asm/irqflags.h @@ -13,6 +13,9 @@  #define _ASM_IRQFLAGS_H  #include <asm/cpu-regs.h> +#ifndef __ASSEMBLY__ +#include <linux/smp.h> +#endif  /*   * interrupt control @@ -60,11 +63,12 @@ static inline unsigned long arch_local_irq_save(void)  /*   * we make sure arch_irq_enable() doesn't cause priority inversion   */ -extern unsigned long __mn10300_irq_enabled_epsw; +extern unsigned long __mn10300_irq_enabled_epsw[];  static inline void arch_local_irq_enable(void)  {  	unsigned long tmp; +	int cpu = raw_smp_processor_id();  	asm volatile(  		"	mov	epsw,%0		\n" @@ -72,8 +76,8 @@ static inline void arch_local_irq_enable(void)  		"	or	%2,%0		\n"  		"	mov	%0,epsw		\n"  		: "=&d"(tmp) -		: "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw) -		: "memory"); +		: "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw[cpu]) +		: "memory", "cc");  }  static inline void arch_local_irq_restore(unsigned long flags) @@ -105,6 +109,9 @@ static inline bool arch_irqs_disabled(void)   */  static inline void arch_safe_halt(void)  { +#ifdef CONFIG_SMP +	arch_local_irq_enable(); +#else  	asm volatile(  		"	or	%0,epsw	\n"  		"	nop		\n" @@ -113,8 +120,21 @@ static inline void arch_safe_halt(void)  		:  		: "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)  		: "cc"); +#endif  } +#define __sleep_cpu()				\ +do {						\ +	asm volatile(				\ +		"	bset	%1,(%0)\n"	\ +		"1:	btst	%1,(%0)\n"	\ +		"	bne	1b\n"		\ +		:				\ +		: "i"(&CPUM), "i"(CPUM_SLEEP)	\ +		: "cc"				\ +		);				\ +} while (0) +  static inline void arch_local_cli(void)  {  	asm volatile( diff --git a/arch/mn10300/include/asm/pgtable.h b/arch/mn10300/include/asm/pgtable.h index 05dda641af8..cd568bf5407 100644 --- a/arch/mn10300/include/asm/pgtable.h +++ b/arch/mn10300/include/asm/pgtable.h @@ -90,9 +90,15 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];   * The vmalloc() routines also leaves a hole of 4kB between each vmalloced   * area to catch addressing errors.   */ +#ifndef __ASSEMBLY__ +#define VMALLOC_OFFSET	(8UL * 1024 * 1024) +#define VMALLOC_START	(0x70000000UL) +#define VMALLOC_END	(0x7C000000UL) +#else  #define VMALLOC_OFFSET	(8 * 1024 * 1024)  #define VMALLOC_START	(0x70000000)  #define VMALLOC_END	(0x7C000000) +#endif  #ifndef __ASSEMBLY__  extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE]; @@ -329,11 +335,7 @@ static inline int pte_exec_kernel(pte_t pte)  	return 1;  } -/* - * Bits 0 and 1 are taken, split up the 29 bits of offset - * into this range: - */ -#define PTE_FILE_MAX_BITS	29 +#define PTE_FILE_MAX_BITS	30  #define pte_to_pgoff(pte)	(pte_val(pte) >> 2)  #define pgoff_to_pte(off)	__pte((off) << 2 | _PAGE_FILE) @@ -379,8 +381,13 @@ static inline void ptep_mkdirty(pte_t *ptep)   * Macro to mark a page protection value as "uncacheable".  On processors which   * do not support it, this is a no-op.   */ -#define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) | _PAGE_CACHE) +#define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) & ~_PAGE_CACHE) +/* + * Macro to mark a page protection value as "Write-Through". + * On processors which do not support it, this is a no-op. + */ +#define pgprot_through(prot)	__pgprot(pgprot_val(prot) | _PAGE_CACHE_WT)  /*   * Conversion functions: convert a page and protection to a page entry, diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h index 0032fc76c8b..75c422abcd6 100644 --- a/arch/mn10300/include/asm/processor.h +++ b/arch/mn10300/include/asm/processor.h @@ -33,6 +33,8 @@ struct mm_struct;  	__pc;					\  }) +extern void get_mem_info(unsigned long *mem_base, unsigned long *mem_size); +  extern void show_registers(struct pt_regs *regs);  /* @@ -43,17 +45,22 @@ extern void show_registers(struct pt_regs *regs);  struct mn10300_cpuinfo {  	int		type; -	unsigned long	loops_per_sec; +	unsigned long	loops_per_jiffy;  	char		hard_math; -	unsigned long	*pgd_quick; -	unsigned long	*pte_quick; -	unsigned long	pgtable_cache_sz;  };  extern struct mn10300_cpuinfo boot_cpu_data; +#ifdef CONFIG_SMP +#if CONFIG_NR_CPUS < 2 || CONFIG_NR_CPUS > 8 +# error Sorry, NR_CPUS should be 2 to 8 +#endif +extern struct mn10300_cpuinfo cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else  /* CONFIG_SMP */  #define cpu_data &boot_cpu_data  #define current_cpu_data boot_cpu_data +#endif /* CONFIG_SMP */  extern void identify_cpu(struct mn10300_cpuinfo *);  extern void print_cpu_info(struct mn10300_cpuinfo *); @@ -92,21 +99,21 @@ struct thread_struct {  	unsigned long		a3;		/* kernel FP */  	unsigned long		wchan;  	unsigned long		usp; -	struct pt_regs		*__frame; +	struct pt_regs		*frame;  	unsigned long		fpu_flags;  #define THREAD_USING_FPU	0x00000001	/* T if this task is using the FPU */  #define THREAD_HAS_FPU		0x00000002	/* T if this task owns the FPU right now */  	struct fpu_state_struct	fpu_state;  }; -#define INIT_THREAD				\ -{						\ -	.uregs		= init_uregs,		\ -	.pc		= 0,			\ -	.sp		= 0,			\ -	.a3		= 0,			\ -	.wchan		= 0,			\ -	.__frame	= NULL,			\ +#define INIT_THREAD		\ +{				\ +	.uregs	= init_uregs,	\ +	.pc	= 0,		\ +	.sp	= 0,		\ +	.a3	= 0,		\ +	.wchan	= 0,		\ +	.frame	= NULL,		\  }  #define INIT_MMAP \ @@ -118,6 +125,19 @@ struct thread_struct {   * - need to discard the frame stacked by the kernel thread invoking the execve   *   syscall (see RESTORE_ALL macro)   */ +#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) /* FIXME */ +#define start_thread(regs, new_pc, new_sp) do {		\ +	int cpu;					\ +	preempt_disable();				\ +	cpu = CPUID;					\ +	set_fs(USER_DS);				\ +	___frame[cpu] = current->thread.uregs;		\ +	___frame[cpu]->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;\ +	___frame[cpu]->pc = new_pc;			\ +	___frame[cpu]->sp = new_sp;			\ +	preempt_enable();				\ +} while (0) +#else  /* CONFIG_SMP && CONFIG_PREEMPT */  #define start_thread(regs, new_pc, new_sp) do {		\  	set_fs(USER_DS);				\  	__frame = current->thread.uregs;		\ @@ -125,6 +145,7 @@ struct thread_struct {  	__frame->pc = new_pc;				\  	__frame->sp = new_sp;				\  } while (0) +#endif /* CONFIG_SMP && CONFIG_PREEMPT */  /* Free all resources held by a thread. */  extern void release_thread(struct task_struct *); diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h index 7c2e911052b..c2b77bd3064 100644 --- a/arch/mn10300/include/asm/ptrace.h +++ b/arch/mn10300/include/asm/ptrace.h @@ -40,7 +40,6 @@  #define	PT_PC		26  #define NR_PTREGS	27 -#ifndef __ASSEMBLY__  /*   * This defines the way registers are stored in the event of an exception   * - the strange order is due to the MOVM instruction @@ -75,7 +74,6 @@ struct pt_regs {  	unsigned long		epsw;  	unsigned long		pc;  }; -#endif  /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */  #define PTRACE_GETREGS            12 @@ -86,12 +84,13 @@ struct pt_regs {  /* options set using PTRACE_SETOPTIONS */  #define PTRACE_O_TRACESYSGOOD     0x00000001 -#if defined(__KERNEL__) +#ifdef __KERNEL__ +#ifdef CONFIG_SMP +extern struct pt_regs *___frame[];	/* current frame pointer */ +#else  extern struct pt_regs *__frame;		/* current frame pointer */ - -#if !defined(__ASSEMBLY__) -struct task_struct; +#endif  #define user_mode(regs)			(((regs)->epsw & EPSW_nSL) == EPSW_nSL)  #define instruction_pointer(regs)	((regs)->pc) @@ -100,9 +99,7 @@ extern void show_regs(struct pt_regs *);  #define arch_has_single_step()	(1) -#endif  /*  !__ASSEMBLY  */ -  #define profile_pc(regs) ((regs)->pc) -#endif  /*  __KERNEL__  */ +#endif /* __KERNEL__  */  #endif /* _ASM_PTRACE_H */ diff --git a/arch/mn10300/include/asm/reset-regs.h b/arch/mn10300/include/asm/reset-regs.h index 174523d5013..10c7502a113 100644 --- a/arch/mn10300/include/asm/reset-regs.h +++ b/arch/mn10300/include/asm/reset-regs.h @@ -50,7 +50,7 @@ static inline void mn10300_proc_hard_reset(void)  	RSTCTR |= RSTCTR_CHIPRST;  } -extern unsigned int watchdog_alert_counter; +extern unsigned int watchdog_alert_counter[];  extern void watchdog_go(void);  extern asmlinkage void watchdog_handler(void); diff --git a/arch/mn10300/include/asm/rtc.h b/arch/mn10300/include/asm/rtc.h index c295194cc70..6c14bb1d0d9 100644 --- a/arch/mn10300/include/asm/rtc.h +++ b/arch/mn10300/include/asm/rtc.h @@ -15,25 +15,14 @@  #include <linux/init.h> -extern void check_rtc_time(void);  extern void __init calibrate_clock(void); -extern unsigned long __init get_initial_rtc_time(void);  #else /* !CONFIG_MN10300_RTC */ -static inline void check_rtc_time(void) -{ -} -  static inline void calibrate_clock(void)  {  } -static inline unsigned long get_initial_rtc_time(void) -{ -	return 0; -} -  #endif /* !CONFIG_MN10300_RTC */  #include <asm-generic/rtc.h> diff --git a/arch/mn10300/include/asm/rwlock.h b/arch/mn10300/include/asm/rwlock.h new file mode 100644 index 00000000000..6d594d4a0e1 --- /dev/null +++ b/arch/mn10300/include/asm/rwlock.h @@ -0,0 +1,125 @@ +/* + * Helpers used by both rw spinlocks and rw semaphores. + * + * Based in part on code from semaphore.h and + * spinlock.h Copyright 1996 Linus Torvalds. + * + * Copyright 1999 Red Hat, Inc. + * + * Written by Benjamin LaHaise. + * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + * 13-Nov-2006 MEI Temporarily delete lock functions for SMP support. + * + * 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; either version 2 of the License, or (at your option) + * any later version. + */ +#ifndef _ASM_RWLOCK_H +#define _ASM_RWLOCK_H + +#define RW_LOCK_BIAS		 0x01000000 + +#ifndef CONFIG_SMP + +typedef struct { unsigned long a[100]; } __dummy_lock_t; +#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) + +#define RW_LOCK_BIAS_STR	"0x01000000" + +#define __build_read_lock_ptr(rw, helper)				\ +	do {								\ +		asm volatile(						\ +			"	mov	(%0),d3			\n"	\ +			"	sub	1,d3			\n"	\ +			"	mov	d3,(%0)			\n"	\ +			"	blt	1f			\n"	\ +			"	bra	2f			\n"	\ +			"1:	jmp	3f			\n"	\ +			"2:					\n"	\ +			"	.section .text.lock,\"ax\"	\n"	\ +			"3:	call	"helper"[],0		\n"	\ +			"	jmp	2b			\n"	\ +			"	.previous"				\ +			:						\ +			: "d" (rw)					\ +			: "memory", "d3", "cc");			\ +	} while (0) + +#define __build_read_lock_const(rw, helper)				\ +	do {								\ +		asm volatile(						\ +			"	mov	(%0),d3			\n"	\ +			"	sub	1,d3			\n"	\ +			"	mov	d3,(%0)			\n"	\ +			"	blt	1f			\n"	\ +			"	bra	2f			\n"	\ +			"1:	jmp	3f			\n"	\ +			"2:					\n"	\ +			"	.section .text.lock,\"ax\"	\n"	\ +			"3:	call	"helper"[],0		\n"	\ +			"	jmp	2b			\n"	\ +			"	.previous"				\ +			:						\ +			: "d" (rw)					\ +			: "memory", "d3", "cc");			\ +	} while (0) + +#define __build_read_lock(rw, helper) \ +	do {								\ +		if (__builtin_constant_p(rw))				\ +			__build_read_lock_const(rw, helper);		\ +		else							\ +			__build_read_lock_ptr(rw, helper);		\ +	} while (0) + +#define __build_write_lock_ptr(rw, helper)				\ +	do {								\ +		asm volatile(						\ +			"	mov	(%0),d3			\n"	\ +			"	sub	1,d3			\n"	\ +			"	mov	d3,(%0)			\n"	\ +			"	blt	1f			\n"	\ +			"	bra	2f			\n"	\ +			"1:	jmp	3f			\n"	\ +			"2:					\n"	\ +			"	.section .text.lock,\"ax\"	\n"	\ +			"3:	call	"helper"[],0		\n"	\ +			"	jmp	2b			\n"	\ +			"	.previous"				\ +			:						\ +			: "d" (rw)					\ +			: "memory", "d3", "cc");			\ +	} while (0) + +#define __build_write_lock_const(rw, helper)				\ +	do {								\ +		asm volatile(						\ +			"	mov	(%0),d3			\n"	\ +			"	sub	1,d3			\n"	\ +			"	mov	d3,(%0)			\n"	\ +			"	blt	1f			\n"	\ +			"	bra	2f			\n"	\ +			"1:	jmp	3f			\n"	\ +			"2:					\n"	\ +			"	.section .text.lock,\"ax\"	\n"	\ +			"3:	call	"helper"[],0		\n"	\ +			"	jmp	2b			\n"	\ +			"	.previous"				\ +			:						\ +			: "d" (rw)					\ +			: "memory", "d3", "cc");			\ +	} while (0) + +#define __build_write_lock(rw, helper)					\ +	do {								\ +		if (__builtin_constant_p(rw))				\ +			__build_write_lock_const(rw, helper);		\ +		else							\ +			__build_write_lock_ptr(rw, helper);		\ +	} while (0) + +#endif /* CONFIG_SMP */ +#endif /* _ASM_RWLOCK_H */ diff --git a/arch/mn10300/include/asm/serial-regs.h b/arch/mn10300/include/asm/serial-regs.h index 6498469e93a..8320cda32f5 100644 --- a/arch/mn10300/include/asm/serial-regs.h +++ b/arch/mn10300/include/asm/serial-regs.h @@ -20,18 +20,25 @@  /* serial port 0 */  #define	SC0CTR			__SYSREG(0xd4002000, u16)	/* control reg */  #define	SC01CTR_CK		0x0007	/* clock source select */ -#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */ -#define	SC1CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow (serial port 1 only) */  #define	SC01CTR_CK_IOCLK_8	0x0001	/* - 1/8 IOCLK */  #define	SC01CTR_CK_IOCLK_32	0x0002	/* - 1/32 IOCLK */ +#define	SC01CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */ +#define	SC01CTR_CK_EXTERN	0x0007	/* - external closk */ +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) +#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */  #define	SC0CTR_CK_TM2UFLOW_2	0x0003	/* - 1/2 timer 2 underflow (serial port 0 only) */ -#define	SC1CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow (serial port 1 only) */ -#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 1 underflow (serial port 0 only) */ -#define	SC1CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 2 underflow (serial port 1 only) */ +#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 0 underflow (serial port 0 only) */  #define	SC0CTR_CK_TM2UFLOW_8	0x0005	/* - 1/8 timer 2 underflow (serial port 0 only) */ +#define	SC1CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow (serial port 1 only) */ +#define	SC1CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow (serial port 1 only) */ +#define	SC1CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 1 underflow (serial port 1 only) */  #define	SC1CTR_CK_TM3UFLOW_8	0x0005	/* - 1/8 timer 3 underflow (serial port 1 only) */ -#define	SC01CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */ -#define	SC01CTR_CK_EXTERN	0x0007	/* - external closk */ +#else  /* CONFIG_AM33_2 || CONFIG_AM33_3 */ +#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */ +#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 0 underflow (serial port 0 only) */ +#define	SC0CTR_CK_TM2UFLOW_8	0x0005	/* - 1/8 timer 2 underflow (serial port 0 only) */ +#define	SC1CTR_CK_TM12UFLOW_8	0x0000	/* - 1/8 timer 12 underflow (serial port 1 only) */ +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */  #define	SC01CTR_STB		0x0008	/* stop bit select */  #define	SC01CTR_STB_1BIT	0x0000	/* - 1 stop bit */  #define	SC01CTR_STB_2BIT	0x0008	/* - 2 stop bits */ @@ -100,11 +107,23 @@  /* serial port 2 */  #define	SC2CTR			__SYSREG(0xd4002020, u16)	/* control reg */ +#ifdef CONFIG_AM33_2  #define	SC2CTR_CK		0x0003	/* clock source select */  #define	SC2CTR_CK_TM10UFLOW	0x0000	/* - timer 10 underflow */  #define	SC2CTR_CK_TM2UFLOW	0x0001	/* - timer 2 underflow */  #define	SC2CTR_CK_EXTERN	0x0002	/* - external closk */  #define	SC2CTR_CK_TM3UFLOW	0x0003	/* - timer 3 underflow */ +#else  /* CONFIG_AM33_2 */ +#define	SC2CTR_CK		0x0007	/* clock source select */ +#define	SC2CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow */ +#define	SC2CTR_CK_IOCLK_8	0x0001	/* - 1/8 IOCLK */ +#define	SC2CTR_CK_IOCLK_32	0x0002	/* - 1/32 IOCLK */ +#define	SC2CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow */ +#define	SC2CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 1 underflow */ +#define	SC2CTR_CK_TM3UFLOW_8	0x0005	/* - 1/8 timer 3 underflow */ +#define	SC2CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */ +#define	SC2CTR_CK_EXTERN	0x0007	/* - external closk */ +#endif /* CONFIG_AM33_2 */  #define	SC2CTR_STB		0x0008	/* stop bit select */  #define	SC2CTR_STB_1BIT		0x0000	/* - 1 stop bit */  #define	SC2CTR_STB_2BIT		0x0008	/* - 2 stop bits */ @@ -134,9 +153,14 @@  #define SC2ICR_RES		0x04	/* receive error select */  #define SC2ICR_RI		0x01	/* receive interrupt cause */ -#define	SC2TXB			__SYSREG(0xd4002018, u8)	/* transmit buffer reg */ -#define	SC2RXB			__SYSREG(0xd4002019, u8)	/* receive buffer reg */ -#define	SC2STR			__SYSREG(0xd400201c, u8)	/* status reg */ +#define	SC2TXB			__SYSREG(0xd4002028, u8)	/* transmit buffer reg */ +#define	SC2RXB			__SYSREG(0xd4002029, u8)	/* receive buffer reg */ + +#ifdef CONFIG_AM33_2 +#define	SC2STR			__SYSREG(0xd400202c, u8)	/* status reg */ +#else  /* CONFIG_AM33_2 */ +#define	SC2STR			__SYSREG(0xd400202c, u16)	/* status reg */ +#endif /* CONFIG_AM33_2 */  #define SC2STR_OEF		0x0001	/* overrun error found */  #define SC2STR_PEF		0x0002	/* parity error found */  #define SC2STR_FEF		0x0004	/* framing error found */ @@ -146,10 +170,17 @@  #define SC2STR_RXF		0x0040	/* receive status */  #define SC2STR_TXF		0x0080	/* transmit status */ +#ifdef CONFIG_AM33_2  #define	SC2TIM			__SYSREG(0xd400202d, u8)	/* status reg */ +#endif +#ifdef CONFIG_AM33_2  #define SC2RXIRQ		24	/* serial 2 Receive IRQ */  #define SC2TXIRQ		25	/* serial 2 Transmit IRQ */ +#else  /* CONFIG_AM33_2 */ +#define SC2RXIRQ		68	/* serial 2 Receive IRQ */ +#define SC2TXIRQ		69	/* serial 2 Transmit IRQ */ +#endif /* CONFIG_AM33_2 */  #define	SC2RXICR		GxICR(SC2RXIRQ)	/* serial 2 receive intr ctrl reg */  #define	SC2TXICR		GxICR(SC2TXIRQ)	/* serial 2 transmit intr ctrl reg */ diff --git a/arch/mn10300/include/asm/serial.h b/arch/mn10300/include/asm/serial.h index a29445cddd6..23a79929359 100644 --- a/arch/mn10300/include/asm/serial.h +++ b/arch/mn10300/include/asm/serial.h @@ -9,10 +9,8 @@   * 2 of the Licence, or (at your option) any later version.   */ -/* - * The ASB2305 has an 18.432 MHz clock the UART - */ -#define BASE_BAUD	(18432000 / 16) +#ifndef _ASM_SERIAL_H +#define _ASM_SERIAL_H  /* Standard COM flags (except for COM4, because of the 8514 problem) */  #ifdef CONFIG_SERIAL_DETECT_IRQ @@ -34,3 +32,5 @@  #endif  #include <unit/serial.h> + +#endif /* _ASM_SERIAL_H */ diff --git a/arch/mn10300/include/asm/smp.h b/arch/mn10300/include/asm/smp.h index 4eb8c61b7da..b8585b4e8cd 100644 --- a/arch/mn10300/include/asm/smp.h +++ b/arch/mn10300/include/asm/smp.h @@ -3,6 +3,16 @@   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.   * Written by David Howells (dhowells@redhat.com)   * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + *  13-Nov-2006 MEI Define IPI-IRQ number and add inline/macro function + *                  for SMP support. + *  22-Jan-2007 MEI Add the define related to SMP_BOOT_IRQ. + *  23-Feb-2007 MEI Add the define related to SMP icahce invalidate. + *  23-Jun-2008 MEI Delete INTC_IPI. + *  22-Jul-2008 MEI Add smp_nmi_call_function and related defines. + *  04-Aug-2008 MEI Delete USE_DOIRQ_CACHE_IPI. + *   * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public Licence   * as published by the Free Software Foundation; either version @@ -11,8 +21,98 @@  #ifndef _ASM_SMP_H  #define _ASM_SMP_H +#ifndef __ASSEMBLY__ +#include <linux/threads.h> +#include <linux/cpumask.h> +#endif +  #ifdef CONFIG_SMP -#error SMP not yet supported for MN10300 +#include <proc/smp-regs.h> + +#define RESCHEDULE_IPI		63 +#define CALL_FUNC_SINGLE_IPI	192 +#define LOCAL_TIMER_IPI		193 +#define FLUSH_CACHE_IPI		194 +#define CALL_FUNCTION_NMI_IPI	195 +#define GDB_NMI_IPI		196 + +#define SMP_BOOT_IRQ		195 + +#define RESCHEDULE_GxICR_LV	GxICR_LEVEL_6 +#define CALL_FUNCTION_GxICR_LV	GxICR_LEVEL_4 +#define LOCAL_TIMER_GxICR_LV	GxICR_LEVEL_4 +#define FLUSH_CACHE_GxICR_LV	GxICR_LEVEL_0 +#define SMP_BOOT_GxICR_LV	GxICR_LEVEL_0 + +#define TIME_OUT_COUNT_BOOT_IPI	100 +#define DELAY_TIME_BOOT_IPI	75000 + + +#ifndef __ASSEMBLY__ + +/** + * raw_smp_processor_id - Determine the raw CPU ID of the CPU running it + * + * What we really want to do is to use the CPUID hardware CPU register to get + * this information, but accesses to that aren't cached, and run at system bus + * speed, not CPU speed.  A copy of this value is, however, stored in the + * thread_info struct, and that can be cached. + * + * An alternate way of dealing with this could be to use the EPSW.S bits to + * cache this information for systems with up to four CPUs. + */ +#if 0 +#define raw_smp_processor_id()	(CPUID) +#else +#define raw_smp_processor_id()	(current_thread_info()->cpu)  #endif +static inline int cpu_logical_map(int cpu) +{ +	return cpu; +} + +static inline int cpu_number_map(int cpu) +{ +	return cpu; +} + + +extern cpumask_t cpu_boot_map; + +extern void smp_init_cpus(void); +extern void smp_cache_interrupt(void); +extern void send_IPI_allbutself(int irq); +extern int smp_nmi_call_function(smp_call_func_t func, void *info, int wait); + +extern void arch_send_call_function_single_ipi(int cpu); +extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); + +#ifdef CONFIG_HOTPLUG_CPU +extern int __cpu_disable(void); +extern void __cpu_die(unsigned int cpu); +#endif /* CONFIG_HOTPLUG_CPU */ + +#ifdef CONFIG_PREEMPT /* FIXME */ +#define __frame					\ +	({					\ +		struct pt_regs *f;		\ +		preempt_disable();		\ +		f = ___frame[CPUID];		\ +		preempt_enable();		\ +		f;				\ +	}) +#else +#define __frame ___frame[CPUID]  #endif + +#endif /* __ASSEMBLY__ */ +#else /* CONFIG_SMP */ +#ifndef __ASSEMBLY__ + +static inline void smp_init_cpus(void) {} + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_SMP */ + +#endif /* _ASM_SMP_H */ diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h index 4bf9c8b169e..93429154e89 100644 --- a/arch/mn10300/include/asm/spinlock.h +++ b/arch/mn10300/include/asm/spinlock.h @@ -11,6 +11,183 @@  #ifndef _ASM_SPINLOCK_H  #define _ASM_SPINLOCK_H -#error SMP spinlocks not implemented for MN10300 +#include <asm/atomic.h> +#include <asm/rwlock.h> +#include <asm/page.h> +/* + * Simple spin lock operations.  There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ + +#define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0) +#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock(arch_spinlock_t *lock) +{ +	asm volatile( +		"	bclr	1,(0,%0)	\n" +		: +		: "a"(&lock->slock) +		: "memory", "cc"); +} + +static inline int arch_spin_trylock(arch_spinlock_t *lock) +{ +	int ret; + +	asm volatile( +		"	mov	1,%0		\n" +		"	bset	%0,(%1)		\n" +		"	bne	1f		\n" +		"	clr	%0		\n" +		"1:	xor	1,%0		\n" +		: "=d"(ret) +		: "a"(&lock->slock) +		: "memory", "cc"); + +	return ret; +} + +static inline void arch_spin_lock(arch_spinlock_t *lock) +{ +	asm volatile( +		"1:	bset	1,(0,%0)	\n" +		"	bne	1b		\n" +		: +		: "a"(&lock->slock) +		: "memory", "cc"); +} + +static inline void arch_spin_lock_flags(arch_spinlock_t *lock, +					 unsigned long flags) +{ +	int temp; + +	asm volatile( +		"1:	bset	1,(0,%2)	\n" +		"	beq	3f		\n" +		"	mov	%1,epsw		\n" +		"2:	mov	(0,%2),%0	\n" +		"	or	%0,%0		\n" +		"	bne	2b		\n" +		"	mov	%3,%0		\n" +		"	mov	%0,epsw		\n" +		"	nop			\n" +		"	nop			\n" +		"	bra	1b\n" +		"3:				\n" +		: "=&d" (temp) +		: "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL) +		: "memory", "cc"); +} + +#ifdef __KERNEL__ + +/* + * Read-write spinlocks, allowing multiple readers + * but only one writer. + * + * NOTE! it is quite common to have readers in interrupts + * but no interrupt writers. For those circumstances we + * can "mix" irq-safe locks - any writer needs to get a + * irq-safe write-lock, but readers can get non-irqsafe + * read-locks. + */ + +/** + * read_can_lock - would read_trylock() succeed? + * @lock: the rwlock in question. + */ +#define arch_read_can_lock(x) ((int)(x)->lock > 0) + +/** + * write_can_lock - would write_trylock() succeed? + * @lock: the rwlock in question. + */ +#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) + +/* + * On mn10300, we implement read-write locks as a 32-bit counter + * with the high bit (sign) being the "contended" bit. + */ +static inline void arch_read_lock(arch_rwlock_t *rw) +{ +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT +	__build_read_lock(rw, "__read_lock_failed"); +#else +	{ +		atomic_t *count = (atomic_t *)rw; +		while (atomic_dec_return(count) < 0) +			atomic_inc(count); +	} +#endif +} + +static inline void arch_write_lock(arch_rwlock_t *rw) +{ +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT +	__build_write_lock(rw, "__write_lock_failed"); +#else +	{ +		atomic_t *count = (atomic_t *)rw; +		while (!atomic_sub_and_test(RW_LOCK_BIAS, count)) +			atomic_add(RW_LOCK_BIAS, count); +	} +#endif +} + +static inline void arch_read_unlock(arch_rwlock_t *rw) +{ +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT +	__build_read_unlock(rw); +#else +	{ +		atomic_t *count = (atomic_t *)rw; +		atomic_inc(count); +	} +#endif +} + +static inline void arch_write_unlock(arch_rwlock_t *rw) +{ +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT +	__build_write_unlock(rw); +#else +	{ +		atomic_t *count = (atomic_t *)rw; +		atomic_add(RW_LOCK_BIAS, count); +	} +#endif +} + +static inline int arch_read_trylock(arch_rwlock_t *lock) +{ +	atomic_t *count = (atomic_t *)lock; +	atomic_dec(count); +	if (atomic_read(count) >= 0) +		return 1; +	atomic_inc(count); +	return 0; +} + +static inline int arch_write_trylock(arch_rwlock_t *lock) +{ +	atomic_t *count = (atomic_t *)lock; +	if (atomic_sub_and_test(RW_LOCK_BIAS, count)) +		return 1; +	atomic_add(RW_LOCK_BIAS, count); +	return 0; +} + +#define arch_read_lock_flags(lock, flags)  arch_read_lock(lock) +#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) + +#define _raw_spin_relax(lock)	cpu_relax() +#define _raw_read_relax(lock)	cpu_relax() +#define _raw_write_relax(lock)	cpu_relax() + +#endif /* __KERNEL__ */  #endif /* _ASM_SPINLOCK_H */ diff --git a/arch/mn10300/include/asm/spinlock_types.h b/arch/mn10300/include/asm/spinlock_types.h new file mode 100644 index 00000000000..653dc519b40 --- /dev/null +++ b/arch/mn10300/include/asm/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef _ASM_SPINLOCK_TYPES_H +#define _ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct arch_spinlock { +	unsigned int slock; +} arch_spinlock_t; + +#define __ARCH_SPIN_LOCK_UNLOCKED	{ 0 } + +typedef struct { +	unsigned int lock; +} arch_rwlock_t; + +#define __ARCH_RW_LOCK_UNLOCKED		{ RW_LOCK_BIAS } + +#endif /* _ASM_SPINLOCK_TYPES_H */ diff --git a/arch/mn10300/include/asm/system.h b/arch/mn10300/include/asm/system.h index 7de90bc4cf8..8ff3e5aaca4 100644 --- a/arch/mn10300/include/asm/system.h +++ b/arch/mn10300/include/asm/system.h @@ -12,6 +12,7 @@  #define _ASM_SYSTEM_H  #include <asm/cpu-regs.h> +#include <asm/intctl-regs.h>  #ifdef __KERNEL__  #ifndef __ASSEMBLY__ @@ -57,8 +58,6 @@ do {									\  #define nop() asm volatile ("nop") -#endif /* !__ASSEMBLY__ */ -  /*   * Force strict CPU ordering.   * And yes, this is required on UP too when we're talking @@ -85,17 +84,19 @@ do {									\  #define smp_mb()	mb()  #define smp_rmb()	rmb()  #define smp_wmb()	wmb() -#else +#define set_mb(var, value)  do { xchg(&var, value); } while (0) +#else  /* CONFIG_SMP */  #define smp_mb()	barrier()  #define smp_rmb()	barrier()  #define smp_wmb()	barrier() -#endif -  #define set_mb(var, value)  do { var = value;  mb(); } while (0) +#endif /* CONFIG_SMP */ +  #define set_wmb(var, value) do { var = value; wmb(); } while (0)  #define read_barrier_depends()		do {} while (0)  #define smp_read_barrier_depends()	do {} while (0) +#endif /* !__ASSEMBLY__ */  #endif /* __KERNEL__ */  #endif /* _ASM_SYSTEM_H */ diff --git a/arch/mn10300/include/asm/timer-regs.h b/arch/mn10300/include/asm/timer-regs.h index 1d883b7f94a..c634977caf6 100644 --- a/arch/mn10300/include/asm/timer-regs.h +++ b/arch/mn10300/include/asm/timer-regs.h @@ -17,21 +17,27 @@  #ifdef __KERNEL__ -/* timer prescalar control */ +/* + * Timer prescalar control + */  #define	TMPSCNT			__SYSREG(0xd4003071, u8) /* timer prescaler control */  #define	TMPSCNT_ENABLE		0x80	/* timer prescaler enable */  #define	TMPSCNT_DISABLE		0x00	/* timer prescaler disable */ -/* 8 bit timers */ +/* + * 8-bit timers + */  #define	TM0MD			__SYSREG(0xd4003000, u8) /* timer 0 mode register */  #define	TM0MD_SRC		0x07	/* timer source */  #define	TM0MD_SRC_IOCLK		0x00	/* - IOCLK */  #define	TM0MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */  #define	TM0MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ -#define	TM0MD_SRC_TM2IO		0x03	/* - TM2IO pin input */  #define	TM0MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM0MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if	defined(CONFIG_AM33_2) +#define	TM0MD_SRC_TM2IO		0x03	/* - TM2IO pin input */  #define	TM0MD_SRC_TM0IO		0x07	/* - TM0IO pin input */ +#endif /* CONFIG_AM33_2 */  #define	TM0MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM0MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -43,7 +49,9 @@  #define	TM1MD_SRC_TM0CASCADE	0x03	/* - cascade with timer 0 */  #define	TM1MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM1MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM1MD_SRC_TM1IO		0x07	/* - TM1IO pin input */ +#endif	/* CONFIG_AM33_2 */  #define	TM1MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM1MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -55,7 +63,9 @@  #define	TM2MD_SRC_TM1CASCADE	0x03	/* - cascade with timer 1 */  #define	TM2MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM2MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM2MD_SRC_TM2IO		0x07	/* - TM2IO pin input */ +#endif	/* CONFIG_AM33_2 */  #define	TM2MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM2MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -64,11 +74,13 @@  #define	TM3MD_SRC_IOCLK		0x00	/* - IOCLK */  #define	TM3MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */  #define	TM3MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ -#define	TM3MD_SRC_TM1CASCADE	0x03	/* - cascade with timer 2 */ +#define	TM3MD_SRC_TM2CASCADE	0x03	/* - cascade with timer 2 */  #define	TM3MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM3MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM3MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM3MD_SRC_TM3IO		0x07	/* - TM3IO pin input */ +#endif	/* CONFIG_AM33_2 */  #define	TM3MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM3MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -96,7 +108,9 @@  #define	TM2ICR			GxICR(TM2IRQ)	/* timer 2 uflow intr ctrl reg */  #define	TM3ICR			GxICR(TM3IRQ)	/* timer 3 uflow intr ctrl reg */ -/* 16-bit timers 4,5 & 7-11 */ +/* + * 16-bit timers 4,5 & 7-15 + */  #define	TM4MD			__SYSREG(0xd4003080, u8)   /* timer 4 mode register */  #define	TM4MD_SRC		0x07	/* timer source */  #define	TM4MD_SRC_IOCLK		0x00	/* - IOCLK */ @@ -105,7 +119,9 @@  #define	TM4MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM4MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM4MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM4MD_SRC_TM4IO		0x07	/* - TM4IO pin input */ +#endif	/* CONFIG_AM33_2 */  #define	TM4MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM4MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -118,7 +134,11 @@  #define	TM5MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM5MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM5MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM5MD_SRC_TM5IO		0x07	/* - TM5IO pin input */ +#else	/* !CONFIG_AM33_2 */ +#define	TM5MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#endif	/* CONFIG_AM33_2 */  #define	TM5MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM5MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -130,7 +150,9 @@  #define	TM7MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM7MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM7MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM7MD_SRC_TM7IO		0x07	/* - TM7IO pin input */ +#endif	/* CONFIG_AM33_2 */  #define	TM7MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM7MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -143,7 +165,11 @@  #define	TM8MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM8MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM8MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM8MD_SRC_TM8IO		0x07	/* - TM8IO pin input */ +#else	/* !CONFIG_AM33_2 */ +#define	TM8MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#endif	/* CONFIG_AM33_2 */  #define	TM8MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM8MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -156,7 +182,11 @@  #define	TM9MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM9MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM9MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM9MD_SRC_TM9IO		0x07	/* - TM9IO pin input */ +#else	/* !CONFIG_AM33_2 */ +#define	TM9MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#endif	/* CONFIG_AM33_2 */  #define	TM9MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM9MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -169,7 +199,11 @@  #define	TM10MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM10MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM10MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM10MD_SRC_TM10IO	0x07	/* - TM10IO pin input */ +#else	/* !CONFIG_AM33_2 */ +#define	TM10MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#endif	/* CONFIG_AM33_2 */  #define	TM10MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM10MD_COUNT_ENABLE	0x80	/* timer count enable */ @@ -178,32 +212,101 @@  #define	TM11MD_SRC_IOCLK	0x00	/* - IOCLK */  #define	TM11MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */  #define	TM11MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ -#define	TM11MD_SRC_TM7CASCADE	0x03	/* - cascade with timer 7 */  #define	TM11MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */  #define	TM11MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */  #define	TM11MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2)  #define	TM11MD_SRC_TM11IO	0x07	/* - TM11IO pin input */ +#else	/* !CONFIG_AM33_2 */ +#define	TM11MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#endif	/* CONFIG_AM33_2 */  #define	TM11MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */  #define	TM11MD_COUNT_ENABLE	0x80	/* timer count enable */ +#if defined(CONFIG_AM34_2) +#define	TM12MD			__SYSREG(0xd4003180, u8)   /* timer 11 mode register */ +#define	TM12MD_SRC		0x07	/* timer source */ +#define	TM12MD_SRC_IOCLK	0x00	/* - IOCLK */ +#define	TM12MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */ +#define	TM12MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ +#define	TM12MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */ +#define	TM12MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */ +#define	TM12MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#define	TM12MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#define	TM12MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */ +#define	TM12MD_COUNT_ENABLE	0x80	/* timer count enable */ + +#define	TM13MD			__SYSREG(0xd4003182, u8)   /* timer 11 mode register */ +#define	TM13MD_SRC		0x07	/* timer source */ +#define	TM13MD_SRC_IOCLK	0x00	/* - IOCLK */ +#define	TM13MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */ +#define	TM13MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ +#define	TM13MD_SRC_TM12CASCADE	0x03	/* - cascade with timer 12 */ +#define	TM13MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */ +#define	TM13MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */ +#define	TM13MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#define	TM13MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#define	TM13MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */ +#define	TM13MD_COUNT_ENABLE	0x80	/* timer count enable */ + +#define	TM14MD			__SYSREG(0xd4003184, u8)   /* timer 11 mode register */ +#define	TM14MD_SRC		0x07	/* timer source */ +#define	TM14MD_SRC_IOCLK	0x00	/* - IOCLK */ +#define	TM14MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */ +#define	TM14MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ +#define	TM14MD_SRC_TM13CASCADE	0x03	/* - cascade with timer 13 */ +#define	TM14MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */ +#define	TM14MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */ +#define	TM14MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#define	TM14MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#define	TM14MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */ +#define	TM14MD_COUNT_ENABLE	0x80	/* timer count enable */ + +#define	TM15MD			__SYSREG(0xd4003186, u8)   /* timer 11 mode register */ +#define	TM15MD_SRC		0x07	/* timer source */ +#define	TM15MD_SRC_IOCLK	0x00	/* - IOCLK */ +#define	TM15MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */ +#define	TM15MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */ +#define	TM15MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */ +#define	TM15MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */ +#define	TM15MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */ +#define	TM15MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */ +#define	TM15MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */ +#define	TM15MD_COUNT_ENABLE	0x80	/* timer count enable */ +#endif	/* CONFIG_AM34_2 */ + +  #define	TM4BR			__SYSREG(0xd4003090, u16)  /* timer 4 base register */  #define	TM5BR			__SYSREG(0xd4003092, u16)  /* timer 5 base register */ +#define	TM45BR			__SYSREG(0xd4003090, u32)  /* timer 4:5 base register */  #define	TM7BR			__SYSREG(0xd4003096, u16)  /* timer 7 base register */  #define	TM8BR			__SYSREG(0xd4003098, u16)  /* timer 8 base register */  #define	TM9BR			__SYSREG(0xd400309a, u16)  /* timer 9 base register */ +#define	TM89BR			__SYSREG(0xd4003098, u32)  /* timer 8:9 base register */  #define	TM10BR			__SYSREG(0xd400309c, u16)  /* timer 10 base register */  #define	TM11BR			__SYSREG(0xd400309e, u16)  /* timer 11 base register */ -#define	TM45BR			__SYSREG(0xd4003090, u32)  /* timer 4:5 base register */ +#if defined(CONFIG_AM34_2) +#define	TM12BR			__SYSREG(0xd4003190, u16)  /* timer 12 base register */ +#define	TM13BR			__SYSREG(0xd4003192, u16)  /* timer 13 base register */ +#define	TM14BR			__SYSREG(0xd4003194, u16)  /* timer 14 base register */ +#define	TM15BR			__SYSREG(0xd4003196, u16)  /* timer 15 base register */ +#endif	/* CONFIG_AM34_2 */  #define	TM4BC			__SYSREG(0xd40030a0, u16)  /* timer 4 binary counter */  #define	TM5BC			__SYSREG(0xd40030a2, u16)  /* timer 5 binary counter */  #define	TM45BC			__SYSREG(0xd40030a0, u32)  /* timer 4:5 binary counter */ -  #define	TM7BC			__SYSREG(0xd40030a6, u16)  /* timer 7 binary counter */  #define	TM8BC			__SYSREG(0xd40030a8, u16)  /* timer 8 binary counter */  #define	TM9BC			__SYSREG(0xd40030aa, u16)  /* timer 9 binary counter */ +#define	TM89BC			__SYSREG(0xd40030a8, u32)  /* timer 8:9 binary counter */  #define	TM10BC			__SYSREG(0xd40030ac, u16)  /* timer 10 binary counter */  #define	TM11BC			__SYSREG(0xd40030ae, u16)  /* timer 11 binary counter */ +#if defined(CONFIG_AM34_2) +#define	TM12BC			__SYSREG(0xd40031a0, u16)  /* timer 12 binary counter */ +#define	TM13BC			__SYSREG(0xd40031a2, u16)  /* timer 13 binary counter */ +#define	TM14BC			__SYSREG(0xd40031a4, u16)  /* timer 14 binary counter */ +#define	TM15BC			__SYSREG(0xd40031a6, u16)  /* timer 15 binary counter */ +#endif	/* CONFIG_AM34_2 */  #define TM4IRQ			6	/* timer 4 IRQ */  #define TM5IRQ			7	/* timer 5 IRQ */ @@ -212,6 +315,12 @@  #define TM9IRQ			13	/* timer 9 IRQ */  #define TM10IRQ			14	/* timer 10 IRQ */  #define TM11IRQ			15	/* timer 11 IRQ */ +#if defined(CONFIG_AM34_2) +#define TM12IRQ			64	/* timer 12 IRQ */ +#define TM13IRQ			65	/* timer 13 IRQ */ +#define TM14IRQ			66	/* timer 14 IRQ */ +#define TM15IRQ			67	/* timer 15 IRQ */ +#endif	/* CONFIG_AM34_2 */  #define	TM4ICR			GxICR(TM4IRQ)	/* timer 4 uflow intr ctrl reg */  #define	TM5ICR			GxICR(TM5IRQ)	/* timer 5 uflow intr ctrl reg */ @@ -220,8 +329,16 @@  #define	TM9ICR			GxICR(TM9IRQ)	/* timer 9 uflow intr ctrl reg */  #define	TM10ICR			GxICR(TM10IRQ)	/* timer 10 uflow intr ctrl reg */  #define	TM11ICR			GxICR(TM11IRQ)	/* timer 11 uflow intr ctrl reg */ +#if defined(CONFIG_AM34_2) +#define	TM12ICR			GxICR(TM12IRQ)	/* timer 12 uflow intr ctrl reg */ +#define	TM13ICR			GxICR(TM13IRQ)	/* timer 13 uflow intr ctrl reg */ +#define	TM14ICR			GxICR(TM14IRQ)	/* timer 14 uflow intr ctrl reg */ +#define	TM15ICR			GxICR(TM15IRQ)	/* timer 15 uflow intr ctrl reg */ +#endif	/* CONFIG_AM34_2 */ -/* 16-bit timer 6 */ +/* + * 16-bit timer 6 + */  #define	TM6MD			__SYSREG(0xd4003084, u16)  /* timer6 mode register */  #define	TM6MD_SRC		0x0007	/* timer source */  #define	TM6MD_SRC_IOCLK		0x0000	/* - IOCLK */ @@ -229,10 +346,14 @@  #define	TM6MD_SRC_IOCLK_32	0x0002	/* - 1/32 IOCLK */  #define	TM6MD_SRC_TM0UFLOW	0x0004	/* - timer 0 underflow */  #define	TM6MD_SRC_TM1UFLOW	0x0005	/* - timer 1 underflow */ -#define	TM6MD_SRC_TM6IOB_BOTH	0x0006	/* - TM6IOB pin input (both edges) */ +#define	TM6MD_SRC_TM2UFLOW	0x0006	/* - timer 2 underflow */ +#if defined(CONFIG_AM33_2) +/* #define	TM6MD_SRC_TM6IOB_BOTH	0x0006 */	/* - TM6IOB pin input (both edges) */  #define	TM6MD_SRC_TM6IOB_SINGLE	0x0007	/* - TM6IOB pin input (single edge) */ -#define	TM6MD_CLR_ENABLE	0x0010	/* clear count enable */ +#endif	/* CONFIG_AM33_2 */  #define	TM6MD_ONESHOT_ENABLE	0x0040	/* oneshot count */ +#define	TM6MD_CLR_ENABLE	0x0010	/* clear count enable */ +#if	defined(CONFIG_AM33_2)  #define	TM6MD_TRIG_ENABLE	0x0080	/* TM6IOB pin trigger enable */  #define TM6MD_PWM		0x3800	/* PWM output mode */  #define TM6MD_PWM_DIS		0x0000	/* - disabled */ @@ -240,10 +361,15 @@  #define	TM6MD_PWM_11BIT		0x1800	/* - 11 bits mode */  #define	TM6MD_PWM_12BIT		0x3000	/* - 12 bits mode */  #define	TM6MD_PWM_14BIT		0x3800	/* - 14 bits mode */ +#endif	/* CONFIG_AM33_2 */ +  #define	TM6MD_INIT_COUNTER	0x4000	/* initialize TMnBC to zero */  #define	TM6MD_COUNT_ENABLE	0x8000	/* timer count enable */  #define	TM6MDA			__SYSREG(0xd40030b4, u8)   /* timer6 cmp/cap A mode reg */ +#define	TM6MDA_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */ +#define	TM6MDA_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */ +#if	defined(CONFIG_AM33_2)  #define TM6MDA_OUT		0x07	/* output select */  #define	TM6MDA_OUT_SETA_RESETB	0x00	/* - set at match A, reset at match B */  #define	TM6MDA_OUT_SETA_RESETOV	0x01	/* - set at match A, reset at overflow */ @@ -251,30 +377,35 @@  #define	TM6MDA_OUT_RESETA	0x03	/* - reset at match A */  #define	TM6MDA_OUT_TOGGLE	0x04	/* - toggle on match A */  #define TM6MDA_MODE		0xc0	/* compare A register mode */ -#define	TM6MDA_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */ -#define	TM6MDA_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */  #define	TM6MDA_MODE_CAP_S_EDGE	0x80	/* - capture, single edge mode */  #define	TM6MDA_MODE_CAP_D_EDGE	0xc0	/* - capture, double edge mode */  #define TM6MDA_EDGE		0x20	/* compare A edge select */  #define	TM6MDA_EDGE_FALLING	0x00	/* capture on falling edge */  #define	TM6MDA_EDGE_RISING	0x20	/* capture on rising edge */  #define	TM6MDA_CAPTURE_ENABLE	0x10	/* capture enable */ +#else	/* !CONFIG_AM33_2 */ +#define	TM6MDA_MODE		0x40	/* compare A register mode */ +#endif	/* CONFIG_AM33_2 */  #define	TM6MDB			__SYSREG(0xd40030b5, u8)   /* timer6 cmp/cap B mode reg */ +#define	TM6MDB_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */ +#define	TM6MDB_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */ +#if defined(CONFIG_AM33_2)  #define TM6MDB_OUT		0x07	/* output select */  #define	TM6MDB_OUT_SETB_RESETA	0x00	/* - set at match B, reset at match A */  #define	TM6MDB_OUT_SETB_RESETOV	0x01	/* - set at match B */  #define	TM6MDB_OUT_RESETB	0x03	/* - reset at match B */  #define	TM6MDB_OUT_TOGGLE	0x04	/* - toggle on match B */  #define TM6MDB_MODE		0xc0	/* compare B register mode */ -#define	TM6MDB_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */ -#define	TM6MDB_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */  #define	TM6MDB_MODE_CAP_S_EDGE	0x80	/* - capture, single edge mode */  #define	TM6MDB_MODE_CAP_D_EDGE	0xc0	/* - capture, double edge mode */  #define TM6MDB_EDGE		0x20	/* compare B edge select */  #define	TM6MDB_EDGE_FALLING	0x00	/* capture on falling edge */  #define	TM6MDB_EDGE_RISING	0x20	/* capture on rising edge */  #define	TM6MDB_CAPTURE_ENABLE	0x10	/* capture enable */ +#else	/* !CONFIG_AM33_2 */ +#define	TM6MDB_MODE		0x40	/* compare B register mode */ +#endif	/* CONFIG_AM33_2 */  #define	TM6CA			__SYSREG(0xd40030c4, u16)   /* timer6 cmp/capture reg A */  #define	TM6CB			__SYSREG(0xd40030d4, u16)   /* timer6 cmp/capture reg B */ @@ -288,6 +419,34 @@  #define	TM6AICR			GxICR(TM6AIRQ)	/* timer 6A intr control reg */  #define	TM6BICR			GxICR(TM6BIRQ)	/* timer 6B intr control reg */ +#if defined(CONFIG_AM34_2) +/* + * MTM: OS Tick-Timer + */ +#define	TMTMD			__SYSREG(0xd4004100, u8)	/* Tick Timer mode register */ +#define	TMTMD_TMTLDE		0x40	/* initialize TMTBC = TMTBR */ +#define	TMTMD_TMTCNE		0x80	/* timer count enable       */ + +#define	TMTBR			__SYSREG(0xd4004110, u32)	/* Tick Timer mode reg */ +#define	TMTBC			__SYSREG(0xd4004120, u32)	/* Tick Timer mode reg */ + +/* + * MTM: OS Timestamp-Timer + */ +#define	TMSMD			__SYSREG(0xd4004140, u8)	/* Tick Timer mode register */ +#define	TMSMD_TMSLDE		0x40		/* initialize TMSBC = TMSBR */ +#define	TMSMD_TMSCNE		0x80		/* timer count enable       */ + +#define	TMSBR			__SYSREG(0xd4004150, u32)	/* Tick Timer mode register */ +#define	TMSBC			__SYSREG(0xd4004160, u32)	/* Tick Timer mode register */ + +#define TMTIRQ			119		/* OS Tick timer   IRQ */ +#define TMSIRQ			120		/* Timestamp timer IRQ */ + +#define	TMTICR			GxICR(TMTIRQ)	/* OS Tick timer   uflow intr ctrl reg */ +#define	TMSICR			GxICR(TMSIRQ)	/* Timestamp timer uflow intr ctrl reg */ +#endif	/* CONFIG_AM34_2 */ +  #endif /* __KERNEL__ */  #endif /* _ASM_TIMER_REGS_H */ diff --git a/arch/mn10300/include/asm/timex.h b/arch/mn10300/include/asm/timex.h index 8d031f9e117..ce5719a2ce7 100644 --- a/arch/mn10300/include/asm/timex.h +++ b/arch/mn10300/include/asm/timex.h @@ -16,8 +16,7 @@  #define TICK_SIZE (tick_nsec / 1000) -#define CLOCK_TICK_RATE 1193180 /* Underlying HZ - this should probably be set -				 * to something appropriate, but what? */ +#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */  extern cycles_t cacheflush_time; diff --git a/arch/mn10300/include/asm/uaccess.h b/arch/mn10300/include/asm/uaccess.h index 197a7af3dd8..47e7951e689 100644 --- a/arch/mn10300/include/asm/uaccess.h +++ b/arch/mn10300/include/asm/uaccess.h @@ -377,7 +377,7 @@ unsigned long __generic_copy_to_user_nocheck(void *to, const void *from,  #if 0 -#error don't use - these macros don't increment to & from pointers +#error "don't use - these macros don't increment to & from pointers"  /* Optimize just a little bit when we know the size of the move. */  #define __constant_copy_user(to, from, size)	\  do {						\ diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile index 99022351717..5b41192f496 100644 --- a/arch/mn10300/kernel/Makefile +++ b/arch/mn10300/kernel/Makefile @@ -10,8 +10,9 @@ obj-y   := process.o signal.o entry.o traps.o irq.o \  	   ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \  	   switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) -obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o +obj-$(CONFIG_SMP) += smp.o smp-low.o +obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o  obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \  			       mn10300-debug.o diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c index 78e290e342f..54cc5b6b13f 100644 --- a/arch/mn10300/kernel/asm-offsets.c +++ b/arch/mn10300/kernel/asm-offsets.c @@ -66,7 +66,7 @@ void foo(void)  	OFFSET(THREAD_SP,		thread_struct, sp);  	OFFSET(THREAD_A3,		thread_struct, a3);  	OFFSET(THREAD_USP,		thread_struct, usp); -	OFFSET(THREAD_FRAME,		thread_struct, __frame); +	OFFSET(THREAD_FRAME,		thread_struct, frame);  #ifdef CONFIG_FPU  	OFFSET(THREAD_FPU_FLAGS,	thread_struct, fpu_flags);  	OFFSET(THREAD_FPU_STATE,	thread_struct, fpu_state); diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S index 355f6817677..f00b9bafcd3 100644 --- a/arch/mn10300/kernel/entry.S +++ b/arch/mn10300/kernel/entry.S @@ -28,25 +28,17 @@  #include <asm/asm-offsets.h>  #include <asm/frame.inc> +#if defined(CONFIG_SMP) && defined(CONFIG_GDBSTUB) +#include <asm/gdb-stub.h> +#endif /* CONFIG_SMP && CONFIG_GDBSTUB */ +  #ifdef CONFIG_PREEMPT -#define preempt_stop		__cli +#define preempt_stop		LOCAL_IRQ_DISABLE  #else  #define preempt_stop  #define resume_kernel		restore_all  #endif -	.macro __cli -	and	~EPSW_IM,epsw -	or	EPSW_IE|MN10300_CLI_LEVEL,epsw -	nop -	nop -	nop -	.endm -	.macro __sti -	or	EPSW_IE|EPSW_IM_7,epsw -	.endm - -  	.am33_2  ############################################################################### @@ -88,7 +80,7 @@ syscall_call:  syscall_exit:  	# make sure we don't miss an interrupt setting need_resched or  	# sigpending between sampling and the rti -	__cli +	LOCAL_IRQ_DISABLE  	mov	(TI_flags,a2),d2  	btst	_TIF_ALLWORK_MASK,d2  	bne	syscall_exit_work @@ -105,7 +97,7 @@ restore_all:  syscall_exit_work:  	btst	_TIF_SYSCALL_TRACE,d2  	beq	work_pending -	__sti				# could let syscall_trace_exit() call +	LOCAL_IRQ_ENABLE		# could let syscall_trace_exit() call  					# schedule() instead  	mov	fp,d0  	call	syscall_trace_exit[],0	# do_syscall_trace(regs) @@ -121,7 +113,7 @@ work_resched:  	# make sure we don't miss an interrupt setting need_resched or  	# sigpending between sampling and the rti -	__cli +	LOCAL_IRQ_DISABLE  	# is there any work to be done other than syscall tracing?  	mov	(TI_flags,a2),d2 @@ -168,7 +160,7 @@ ret_from_intr:  ENTRY(resume_userspace)  	# make sure we don't miss an interrupt setting need_resched or  	# sigpending between sampling and the rti -	__cli +	LOCAL_IRQ_DISABLE  	# is there any work to be done on int/exception return?  	mov	(TI_flags,a2),d2 @@ -178,7 +170,7 @@ ENTRY(resume_userspace)  #ifdef CONFIG_PREEMPT  ENTRY(resume_kernel) -	__cli +	LOCAL_IRQ_DISABLE  	mov	(TI_preempt_count,a2),d0	# non-zero preempt_count ?  	cmp	0,d0  	bne	restore_all @@ -281,6 +273,79 @@ ENTRY(nmi_handler)  	add	-4,sp  	mov	d0,(sp)  	mov	(TBR),d0 + +#ifdef CONFIG_SMP +	add	-4,sp +	mov	d0,(sp)			# save d0(TBR) +	movhu	(NMIAGR),d0 +	and	NMIAGR_GN,d0 +	lsr	0x2,d0 +	cmp	CALL_FUNCTION_NMI_IPI,d0 +	bne	5f			# if not call function, jump + +	# function call nmi ipi +	add	4,sp			# no need to store TBR +	mov	GxICR_DETECT,d0		# clear NMI request +	movbu	d0,(GxICR(CALL_FUNCTION_NMI_IPI)) +	movhu	(GxICR(CALL_FUNCTION_NMI_IPI)),d0 +	and	~EPSW_NMID,epsw		# enable NMI + +	mov	(sp),d0			# restore d0 +	SAVE_ALL +	call	smp_nmi_call_function_interrupt[],0 +	RESTORE_ALL + +5: +#ifdef CONFIG_GDBSTUB +	cmp	GDB_NMI_IPI,d0 +	bne	3f			# if not gdb nmi ipi, jump + +	# gdb nmi ipi +	add	4,sp			# no need to store TBR +	mov	GxICR_DETECT,d0		# clear NMI +	movbu	d0,(GxICR(GDB_NMI_IPI)) +	movhu	(GxICR(GDB_NMI_IPI)),d0 +	and	~EPSW_NMID,epsw		# enable NMI +#ifdef CONFIG_MN10300_CACHE_ENABLED +	mov	(gdbstub_nmi_opr_type),d0 +	cmp	GDBSTUB_NMI_CACHE_PURGE,d0 +	bne	4f			# if not gdb cache purge, jump + +	# gdb cache purge nmi ipi +	add	-20,sp +	mov	d1,(4,sp) +	mov	a0,(8,sp) +	mov	a1,(12,sp) +	mov	mdr,d0 +	mov	d0,(16,sp) +	call	gdbstub_local_purge_cache[],0 +	mov	0x1,d0 +	mov	(CPUID),d1 +	asl	d1,d0 +	mov	gdbstub_nmi_cpumask,a0 +	bclr	d0,(a0) +	mov	(4,sp),d1 +	mov	(8,sp),a0 +	mov	(12,sp),a1 +	mov	(16,sp),d0 +	mov	d0,mdr +	add	20,sp +	mov	(sp),d0 +	add	4,sp +	rti +4: +#endif /* CONFIG_MN10300_CACHE_ENABLED */ +	# gdb wait nmi ipi +	mov     (sp),d0 +	SAVE_ALL +	call    gdbstub_nmi_wait[],0 +	RESTORE_ALL +3: +#endif /* CONFIG_GDBSTUB */ +	mov     (sp),d0                 # restore TBR to d0 +	add     4,sp +#endif /* CONFIG_SMP */ +  	bra	__common_exception_nonmi  ENTRY(__common_exception) @@ -314,15 +379,21 @@ __common_exception_nonmi:  	mov	d0,(REG_ORIG_D0,fp)  #ifdef CONFIG_GDBSTUB +#ifdef CONFIG_SMP +	call	gdbstub_busy_check[],0 +	and	d0,d0			# check return value +	beq	2f +#else  /* CONFIG_SMP */  	btst	0x01,(gdbstub_busy)  	beq	2f +#endif /* CONFIG_SMP */  	and	~EPSW_IE,epsw  	mov	fp,d0  	mov	a2,d1  	call	gdbstub_exception[],0	# gdbstub itself caused an exception  	bra	restore_all  2: -#endif +#endif /* CONFIG_GDBSTUB */  	mov	fp,d0			# arg 0: stacked register file  	mov	a2,d1			# arg 1: exception number @@ -357,11 +428,7 @@ ENTRY(set_excp_vector)  	add	exception_table,d0  	mov	d1,(d0)  	mov	4,d1 -#if defined(CONFIG_MN10300_CACHE_WBACK) -	jmp	mn10300_dcache_flush_inv_range2 -#else  	ret	[],0 -#endif  ###############################################################################  # diff --git a/arch/mn10300/kernel/gdb-io-serial-low.S b/arch/mn10300/kernel/gdb-io-serial-low.S index 4998b24f5d3..b1d0152e96c 100644 --- a/arch/mn10300/kernel/gdb-io-serial-low.S +++ b/arch/mn10300/kernel/gdb-io-serial-low.S @@ -18,6 +18,7 @@  #include <asm/thread_info.h>  #include <asm/frame.inc>  #include <asm/intctl-regs.h> +#include <asm/irqflags.h>  #include <unit/serial.h>  	.text @@ -69,7 +70,7 @@ gdbstub_io_rx_overflow:  	bra	gdbstub_io_rx_done  gdbstub_io_rx_enter: -	or	EPSW_IE|EPSW_IM_1,epsw +	LOCAL_CHANGE_INTR_MASK_LEVEL(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL+1))  	add	-4,sp  	SAVE_ALL @@ -80,7 +81,7 @@ gdbstub_io_rx_enter:  	mov	fp,d0  	call	gdbstub_rx_irq[],0	# gdbstub_rx_irq(regs,excep) -	and	~EPSW_IE,epsw +	LOCAL_CLI  	bclr	0x01,(gdbstub_busy)  	.globl gdbstub_return diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c index ae663dc717e..0d5d63c91dc 100644 --- a/arch/mn10300/kernel/gdb-io-serial.c +++ b/arch/mn10300/kernel/gdb-io-serial.c @@ -23,6 +23,7 @@  #include <asm/exceptions.h>  #include <asm/serial-regs.h>  #include <unit/serial.h> +#include <asm/smp.h>  /*   * initialise the GDB stub @@ -45,22 +46,34 @@ void gdbstub_io_init(void)  	XIRQxICR(GDBPORT_SERIAL_IRQ) = 0;  	tmp = XIRQxICR(GDBPORT_SERIAL_IRQ); +#if   CONFIG_GDBSTUB_IRQ_LEVEL == 0  	IVAR0 = EXCEP_IRQ_LEVEL0; -	set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler); +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 1 +	IVAR1 = EXCEP_IRQ_LEVEL1; +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 2 +	IVAR2 = EXCEP_IRQ_LEVEL2; +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 3 +	IVAR3 = EXCEP_IRQ_LEVEL3; +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 4 +	IVAR4 = EXCEP_IRQ_LEVEL4; +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 5 +	IVAR5 = EXCEP_IRQ_LEVEL5; +#else +#error "Unknown irq level for gdbstub." +#endif + +	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), +		gdbstub_io_rx_handler);  	XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST; -	XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0; +	XIRQxICR(GDBPORT_SERIAL_IRQ) = +		GxICR_ENABLE | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL);  	tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);  	GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;  	/* permit level 0 IRQs to take place */ -	asm volatile( -		"	and %0,epsw	\n" -		"	or %1,epsw	\n" -		: -		: "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1) -		); +	local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));  }  /* @@ -87,6 +100,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)  {  	unsigned ix;  	u8 ch, st; +#if defined(CONFIG_MN10300_WD_TIMER) +	int cpu; +#endif  	*_ch = 0xff; @@ -104,8 +120,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)  		if (nonblock)  			return -EAGAIN;  #ifdef CONFIG_MN10300_WD_TIMER -		watchdog_alert_counter = 0; -#endif /* CONFIG_MN10300_WD_TIMER */ +	for (cpu = 0; cpu < NR_CPUS; cpu++) +		watchdog_alert_counter[cpu] = 0; +#endif  		goto try_again;  	} diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c index a560bbc3137..97dfda23342 100644 --- a/arch/mn10300/kernel/gdb-io-ttysm.c +++ b/arch/mn10300/kernel/gdb-io-ttysm.c @@ -58,9 +58,12 @@ void __init gdbstub_io_init(void)  	gdbstub_io_set_baud(115200);  	/* we want to get serial receive interrupts */ -	set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0); -	set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0); -	set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler); +	set_intr_level(gdbstub_port->rx_irq, +		NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); +	set_intr_level(gdbstub_port->tx_irq, +		NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); +	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), +		gdbstub_io_rx_handler);  	*gdbstub_port->rx_icr |= GxICR_ENABLE;  	tmp = *gdbstub_port->rx_icr; @@ -84,12 +87,7 @@ void __init gdbstub_io_init(void)  	tmp = *gdbstub_port->_control;  	/* permit level 0 IRQs only */ -	asm volatile( -		"	and %0,epsw	\n" -		"	or %1,epsw	\n" -		: -		: "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1) -		); +	local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));  }  /* @@ -184,6 +182,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)  {  	unsigned ix;  	u8 ch, st; +#if defined(CONFIG_MN10300_WD_TIMER) +	int cpu; +#endif  	*_ch = 0xff; @@ -201,8 +202,9 @@ try_again:  		if (nonblock)  			return -EAGAIN;  #ifdef CONFIG_MN10300_WD_TIMER -		watchdog_alert_counter = 0; -#endif /* CONFIG_MN10300_WD_TIMER */ +	for (cpu = 0; cpu < NR_CPUS; cpu++) +		watchdog_alert_counter[cpu] = 0; +#endif  		goto try_again;  	} diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c index 41b11706c8e..a5fc3f05309 100644 --- a/arch/mn10300/kernel/gdb-stub.c +++ b/arch/mn10300/kernel/gdb-stub.c @@ -440,15 +440,11 @@ static const unsigned char gdbstub_insn_sizes[256] =  static int __gdbstub_mark_bp(u8 *addr, int ix)  { -	if (addr < (u8 *) 0x70000000UL) -		return 0; -	/* 70000000-7fffffff: vmalloc area */ -	if (addr < (u8 *) 0x80000000UL) +	/* vmalloc area */ +	if (((u8 *) VMALLOC_START <= addr) && (addr < (u8 *) VMALLOC_END))  		goto okay; -	if (addr < (u8 *) 0x8c000000UL) -		return 0; -	/* 8c000000-93ffffff: SRAM, SDRAM */ -	if (addr < (u8 *) 0x94000000UL) +	/* SRAM, SDRAM */ +	if (((u8 *) 0x80000000UL <= addr) && (addr < (u8 *) 0xa0000000UL))  		goto okay;  	return 0; @@ -1197,9 +1193,8 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)  	mn10300_set_gdbleds(1);  	asm volatile("mov mdr,%0" : "=d"(mdr)); -	asm volatile("mov epsw,%0" : "=d"(epsw)); -	asm volatile("mov %0,epsw" -		     :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1)); +	local_save_flags(epsw); +	local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));  	gdbstub_store_fpu(); diff --git a/arch/mn10300/kernel/head.S b/arch/mn10300/kernel/head.S index a81e34fba65..73e00fc7807 100644 --- a/arch/mn10300/kernel/head.S +++ b/arch/mn10300/kernel/head.S @@ -19,6 +19,12 @@  #include <asm/frame.inc>  #include <asm/param.h>  #include <unit/serial.h> +#ifdef CONFIG_SMP +#include <asm/smp.h> +#include <asm/intctl-regs.h> +#include <asm/cpu-regs.h> +#include <proc/smp-regs.h> +#endif /* CONFIG_SMP */  	__HEAD @@ -30,17 +36,51 @@  	.globl	_start  	.type	_start,@function  _start: +#ifdef CONFIG_SMP +	# +	# If this is a secondary CPU (AP), then deal with that elsewhere +	# +	mov	(CPUID),d3 +	and	CPUID_MASK,d3 +	bne	startup_secondary + +	# +	# We're dealing with the primary CPU (BP) here, then. +	# Keep BP's D0,D1,D2 register for boot check. +	# + +	# Set up the Boot IPI for each secondary CPU +	mov	0x1,a0 +loop_set_secondary_icr: +	mov	a0,a1 +	asl	CROSS_ICR_CPU_SHIFT,a1 +	add	CROSS_GxICR(SMP_BOOT_IRQ,0),a1 +	movhu	(a1),d3 +	or	GxICR_ENABLE|GxICR_LEVEL_0,d3 +	movhu	d3,(a1) +	movhu	(a1),d3				# flush +	inc	a0 +	cmp	NR_CPUS,a0 +	bne	loop_set_secondary_icr +#endif /* CONFIG_SMP */ +  	# save commandline pointer  	mov	d0,a3  	# preload the PGD pointer register  	mov	swapper_pg_dir,d0  	mov	d0,(PTBR) +	clr	d0 +	movbu	d0,(PIDR)  	# turn on the TLBs  	mov	MMUCTR_IIV|MMUCTR_DIV,d0  	mov	d0,(MMUCTR) +#ifdef CONFIG_AM34_2 +	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 +#else  	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 +#endif  	mov	d0,(MMUCTR)  	# turn on AM33v2 exception handling mode and set the trap table base @@ -51,6 +91,11 @@ _start:  	mov	d0,(TBR)  	# invalidate and enable both of the caches +#ifdef CONFIG_SMP +	mov	ECHCTR,a0 +	clr	d0 +	mov	d0,(a0) +#endif  	mov	CHCTR,a0  	clr	d0  	movhu	d0,(a0)					# turn off first @@ -206,6 +251,44 @@ __no_parameters:  	call	processor_init[],0  	call	unit_init[],0 +#ifdef CONFIG_SMP +	# mark the primary CPU in cpu_boot_map +	mov	cpu_boot_map,a0 +	mov	0x1,d0 +	mov	d0,(a0) + +	# signal each secondary CPU to begin booting +	mov	0x1,d2				# CPU ID + +loop_request_boot_secondary: +	mov	d2,a0 +	# send SMP_BOOT_IPI to secondary CPU +	asl	CROSS_ICR_CPU_SHIFT,a0 +	add	CROSS_GxICR(SMP_BOOT_IRQ,0),a0 +	movhu	(a0),d0 +	or	GxICR_REQUEST|GxICR_DETECT,d0 +	movhu	d0,(a0) +	movhu	(a0),d0				# flush + +	# wait up to 100ms for AP's IPI to be received +	clr	d3 +wait_on_secondary_boot: +	mov	DELAY_TIME_BOOT_IPI,d0 +	call	__delay[],0 +	inc	d3 +	mov	cpu_boot_map,a0 +	mov	(a0),d0 +	lsr	d2,d0 +	btst	0x1,d0 +	bne	1f +	cmp	TIME_OUT_COUNT_BOOT_IPI,d3 +	bne	wait_on_secondary_boot +1: +	inc	d2 +	cmp	NR_CPUS,d2 +	bne	loop_request_boot_secondary +#endif /* CONFIG_SMP */ +  #ifdef CONFIG_GDBSTUB  	call	gdbstub_init[],0 @@ -217,7 +300,118 @@ __gdbstub_pause:  #endif  	jmp	start_kernel -	.size	_start, _start-. +	.size	_start,.-_start + +############################################################################### +# +# Secondary CPU boot point +# +############################################################################### +#ifdef CONFIG_SMP +startup_secondary: +	# preload the PGD pointer register +	mov	swapper_pg_dir,d0 +	mov	d0,(PTBR) +	clr	d0 +	movbu	d0,(PIDR) + +	# turn on the TLBs +	mov	MMUCTR_IIV|MMUCTR_DIV,d0 +	mov	d0,(MMUCTR) +#ifdef CONFIG_AM34_2 +	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 +#else +	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 +#endif +	mov	d0,(MMUCTR) + +	# turn on AM33v2 exception handling mode and set the trap table base +	movhu	(CPUP),d0 +	or	CPUP_EXM_AM33V2,d0 +	movhu	d0,(CPUP) + +	# set the interrupt vector table +	mov	CONFIG_INTERRUPT_VECTOR_BASE,d0 +	mov	d0,(TBR) + +	# invalidate and enable both of the caches +	mov	ECHCTR,a0 +	clr	d0 +	mov	d0,(a0) +	mov	CHCTR,a0 +	clr	d0 +	movhu	d0,(a0)					# turn off first +	mov	CHCTR_ICINV|CHCTR_DCINV,d0 +	movhu	d0,(a0) +	setlb +	mov	(a0),d0 +	btst	CHCTR_ICBUSY|CHCTR_DCBUSY,d0		# wait till not busy (use CPU loop buffer) +	lne + +#ifdef CONFIG_MN10300_CACHE_ENABLED +#ifdef  CONFIG_MN10300_CACHE_WBACK +#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC +	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 +#else +	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0 +#endif  /* !NOWRALLOC */ +#else +	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 +#endif  /* WBACK */ +	movhu	d0,(a0)					# enable +#endif  /* ENABLED */ + +	# Clear the boot IPI interrupt for this CPU +	movhu	(GxICR(SMP_BOOT_IRQ)),d0 +	and	~GxICR_REQUEST,d0 +	movhu	d0,(GxICR(SMP_BOOT_IRQ)) +	movhu	(GxICR(SMP_BOOT_IRQ)),d0		# flush + +	/* get stack */ +	mov	CONFIG_INTERRUPT_VECTOR_BASE + CONFIG_BOOT_STACK_OFFSET,a0 +	mov	(CPUID),d0 +	and	CPUID_MASK,d0 +	mulu	CONFIG_BOOT_STACK_SIZE,d0 +	sub	d0,a0 +	mov	a0,sp + +	# init interrupt for AP +	call	smp_prepare_cpu_init[],0 + +	# mark this secondary CPU in cpu_boot_map +	mov	(CPUID),d0 +	mov	0x1,d1 +	asl	d0,d1 +	mov	cpu_boot_map,a0 +	bset	d1,(a0) + +	or	EPSW_IE|EPSW_IM_1,epsw  # permit level 0 interrupts +	nop +	nop +#ifdef  CONFIG_MN10300_CACHE_WBACK +	# flush the local cache if it's in writeback mode +	call	mn10300_local_dcache_flush_inv[],0 +	setlb +	mov	(CHCTR),d0 +	btst	CHCTR_DCBUSY,d0		# wait till not busy (use CPU loop buffer) +	lne +#endif + +	# now sleep waiting for further instructions +secondary_sleep: +	mov	CPUM_SLEEP,d0 +	movhu	d0,(CPUM) +	nop +	nop +	bra	secondary_sleep +	.size	startup_secondary,.-startup_secondary +#endif /* CONFIG_SMP */ + +############################################################################### +# +# +# +###############################################################################  ENTRY(__head_end)  /* diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h index eee2eee8626..3b1f48b7e7f 100644 --- a/arch/mn10300/kernel/internal.h +++ b/arch/mn10300/kernel/internal.h @@ -18,3 +18,15 @@ extern int kernel_thread_helper(int);   * entry.S   */  extern void ret_from_fork(struct task_struct *) __attribute__((noreturn)); + +/* + * smp-low.S + */ +#ifdef CONFIG_SMP +extern void mn10300_low_ipi_handler(void); +#endif + +/* + * time.c + */ +extern irqreturn_t local_timer_interrupt(void); diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c index b5b970d2954..80f15725eca 100644 --- a/arch/mn10300/kernel/irq.c +++ b/arch/mn10300/kernel/irq.c @@ -12,11 +12,34 @@  #include <linux/interrupt.h>  #include <linux/kernel_stat.h>  #include <linux/seq_file.h> +#include <linux/cpumask.h>  #include <asm/setup.h> +#include <asm/serial-regs.h> -unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7; +#ifdef CONFIG_SMP +#undef  GxICR +#define GxICR(X) CROSS_GxICR(X, irq_affinity_online[X]) + +#undef  GxICR_u8 +#define GxICR_u8(X) CROSS_GxICR_u8(X, irq_affinity_online[X]) +#endif /* CONFIG_SMP */ + +unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = { +	[0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7 +};  EXPORT_SYMBOL(__mn10300_irq_enabled_epsw); +#ifdef CONFIG_SMP +static char irq_affinity_online[NR_IRQS] = { +	[0 ... NR_IRQS - 1] = 0 +}; + +#define NR_IRQ_WORDS	((NR_IRQS + 31) / 32) +static unsigned long irq_affinity_request[NR_IRQ_WORDS] = { +	[0 ... NR_IRQ_WORDS - 1] = 0 +}; +#endif  /* CONFIG_SMP */ +  atomic_t irq_err_count;  /* @@ -24,30 +47,65 @@ atomic_t irq_err_count;   */  static void mn10300_cpupic_ack(unsigned int irq)  { +	unsigned long flags;  	u16 tmp; -	*(volatile u8 *) &GxICR(irq) = GxICR_DETECT; + +	flags = arch_local_cli_save(); +	GxICR_u8(irq) = GxICR_DETECT;  	tmp = GxICR(irq); +	arch_local_irq_restore(flags);  } -static void mn10300_cpupic_mask(unsigned int irq) +static void __mask_and_set_icr(unsigned int irq, +			       unsigned int mask, unsigned int set)  { -	u16 tmp = GxICR(irq); -	GxICR(irq) = (tmp & GxICR_LEVEL); +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); +	tmp = GxICR(irq); +	GxICR(irq) = (tmp & mask) | set;  	tmp = GxICR(irq); +	arch_local_irq_restore(flags); +} + +static void mn10300_cpupic_mask(unsigned int irq) +{ +	__mask_and_set_icr(irq, GxICR_LEVEL, 0);  }  static void mn10300_cpupic_mask_ack(unsigned int irq)  { -	u16 tmp = GxICR(irq); -	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; -	tmp = GxICR(irq); +#ifdef CONFIG_SMP +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); + +	if (!test_and_clear_bit(irq, irq_affinity_request)) { +		tmp = GxICR(irq); +		GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; +		tmp = GxICR(irq); +	} else { +		u16 tmp2; +		tmp = GxICR(irq); +		GxICR(irq) = (tmp & GxICR_LEVEL); +		tmp2 = GxICR(irq); + +		irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); +		GxICR(irq) = (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT; +		tmp = GxICR(irq); +	} + +	arch_local_irq_restore(flags); +#else  /* CONFIG_SMP */ +	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_DETECT); +#endif /* CONFIG_SMP */  }  static void mn10300_cpupic_unmask(unsigned int irq)  { -	u16 tmp = GxICR(irq); -	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE; -	tmp = GxICR(irq); +	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE);  }  static void mn10300_cpupic_unmask_clear(unsigned int irq) @@ -56,11 +114,89 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq)  	 * device has ceased to assert its interrupt line and the interrupt  	 * channel has been disabled in the PIC, so for level-triggered  	 * interrupts we need to clear the request bit when we re-enable */ -	u16 tmp = GxICR(irq); -	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; -	tmp = GxICR(irq); +#ifdef CONFIG_SMP +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); + +	if (!test_and_clear_bit(irq, irq_affinity_request)) { +		tmp = GxICR(irq); +		GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; +		tmp = GxICR(irq); +	} else { +		tmp = GxICR(irq); + +		irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); +		GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; +		tmp = GxICR(irq); +	} + +	arch_local_irq_restore(flags); +#else  /* CONFIG_SMP */ +	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE | GxICR_DETECT); +#endif /* CONFIG_SMP */  } +#ifdef CONFIG_SMP +static int +mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask) +{ +	unsigned long flags; +	int err; + +	flags = arch_local_cli_save(); + +	/* check irq no */ +	switch (irq) { +	case TMJCIRQ: +	case RESCHEDULE_IPI: +	case CALL_FUNC_SINGLE_IPI: +	case LOCAL_TIMER_IPI: +	case FLUSH_CACHE_IPI: +	case CALL_FUNCTION_NMI_IPI: +	case GDB_NMI_IPI: +#ifdef CONFIG_MN10300_TTYSM0 +	case SC0RXIRQ: +	case SC0TXIRQ: +#ifdef CONFIG_MN10300_TTYSM0_TIMER8 +	case TM8IRQ: +#elif CONFIG_MN10300_TTYSM0_TIMER2 +	case TM2IRQ: +#endif /* CONFIG_MN10300_TTYSM0_TIMER8 */ +#endif /* CONFIG_MN10300_TTYSM0 */ + +#ifdef CONFIG_MN10300_TTYSM1 +	case SC1RXIRQ: +	case SC1TXIRQ: +#ifdef CONFIG_MN10300_TTYSM1_TIMER12 +	case TM12IRQ: +#elif CONFIG_MN10300_TTYSM1_TIMER9 +	case TM9IRQ: +#elif CONFIG_MN10300_TTYSM1_TIMER3 +	case TM3IRQ: +#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */ +#endif /* CONFIG_MN10300_TTYSM1 */ + +#ifdef CONFIG_MN10300_TTYSM2 +	case SC2RXIRQ: +	case SC2TXIRQ: +	case TM10IRQ: +#endif /* CONFIG_MN10300_TTYSM2 */ +		err = -1; +		break; + +	default: +		set_bit(irq, irq_affinity_request); +		err = 0; +		break; +	} + +	arch_local_irq_restore(flags); +	return err; +} +#endif /* CONFIG_SMP */ +  /*   * MN10300 PIC level-triggered IRQ handling.   * @@ -79,6 +215,9 @@ static struct irq_chip mn10300_cpu_pic_level = {  	.mask		= mn10300_cpupic_mask,  	.mask_ack	= mn10300_cpupic_mask,  	.unmask		= mn10300_cpupic_unmask_clear, +#ifdef CONFIG_SMP +	.set_affinity	= mn10300_cpupic_setaffinity, +#endif /* CONFIG_SMP */  };  /* @@ -94,6 +233,9 @@ static struct irq_chip mn10300_cpu_pic_edge = {  	.mask		= mn10300_cpupic_mask,  	.mask_ack	= mn10300_cpupic_mask_ack,  	.unmask		= mn10300_cpupic_unmask, +#ifdef CONFIG_SMP +	.set_affinity	= mn10300_cpupic_setaffinity, +#endif /* CONFIG_SMP */  };  /* @@ -111,14 +253,34 @@ void ack_bad_irq(int irq)   */  void set_intr_level(int irq, u16 level)  { -	u16 tmp; +	BUG_ON(in_interrupt()); -	if (in_interrupt()) -		BUG(); +	__mask_and_set_icr(irq, GxICR_ENABLE, level); +} -	tmp = GxICR(irq); -	GxICR(irq) = (tmp & GxICR_ENABLE) | level; -	tmp = GxICR(irq); +void mn10300_intc_set_level(unsigned int irq, unsigned int level) +{ +	set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL); +} + +void mn10300_intc_clear(unsigned int irq) +{ +	__mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT); +} + +void mn10300_intc_set(unsigned int irq) +{ +	__mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT); +} + +void mn10300_intc_enable(unsigned int irq) +{ +	mn10300_cpupic_unmask(irq); +} + +void mn10300_intc_disable(unsigned int irq) +{ +	mn10300_cpupic_mask(irq);  }  /* @@ -126,7 +288,7 @@ void set_intr_level(int irq, u16 level)   * than before   * - see Documentation/mn10300/features.txt   */ -void set_intr_postackable(int irq) +void mn10300_set_lateack_irq_type(int irq)  {  	set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level,  				 handle_level_irq); @@ -147,6 +309,7 @@ void __init init_IRQ(void)  			 * interrupts */  			set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge,  						 handle_level_irq); +  	unit_init_IRQ();  } @@ -156,6 +319,7 @@ void __init init_IRQ(void)  asmlinkage void do_IRQ(void)  {  	unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw; +	unsigned int cpu_id = smp_processor_id();  	int irq;  	sp = current_stack_pointer(); @@ -163,12 +327,14 @@ asmlinkage void do_IRQ(void)  	/* make sure local_irq_enable() doesn't muck up the interrupt priority  	 * setting in EPSW */ -	old_irq_enabled_epsw = __mn10300_irq_enabled_epsw; +	old_irq_enabled_epsw = __mn10300_irq_enabled_epsw[cpu_id];  	local_save_flags(epsw); -	__mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw); +	__mn10300_irq_enabled_epsw[cpu_id] = EPSW_IE | (EPSW_IM & epsw);  	irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL; -	__IRQ_STAT(smp_processor_id(), __irq_count)++; +#ifdef CONFIG_MN10300_WD_TIMER +	__IRQ_STAT(cpu_id, __irq_count)++; +#endif  	irq_enter(); @@ -188,7 +354,7 @@ asmlinkage void do_IRQ(void)  		local_irq_restore(epsw);  	} -	__mn10300_irq_enabled_epsw = old_irq_enabled_epsw; +	__mn10300_irq_enabled_epsw[cpu_id] = old_irq_enabled_epsw;  	irq_exit();  } @@ -239,11 +405,13 @@ int show_interrupts(struct seq_file *p, void *v)  		/* polish off with NMI and error counters */  	case NR_IRQS: +#ifdef CONFIG_MN10300_WD_TIMER  		seq_printf(p, "NMI: ");  		for (j = 0; j < NR_CPUS; j++)  			if (cpu_online(j))  				seq_printf(p, "%10u ", nmi_count(j));  		seq_putc(p, '\n'); +#endif  		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));  		break; @@ -251,3 +419,51 @@ int show_interrupts(struct seq_file *p, void *v)  	return 0;  } + +#ifdef CONFIG_HOTPLUG_CPU +void migrate_irqs(void) +{ +	irq_desc_t *desc; +	int irq; +	unsigned int self, new; +	unsigned long flags; + +	self = smp_processor_id(); +	for (irq = 0; irq < NR_IRQS; irq++) { +		desc = irq_desc + irq; + +		if (desc->status == IRQ_PER_CPU) +			continue; + +		if (cpu_isset(self, irq_desc[irq].affinity) && +		    !cpus_intersects(irq_affinity[irq], cpu_online_map)) { +			int cpu_id; +			cpu_id = first_cpu(cpu_online_map); +			cpu_set(cpu_id, irq_desc[irq].affinity); +		} +		/* We need to operate irq_affinity_online atomically. */ +		arch_local_cli_save(flags); +		if (irq_affinity_online[irq] == self) { +			u16 x, tmp; + +			x = CROSS_GxICR(irq, self); +			CROSS_GxICR(irq, self) = x & GxICR_LEVEL; +			tmp = CROSS_GxICR(irq, self); + +			new = any_online_cpu(irq_desc[irq].affinity); +			irq_affinity_online[irq] = new; + +			CROSS_GxICR(irq, new) = +				(x & GxICR_LEVEL) | GxICR_DETECT; +			tmp = CROSS_GxICR(irq, new); + +			x &= GxICR_LEVEL | GxICR_ENABLE; +			if (CROSS_GxICR(irq, self) & GxICR_REQUEST) +				x |= GxICR_REQUEST | GxICR_DETECT; +			CROSS_GxICR(irq, new) = x; +			tmp = CROSS_GxICR(irq, new); +		} +		arch_local_irq_restore(flags); +	} +} +#endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/mn10300/kernel/mn10300-serial-low.S b/arch/mn10300/kernel/mn10300-serial-low.S index 66702d25661..dfc1b6f2fa9 100644 --- a/arch/mn10300/kernel/mn10300-serial-low.S +++ b/arch/mn10300/kernel/mn10300-serial-low.S @@ -39,7 +39,7 @@  ###############################################################################  	.balign	L1_CACHE_BYTES  ENTRY(mn10300_serial_vdma_interrupt) -	or	EPSW_IE,psw			# permit overriding by +#	or	EPSW_IE,psw			# permit overriding by  						# debugging interrupts  	movm	[d2,d3,a2,a3,exreg0],(sp) @@ -164,7 +164,7 @@ mnsc_vdma_tx_noint:  	rti  mnsc_vdma_tx_empty: -	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2 +	mov	+(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2  	movhu	d2,(e3)			# disable the interrupt  	movhu	(e3),d2			# flush @@ -175,7 +175,7 @@ mnsc_vdma_tx_break:  	movhu	(SCxCTR,e2),d2		# turn on break mode  	or	SC01CTR_BKE,d2  	movhu	d2,(SCxCTR,e2) -	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2 +	mov	+(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2  	movhu	d2,(e3)			# disable transmit interrupts on this  					# channel  	movhu	(e3),d2			# flush diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index db509dd8056..996384dba45 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c @@ -44,6 +44,11 @@ static const char serial_revdate[] = "2007-11-06";  #include <unit/timex.h>  #include "mn10300-serial.h" +#ifdef CONFIG_SMP +#undef  GxICR +#define GxICR(X) CROSS_GxICR(X, 0) +#endif /* CONFIG_SMP */ +  #define kenter(FMT, ...) \  	printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)  #define _enter(FMT, ...) \ @@ -57,6 +62,11 @@ static const char serial_revdate[] = "2007-11-06";  #define _proto(FMT, ...) \  	no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) +#ifndef CODMSB +/* c_cflag bit meaning */ +#define CODMSB	004000000000	/* change Transfer bit-order */ +#endif +  #define NR_UARTS 3  #ifdef CONFIG_MN10300_TTYSM_CONSOLE @@ -152,26 +162,35 @@ struct mn10300_serial_port mn10300_serial_port_sif0 = {  	.name		= "ttySM0",  	._iobase	= &SC0CTR,  	._control	= &SC0CTR, -	._status	= (volatile u8 *) &SC0STR, +	._status	= (volatile u8 *)&SC0STR,  	._intr		= &SC0ICR,  	._rxb		= &SC0RXB,  	._txb		= &SC0TXB,  	.rx_name	= "ttySM0:Rx",  	.tx_name	= "ttySM0:Tx", -#ifdef CONFIG_MN10300_TTYSM0_TIMER8 +#if defined(CONFIG_MN10300_TTYSM0_TIMER8)  	.tm_name	= "ttySM0:Timer8",  	._tmxmd		= &TM8MD,  	._tmxbr		= &TM8BR,  	._tmicr		= &TM8ICR,  	.tm_irq		= TM8IRQ,  	.div_timer	= MNSCx_DIV_TIMER_16BIT, -#else /* CONFIG_MN10300_TTYSM0_TIMER2 */ +#elif defined(CONFIG_MN10300_TTYSM0_TIMER0) +	.tm_name	= "ttySM0:Timer0", +	._tmxmd		= &TM0MD, +	._tmxbr		= (volatile u16 *)&TM0BR, +	._tmicr		= &TM0ICR, +	.tm_irq		= TM0IRQ, +	.div_timer	= MNSCx_DIV_TIMER_8BIT, +#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)  	.tm_name	= "ttySM0:Timer2",  	._tmxmd		= &TM2MD, -	._tmxbr		= (volatile u16 *) &TM2BR, +	._tmxbr		= (volatile u16 *)&TM2BR,  	._tmicr		= &TM2ICR,  	.tm_irq		= TM2IRQ,  	.div_timer	= MNSCx_DIV_TIMER_8BIT, +#else +#error "Unknown config for ttySM0"  #endif  	.rx_irq		= SC0RXIRQ,  	.tx_irq		= SC0TXIRQ, @@ -205,26 +224,35 @@ struct mn10300_serial_port mn10300_serial_port_sif1 = {  	.name		= "ttySM1",  	._iobase	= &SC1CTR,  	._control	= &SC1CTR, -	._status	= (volatile u8 *) &SC1STR, +	._status	= (volatile u8 *)&SC1STR,  	._intr		= &SC1ICR,  	._rxb		= &SC1RXB,  	._txb		= &SC1TXB,  	.rx_name	= "ttySM1:Rx",  	.tx_name	= "ttySM1:Tx", -#ifdef CONFIG_MN10300_TTYSM1_TIMER9 +#if defined(CONFIG_MN10300_TTYSM1_TIMER9)  	.tm_name	= "ttySM1:Timer9",  	._tmxmd		= &TM9MD,  	._tmxbr		= &TM9BR,  	._tmicr		= &TM9ICR,  	.tm_irq		= TM9IRQ,  	.div_timer	= MNSCx_DIV_TIMER_16BIT, -#else /* CONFIG_MN10300_TTYSM1_TIMER3 */ +#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)  	.tm_name	= "ttySM1:Timer3",  	._tmxmd		= &TM3MD, -	._tmxbr		= (volatile u16 *) &TM3BR, +	._tmxbr		= (volatile u16 *)&TM3BR,  	._tmicr		= &TM3ICR,  	.tm_irq		= TM3IRQ,  	.div_timer	= MNSCx_DIV_TIMER_8BIT, +#elif defined(CONFIG_MN10300_TTYSM1_TIMER12) +	.tm_name	= "ttySM1/Timer12", +	._tmxmd		= &TM12MD, +	._tmxbr		= &TM12BR, +	._tmicr		= &TM12ICR, +	.tm_irq		= TM12IRQ, +	.div_timer	= MNSCx_DIV_TIMER_16BIT, +#else +#error "Unknown config for ttySM1"  #endif  	.rx_irq		= SC1RXIRQ,  	.tx_irq		= SC1TXIRQ, @@ -260,20 +288,45 @@ struct mn10300_serial_port mn10300_serial_port_sif2 = {  	.uart.lock	=  	__SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock),  	.name		= "ttySM2", -	.rx_name	= "ttySM2:Rx", -	.tx_name	= "ttySM2:Tx", -	.tm_name	= "ttySM2:Timer10",  	._iobase	= &SC2CTR,  	._control	= &SC2CTR, -	._status	= &SC2STR, +	._status	= (volatile u8 *)&SC2STR,  	._intr		= &SC2ICR,  	._rxb		= &SC2RXB,  	._txb		= &SC2TXB, +	.rx_name	= "ttySM2:Rx", +	.tx_name	= "ttySM2:Tx", +#if defined(CONFIG_MN10300_TTYSM2_TIMER10) +	.tm_name	= "ttySM2/Timer10",  	._tmxmd		= &TM10MD,  	._tmxbr		= &TM10BR,  	._tmicr		= &TM10ICR,  	.tm_irq		= TM10IRQ,  	.div_timer	= MNSCx_DIV_TIMER_16BIT, +#elif defined(CONFIG_MN10300_TTYSM2_TIMER9) +	.tm_name	= "ttySM2/Timer9", +	._tmxmd		= &TM9MD, +	._tmxbr		= &TM9BR, +	._tmicr		= &TM9ICR, +	.tm_irq		= TM9IRQ, +	.div_timer	= MNSCx_DIV_TIMER_16BIT, +#elif defined(CONFIG_MN10300_TTYSM2_TIMER1) +	.tm_name	= "ttySM2/Timer1", +	._tmxmd		= &TM1MD, +	._tmxbr		= (volatile u16 *)&TM1BR, +	._tmicr		= &TM1ICR, +	.tm_irq		= TM1IRQ, +	.div_timer	= MNSCx_DIV_TIMER_8BIT, +#elif defined(CONFIG_MN10300_TTYSM2_TIMER3) +	.tm_name	= "ttySM2/Timer3", +	._tmxmd		= &TM3MD, +	._tmxbr		= (volatile u16 *)&TM3BR, +	._tmicr		= &TM3ICR, +	.tm_irq		= TM3IRQ, +	.div_timer	= MNSCx_DIV_TIMER_8BIT, +#else +#error "Unknown config for ttySM2" +#endif  	.rx_irq		= SC2RXIRQ,  	.tx_irq		= SC2TXIRQ,  	.rx_icr		= &GxICR(SC2RXIRQ), @@ -322,9 +375,13 @@ struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = {   */  static void mn10300_serial_mask_ack(unsigned int irq)  { +	unsigned long flags;  	u16 tmp; + +	flags = arch_local_cli_save();  	GxICR(irq) = GxICR_LEVEL_6;  	tmp = GxICR(irq); /* flush write buffer */ +	arch_local_irq_restore(flags);  }  static void mn10300_serial_nop(unsigned int irq) @@ -348,23 +405,36 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS];  static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)  { +	unsigned long flags;  	u16 x; -	*port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT; + +	flags = arch_local_cli_save(); +	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);  	x = *port->tx_icr; +	arch_local_irq_restore(flags);  }  static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)  { +	unsigned long flags;  	u16 x; -	*port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE; + +	flags = arch_local_cli_save(); +	*port->tx_icr = +		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;  	x = *port->tx_icr; +	arch_local_irq_restore(flags);  }  static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)  { +	unsigned long flags;  	u16 x; -	*port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT; + +	flags = arch_local_cli_save(); +	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);  	x = *port->rx_icr; +	arch_local_irq_restore(flags);  }  /* @@ -650,7 +720,7 @@ static unsigned int mn10300_serial_tx_empty(struct uart_port *_port)  static void mn10300_serial_set_mctrl(struct uart_port *_port,  				     unsigned int mctrl)  { -	struct mn10300_serial_port *port = +	struct mn10300_serial_port *port __attribute__ ((unused)) =  		container_of(_port, struct mn10300_serial_port, uart);  	_enter("%s,%x", port->name, mctrl); @@ -706,6 +776,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port)  			UART_XMIT_SIZE));  	/* kick the virtual DMA controller */ +	arch_local_cli();  	x = *port->tx_icr;  	x |= GxICR_ENABLE; @@ -716,10 +787,14 @@ static void mn10300_serial_start_tx(struct uart_port *_port)  	_debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",  	       *port->_control, *port->_intr, *port->_status, -	       *port->_tmxmd, *port->_tmxbr, *port->tx_icr); +	       *port->_tmxmd, +	       (port->div_timer == MNSCx_DIV_TIMER_8BIT) ? +	           *(volatile u8 *)port->_tmxbr : *port->_tmxbr, +	       *port->tx_icr);  	*port->tx_icr = x;  	x = *port->tx_icr; +	arch_local_sti();  }  /* @@ -842,8 +917,10 @@ static int mn10300_serial_startup(struct uart_port *_port)  	pint->port = port;  	pint->vdma = mn10300_serial_vdma_tx_handler; -	set_intr_level(port->rx_irq, GxICR_LEVEL_1); -	set_intr_level(port->tx_irq, GxICR_LEVEL_1); +	set_intr_level(port->rx_irq, +		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)); +	set_intr_level(port->tx_irq, +		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));  	set_irq_chip(port->tm_irq, &mn10300_serial_pic);  	if (request_irq(port->rx_irq, mn10300_serial_interrupt, @@ -876,6 +953,7 @@ error:   */  static void mn10300_serial_shutdown(struct uart_port *_port)  { +	u16 x;  	struct mn10300_serial_port *port =  		container_of(_port, struct mn10300_serial_port, uart); @@ -897,8 +975,12 @@ static void mn10300_serial_shutdown(struct uart_port *_port)  	free_irq(port->rx_irq, port);  	free_irq(port->tx_irq, port); -	*port->rx_icr = GxICR_LEVEL_1; -	*port->tx_icr = GxICR_LEVEL_1; +	arch_local_cli(); +	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); +	x = *port->rx_icr; +	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); +	x = *port->tx_icr; +	arch_local_sti();  }  /* @@ -947,11 +1029,66 @@ static void mn10300_serial_change_speed(struct mn10300_serial_port *port,  	/* Determine divisor based on baud rate */  	battempt = 0; -	if (div_timer == MNSCx_DIV_TIMER_16BIT) -		scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8 -						 *   == SC2CTR_CK_TM10UFLOW) */ -	else if (div_timer == MNSCx_DIV_TIMER_8BIT) +	switch (port->uart.line) { +#ifdef CONFIG_MN10300_TTYSM0 +	case 0: /* ttySM0 */ +#if   defined(CONFIG_MN10300_TTYSM0_TIMER8) +		scxctr |= SC0CTR_CK_TM8UFLOW_8; +#elif defined(CONFIG_MN10300_TTYSM0_TIMER0) +		scxctr |= SC0CTR_CK_TM0UFLOW_8; +#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)  		scxctr |= SC0CTR_CK_TM2UFLOW_8; +#else +#error "Unknown config for ttySM0" +#endif +		break; +#endif /* CONFIG_MN10300_TTYSM0 */ + +#ifdef CONFIG_MN10300_TTYSM1 +	case 1: /* ttySM1 */ +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) +#if   defined(CONFIG_MN10300_TTYSM1_TIMER9) +		scxctr |= SC1CTR_CK_TM9UFLOW_8; +#elif defined(CONFIG_MN10300_TTYSM1_TIMER3) +		scxctr |= SC1CTR_CK_TM3UFLOW_8; +#else +#error "Unknown config for ttySM1" +#endif +#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ +#if defined(CONFIG_MN10300_TTYSM1_TIMER12) +		scxctr |= SC1CTR_CK_TM12UFLOW_8; +#else +#error "Unknown config for ttySM1" +#endif +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ +		break; +#endif /* CONFIG_MN10300_TTYSM1 */ + +#ifdef CONFIG_MN10300_TTYSM2 +	case 2: /* ttySM2 */ +#if defined(CONFIG_AM33_2) +#if   defined(CONFIG_MN10300_TTYSM2_TIMER10) +		scxctr |= SC2CTR_CK_TM10UFLOW; +#else +#error "Unknown config for ttySM2" +#endif +#else /* CONFIG_AM33_2 */ +#if   defined(CONFIG_MN10300_TTYSM2_TIMER9) +		scxctr |= SC2CTR_CK_TM9UFLOW_8; +#elif defined(CONFIG_MN10300_TTYSM2_TIMER1) +		scxctr |= SC2CTR_CK_TM1UFLOW_8; +#elif defined(CONFIG_MN10300_TTYSM2_TIMER3) +		scxctr |= SC2CTR_CK_TM3UFLOW_8; +#else +#error "Unknown config for ttySM2" +#endif +#endif /* CONFIG_AM33_2 */ +		break; +#endif /* CONFIG_MN10300_TTYSM2 */ + +	default: +		break; +	}  try_alternative:  	baud = uart_get_baud_rate(&port->uart, new, old, 0, @@ -1195,6 +1332,12 @@ static void mn10300_serial_set_termios(struct uart_port *_port,  		ctr &= ~SC2CTR_TWE;  		*port->_control = ctr;  	} + +	/* change Transfer bit-order (LSB/MSB) */ +	if (new->c_cflag & CODMSB) +		*port->_control |= SC01CTR_OD_MSBFIRST; /* MSB MODE */ +	else +		*port->_control &= ~SC01CTR_OD_MSBFIRST; /* LSB MODE */  }  /* @@ -1302,11 +1445,16 @@ static int __init mn10300_serial_init(void)  	printk(KERN_INFO "%s version %s (%s)\n",  	       serial_name, serial_version, serial_revdate); -#ifdef CONFIG_MN10300_TTYSM2 -	SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ +#if defined(CONFIG_MN10300_TTYSM2) && defined(CONFIG_AM33_2) +	{ +		int tmp; +		SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ +		tmp = SC2TIM; +	}  #endif -	set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt); +	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL), +		mn10300_serial_vdma_interrupt);  	ret = uart_register_driver(&mn10300_serial_driver);  	if (!ret) { @@ -1366,9 +1514,11 @@ static void mn10300_serial_console_write(struct console *co,  	port = mn10300_serial_ports[co->index];  	/* firstly hijack the serial port from the "virtual DMA" controller */ +	arch_local_cli();  	txicr = *port->tx_icr; -	*port->tx_icr = GxICR_LEVEL_1; +	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);  	tmp = *port->tx_icr; +	arch_local_sti();  	/* the transmitter may be disabled */  	scxctr = *port->_control; @@ -1422,8 +1572,10 @@ static void mn10300_serial_console_write(struct console *co,  	if (!(scxctr & SC01CTR_TXE))  		*port->_control = scxctr; +	arch_local_cli();  	*port->tx_icr = txicr;  	tmp = *port->tx_icr; +	arch_local_sti();  }  /* diff --git a/arch/mn10300/kernel/mn10300-watchdog-low.S b/arch/mn10300/kernel/mn10300-watchdog-low.S index 996244745cc..f2f5c9cfaab 100644 --- a/arch/mn10300/kernel/mn10300-watchdog-low.S +++ b/arch/mn10300/kernel/mn10300-watchdog-low.S @@ -16,6 +16,7 @@  #include <asm/intctl-regs.h>  #include <asm/timer-regs.h>  #include <asm/frame.inc> +#include <linux/threads.h>  	.text @@ -53,7 +54,13 @@ watchdog_handler:  	.type	touch_nmi_watchdog,@function  touch_nmi_watchdog:  	clr	d0 -	mov	d0,(watchdog_alert_counter) +	clr	d1 +	mov	watchdog_alert_counter, a0 +	setlb +	mov	d0, (a0+) +	inc	d1 +	cmp	NR_CPUS, d1 +	lne  	ret	[],0  	.size	touch_nmi_watchdog,.-touch_nmi_watchdog diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c index f362d9d138f..965dd61656c 100644 --- a/arch/mn10300/kernel/mn10300-watchdog.c +++ b/arch/mn10300/kernel/mn10300-watchdog.c @@ -30,7 +30,7 @@  static DEFINE_SPINLOCK(watchdog_print_lock);  static unsigned int watchdog;  static unsigned int watchdog_hz = 1; -unsigned int watchdog_alert_counter; +unsigned int watchdog_alert_counter[NR_CPUS];  EXPORT_SYMBOL(touch_nmi_watchdog); @@ -39,9 +39,6 @@ EXPORT_SYMBOL(touch_nmi_watchdog);   * is to check its timer makes IRQ counts. If they are not   * changing then that CPU has some problem.   * - * as these watchdog NMI IRQs are generated on every CPU, we only - * have to check the current processor. - *   * since NMIs dont listen to _any_ locks, we have to be extremely   * careful not to rely on unsafe variables. The printk might lock   * up though, so we have to break up any console locks first ... @@ -69,8 +66,8 @@ int __init check_watchdog(void)  	printk(KERN_INFO "OK.\n"); -	/* now that we know it works we can reduce NMI frequency to -	 * something more reasonable; makes a difference in some configs +	/* now that we know it works we can reduce NMI frequency to something +	 * more reasonable; makes a difference in some configs  	 */  	watchdog_hz = 1; @@ -121,15 +118,22 @@ void __init watchdog_go(void)  	}  } +#ifdef CONFIG_SMP +static void watchdog_dump_register(void *dummy) +{ +	printk(KERN_ERR "--- Register Dump (CPU%d) ---\n", CPUID); +	show_registers(__frame); +} +#endif +  asmlinkage  void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)  { -  	/*  	 * Since current-> is always on the stack, and we always switch  	 * the stack NMI-atomically, it's safe to use smp_processor_id().  	 */ -	int sum, cpu = smp_processor_id(); +	int sum, cpu;  	int irq = NMIIRQ;  	u8 wdt, tmp; @@ -138,43 +142,61 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)  	tmp = WDCTR;  	NMICR = NMICR_WDIF; -	nmi_count(cpu)++; +	nmi_count(smp_processor_id())++;  	kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); -	sum = irq_stat[cpu].__irq_count; -	if (last_irq_sums[cpu] == sum) { -		/* -		 * Ayiee, looks like this CPU is stuck ... -		 * wait a few IRQs (5 seconds) before doing the oops ... -		 */ -		watchdog_alert_counter++; -		if (watchdog_alert_counter == 5 * watchdog_hz) { -			spin_lock(&watchdog_print_lock); +	for_each_online_cpu(cpu) { + +		sum = irq_stat[cpu].__irq_count; + +		if ((last_irq_sums[cpu] == sum) +#if defined(CONFIG_GDBSTUB) && defined(CONFIG_SMP) +			&& !(CHK_GDBSTUB_BUSY() +			     || atomic_read(&cpu_doing_single_step)) +#endif +			) {  			/* -			 * We are in trouble anyway, lets at least try -			 * to get a message out. +			 * Ayiee, looks like this CPU is stuck ... +			 * wait a few IRQs (5 seconds) before doing the oops ...  			 */ -			bust_spinlocks(1); -			printk(KERN_ERR -			       "NMI Watchdog detected LOCKUP on CPU%d," -			       " pc %08lx, registers:\n", -			       cpu, regs->pc); -			show_registers(regs); -			printk("console shuts up ...\n"); -			console_silent(); -			spin_unlock(&watchdog_print_lock); -			bust_spinlocks(0); +			watchdog_alert_counter[cpu]++; +			if (watchdog_alert_counter[cpu] == 5 * watchdog_hz) { +				spin_lock(&watchdog_print_lock); +				/* +				 * We are in trouble anyway, lets at least try +				 * to get a message out. +				 */ +				bust_spinlocks(1); +				printk(KERN_ERR +				       "NMI Watchdog detected LOCKUP on CPU%d," +				       " pc %08lx, registers:\n", +				       cpu, regs->pc); +#ifdef CONFIG_SMP +				printk(KERN_ERR +				       "--- Register Dump (CPU%d) ---\n", +				       CPUID); +#endif +				show_registers(regs); +#ifdef CONFIG_SMP +				smp_nmi_call_function(watchdog_dump_register, +					NULL, 1); +#endif +				printk(KERN_NOTICE "console shuts up ...\n"); +				console_silent(); +				spin_unlock(&watchdog_print_lock); +				bust_spinlocks(0);  #ifdef CONFIG_GDBSTUB -			if (gdbstub_busy) -				gdbstub_exception(regs, excep); -			else -				gdbstub_intercept(regs, excep); +				if (CHK_GDBSTUB_BUSY_AND_ACTIVE()) +					gdbstub_exception(regs, excep); +				else +					gdbstub_intercept(regs, excep);  #endif -			do_exit(SIGSEGV); +				do_exit(SIGSEGV); +			} +		} else { +			last_irq_sums[cpu] = sum; +			watchdog_alert_counter[cpu] = 0;  		} -	} else { -		last_irq_sums[cpu] = sum; -		watchdog_alert_counter = 0;  	}  	WDCTR = wdt | WDCTR_WDRST; diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 243e33cd874..b2e85ed73a5 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -57,6 +57,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)  void (*pm_power_off)(void);  EXPORT_SYMBOL(pm_power_off); +#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)  /*   * we use this if we don't have any better idle routine   */ @@ -69,6 +70,35 @@ static void default_idle(void)  		local_irq_enable();  } +#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU  */ +/* + * On SMP it's slightly faster (but much more power-consuming!) + * to poll the ->work.need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +static inline void poll_idle(void) +{ +	int oldval; + +	local_irq_enable(); + +	/* +	 * Deal with another CPU just having chosen a thread to +	 * run here: +	 */ +	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); + +	if (!oldval) { +		set_thread_flag(TIF_POLLING_NRFLAG); +		while (!need_resched()) +			cpu_relax(); +		clear_thread_flag(TIF_POLLING_NRFLAG); +	} else { +		set_need_resched(); +	} +} +#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */ +  /*   * the idle thread   * - there's no useful work to be done, so just try to conserve power and have @@ -77,8 +107,6 @@ static void default_idle(void)   */  void cpu_idle(void)  { -	int cpu = smp_processor_id(); -  	/* endless idle loop with no priority at all */  	for (;;) {  		while (!need_resched()) { @@ -86,8 +114,13 @@ void cpu_idle(void)  			smp_rmb();  			idle = pm_idle; -			if (!idle) +			if (!idle) { +#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU) +				idle = poll_idle; +#else  /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */  				idle = default_idle; +#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */ +			}  			idle();  		} @@ -233,7 +266,7 @@ int copy_thread(unsigned long clone_flags,  	}  	/* set up things up so the scheduler can start the new task */ -	p->thread.__frame = c_kregs; +	p->thread.frame = c_kregs;  	p->thread.a3	= (unsigned long) c_kregs;  	p->thread.sp	= c_ksp;  	p->thread.pc	= (unsigned long) ret_from_fork; diff --git a/arch/mn10300/kernel/profile.c b/arch/mn10300/kernel/profile.c index 20d7d0306b1..4f342f75d00 100644 --- a/arch/mn10300/kernel/profile.c +++ b/arch/mn10300/kernel/profile.c @@ -41,7 +41,7 @@ static __init int profile_init(void)  	tmp = TM11ICR;  	printk(KERN_INFO "Profiling initiated on timer 11, priority 0, %uHz\n", -	       mn10300_ioclk / 8 / (TM11BR + 1)); +	       MN10300_IOCLK / 8 / (TM11BR + 1));  	printk(KERN_INFO "Profile histogram stored %p-%p\n",  	       prof_buffer, (u8 *)(prof_buffer + prof_len) - 1); diff --git a/arch/mn10300/kernel/rtc.c b/arch/mn10300/kernel/rtc.c index 4eef0e7224f..e9e20f9a4dd 100644 --- a/arch/mn10300/kernel/rtc.c +++ b/arch/mn10300/kernel/rtc.c @@ -20,18 +20,22 @@  DEFINE_SPINLOCK(rtc_lock);  EXPORT_SYMBOL(rtc_lock); -/* time for RTC to update itself in ioclks */ -static unsigned long mn10300_rtc_update_period; - +/* + * Read the current RTC time + */  void read_persistent_clock(struct timespec *ts)  {  	struct rtc_time tm;  	get_rtc_time(&tm); -	ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, -		      tm.tm_hour, tm.tm_min, tm.tm_sec);  	ts->tv_nsec = 0; +	ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, +			    tm.tm_hour, tm.tm_min, tm.tm_sec); + +	/* if rtc is way off in the past, set something reasonable */ +	if (ts->tv_sec < 0) +		ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0);  }  /* @@ -115,39 +119,14 @@ int update_persistent_clock(struct timespec now)   */  void __init calibrate_clock(void)  { -	unsigned long count0, counth, count1;  	unsigned char status;  	/* make sure the RTC is running and is set to operate in 24hr mode */  	status = RTSRC;  	RTCRB |= RTCRB_SET;  	RTCRB |= RTCRB_TM_24HR; +	RTCRB &= ~RTCRB_DM_BINARY;  	RTCRA |= RTCRA_DVR;  	RTCRA &= ~RTCRA_DVR;  	RTCRB &= ~RTCRB_SET; - -	/* work out the clock speed by counting clock cycles between ends of -	 * the RTC update cycle - track the RTC through one complete update -	 * cycle (1 second) -	 */ -	startup_timestamp_counter(); - -	while (!(RTCRA & RTCRA_UIP)) {} -	while ((RTCRA & RTCRA_UIP)) {} - -	count0 = TMTSCBC; - -	while (!(RTCRA & RTCRA_UIP)) {} - -	counth = TMTSCBC; - -	while ((RTCRA & RTCRA_UIP)) {} - -	count1 = TMTSCBC; - -	shutdown_timestamp_counter(); - -	MN10300_TSCCLK = count0 - count1; /* the timers count down */ -	mn10300_rtc_update_period = counth - count1; -	MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ;  } diff --git a/arch/mn10300/kernel/setup.c b/arch/mn10300/kernel/setup.c index d464affcba0..12514570ed5 100644 --- a/arch/mn10300/kernel/setup.c +++ b/arch/mn10300/kernel/setup.c @@ -22,6 +22,7 @@  #include <linux/init.h>  #include <linux/bootmem.h>  #include <linux/seq_file.h> +#include <linux/cpu.h>  #include <asm/processor.h>  #include <linux/console.h>  #include <asm/uaccess.h> @@ -30,7 +31,6 @@  #include <asm/io.h>  #include <asm/smp.h>  #include <proc/proc.h> -#include <asm/busctl-regs.h>  #include <asm/fpu.h>  #include <asm/sections.h> @@ -64,11 +64,13 @@ unsigned long memory_size;  struct thread_info *__current_ti = &init_thread_union.thread_info;  struct task_struct *__current = &init_task; -#define mn10300_known_cpus 3 +#define mn10300_known_cpus 5  static const char *const mn10300_cputypes[] = { -	"am33v1", -	"am33v2", -	"am34v1", +	"am33-1", +	"am33-2", +	"am34-1", +	"am33-3", +	"am34-2",  	"unknown"  }; @@ -123,6 +125,7 @@ void __init setup_arch(char **cmdline_p)  	cpu_init();  	unit_setup(); +	smp_init_cpus();  	parse_mem_cmdline(cmdline_p);  	init_mm.start_code = (unsigned long)&_text; @@ -179,7 +182,6 @@ void __init setup_arch(char **cmdline_p)  void __init cpu_init(void)  {  	unsigned long cpurev = CPUREV, type; -	unsigned long base, size;  	type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;  	if (type > mn10300_known_cpus) @@ -189,47 +191,46 @@ void __init cpu_init(void)  	       mn10300_cputypes[type],  	       (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S); -	/* determine the memory size and base from the memory controller regs */ -	memory_size = 0; - -	base = SDBASE(0); -	if (base & SDBASE_CE) { -		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; -		size = ~size + 1; -		base &= SDBASE_CBA; +	get_mem_info(&phys_memory_base, &memory_size); +	phys_memory_end = phys_memory_base + memory_size; -		printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base); -		memory_size += size; -		phys_memory_base = base; -	} +	fpu_init_state(); +} -	base = SDBASE(1); -	if (base & SDBASE_CE) { -		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; -		size = ~size + 1; -		base &= SDBASE_CBA; +static struct cpu cpu_devices[NR_CPUS]; -		printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base); -		memory_size += size; -		if (phys_memory_base == 0) -			phys_memory_base = base; -	} +static int __init topology_init(void) +{ +	int i; -	phys_memory_end = phys_memory_base + memory_size; +	for_each_present_cpu(i) +		register_cpu(&cpu_devices[i], i); -#ifdef CONFIG_FPU -	fpu_init_state(); -#endif +	return 0;  } +subsys_initcall(topology_init); +  /*   * Get CPU information for use by the procfs.   */  static int show_cpuinfo(struct seq_file *m, void *v)  { +#ifdef CONFIG_SMP +	struct mn10300_cpuinfo *c = v; +	unsigned long cpu_id = c - cpu_data; +	unsigned long cpurev = c->type, type, icachesz, dcachesz; +#else  /* CONFIG_SMP */ +	unsigned long cpu_id = 0;  	unsigned long cpurev = CPUREV, type, icachesz, dcachesz; +#endif /* CONFIG_SMP */ -	type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S; +#ifdef CONFIG_SMP +	if (!cpu_online(cpu_id)) +		return 0; +#endif + +	type = (cpurev & CPUREV_TYPE) >> CPUREV_TYPE_S;  	if (type > mn10300_known_cpus)  		type = mn10300_known_cpus; @@ -244,13 +245,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)  		1024;  	seq_printf(m, -		   "processor  : 0\n" +		   "processor  : %ld\n"  		   "vendor_id  : Matsushita\n"  		   "cpu core   : %s\n"  		   "cpu rev    : %lu\n"  		   "model name : " PROCESSOR_MODEL_NAME		"\n"  		   "icache size: %lu\n"  		   "dcache size: %lu\n", +		   cpu_id,  		   mn10300_cputypes[type],  		   (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S,  		   icachesz, @@ -262,8 +264,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)  		   "bogomips   : %lu.%02lu\n\n",  		   MN10300_IOCLK / 1000000,  		   (MN10300_IOCLK / 10000) % 100, +#ifdef CONFIG_SMP +		   c->loops_per_jiffy / (500000 / HZ), +		   (c->loops_per_jiffy / (5000 / HZ)) % 100 +#else  /* CONFIG_SMP */  		   loops_per_jiffy / (500000 / HZ),  		   (loops_per_jiffy / (5000 / HZ)) % 100 +#endif /* CONFIG_SMP */  		   );  	return 0; diff --git a/arch/mn10300/kernel/smp-low.S b/arch/mn10300/kernel/smp-low.S new file mode 100644 index 00000000000..72938cefc05 --- /dev/null +++ b/arch/mn10300/kernel/smp-low.S @@ -0,0 +1,97 @@ +/* SMP IPI low-level handler + * + * Copyright (C) 2006-2007 Matsushita Electric Industrial Co., Ltd. + * All Rights Reserved. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/sys.h> +#include <linux/linkage.h> +#include <asm/smp.h> +#include <asm/system.h> +#include <asm/thread_info.h> +#include <asm/cpu-regs.h> +#include <proc/smp-regs.h> +#include <asm/asm-offsets.h> +#include <asm/frame.inc> + +	.am33_2 + +############################################################################### +# +# IPI interrupt handler +# +############################################################################### +	.globl mn10300_low_ipi_handler +mn10300_low_ipi_handler: +	add	-4,sp +	mov	d0,(sp) +	movhu	(IAGR),d0 +	and	IAGR_GN,d0 +	lsr	0x2,d0 +#ifdef CONFIG_MN10300_CACHE_ENABLED +	cmp	FLUSH_CACHE_IPI,d0 +	beq	mn10300_flush_cache_ipi +#endif +	cmp	SMP_BOOT_IRQ,d0 +	beq	mn10300_smp_boot_ipi +	/* OTHERS */ +	mov	(sp),d0 +	add	4,sp +#ifdef CONFIG_GDBSTUB +	jmp	gdbstub_io_rx_handler +#else +	jmp	end +#endif + +############################################################################### +# +# Cache flush IPI interrupt handler +# +############################################################################### +#ifdef CONFIG_MN10300_CACHE_ENABLED +mn10300_flush_cache_ipi: +	mov	(sp),d0 +	add	4,sp + +	/* FLUSH_CACHE_IPI */ +	add	-4,sp +	SAVE_ALL +	mov	GxICR_DETECT,d2 +	movbu	d2,(GxICR(FLUSH_CACHE_IPI))	# ACK the interrupt +	movhu	(GxICR(FLUSH_CACHE_IPI)),d2 +	call	smp_cache_interrupt[],0 +	RESTORE_ALL +	jmp	end +#endif + +############################################################################### +# +# SMP boot CPU IPI interrupt handler +# +############################################################################### +mn10300_smp_boot_ipi: +	/* clear interrupt */ +	movhu	(GxICR(SMP_BOOT_IRQ)),d0 +	and	~GxICR_REQUEST,d0 +	movhu	d0,(GxICR(SMP_BOOT_IRQ)) +	mov	(sp),d0 +	add	4,sp + +	# get stack +	mov	(CPUID),a0 +	add	-1,a0 +	add	a0,a0 +	add	a0,a0 +	mov	(start_stack,a0),a0 +	mov	a0,sp +	jmp	initialize_secondary + + +# Jump here after RTI to suppress the icache lookahead +end: diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c new file mode 100644 index 00000000000..b80234c28e0 --- /dev/null +++ b/arch/mn10300/kernel/smp.c @@ -0,0 +1,1141 @@ +/* SMP support routines. + * + * Copyright (C) 2006-2008 Panasonic Corporation + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/cpumask.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/profile.h> +#include <linux/smp.h> +#include <asm/tlbflush.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/processor.h> +#include <asm/bug.h> +#include <asm/exceptions.h> +#include <asm/hardirq.h> +#include <asm/fpu.h> +#include <asm/mmu_context.h> +#include <asm/thread_info.h> +#include <asm/cpu-regs.h> +#include <asm/intctl-regs.h> +#include "internal.h" + +#ifdef CONFIG_HOTPLUG_CPU +#include <linux/cpu.h> +#include <asm/cacheflush.h> + +static unsigned long sleep_mode[NR_CPUS]; + +static void run_sleep_cpu(unsigned int cpu); +static void run_wakeup_cpu(unsigned int cpu); +#endif /* CONFIG_HOTPLUG_CPU */ + +/* + * Debug Message function + */ + +#undef DEBUG_SMP +#ifdef DEBUG_SMP +#define Dprintk(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__) +#else +#define Dprintk(fmt, ...) no_printk(KERN_DEBUG fmt, ##__VA_ARGS__) +#endif + +/* timeout value in msec for smp_nmi_call_function. zero is no timeout. */ +#define	CALL_FUNCTION_NMI_IPI_TIMEOUT	0 + +/* + * Structure and data for smp_nmi_call_function(). + */ +struct nmi_call_data_struct { +	smp_call_func_t	func; +	void		*info; +	cpumask_t	started; +	cpumask_t	finished; +	int		wait; +	char		size_alignment[0] +	__attribute__ ((__aligned__(SMP_CACHE_BYTES))); +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); + +static DEFINE_SPINLOCK(smp_nmi_call_lock); +static struct nmi_call_data_struct *nmi_call_data; + +/* + * Data structures and variables + */ +static cpumask_t cpu_callin_map;	/* Bitmask of callin CPUs */ +static cpumask_t cpu_callout_map;	/* Bitmask of callout CPUs */ +cpumask_t cpu_boot_map;			/* Bitmask of boot APs */ +unsigned long start_stack[NR_CPUS - 1]; + +/* + * Per CPU parameters + */ +struct mn10300_cpuinfo cpu_data[NR_CPUS] __cacheline_aligned; + +static int cpucount;			/* The count of boot CPUs */ +static cpumask_t smp_commenced_mask; +cpumask_t cpu_initialized __initdata = CPU_MASK_NONE; + +/* + * Function Prototypes + */ +static int do_boot_cpu(int); +static void smp_show_cpu_info(int cpu_id); +static void smp_callin(void); +static void smp_online(void); +static void smp_store_cpu_info(int); +static void smp_cpu_init(void); +static void smp_tune_scheduling(void); +static void send_IPI_mask(const cpumask_t *cpumask, int irq); +static void init_ipi(void); + +/* + * IPI Initialization interrupt definitions + */ +static void mn10300_ipi_disable(unsigned int irq); +static void mn10300_ipi_enable(unsigned int irq); +static void mn10300_ipi_ack(unsigned int irq); +static void mn10300_ipi_nop(unsigned int irq); + +static struct irq_chip mn10300_ipi_type = { +	.name		= "cpu_ipi", +	.disable	= mn10300_ipi_disable, +	.enable		= mn10300_ipi_enable, +	.ack		= mn10300_ipi_ack, +	.eoi		= mn10300_ipi_nop +}; + +static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id); +static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id); +static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id); + +static struct irqaction reschedule_ipi = { +	.handler	= smp_reschedule_interrupt, +	.name		= "smp reschedule IPI" +}; +static struct irqaction call_function_ipi = { +	.handler	= smp_call_function_interrupt, +	.name		= "smp call function IPI" +}; +static struct irqaction local_timer_ipi = { +	.handler	= smp_ipi_timer_interrupt, +	.flags		= IRQF_DISABLED, +	.name		= "smp local timer IPI" +}; + +/** + * init_ipi - Initialise the IPI mechanism + */ +static void init_ipi(void) +{ +	unsigned long flags; +	u16 tmp16; + +	/* set up the reschedule IPI */ +	set_irq_chip_and_handler(RESCHEDULE_IPI, +				 &mn10300_ipi_type, handle_percpu_irq); +	setup_irq(RESCHEDULE_IPI, &reschedule_ipi); +	set_intr_level(RESCHEDULE_IPI, RESCHEDULE_GxICR_LV); +	mn10300_ipi_enable(RESCHEDULE_IPI); + +	/* set up the call function IPI */ +	set_irq_chip_and_handler(CALL_FUNC_SINGLE_IPI, +				 &mn10300_ipi_type, handle_percpu_irq); +	setup_irq(CALL_FUNC_SINGLE_IPI, &call_function_ipi); +	set_intr_level(CALL_FUNC_SINGLE_IPI, CALL_FUNCTION_GxICR_LV); +	mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI); + +	/* set up the local timer IPI */ +	set_irq_chip_and_handler(LOCAL_TIMER_IPI, +				 &mn10300_ipi_type, handle_percpu_irq); +	setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi); +	set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV); +	mn10300_ipi_enable(LOCAL_TIMER_IPI); + +#ifdef CONFIG_MN10300_CACHE_ENABLED +	/* set up the cache flush IPI */ +	flags = arch_local_cli_save(); +	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(FLUSH_CACHE_GxICR_LV), +			mn10300_low_ipi_handler); +	GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT; +	mn10300_ipi_enable(FLUSH_CACHE_IPI); +	arch_local_irq_restore(flags); +#endif + +	/* set up the NMI call function IPI */ +	flags = arch_local_cli_save(); +	GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; +	tmp16 = GxICR(CALL_FUNCTION_NMI_IPI); +	arch_local_irq_restore(flags); + +	/* set up the SMP boot IPI */ +	flags = arch_local_cli_save(); +	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(SMP_BOOT_GxICR_LV), +			mn10300_low_ipi_handler); +	arch_local_irq_restore(flags); +} + +/** + * mn10300_ipi_shutdown - Shut down handling of an IPI + * @irq: The IPI to be shut down. + */ +static void mn10300_ipi_shutdown(unsigned int irq) +{ +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); + +	tmp = GxICR(irq); +	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; +	tmp = GxICR(irq); + +	arch_local_irq_restore(flags); +} + +/** + * mn10300_ipi_enable - Enable an IPI + * @irq: The IPI to be enabled. + */ +static void mn10300_ipi_enable(unsigned int irq) +{ +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); + +	tmp = GxICR(irq); +	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE; +	tmp = GxICR(irq); + +	arch_local_irq_restore(flags); +} + +/** + * mn10300_ipi_disable - Disable an IPI + * @irq: The IPI to be disabled. + */ +static void mn10300_ipi_disable(unsigned int irq) +{ +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); + +	tmp = GxICR(irq); +	GxICR(irq) = tmp & GxICR_LEVEL; +	tmp = GxICR(irq); + +	arch_local_irq_restore(flags); +} + +/** + * mn10300_ipi_ack - Acknowledge an IPI interrupt in the PIC + * @irq: The IPI to be acknowledged. + * + * Clear the interrupt detection flag for the IPI on the appropriate interrupt + * channel in the PIC. + */ +static void mn10300_ipi_ack(unsigned int irq) +{ +	unsigned long flags; +	u16 tmp; + +	flags = arch_local_cli_save(); +	GxICR_u8(irq) = GxICR_DETECT; +	tmp = GxICR(irq); +	arch_local_irq_restore(flags); +} + +/** + * mn10300_ipi_nop - Dummy IPI action + * @irq: The IPI to be acted upon. + */ +static void mn10300_ipi_nop(unsigned int irq) +{ +} + +/** + * send_IPI_mask - Send IPIs to all CPUs in list + * @cpumask: The list of CPUs to target. + * @irq: The IPI request to be sent. + * + * Send the specified IPI to all the CPUs in the list, not waiting for them to + * finish before returning.  The caller is responsible for synchronisation if + * that is needed. + */ +static void send_IPI_mask(const cpumask_t *cpumask, int irq) +{ +	int i; +	u16 tmp; + +	for (i = 0; i < NR_CPUS; i++) { +		if (cpu_isset(i, *cpumask)) { +			/* send IPI */ +			tmp = CROSS_GxICR(irq, i); +			CROSS_GxICR(irq, i) = +				tmp | GxICR_REQUEST | GxICR_DETECT; +			tmp = CROSS_GxICR(irq, i); /* flush write buffer */ +		} +	} +} + +/** + * send_IPI_self - Send an IPI to this CPU. + * @irq: The IPI request to be sent. + * + * Send the specified IPI to the current CPU. + */ +void send_IPI_self(int irq) +{ +	send_IPI_mask(cpumask_of(smp_processor_id()), irq); +} + +/** + * send_IPI_allbutself - Send IPIs to all the other CPUs. + * @irq: The IPI request to be sent. + * + * Send the specified IPI to all CPUs in the system barring the current one, + * not waiting for them to finish before returning.  The caller is responsible + * for synchronisation if that is needed. + */ +void send_IPI_allbutself(int irq) +{ +	cpumask_t cpumask; + +	cpumask = cpu_online_map; +	cpu_clear(smp_processor_id(), cpumask); +	send_IPI_mask(&cpumask, irq); +} + +void arch_send_call_function_ipi_mask(const struct cpumask *mask) +{ +	BUG(); +	/*send_IPI_mask(mask, CALL_FUNCTION_IPI);*/ +} + +void arch_send_call_function_single_ipi(int cpu) +{ +	send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI); +} + +/** + * smp_send_reschedule - Send reschedule IPI to a CPU + * @cpu: The CPU to target. + */ +void smp_send_reschedule(int cpu) +{ +	send_IPI_mask(cpumask_of(cpu), RESCHEDULE_IPI); +} + +/** + * smp_nmi_call_function - Send a call function NMI IPI to all CPUs + * @func: The function to ask to be run. + * @info: The context data to pass to that function. + * @wait: If true, wait (atomically) until function is run on all CPUs. + * + * Send a non-maskable request to all CPUs in the system, requesting them to + * run the specified function with the given context data, and, potentially, to + * wait for completion of that function on all CPUs. + * + * Returns 0 if successful, -ETIMEDOUT if we were asked to wait, but hit the + * timeout. + */ +int smp_nmi_call_function(smp_call_func_t func, void *info, int wait) +{ +	struct nmi_call_data_struct data; +	unsigned long flags; +	unsigned int cnt; +	int cpus, ret = 0; + +	cpus = num_online_cpus() - 1; +	if (cpus < 1) +		return 0; + +	data.func = func; +	data.info = info; +	data.started = cpu_online_map; +	cpu_clear(smp_processor_id(), data.started); +	data.wait = wait; +	if (wait) +		data.finished = data.started; + +	spin_lock_irqsave(&smp_nmi_call_lock, flags); +	nmi_call_data = &data; +	smp_mb(); + +	/* Send a message to all other CPUs and wait for them to respond */ +	send_IPI_allbutself(CALL_FUNCTION_NMI_IPI); + +	/* Wait for response */ +	if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) { +		for (cnt = 0; +		     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT && +			     !cpus_empty(data.started); +		     cnt++) +			mdelay(1); + +		if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) { +			for (cnt = 0; +			     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT && +				     !cpus_empty(data.finished); +			     cnt++) +				mdelay(1); +		} + +		if (cnt >= CALL_FUNCTION_NMI_IPI_TIMEOUT) +			ret = -ETIMEDOUT; + +	} else { +		/* If timeout value is zero, wait until cpumask has been +		 * cleared */ +		while (!cpus_empty(data.started)) +			barrier(); +		if (wait) +			while (!cpus_empty(data.finished)) +				barrier(); +	} + +	spin_unlock_irqrestore(&smp_nmi_call_lock, flags); +	return ret; +} + +/** + * stop_this_cpu - Callback to stop a CPU. + * @unused: Callback context (ignored). + */ +void stop_this_cpu(void *unused) +{ +	static volatile int stopflag; +	unsigned long flags; + +#ifdef CONFIG_GDBSTUB +	/* In case of single stepping smp_send_stop by other CPU, +	 * clear procindebug to avoid deadlock. +	 */ +	atomic_set(&procindebug[smp_processor_id()], 0); +#endif	/* CONFIG_GDBSTUB */ + +	flags = arch_local_cli_save(); +	cpu_clear(smp_processor_id(), cpu_online_map); + +	while (!stopflag) +		cpu_relax(); + +	cpu_set(smp_processor_id(), cpu_online_map); +	arch_local_irq_restore(flags); +} + +/** + * smp_send_stop - Send a stop request to all CPUs. + */ +void smp_send_stop(void) +{ +	smp_nmi_call_function(stop_this_cpu, NULL, 0); +} + +/** + * smp_reschedule_interrupt - Reschedule IPI handler + * @irq: The interrupt number. + * @dev_id: The device ID. + * + * We need do nothing here, since the scheduling will be effected on our way + * back through entry.S. + * + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. + */ +static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) +{ +	/* do nothing */ +	return IRQ_HANDLED; +} + +/** + * smp_call_function_interrupt - Call function IPI handler + * @irq: The interrupt number. + * @dev_id: The device ID. + * + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. + */ +static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id) +{ +	/* generic_smp_call_function_interrupt(); */ +	generic_smp_call_function_single_interrupt(); +	return IRQ_HANDLED; +} + +/** + * smp_nmi_call_function_interrupt - Non-maskable call function IPI handler + */ +void smp_nmi_call_function_interrupt(void) +{ +	smp_call_func_t func = nmi_call_data->func; +	void *info = nmi_call_data->info; +	int wait = nmi_call_data->wait; + +	/* Notify the initiating CPU that I've grabbed the data and am about to +	 * execute the function +	 */ +	smp_mb(); +	cpu_clear(smp_processor_id(), nmi_call_data->started); +	(*func)(info); + +	if (wait) { +		smp_mb(); +		cpu_clear(smp_processor_id(), nmi_call_data->finished); +	} +} + +/** + * smp_ipi_timer_interrupt - Local timer IPI handler + * @irq: The interrupt number. + * @dev_id: The device ID. + * + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. + */ +static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id) +{ +	return local_timer_interrupt(); +} + +void __init smp_init_cpus(void) +{ +	int i; +	for (i = 0; i < NR_CPUS; i++) { +		set_cpu_possible(i, true); +		set_cpu_present(i, true); +	} +} + +/** + * smp_cpu_init - Initialise AP in start_secondary. + * + * For this Application Processor, set up init_mm, initialise FPU and set + * interrupt level 0-6 setting. + */ +static void __init smp_cpu_init(void) +{ +	unsigned long flags; +	int cpu_id = smp_processor_id(); +	u16 tmp16; + +	if (test_and_set_bit(cpu_id, &cpu_initialized)) { +		printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id); +		for (;;) +			local_irq_enable(); +	} +	printk(KERN_INFO "Initializing CPU#%d\n", cpu_id); + +	atomic_inc(&init_mm.mm_count); +	current->active_mm = &init_mm; +	BUG_ON(current->mm); + +	enter_lazy_tlb(&init_mm, current); + +	/* Force FPU initialization */ +	clear_using_fpu(current); + +	GxICR(CALL_FUNC_SINGLE_IPI) = CALL_FUNCTION_GxICR_LV | GxICR_DETECT; +	mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI); + +	GxICR(LOCAL_TIMER_IPI) = LOCAL_TIMER_GxICR_LV | GxICR_DETECT; +	mn10300_ipi_enable(LOCAL_TIMER_IPI); + +	GxICR(RESCHEDULE_IPI) = RESCHEDULE_GxICR_LV | GxICR_DETECT; +	mn10300_ipi_enable(RESCHEDULE_IPI); + +#ifdef CONFIG_MN10300_CACHE_ENABLED +	GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT; +	mn10300_ipi_enable(FLUSH_CACHE_IPI); +#endif + +	mn10300_ipi_shutdown(SMP_BOOT_IRQ); + +	/* Set up the non-maskable call function IPI */ +	flags = arch_local_cli_save(); +	GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; +	tmp16 = GxICR(CALL_FUNCTION_NMI_IPI); +	arch_local_irq_restore(flags); +} + +/** + * smp_prepare_cpu_init - Initialise CPU in startup_secondary + * + * Set interrupt level 0-6 setting and init ICR of gdbstub. + */ +void smp_prepare_cpu_init(void) +{ +	int loop; + +	/* Set the interrupt vector registers */ +	IVAR0 = EXCEP_IRQ_LEVEL0; +	IVAR1 = EXCEP_IRQ_LEVEL1; +	IVAR2 = EXCEP_IRQ_LEVEL2; +	IVAR3 = EXCEP_IRQ_LEVEL3; +	IVAR4 = EXCEP_IRQ_LEVEL4; +	IVAR5 = EXCEP_IRQ_LEVEL5; +	IVAR6 = EXCEP_IRQ_LEVEL6; + +	/* Disable all interrupts and set to priority 6 (lowest) */ +	for (loop = 0; loop < GxICR_NUM_IRQS; loop++) +		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; + +#ifdef CONFIG_GDBSTUB +	/* initialise GDB-stub */ +	do { +		unsigned long flags; +		u16 tmp16; + +		flags = arch_local_cli_save(); +		GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; +		tmp16 = GxICR(GDB_NMI_IPI); +		arch_local_irq_restore(flags); +	} while (0); +#endif +} + +/** + * start_secondary - Activate a secondary CPU (AP) + * @unused: Thread parameter (ignored). + */ +int __init start_secondary(void *unused) +{ +	smp_cpu_init(); + +	smp_callin(); +	while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) +		cpu_relax(); + +	local_flush_tlb(); +	preempt_disable(); +	smp_online(); + +	cpu_idle(); +	return 0; +} + +/** + * smp_prepare_cpus - Boot up secondary CPUs (APs) + * @max_cpus: Maximum number of CPUs to boot. + * + * Call do_boot_cpu, and boot up APs. + */ +void __init smp_prepare_cpus(unsigned int max_cpus) +{ +	int phy_id; + +	/* Setup boot CPU information */ +	smp_store_cpu_info(0); +	smp_tune_scheduling(); + +	init_ipi(); + +	/* If SMP should be disabled, then finish */ +	if (max_cpus == 0) { +		printk(KERN_INFO "SMP mode deactivated.\n"); +		goto smp_done; +	} + +	/* Boot secondary CPUs (for which phy_id > 0) */ +	for (phy_id = 0; phy_id < NR_CPUS; phy_id++) { +		/* Don't boot primary CPU */ +		if (max_cpus <= cpucount + 1) +			continue; +		if (phy_id != 0) +			do_boot_cpu(phy_id); +		set_cpu_possible(phy_id, true); +		smp_show_cpu_info(phy_id); +	} + +smp_done: +	Dprintk("Boot done.\n"); +} + +/** + * smp_store_cpu_info - Save a CPU's information + * @cpu: The CPU to save for. + * + * Save boot_cpu_data and jiffy for the specified CPU. + */ +static void __init smp_store_cpu_info(int cpu) +{ +	struct mn10300_cpuinfo *ci = &cpu_data[cpu]; + +	*ci = boot_cpu_data; +	ci->loops_per_jiffy = loops_per_jiffy; +	ci->type = CPUREV; +} + +/** + * smp_tune_scheduling - Set time slice value + * + * Nothing to do here. + */ +static void __init smp_tune_scheduling(void) +{ +} + +/** + * do_boot_cpu: Boot up one CPU + * @phy_id: Physical ID of CPU to boot. + * + * Send an IPI to a secondary CPU to boot it.  Returns 0 on success, 1 + * otherwise. + */ +static int __init do_boot_cpu(int phy_id) +{ +	struct task_struct *idle; +	unsigned long send_status, callin_status; +	int timeout, cpu_id; + +	send_status = GxICR_REQUEST; +	callin_status = 0; +	timeout = 0; +	cpu_id = phy_id; + +	cpucount++; + +	/* Create idle thread for this CPU */ +	idle = fork_idle(cpu_id); +	if (IS_ERR(idle)) +		panic("Failed fork for CPU#%d.", cpu_id); + +	idle->thread.pc = (unsigned long)start_secondary; + +	printk(KERN_NOTICE "Booting CPU#%d\n", cpu_id); +	start_stack[cpu_id - 1] = idle->thread.sp; + +	task_thread_info(idle)->cpu = cpu_id; + +	/* Send boot IPI to AP */ +	send_IPI_mask(cpumask_of(phy_id), SMP_BOOT_IRQ); + +	Dprintk("Waiting for send to finish...\n"); + +	/* Wait for AP's IPI receive in 100[ms] */ +	do { +		udelay(1000); +		send_status = +			CROSS_GxICR(SMP_BOOT_IRQ, phy_id) & GxICR_REQUEST; +	} while (send_status == GxICR_REQUEST && timeout++ < 100); + +	Dprintk("Waiting for cpu_callin_map.\n"); + +	if (send_status == 0) { +		/* Allow AP to start initializing */ +		cpu_set(cpu_id, cpu_callout_map); + +		/* Wait for setting cpu_callin_map */ +		timeout = 0; +		do { +			udelay(1000); +			callin_status = cpu_isset(cpu_id, cpu_callin_map); +		} while (callin_status == 0 && timeout++ < 5000); + +		if (callin_status == 0) +			Dprintk("Not responding.\n"); +	} else { +		printk(KERN_WARNING "IPI not delivered.\n"); +	} + +	if (send_status == GxICR_REQUEST || callin_status == 0) { +		cpu_clear(cpu_id, cpu_callout_map); +		cpu_clear(cpu_id, cpu_callin_map); +		cpu_clear(cpu_id, cpu_initialized); +		cpucount--; +		return 1; +	} +	return 0; +} + +/** + * smp_show_cpu_info - Show SMP CPU information + * @cpu: The CPU of interest. + */ +static void __init smp_show_cpu_info(int cpu) +{ +	struct mn10300_cpuinfo *ci = &cpu_data[cpu]; + +	printk(KERN_INFO +	       "CPU#%d : ioclk speed: %lu.%02luMHz : bogomips : %lu.%02lu\n", +	       cpu, +	       MN10300_IOCLK / 1000000, +	       (MN10300_IOCLK / 10000) % 100, +	       ci->loops_per_jiffy / (500000 / HZ), +	       (ci->loops_per_jiffy / (5000 / HZ)) % 100); +} + +/** + * smp_callin - Set cpu_callin_map of the current CPU ID + */ +static void __init smp_callin(void) +{ +	unsigned long timeout; +	int cpu; + +	cpu = smp_processor_id(); +	timeout = jiffies + (2 * HZ); + +	if (cpu_isset(cpu, cpu_callin_map)) { +		printk(KERN_ERR "CPU#%d already present.\n", cpu); +		BUG(); +	} +	Dprintk("CPU#%d waiting for CALLOUT\n", cpu); + +	/* Wait for AP startup 2s total */ +	while (time_before(jiffies, timeout)) { +		if (cpu_isset(cpu, cpu_callout_map)) +			break; +		cpu_relax(); +	} + +	if (!time_before(jiffies, timeout)) { +		printk(KERN_ERR +		       "BUG: CPU#%d started up but did not get a callout!\n", +		       cpu); +		BUG(); +	} + +#ifdef CONFIG_CALIBRATE_DELAY +	calibrate_delay();		/* Get our bogomips */ +#endif + +	/* Save our processor parameters */ +	smp_store_cpu_info(cpu); + +	/* Allow the boot processor to continue */ +	cpu_set(cpu, cpu_callin_map); +} + +/** + * smp_online - Set cpu_online_map + */ +static void __init smp_online(void) +{ +	int cpu; + +	cpu = smp_processor_id(); + +	local_irq_enable(); + +	cpu_set(cpu, cpu_online_map); +	smp_wmb(); +} + +/** + * smp_cpus_done - + * @max_cpus: Maximum CPU count. + * + * Do nothing. + */ +void __init smp_cpus_done(unsigned int max_cpus) +{ +} + +/* + * smp_prepare_boot_cpu - Set up stuff for the boot processor. + * + * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot + * processor (CPU 0). + */ +void __devinit smp_prepare_boot_cpu(void) +{ +	cpu_set(0, cpu_callout_map); +	cpu_set(0, cpu_callin_map); +	current_thread_info()->cpu = 0; +} + +/* + * initialize_secondary - Initialise a secondary CPU (Application Processor). + * + * Set SP register and jump to thread's PC address. + */ +void initialize_secondary(void) +{ +	asm volatile ( +		"mov	%0,sp	\n" +		"jmp	(%1)	\n" +		: +		: "a"(current->thread.sp), "a"(current->thread.pc)); +} + +/** + * __cpu_up - Set smp_commenced_mask for the nominated CPU + * @cpu: The target CPU. + */ +int __devinit __cpu_up(unsigned int cpu) +{ +	int timeout; + +#ifdef CONFIG_HOTPLUG_CPU +	if (num_online_cpus() == 1) +		disable_hlt(); +	if (sleep_mode[cpu]) +		run_wakeup_cpu(cpu); +#endif /* CONFIG_HOTPLUG_CPU */ + +	cpu_set(cpu, smp_commenced_mask); + +	/* Wait 5s total for a response */ +	for (timeout = 0 ; timeout < 5000 ; timeout++) { +		if (cpu_isset(cpu, cpu_online_map)) +			break; +		udelay(1000); +	} + +	BUG_ON(!cpu_isset(cpu, cpu_online_map)); +	return 0; +} + +/** + * setup_profiling_timer - Set up the profiling timer + * @multiplier - The frequency multiplier to use + * + * The frequency of the profiling timer can be changed by writing a multiplier + * value into /proc/profile. + */ +int setup_profiling_timer(unsigned int multiplier) +{ +	return -EINVAL; +} + +/* + * CPU hotplug routines + */ +#ifdef CONFIG_HOTPLUG_CPU + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static int __init topology_init(void) +{ +	int cpu, ret; + +	for_each_cpu(cpu) { +		ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL); +		if (ret) +			printk(KERN_WARNING +			       "topology_init: register_cpu %d failed (%d)\n", +			       cpu, ret); +	} +	return 0; +} + +subsys_initcall(topology_init); + +int __cpu_disable(void) +{ +	int cpu = smp_processor_id(); +	if (cpu == 0) +		return -EBUSY; + +	migrate_irqs(); +	cpu_clear(cpu, current->active_mm->cpu_vm_mask); +	return 0; +} + +void __cpu_die(unsigned int cpu) +{ +	run_sleep_cpu(cpu); + +	if (num_online_cpus() == 1) +		enable_hlt(); +} + +#ifdef CONFIG_MN10300_CACHE_ENABLED +static inline void hotplug_cpu_disable_cache(void) +{ +	int tmp; +	asm volatile( +		"	movhu	(%1),%0	\n" +		"	and	%2,%0	\n" +		"	movhu	%0,(%1)	\n" +		"1:	movhu	(%1),%0	\n" +		"	btst	%3,%0	\n" +		"	bne	1b	\n" +		: "=&r"(tmp) +		: "a"(&CHCTR), +		  "i"(~(CHCTR_ICEN | CHCTR_DCEN)), +		  "i"(CHCTR_ICBUSY | CHCTR_DCBUSY) +		: "memory", "cc"); +} + +static inline void hotplug_cpu_enable_cache(void) +{ +	int tmp; +	asm volatile( +		"movhu	(%1),%0	\n" +		"or	%2,%0	\n" +		"movhu	%0,(%1)	\n" +		: "=&r"(tmp) +		: "a"(&CHCTR), +		  "i"(CHCTR_ICEN | CHCTR_DCEN) +		: "memory", "cc"); +} + +static inline void hotplug_cpu_invalidate_cache(void) +{ +	int tmp; +	asm volatile ( +		"movhu	(%1),%0	\n" +		"or	%2,%0	\n" +		"movhu	%0,(%1)	\n" +		: "=&r"(tmp) +		: "a"(&CHCTR), +		  "i"(CHCTR_ICINV | CHCTR_DCINV) +		: "cc"); +} + +#else /* CONFIG_MN10300_CACHE_ENABLED */ +#define hotplug_cpu_disable_cache()	do {} while (0) +#define hotplug_cpu_enable_cache()	do {} while (0) +#define hotplug_cpu_invalidate_cache()	do {} while (0) +#endif /* CONFIG_MN10300_CACHE_ENABLED */ + +/** + * hotplug_cpu_nmi_call_function - Call a function on other CPUs for hotplug + * @cpumask: List of target CPUs. + * @func: The function to call on those CPUs. + * @info: The context data for the function to be called. + * @wait: Whether to wait for the calls to complete. + * + * Non-maskably call a function on another CPU for hotplug purposes. + * + * This function must be called with maskable interrupts disabled. + */ +static int hotplug_cpu_nmi_call_function(cpumask_t cpumask, +					 smp_call_func_t func, void *info, +					 int wait) +{ +	/* +	 * The address and the size of nmi_call_func_mask_data +	 * need to be aligned on L1_CACHE_BYTES. +	 */ +	static struct nmi_call_data_struct nmi_call_func_mask_data +		__cacheline_aligned; +	unsigned long start, end; + +	start = (unsigned long)&nmi_call_func_mask_data; +	end = start + sizeof(struct nmi_call_data_struct); + +	nmi_call_func_mask_data.func = func; +	nmi_call_func_mask_data.info = info; +	nmi_call_func_mask_data.started = cpumask; +	nmi_call_func_mask_data.wait = wait; +	if (wait) +		nmi_call_func_mask_data.finished = cpumask; + +	spin_lock(&smp_nmi_call_lock); +	nmi_call_data = &nmi_call_func_mask_data; +	mn10300_local_dcache_flush_range(start, end); +	smp_wmb(); + +	send_IPI_mask(cpumask, CALL_FUNCTION_NMI_IPI); + +	do { +		mn10300_local_dcache_inv_range(start, end); +		barrier(); +	} while (!cpus_empty(nmi_call_func_mask_data.started)); + +	if (wait) { +		do { +			mn10300_local_dcache_inv_range(start, end); +			barrier(); +		} while (!cpus_empty(nmi_call_func_mask_data.finished)); +	} + +	spin_unlock(&smp_nmi_call_lock); +	return 0; +} + +static void restart_wakeup_cpu(void) +{ +	unsigned int cpu = smp_processor_id(); + +	cpu_set(cpu, cpu_callin_map); +	local_flush_tlb(); +	cpu_set(cpu, cpu_online_map); +	smp_wmb(); +} + +static void prepare_sleep_cpu(void *unused) +{ +	sleep_mode[smp_processor_id()] = 1; +	smp_mb(); +	mn10300_local_dcache_flush_inv(); +	hotplug_cpu_disable_cache(); +	hotplug_cpu_invalidate_cache(); +} + +/* when this function called, IE=0, NMID=0. */ +static void sleep_cpu(void *unused) +{ +	unsigned int cpu_id = smp_processor_id(); +	/* +	 * CALL_FUNCTION_NMI_IPI for wakeup_cpu() shall not be requested, +	 * before this cpu goes in SLEEP mode. +	 */ +	do { +		smp_mb(); +		__sleep_cpu(); +	} while (sleep_mode[cpu_id]); +	restart_wakeup_cpu(); +} + +static void run_sleep_cpu(unsigned int cpu) +{ +	unsigned long flags; +	cpumask_t cpumask = cpumask_of(cpu); + +	flags = arch_local_cli_save(); +	hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1); +	hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0); +	udelay(1);		/* delay for the cpu to sleep. */ +	arch_local_irq_restore(flags); +} + +static void wakeup_cpu(void) +{ +	hotplug_cpu_invalidate_cache(); +	hotplug_cpu_enable_cache(); +	smp_mb(); +	sleep_mode[smp_processor_id()] = 0; +} + +static void run_wakeup_cpu(unsigned int cpu) +{ +	unsigned long flags; + +	flags = arch_local_cli_save(); +#if NR_CPUS == 2 +	mn10300_local_dcache_flush_inv(); +#else +	/* +	 * Before waking up the cpu, +	 * all online cpus should stop and flush D-Cache for global data. +	 */ +#error not support NR_CPUS > 2, when CONFIG_HOTPLUG_CPU=y. +#endif +	hotplug_cpu_nmi_call_function(cpumask_of(cpu), wakeup_cpu, NULL, 1); +	arch_local_irq_restore(flags); +} + +#endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/mn10300/kernel/switch_to.S b/arch/mn10300/kernel/switch_to.S index 630aad71b94..b08cb2e3aeb 100644 --- a/arch/mn10300/kernel/switch_to.S +++ b/arch/mn10300/kernel/switch_to.S @@ -15,6 +15,9 @@  #include <linux/linkage.h>  #include <asm/thread_info.h>  #include <asm/cpu-regs.h> +#ifdef CONFIG_SMP +#include <proc/smp-regs.h> +#endif /* CONFIG_SMP */  	.text @@ -35,7 +38,14 @@ ENTRY(__switch_to)  	mov	d1,a1  	# save prev context +#ifdef CONFIG_SMP +	mov	(CPUID),a2 +	add	a2,a2 +	add	a2,a2 +	mov	(___frame,a2),d0 +#else  /* CONFIG_SMP */  	mov	(__frame),d0 +#endif /* CONFIG_SMP */  	mov	d0,(THREAD_FRAME,a0)  	mov	__switch_back,d0  	mov	d0,(THREAD_PC,a0) @@ -59,7 +69,14 @@ ENTRY(__switch_to)  #endif  	mov	(THREAD_FRAME,a1),a2 +#ifdef CONFIG_SMP +	mov	(CPUID),a0 +	add	a0,a0 +	add	a0,a0 +	mov	a2,(___frame,a0) +#else  /* CONFIG_SMP */  	mov	a2,(__frame) +#endif /* CONFIG_SMP */  	mov	(THREAD_PC,a1),a2  	mov	d2,d0			# for ret_from_fork  	mov	d0,a0			# for __switch_to diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c index 0b5c856b426..0cb9bdb3b6b 100644 --- a/arch/mn10300/kernel/time.c +++ b/arch/mn10300/kernel/time.c @@ -22,12 +22,7 @@  #include <asm/processor.h>  #include <asm/intctl-regs.h>  #include <asm/rtc.h> - -#ifdef CONFIG_MN10300_RTC -unsigned long mn10300_ioclk;		/* system I/O clock frequency */ -unsigned long mn10300_iobclk;		/* system I/O clock frequency */ -unsigned long mn10300_tsc_per_HZ;	/* number of ioclks per jiffy */ -#endif /* CONFIG_MN10300_RTC */ +#include "internal.h"  static unsigned long mn10300_last_tsc;	/* time-stamp counter at last time  					 * interrupt occurred */ @@ -95,6 +90,19 @@ static void __init mn10300_sched_clock_init(void)  		__muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK);  } +/** + * local_timer_interrupt - Local timer interrupt handler + * + * Handle local timer interrupts for this CPU.  They may have been propagated + * to this CPU from the CPU that actually gets them by way of an IPI. + */ +irqreturn_t local_timer_interrupt(void) +{ +	profile_tick(CPU_PROFILING); +	update_process_times(user_mode(get_irq_regs())); +	return IRQ_HANDLED; +} +  /*   * advance the kernel's time keeping clocks (xtime and jiffies)   * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time @@ -103,6 +111,7 @@ static void __init mn10300_sched_clock_init(void)  static irqreturn_t timer_interrupt(int irq, void *dev_id)  {  	unsigned tsc, elapse; +	irqreturn_t ret;  	write_seqlock(&xtime_lock); @@ -114,15 +123,16 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)  		mn10300_last_tsc -= MN10300_TSC_PER_HZ;  		/* advance the kernel's time tracking system */ -		profile_tick(CPU_PROFILING);  		do_timer(1);  	}  	write_sequnlock(&xtime_lock); -	update_process_times(user_mode(get_irq_regs())); - -	return IRQ_HANDLED; +	ret = local_timer_interrupt(); +#ifdef CONFIG_SMP +	send_IPI_allbutself(LOCAL_TIMER_IPI); +#endif +	return ret;  }  /* @@ -148,7 +158,7 @@ void __init time_init(void)  	/* use timer 0 & 1 cascaded to tick at as close to HZ as possible */  	setup_irq(TMJCIRQ, &timer_irq); -	set_intr_level(TMJCIRQ, TMJCICR_LEVEL); +	set_intr_level(TMJCIRQ, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));  	startup_jiffies_counter(); diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c index 716a221df2f..c924a1dd332 100644 --- a/arch/mn10300/kernel/traps.c +++ b/arch/mn10300/kernel/traps.c @@ -45,8 +45,13 @@  #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"  #endif +#ifdef CONFIG_SMP +struct pt_regs *___frame[NR_CPUS]; /* current frame pointer */ +EXPORT_SYMBOL(___frame); +#else  /* CONFIG_SMP */  struct pt_regs *__frame; /* current frame pointer */  EXPORT_SYMBOL(__frame); +#endif /* CONFIG_SMP */  int kstack_depth_to_print = 24; @@ -221,11 +226,14 @@ void show_registers_only(struct pt_regs *regs)  	printk(KERN_EMERG "threadinfo=%p task=%p)\n",  	       current_thread_info(), current); -	if ((unsigned long) current >= 0x90000000UL && -	    (unsigned long) current < 0x94000000UL) +	if ((unsigned long) current >= PAGE_OFFSET && +	    (unsigned long) current < (unsigned long)high_memory)  		printk(KERN_EMERG "Process %s (pid: %d)\n",  		       current->comm, current->pid); +#ifdef CONFIG_SMP +	printk(KERN_EMERG "CPUID:  %08x\n", CPUID); +#endif  	printk(KERN_EMERG "CPUP:   %04hx\n", CPUP);  	printk(KERN_EMERG "TBR:    %08x\n", TBR);  	printk(KERN_EMERG "DEAR:   %08x\n", DEAR); @@ -521,8 +529,12 @@ void __init set_intr_stub(enum exception_code code, void *handler)  {  	unsigned long addr;  	u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code); +	unsigned long flags;  	addr = (unsigned long) handler - (unsigned long) vector; + +	flags = arch_local_cli_save(); +  	vector[0] = 0xdc;		/* JMP handler */  	vector[1] = addr;  	vector[2] = addr >> 8; @@ -532,6 +544,8 @@ void __init set_intr_stub(enum exception_code code, void *handler)  	vector[6] = 0xcb;  	vector[7] = 0xcb; +	arch_local_irq_restore(flags); +  #ifndef CONFIG_MN10300_CACHE_SNOOP  	mn10300_dcache_flush_inv();  	mn10300_icache_inv(); diff --git a/arch/mn10300/lib/delay.c b/arch/mn10300/lib/delay.c index fdf6f710f94..8e7ceb8ba33 100644 --- a/arch/mn10300/lib/delay.c +++ b/arch/mn10300/lib/delay.c @@ -38,14 +38,14 @@ EXPORT_SYMBOL(__delay);   */  void __udelay(unsigned long usecs)  { -	signed long ioclk, stop; +	unsigned long start, stop, cnt;  	/* usecs * CLK / 1E6 */  	stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000); -	stop = TMTSCBC - stop; +	start = TMTSCBC;  	do { -		ioclk = TMTSCBC; -	} while (stop < ioclk); +		cnt = start - TMTSCBC; +	} while (cnt < stop);  }  EXPORT_SYMBOL(__udelay); diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c index 906e4c8f9ab..59c3da49d9d 100644 --- a/arch/mn10300/mm/fault.c +++ b/arch/mn10300/mm/fault.c @@ -39,10 +39,6 @@ void bust_spinlocks(int yes)  {  	if (yes) {  		oops_in_progress = 1; -#ifdef CONFIG_SMP -		/* Many serial drivers do __global_cli() */ -		global_irq_lock = 0; -#endif  	} else {  		int loglevel_save = console_loglevel;  #ifdef CONFIG_VT @@ -334,10 +330,10 @@ no_context:   */  out_of_memory:  	up_read(&mm->mmap_sem); -	if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR) -		goto no_context; -	pagefault_out_of_memory(); -	return; +	printk(KERN_ALERT "VM: killing process %s\n", tsk->comm); +	if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) +		do_exit(SIGKILL); +	goto no_context;  do_sigbus:  	up_read(&mm->mmap_sem); diff --git a/arch/mn10300/proc-mn103e010/include/proc/clock.h b/arch/mn10300/proc-mn103e010/include/proc/clock.h index aa23e147d62..704a819f1f4 100644 --- a/arch/mn10300/proc-mn103e010/include/proc/clock.h +++ b/arch/mn10300/proc-mn103e010/include/proc/clock.h @@ -13,6 +13,4 @@  #include <unit/clock.h> -#define MN10300_WDCLK		MN10300_IOCLK -  #endif /* _ASM_PROC_CLOCK_H */ diff --git a/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h b/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h new file mode 100644 index 00000000000..f537801a44b --- /dev/null +++ b/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h @@ -0,0 +1,29 @@ +#ifndef _ASM_PROC_INTCTL_REGS_H +#define _ASM_PROC_INTCTL_REGS_H + +#ifndef _ASM_INTCTL_REGS_H +# error "please don't include this file directly" +#endif + +/* intr acceptance group reg */ +#define IAGR			__SYSREG(0xd4000100, u16) + +/* group number register */ +#define IAGR_GN			0x00fc + +#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3) + +#define __SET_XIRQ_TRIGGER(X, Y, Z)		\ +({						\ +	typeof(Z) x = (Z);			\ +	x &= ~(3 << ((X) * 2));			\ +	x |= ((Y) & 3) << ((X) * 2);		\ +	(Z) = x;				\ +}) + +/* external pin intr spec reg */ +#define EXTMD			__SYSREG(0xd4000200, u16) +#define GET_XIRQ_TRIGGER(X)	__GET_XIRQ_TRIGGER(X, EXTMD) +#define SET_XIRQ_TRIGGER(X, Y)	__SET_XIRQ_TRIGGER(X, Y, EXTMD) + +#endif /* _ASM_PROC_INTCTL_REGS_H */ diff --git a/arch/mn10300/proc-mn103e010/proc-init.c b/arch/mn10300/proc-mn103e010/proc-init.c index 0cee7878bee..27b97980dca 100644 --- a/arch/mn10300/proc-mn103e010/proc-init.c +++ b/arch/mn10300/proc-mn103e010/proc-init.c @@ -11,6 +11,7 @@  #include <linux/kernel.h>  #include <asm/fpu.h>  #include <asm/rtc.h> +#include <asm/busctl-regs.h>  /*   * initialise the on-silicon processor peripherals @@ -75,3 +76,37 @@ asmlinkage void __init processor_init(void)  	calibrate_clock();  } + +/* + * determine the memory size and base from the memory controller regs + */ +void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size) +{ +	unsigned long base, size; + +	*mem_base = 0; +	*mem_size = 0; + +	base = SDBASE(0); +	if (base & SDBASE_CE) { +		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; +		size = ~size + 1; +		base &= SDBASE_CBA; + +		printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base); +		*mem_size += size; +		*mem_base = base; +	} + +	base = SDBASE(1); +	if (base & SDBASE_CE) { +		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; +		size = ~size + 1; +		base &= SDBASE_CBA; + +		printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base); +		*mem_size += size; +		if (*mem_base == 0) +			*mem_base = base; +	} +} diff --git a/arch/mn10300/proc-mn2ws0050/Makefile b/arch/mn10300/proc-mn2ws0050/Makefile new file mode 100644 index 00000000000..d4ca13309a8 --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the linux kernel. +# + +obj-y   := proc-init.o diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h new file mode 100644 index 00000000000..cafd7b5b55b --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h @@ -0,0 +1,48 @@ +/* Cache specification + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + *  13-Nov-2006 MEI Add L1_CACHE_SHIFT_MAX definition. + *  29-Jul-2008 MEI Add define for MN10300_HAS_AREAPURGE_REG. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ASM_PROC_CACHE_H +#define _ASM_PROC_CACHE_H + +/* + * L1 cache + */ +#define L1_CACHE_NWAYS		4		/* number of ways in caches */ +#define L1_CACHE_NENTRIES	128		/* number of entries in each way */ +#define L1_CACHE_BYTES		32		/* bytes per entry */ +#define L1_CACHE_SHIFT		5		/* shift for bytes per entry */ +#define L1_CACHE_WAYDISP	0x1000		/* distance from one way to the next */ + +#define L1_CACHE_TAG_VALID	0x00000001	/* cache tag valid bit */ +#define L1_CACHE_TAG_DIRTY	0x00000008	/* data cache tag dirty bit */ +#define L1_CACHE_TAG_ENTRY	0x00000fe0	/* cache tag entry address mask */ +#define L1_CACHE_TAG_ADDRESS	0xfffff000	/* cache tag line address mask */ + +/* + * specification of the interval between interrupt checking intervals whilst + * managing the cache with the interrupts disabled + */ +#define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL	4 + +/* + * The size of range at which it becomes more economical to just flush the + * whole cache rather than trying to flush the specified range. + */ +#define MN10300_DCACHE_FLUSH_BORDER \ +	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) +#define MN10300_DCACHE_FLUSH_INV_BORDER	\ +	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) + +#endif /* _ASM_PROC_CACHE_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/clock.h b/arch/mn10300/proc-mn2ws0050/include/proc/clock.h new file mode 100644 index 00000000000..fe4c0a4a53a --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/clock.h @@ -0,0 +1,20 @@ +/* clock.h: proc-specific clocks + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + *  23-Feb-2007 MEI Delete define for watchdog timer. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ASM_PROC_CLOCK_H +#define _ASM_PROC_CLOCK_H + +#include <unit/clock.h> + +#endif /* _ASM_PROC_CLOCK_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h new file mode 100644 index 00000000000..4c4319e241d --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h @@ -0,0 +1,103 @@ +/* MN2WS0050 on-board DMA controller registers + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef _ASM_PROC_DMACTL_REGS_H +#define _ASM_PROC_DMACTL_REGS_H + +#include <asm/cpu-regs.h> + +#ifdef __KERNEL__ + +/* DMA registers */ +#define	DMxCTR(N)		__SYSREG(0xd4005000+(N*0x100), u32)	/* control reg */ +#define	DMxCTR_BG		0x0000001f	/* transfer request source */ +#define	DMxCTR_BG_SOFT		0x00000000	/* - software source */ +#define	DMxCTR_BG_SC0TX		0x00000002	/* - serial port 0 transmission */ +#define	DMxCTR_BG_SC0RX		0x00000003	/* - serial port 0 reception */ +#define	DMxCTR_BG_SC1TX		0x00000004	/* - serial port 1 transmission */ +#define	DMxCTR_BG_SC1RX		0x00000005	/* - serial port 1 reception */ +#define	DMxCTR_BG_SC2TX		0x00000006	/* - serial port 2 transmission */ +#define	DMxCTR_BG_SC2RX		0x00000007	/* - serial port 2 reception */ +#define	DMxCTR_BG_TM0UFLOW	0x00000008	/* - timer 0 underflow */ +#define	DMxCTR_BG_TM1UFLOW	0x00000009	/* - timer 1 underflow */ +#define	DMxCTR_BG_TM2UFLOW	0x0000000a	/* - timer 2 underflow */ +#define	DMxCTR_BG_TM3UFLOW	0x0000000b	/* - timer 3 underflow */ +#define	DMxCTR_BG_TM6ACMPCAP	0x0000000c	/* - timer 6A compare/capture */ +#define	DMxCTR_BG_RYBY		0x0000000d	/* - NAND Flash RY/BY request source */ +#define	DMxCTR_BG_RMC		0x0000000e	/* - remote controller output */ +#define	DMxCTR_BG_XIRQ12	0x00000011	/* - XIRQ12 pin interrupt source */ +#define	DMxCTR_BG_XIRQ13	0x00000012	/* - XIRQ13 pin interrupt source */ +#define	DMxCTR_BG_TCK		0x00000014	/* - tick timer underflow */ +#define	DMxCTR_BG_SC4TX		0x00000019	/* - serial port4 transmission */ +#define	DMxCTR_BG_SC4RX		0x0000001a	/* - serial port4 reception */ +#define	DMxCTR_BG_SC5TX		0x0000001b	/* - serial port5 transmission */ +#define	DMxCTR_BG_SC5RX		0x0000001c	/* - serial port5 reception */ +#define	DMxCTR_BG_SC6TX		0x0000001d	/* - serial port6 transmission */ +#define	DMxCTR_BG_SC6RX		0x0000001e	/* - serial port6 reception */ +#define	DMxCTR_BG_TMSUFLOW	0x0000001f	/* - timestamp timer underflow */ +#define	DMxCTR_SAM		0x00000060	/* DMA transfer src addr mode */ +#define	DMxCTR_SAM_INCR		0x00000000	/* - increment */ +#define	DMxCTR_SAM_DECR		0x00000020	/* - decrement */ +#define	DMxCTR_SAM_FIXED	0x00000040	/* - fixed */ +#define	DMxCTR_DAM		0x00000300	/* DMA transfer dest addr mode */ +#define	DMxCTR_DAM_INCR		0x00000000	/* - increment */ +#define	DMxCTR_DAM_DECR		0x00000100	/* - decrement */ +#define	DMxCTR_DAM_FIXED	0x00000200	/* - fixed */ +#define	DMxCTR_UT		0x00006000	/* DMA transfer unit */ +#define	DMxCTR_UT_1		0x00000000	/* - 1 byte */ +#define	DMxCTR_UT_2		0x00002000	/* - 2 byte */ +#define	DMxCTR_UT_4		0x00004000	/* - 4 byte */ +#define	DMxCTR_UT_16		0x00006000	/* - 16 byte */ +#define DMxCTR_RRE		0x00008000	/* DMA round robin enable */ +#define	DMxCTR_TEN		0x00010000	/* DMA channel transfer enable */ +#define	DMxCTR_RQM		0x00060000	/* external request input source mode */ +#define	DMxCTR_RQM_FALLEDGE	0x00000000	/* - falling edge */ +#define	DMxCTR_RQM_RISEEDGE	0x00020000	/* - rising edge */ +#define	DMxCTR_RQM_LOLEVEL	0x00040000	/* - low level */ +#define	DMxCTR_RQM_HILEVEL	0x00060000	/* - high level */ +#define	DMxCTR_RQF		0x01000000	/* DMA transfer request flag */ +#define	DMxCTR_PERR		0x40000000	/* DMA transfer parameter error flag */ +#define	DMxCTR_XEND		0x80000000	/* DMA transfer end flag */ + +#define	DMxSRC(N)		__SYSREG(0xd4005004+(N*0x100), u32)	/* control reg */ + +#define	DMxDST(N)		__SYSREG(0xd4005008+(N*0x100), u32)	/* source addr reg */ + +#define	DMxSIZ(N)		__SYSREG(0xd400500c+(N*0x100), u32)	/* dest addr reg */ +#define DMxSIZ_CT		0x000fffff	/* number of bytes to transfer */ + +#define	DMxCYC(N)		__SYSREG(0xd4005010+(N*0x100), u32)	/* intermittent size reg */ +#define DMxCYC_CYC		0x000000ff	/* number of interrmittent transfers -1 */ + +#define DM0IRQ			16		/* DMA channel 0 complete IRQ */ +#define DM1IRQ			17		/* DMA channel 1 complete IRQ */ +#define DM2IRQ			18		/* DMA channel 2 complete IRQ */ +#define DM3IRQ			19		/* DMA channel 3 complete IRQ */ + +#define	DM0ICR			GxICR(DM0IRQ)	/* DMA channel 0 complete intr ctrl reg */ +#define	DM1ICR			GxICR(DM0IR1)	/* DMA channel 1 complete intr ctrl reg */ +#define	DM2ICR			GxICR(DM0IR2)	/* DMA channel 2 complete intr ctrl reg */ +#define	DM3ICR			GxICR(DM0IR3)	/* DMA channel 3 complete intr ctrl reg */ + +#ifndef __ASSEMBLY__ + +struct mn10300_dmactl_regs { +	u32		ctr; +	const void	*src; +	void		*dst; +	u32		siz; +	u32		cyc; +} __attribute__((aligned(0x100))); + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_PROC_DMACTL_REGS_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h new file mode 100644 index 00000000000..a1e977273d1 --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h @@ -0,0 +1,29 @@ +#ifndef _ASM_PROC_INTCTL_REGS_H +#define _ASM_PROC_INTCTL_REGS_H + +#ifndef _ASM_INTCTL_REGS_H +# error "please don't include this file directly" +#endif + +/* intr acceptance group reg */ +#define IAGR			__SYSREG(0xd4000100, u16) + +/* group number register */ +#define IAGR_GN			0x003fc + +#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3) + +#define __SET_XIRQ_TRIGGER(X, Y, Z)		\ +({						\ +	typeof(Z) x = (Z);			\ +	x &= ~(3 << ((X) * 2));			\ +	x |= ((Y) & 3) << ((X) * 2);		\ +	(Z) = x;				\ +}) + +/* external pin intr spec reg */ +#define EXTMD0			__SYSREG(0xd4000200, u32) +#define GET_XIRQ_TRIGGER(X)	__GET_XIRQ_TRIGGER(X, EXTMD0) +#define SET_XIRQ_TRIGGER(X, Y)	__SET_XIRQ_TRIGGER(X, Y, EXTMD0) + +#endif /* _ASM_PROC_INTCTL_REGS_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/irq.h b/arch/mn10300/proc-mn2ws0050/include/proc/irq.h new file mode 100644 index 00000000000..37777a85ab6 --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/irq.h @@ -0,0 +1,49 @@ +/* MN2WS0050 on-board interrupt controller registers + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + *  13-Nov-2006 MEI Define extended IRQ number for SMP support. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PROC_IRQ_H +#define _PROC_IRQ_H + +#ifdef __KERNEL__ + +#define GxICR_NUM_IRQS		163 +#ifdef CONFIG_SMP +#define GxICR_NUM_EXT_IRQS	197 +#endif  /* CONFIG_SMP */ + +#define GxICR_NUM_XIRQS		16 + +#define XIRQ0		34 +#define XIRQ1		35 +#define XIRQ2		36 +#define XIRQ3		37 +#define XIRQ4		38 +#define XIRQ5		39 +#define XIRQ6		40 +#define XIRQ7		41 +#define XIRQ8		42 +#define XIRQ9		43 +#define XIRQ10		44 +#define XIRQ11		45 +#define XIRQ12		46 +#define XIRQ13		47 +#define XIRQ14		48 +#define XIRQ15		49 + +#define XIRQ2IRQ(num)	(XIRQ0 + num) + +#endif /* __KERNEL__ */ + +#endif /* _PROC_IRQ_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h new file mode 100644 index 00000000000..84448f3828b --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h @@ -0,0 +1,120 @@ +/* NAND flash interface register definitions + * + * Copyright (C) 2008-2009 Panasonic Corporation + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef	_PROC_NAND_REGS_H_ +#define	_PROC_NAND_REGS_H_ + +/* command register */ +#define FCOMMAND_0		__SYSREG(0xd8f00000, u8) /* fcommand[24:31] */ +#define FCOMMAND_1		__SYSREG(0xd8f00001, u8) /* fcommand[16:23] */ +#define FCOMMAND_2		__SYSREG(0xd8f00002, u8) /* fcommand[8:15] */ +#define FCOMMAND_3		__SYSREG(0xd8f00003, u8) /* fcommand[0:7] */ + +/* for dma 16 byte trans, use FCOMMAND2 register */ +#define FCOMMAND2_0		__SYSREG(0xd8f00110, u8) /* fcommand2[24:31] */ +#define FCOMMAND2_1		__SYSREG(0xd8f00111, u8) /* fcommand2[16:23] */ +#define FCOMMAND2_2		__SYSREG(0xd8f00112, u8) /* fcommand2[8:15] */ +#define FCOMMAND2_3		__SYSREG(0xd8f00113, u8) /* fcommand2[0:7] */ + +#define FCOMMAND_FIEN		0x80		/* nand flash I/F enable */ +#define FCOMMAND_BW_8BIT	0x00		/* 8bit bus width */ +#define FCOMMAND_BW_16BIT	0x40		/* 16bit bus width */ +#define FCOMMAND_BLOCKSZ_SMALL	0x00		/* small block */ +#define FCOMMAND_BLOCKSZ_LARGE	0x20		/* large block */ +#define FCOMMAND_DMASTART	0x10		/* dma start */ +#define FCOMMAND_RYBY		0x08		/* ready/busy flag */ +#define FCOMMAND_RYBYINTMSK	0x04		/* mask ready/busy interrupt */ +#define FCOMMAND_XFWP		0x02		/* write protect enable */ +#define FCOMMAND_XFCE		0x01		/* flash device disable */ +#define FCOMMAND_SEQKILL	0x10		/* stop seq-read */ +#define FCOMMAND_ANUM		0x07		/* address cycle */ +#define FCOMMAND_ANUM_NONE	0x00		/* address cycle none */ +#define FCOMMAND_ANUM_1CYC	0x01		/* address cycle 1cycle */ +#define FCOMMAND_ANUM_2CYC	0x02		/* address cycle 2cycle */ +#define FCOMMAND_ANUM_3CYC	0x03		/* address cycle 3cycle */ +#define FCOMMAND_ANUM_4CYC	0x04		/* address cycle 4cycle */ +#define FCOMMAND_ANUM_5CYC	0x05		/* address cycle 5cycle */ +#define FCOMMAND_FCMD_READ0	0x00		/* read1 command */ +#define FCOMMAND_FCMD_SEQIN	0x80		/* page program 1st command */ +#define FCOMMAND_FCMD_PAGEPROG	0x10		/* page program 2nd command */ +#define FCOMMAND_FCMD_RESET	0xff		/* reset command */ +#define FCOMMAND_FCMD_ERASE1	0x60		/* erase 1st command */ +#define FCOMMAND_FCMD_ERASE2	0xd0		/* erase 2nd command */ +#define FCOMMAND_FCMD_STATUS	0x70		/* read status command */ +#define FCOMMAND_FCMD_READID	0x90		/* read id command */ +#define FCOMMAND_FCMD_READOOB	0x50		/* read3 command */ +/* address register */ +#define FADD			__SYSREG(0xd8f00004, u32) +/* address register 2 */ +#define FADD2			__SYSREG(0xd8f00008, u32) +/* error judgement register */ +#define FJUDGE			__SYSREG(0xd8f0000c, u32) +#define FJUDGE_NOERR		0x0		/* no error */ +#define FJUDGE_1BITERR		0x1		/* 1bit error in data area */ +#define FJUDGE_PARITYERR	0x2		/* parity error */ +#define FJUDGE_UNCORRECTABLE	0x3		/* uncorrectable error */ +#define FJUDGE_ERRJDG_MSK	0x3		/* mask of judgement result */ +/* 1st ECC store register */ +#define FECC11			__SYSREG(0xd8f00010, u32) +/* 2nd ECC store register */ +#define FECC12			__SYSREG(0xd8f00014, u32) +/* 3rd ECC store register */ +#define FECC21			__SYSREG(0xd8f00018, u32) +/* 4th ECC store register */ +#define FECC22			__SYSREG(0xd8f0001c, u32) +/* 5th ECC store register */ +#define FECC31			__SYSREG(0xd8f00020, u32) +/* 6th ECC store register */ +#define FECC32			__SYSREG(0xd8f00024, u32) +/* 7th ECC store register */ +#define FECC41			__SYSREG(0xd8f00028, u32) +/* 8th ECC store register */ +#define FECC42			__SYSREG(0xd8f0002c, u32) +/* data register */ +#define FDATA			__SYSREG(0xd8f00030, u32) +/* access pulse register */ +#define FPWS			__SYSREG(0xd8f00100, u32) +#define FPWS_PWS1W_2CLK		0x00000000 /* write pulse width 1clock */ +#define FPWS_PWS1W_3CLK		0x01000000 /* write pulse width 2clock */ +#define FPWS_PWS1W_4CLK		0x02000000 /* write pulse width 4clock */ +#define FPWS_PWS1W_5CLK		0x03000000 /* write pulse width 5clock */ +#define FPWS_PWS1W_6CLK		0x04000000 /* write pulse width 6clock */ +#define FPWS_PWS1W_7CLK		0x05000000 /* write pulse width 7clock */ +#define FPWS_PWS1W_8CLK		0x06000000 /* write pulse width 8clock */ +#define FPWS_PWS1R_3CLK		0x00010000 /* read pulse width 3clock */ +#define FPWS_PWS1R_4CLK		0x00020000 /* read pulse width 4clock */ +#define FPWS_PWS1R_5CLK		0x00030000 /* read pulse width 5clock */ +#define FPWS_PWS1R_6CLK		0x00040000 /* read pulse width 6clock */ +#define FPWS_PWS1R_7CLK		0x00050000 /* read pulse width 7clock */ +#define FPWS_PWS1R_8CLK		0x00060000 /* read pulse width 8clock */ +#define FPWS_PWS2W_2CLK		0x00000100 /* write pulse interval 2clock */ +#define FPWS_PWS2W_3CLK		0x00000200 /* write pulse interval 3clock */ +#define FPWS_PWS2W_4CLK		0x00000300 /* write pulse interval 4clock */ +#define FPWS_PWS2W_5CLK		0x00000400 /* write pulse interval 5clock */ +#define FPWS_PWS2W_6CLK		0x00000500 /* write pulse interval 6clock */ +#define FPWS_PWS2R_2CLK		0x00000001 /* read pulse interval 2clock */ +#define FPWS_PWS2R_3CLK		0x00000002 /* read pulse interval 3clock */ +#define FPWS_PWS2R_4CLK		0x00000003 /* read pulse interval 4clock */ +#define FPWS_PWS2R_5CLK		0x00000004 /* read pulse interval 5clock */ +#define FPWS_PWS2R_6CLK		0x00000005 /* read pulse interval 6clock */ +/* command register 2 */ +#define FCOMMAND2		__SYSREG(0xd8f00110, u32) +/* transfer frequency register */ +#define FNUM			__SYSREG(0xd8f00114, u32) +#define FSDATA_ADDR		0xd8f00400 +/* active data register */ +#define FSDATA			__SYSREG(FSDATA_ADDR, u32) + +#endif /* _PROC_NAND_REGS_H_ */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/proc.h b/arch/mn10300/proc-mn2ws0050/include/proc/proc.h new file mode 100644 index 00000000000..90d5cadd05b --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/proc.h @@ -0,0 +1,18 @@ +/* proc.h: MN2WS0050 processor description + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_PROC_PROC_H +#define _ASM_PROC_PROC_H + +#define PROCESSOR_VENDOR_NAME	"Panasonic" +#define PROCESSOR_MODEL_NAME	"mn2ws0050" + +#endif /* _ASM_PROC_PROC_H */ diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h b/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h new file mode 100644 index 00000000000..22f277fbb4d --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h @@ -0,0 +1,51 @@ +/* MN10300/AM33v2 Microcontroller SMP registers + * + * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd. + * All Rights Reserved. + * Created: + *  13-Nov-2006 MEI Add extended cache and atomic operation register + *                  for SMP support. + *  23-Feb-2007 MEI Add define for gdbstub SMP. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_PROC_SMP_REGS_H +#define _ASM_PROC_SMP_REGS_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ +#include <linux/types.h> +#endif +#include <asm/cpu-regs.h> + +/* + * Reference to the interrupt controllers of other CPUs + */ +#define CROSS_ICR_CPU_SHIFT	16 + +#define CROSS_GxICR(X, CPU)	__SYSREG(0xc4000000 + (X) * 4 + \ +	((X) >= 64 && (X) < 192) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u16) +#define CROSS_GxICR_u8(X, CPU)	__SYSREG(0xc4000000 + (X) * 4 +		\ +	(((X) >= 64) && ((X) < 192)) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u8) + +/* CPU ID register */ +#define CPUID		__SYSREGC(0xc0000054, u32) +#define CPUID_MASK	0x00000007	/* CPU ID mask */ + +/* extended cache control register */ +#define ECHCTR		__SYSREG(0xc0000c20, u32) +#define ECHCTR_IBCM	0x00000001	/* instruction cache broad cast mask */ +#define ECHCTR_DBCM	0x00000002	/* data cache broad cast mask */ +#define ECHCTR_ISPM	0x00000004	/* instruction cache snoop mask */ +#define ECHCTR_DSPM	0x00000008	/* data cache snoop mask */ + +#define NMIAGR		__SYSREG(0xd400013c, u16) +#define NMIAGR_GN	0x03fc + +#endif /* __KERNEL__ */ +#endif /* _ASM_PROC_SMP_REGS_H */ diff --git a/arch/mn10300/proc-mn2ws0050/proc-init.c b/arch/mn10300/proc-mn2ws0050/proc-init.c new file mode 100644 index 00000000000..c58249b9525 --- /dev/null +++ b/arch/mn10300/proc-mn2ws0050/proc-init.c @@ -0,0 +1,134 @@ +/* MN2WS0050 processor initialisation + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <asm/smp.h> +#include <asm/pgalloc.h> +#include <asm/busctl-regs.h> +#include <unit/timex.h> +#include <asm/fpu.h> +#include <asm/rtc.h> + +#define MEMCONF __SYSREGC(0xdf800400, u32) + +/* + * initialise the on-silicon processor peripherals + */ +asmlinkage void __init processor_init(void) +{ +	int loop; + +	/* set up the exception table first */ +	for (loop = 0x000; loop < 0x400; loop += 8) +		__set_intr_stub(loop, __common_exception); + +	__set_intr_stub(EXCEP_ITLBMISS,		itlb_miss); +	__set_intr_stub(EXCEP_DTLBMISS,		dtlb_miss); +	__set_intr_stub(EXCEP_IAERROR,		itlb_aerror); +	__set_intr_stub(EXCEP_DAERROR,		dtlb_aerror); +	__set_intr_stub(EXCEP_BUSERROR,		raw_bus_error); +	__set_intr_stub(EXCEP_DOUBLE_FAULT,	double_fault); +	__set_intr_stub(EXCEP_FPU_DISABLED,	fpu_disabled); +	__set_intr_stub(EXCEP_SYSCALL0,		system_call); + +	__set_intr_stub(EXCEP_NMI,		nmi_handler); +	__set_intr_stub(EXCEP_WDT,		nmi_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL0,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL1,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL2,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL3,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL4,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL5,	irq_handler); +	__set_intr_stub(EXCEP_IRQ_LEVEL6,	irq_handler); + +	IVAR0 = EXCEP_IRQ_LEVEL0; +	IVAR1 = EXCEP_IRQ_LEVEL1; +	IVAR2 = EXCEP_IRQ_LEVEL2; +	IVAR3 = EXCEP_IRQ_LEVEL3; +	IVAR4 = EXCEP_IRQ_LEVEL4; +	IVAR5 = EXCEP_IRQ_LEVEL5; +	IVAR6 = EXCEP_IRQ_LEVEL6; + +#ifndef CONFIG_MN10300_HAS_CACHE_SNOOP +	mn10300_dcache_flush_inv(); +	mn10300_icache_inv(); +#endif + +	/* disable all interrupts and set to priority 6 (lowest) */ +#ifdef	CONFIG_SMP +	for (loop = 0; loop < GxICR_NUM_IRQS; loop++) +		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; +#else	/* !CONFIG_SMP */ +	for (loop = 0; loop < NR_IRQS; loop++) +		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; +#endif	/* !CONFIG_SMP */ + +	/* clear the timers */ +	TM0MD	= 0; +	TM1MD	= 0; +	TM2MD	= 0; +	TM3MD	= 0; +	TM4MD	= 0; +	TM5MD	= 0; +	TM6MD	= 0; +	TM6MDA	= 0; +	TM6MDB	= 0; +	TM7MD	= 0; +	TM8MD	= 0; +	TM9MD	= 0; +	TM10MD	= 0; +	TM11MD	= 0; +	TM12MD	= 0; +	TM13MD	= 0; +	TM14MD	= 0; +	TM15MD	= 0; + +	calibrate_clock(); +} + +/* + * determine the memory size and base from the memory controller regs + */ +void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size) +{ +	unsigned long memconf = MEMCONF; +	unsigned long size = 0; /* order: MByte */ + +	*mem_base = 0x90000000; /* fixed address */ + +	switch (memconf & 0x00000003) { +	case 0x01: +		size = 256 / 8;		/* 256 Mbit per chip */ +		break; +	case 0x02: +		size = 512 / 8;		/* 512 Mbit per chip */ +		break; +	case 0x03: +		size = 1024 / 8;	/*   1 Gbit per chip */ +		break; +	default: +		panic("Invalid SDRAM size"); +		break; +	} + +	printk(KERN_INFO "DDR2-SDRAM: %luMB x 2 @%08lx\n", size, *mem_base); + +	*mem_size = (size * 2) << 20; +} diff --git a/arch/mn10300/unit-asb2303/include/unit/clock.h b/arch/mn10300/unit-asb2303/include/unit/clock.h index 2a0bf79ab96..0316907a012 100644 --- a/arch/mn10300/unit-asb2303/include/unit/clock.h +++ b/arch/mn10300/unit-asb2303/include/unit/clock.h @@ -14,32 +14,11 @@  #ifndef __ASSEMBLY__ -#ifdef CONFIG_MN10300_RTC - -extern unsigned long mn10300_ioclk;	/* IOCLK (crystal speed) in HZ */ -extern unsigned long mn10300_iobclk; -extern unsigned long mn10300_tsc_per_HZ; - -#define MN10300_IOCLK		mn10300_ioclk -/* If this processors has a another clock, uncomment the below. */ -/* #define MN10300_IOBCLK	mn10300_iobclk */ - -#else /* !CONFIG_MN10300_RTC */ -  #define MN10300_IOCLK		33333333UL  /* #define MN10300_IOBCLK	66666666UL */ -#endif /* !CONFIG_MN10300_RTC */ - -#define MN10300_JCCLK		MN10300_IOCLK -#define MN10300_TSCCLK		MN10300_IOCLK - -#ifdef CONFIG_MN10300_RTC -#define MN10300_TSC_PER_HZ	mn10300_tsc_per_HZ -#else /* !CONFIG_MN10300_RTC */ -#define MN10300_TSC_PER_HZ	(MN10300_TSCCLK/HZ) -#endif /* !CONFIG_MN10300_RTC */ -  #endif /* !__ASSEMBLY__ */ +#define MN10300_WDCLK		MN10300_IOCLK +  #endif /* _ASM_UNIT_CLOCK_H */ diff --git a/arch/mn10300/unit-asb2303/include/unit/serial.h b/arch/mn10300/unit-asb2303/include/unit/serial.h index 047566cd2e3..991e356bac5 100644 --- a/arch/mn10300/unit-asb2303/include/unit/serial.h +++ b/arch/mn10300/unit-asb2303/include/unit/serial.h @@ -22,6 +22,11 @@  #define SERIAL_IRQ	XIRQ0	/* Dual serial (PC16552)	(Hi) */  /* + * The ASB2303 has an 18.432 MHz clock the UART + */ +#define BASE_BAUD	(18432000 / 16) + +/*   * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports   */  #ifndef CONFIG_GDBSTUB_ON_TTYSx diff --git a/arch/mn10300/unit-asb2303/include/unit/timex.h b/arch/mn10300/unit-asb2303/include/unit/timex.h index 88cd96bb252..d1b8dafe7d7 100644 --- a/arch/mn10300/unit-asb2303/include/unit/timex.h +++ b/arch/mn10300/unit-asb2303/include/unit/timex.h @@ -1,4 +1,4 @@ -/* ASB2303-specific timer specifcations +/* ASB2303-specific timer specifications   *   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.   * Written by David Howells (dhowells@redhat.com) @@ -17,6 +17,7 @@  #include <asm/timer-regs.h>  #include <unit/clock.h> +#include <asm/param.h>  /*   * jiffies counter specifications @@ -29,32 +30,43 @@  #define	TMJCBR			TM01BR  #define	TMJCIRQ			TM1IRQ  #define	TMJCICR			TM1ICR -#define	TMJCICR_LEVEL		GxICR_LEVEL_5  #ifndef __ASSEMBLY__ -static inline void startup_jiffies_counter(void) -{ -	unsigned rate; -	u16 md, t16; +#define MN10300_SRC_IOCLK	MN10300_IOCLK -	/* use as little prescaling as possible to avoid losing accuracy */ -	md = TM0MD_SRC_IOCLK; -	rate = MN10300_JCCLK / HZ; +#ifndef HZ +# error HZ undeclared. +#endif /* !HZ */ +/* use as little prescaling as possible to avoid losing accuracy */ +#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		1 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK +#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		8 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_8 +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_8 +#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		32 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_32 +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_32 +#else +# error You lose. +#endif -	if (rate > TMJCBR_MAX) { -		md = TM0MD_SRC_IOCLK_8; -		rate = MN10300_JCCLK / 8 / HZ; +#define MN10300_JCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE) +#define MN10300_TSCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE) -		if (rate > TMJCBR_MAX) { -			md = TM0MD_SRC_IOCLK_32; -			rate = MN10300_JCCLK / 32 / HZ; +#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ) +#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ) -			BUG_ON(rate > TMJCBR_MAX); -		} -	} +static inline void startup_jiffies_counter(void) +{ +	u16 md, t16; -	TMJCBR = rate - 1; +	md = JC_TIMER_CLKSRC; +	TMJCBR = MN10300_JC_PER_HZ - 1;  	t16 = TMJCBR;  	TMJCMD = @@ -93,29 +105,39 @@ static inline void shutdown_jiffies_counter(void)  static inline void startup_timestamp_counter(void)  { +	u32 t32; +  	/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time  	 * - count down from 4Gig-1 to 0 and wrap at IOCLK rate  	 */  	TM45BR = TMTSCBR_MAX; +	t32 = TM45BR; -	TM4MD = TM4MD_SRC_IOCLK; +	TM4MD = TSC_TIMER_CLKSRC;  	TM4MD |= TM4MD_INIT_COUNTER;  	TM4MD &= ~TM4MD_INIT_COUNTER;  	TM4ICR = 0; +	t32 = TM4ICR;  	TM5MD = TM5MD_SRC_TM4CASCADE;  	TM5MD |= TM5MD_INIT_COUNTER;  	TM5MD &= ~TM5MD_INIT_COUNTER;  	TM5ICR = 0; +	t32 = TM5ICR;  	TM5MD |= TM5MD_COUNT_ENABLE;  	TM4MD |= TM4MD_COUNT_ENABLE; +	t32 = TM5MD; +	t32 = TM4MD;  }  static inline void shutdown_timestamp_counter(void)  { +	u8 t8;  	TM4MD = 0;  	TM5MD = 0; +	t8 = TM4MD; +	t8 = TM5MD;  }  /* diff --git a/arch/mn10300/unit-asb2303/unit-init.c b/arch/mn10300/unit-asb2303/unit-init.c index 70e8cb4ea26..834a76aa551 100644 --- a/arch/mn10300/unit-asb2303/unit-init.c +++ b/arch/mn10300/unit-asb2303/unit-init.c @@ -31,6 +31,14 @@ asmlinkage void __init unit_init(void)  	SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL);  	SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL);  	SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL); + +#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL +	set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL)); +#endif + +#ifdef CONFIG_ETHERNET_IRQ_LEVEL +	set_intr_level(XIRQ3, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL)); +#endif  }  /* @@ -51,7 +59,7 @@ void __init unit_init_IRQ(void)  		switch (GET_XIRQ_TRIGGER(extnum)) {  		case XIRQ_TRIGGER_HILEVEL:  		case XIRQ_TRIGGER_LOWLEVEL: -			set_intr_postackable(XIRQ2IRQ(extnum)); +			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));  			break;  		default:  			break; diff --git a/arch/mn10300/unit-asb2305/include/unit/clock.h b/arch/mn10300/unit-asb2305/include/unit/clock.h index 67be3f2eb18..29e3425431c 100644 --- a/arch/mn10300/unit-asb2305/include/unit/clock.h +++ b/arch/mn10300/unit-asb2305/include/unit/clock.h @@ -14,32 +14,11 @@  #ifndef __ASSEMBLY__ -#ifdef CONFIG_MN10300_RTC - -extern unsigned long mn10300_ioclk;	/* IOCLK (crystal speed) in HZ */ -extern unsigned long mn10300_iobclk; -extern unsigned long mn10300_tsc_per_HZ; - -#define MN10300_IOCLK		mn10300_ioclk -/* If this processors has a another clock, uncomment the below. */ -/* #define MN10300_IOBCLK	mn10300_iobclk */ - -#else /* !CONFIG_MN10300_RTC */ -  #define MN10300_IOCLK		33333333UL  /* #define MN10300_IOBCLK	66666666UL */ -#endif /* !CONFIG_MN10300_RTC */ - -#define MN10300_JCCLK		MN10300_IOCLK -#define MN10300_TSCCLK		MN10300_IOCLK - -#ifdef CONFIG_MN10300_RTC -#define MN10300_TSC_PER_HZ	mn10300_tsc_per_HZ -#else /* !CONFIG_MN10300_RTC */ -#define MN10300_TSC_PER_HZ	(MN10300_TSCCLK/HZ) -#endif /* !CONFIG_MN10300_RTC */ -  #endif /* !__ASSEMBLY__ */ +#define MN10300_WDCLK		MN10300_IOCLK +  #endif /* _ASM_UNIT_CLOCK_H */ diff --git a/arch/mn10300/unit-asb2305/include/unit/serial.h b/arch/mn10300/unit-asb2305/include/unit/serial.h index 8086cc092ce..88c08219315 100644 --- a/arch/mn10300/unit-asb2305/include/unit/serial.h +++ b/arch/mn10300/unit-asb2305/include/unit/serial.h @@ -21,6 +21,11 @@  #define SERIAL_IRQ	XIRQ0	/* Dual serial (PC16552)	(Hi) */  /* + * The ASB2305 has an 18.432 MHz clock the UART + */ +#define BASE_BAUD	(18432000 / 16) + +/*   * dispose of the /dev/ttyS0 serial port   */  #ifndef CONFIG_GDBSTUB_ON_TTYSx diff --git a/arch/mn10300/unit-asb2305/include/unit/timex.h b/arch/mn10300/unit-asb2305/include/unit/timex.h index 0860186eedb..cd8bc14e3ca 100644 --- a/arch/mn10300/unit-asb2305/include/unit/timex.h +++ b/arch/mn10300/unit-asb2305/include/unit/timex.h @@ -1,4 +1,4 @@ -/* ASB2305 timer specifcations +/* ASB2305-specific timer specifications   *   * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.   * Written by David Howells (dhowells@redhat.com) @@ -17,6 +17,7 @@  #include <asm/timer-regs.h>  #include <unit/clock.h> +#include <asm/param.h>  /*   * jiffies counter specifications @@ -29,32 +30,43 @@  #define	TMJCBR			TM01BR  #define	TMJCIRQ			TM1IRQ  #define	TMJCICR			TM1ICR -#define	TMJCICR_LEVEL		GxICR_LEVEL_5  #ifndef __ASSEMBLY__ -static inline void startup_jiffies_counter(void) -{ -	unsigned rate; -	u16 md, t16; +#define MN10300_SRC_IOCLK	MN10300_IOCLK -	/* use as little prescaling as possible to avoid losing accuracy */ -	md = TM0MD_SRC_IOCLK; -	rate = MN10300_JCCLK / HZ; +#ifndef HZ +# error HZ undeclared. +#endif /* !HZ */ +/* use as little prescaling as possible to avoid losing accuracy */ +#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		1 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK +#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		8 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_8 +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_8 +#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX +# define IOCLK_PRESCALE		32 +# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_32 +# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_32 +#else +# error You lose. +#endif -	if (rate > TMJCBR_MAX) { -		md = TM0MD_SRC_IOCLK_8; -		rate = MN10300_JCCLK / 8 / HZ; +#define MN10300_JCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE) +#define MN10300_TSCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE) -		if (rate > TMJCBR_MAX) { -			md = TM0MD_SRC_IOCLK_32; -			rate = MN10300_JCCLK / 32 / HZ; +#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ) +#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ) -			BUG_ON(rate > TMJCBR_MAX); -		} -	} +static inline void startup_jiffies_counter(void) +{ +	u16 md, t16; -	TMJCBR = rate - 1; +	md = JC_TIMER_CLKSRC; +	TMJCBR = MN10300_JC_PER_HZ - 1;  	t16 = TMJCBR;  	TMJCMD = @@ -93,29 +105,39 @@ static inline void shutdown_jiffies_counter(void)  static inline void startup_timestamp_counter(void)  { +	u32 t32; +  	/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time  	 * - count down from 4Gig-1 to 0 and wrap at IOCLK rate  	 */  	TM45BR = TMTSCBR_MAX; +	t32 = TM45BR; -	TM4MD = TM4MD_SRC_IOCLK; +	TM4MD = TSC_TIMER_CLKSRC;  	TM4MD |= TM4MD_INIT_COUNTER;  	TM4MD &= ~TM4MD_INIT_COUNTER;  	TM4ICR = 0; +	t32 = TM4ICR;  	TM5MD = TM5MD_SRC_TM4CASCADE;  	TM5MD |= TM5MD_INIT_COUNTER;  	TM5MD &= ~TM5MD_INIT_COUNTER;  	TM5ICR = 0; +	t32 = TM5ICR;  	TM5MD |= TM5MD_COUNT_ENABLE;  	TM4MD |= TM4MD_COUNT_ENABLE; +	t32 = TM5MD; +	t32 = TM4MD;  }  static inline void shutdown_timestamp_counter(void)  { +	u8 t8;  	TM4MD = 0;  	TM5MD = 0; +	t8 = TM4MD; +	t8 = TM5MD;  }  /* @@ -126,7 +148,7 @@ typedef unsigned long cycles_t;  static inline cycles_t read_timestamp_counter(void)  { -	return (cycles_t) TMTSCBC; +	return (cycles_t)TMTSCBC;  }  #endif /* !__ASSEMBLY__ */ diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 6d8720a0a59..a4954fe8209 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -503,7 +503,7 @@ asmlinkage void __init unit_pci_init(void)  	struct pci_ops *o = &pci_direct_ampci;  	u32 x; -	set_intr_level(XIRQ1, GxICR_LEVEL_3); +	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_PCI_IRQ_LEVEL));  	memset(&bus, 0, sizeof(bus)); diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c index a76c8e0ab90..e1becd6b757 100644 --- a/arch/mn10300/unit-asb2305/unit-init.c +++ b/arch/mn10300/unit-asb2305/unit-init.c @@ -26,8 +26,10 @@ asmlinkage void __init unit_init(void)  {  #ifndef CONFIG_GDBSTUB_ON_TTYSx  	/* set the 16550 interrupt line to level 3 if not being used for GDB */ -	set_intr_level(XIRQ0, GxICR_LEVEL_3); +#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL +	set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));  #endif +#endif /* CONFIG_GDBSTUB_ON_TTYSx */  }  /* @@ -51,7 +53,7 @@ void __init unit_init_IRQ(void)  		switch (GET_XIRQ_TRIGGER(extnum)) {  		case XIRQ_TRIGGER_HILEVEL:  		case XIRQ_TRIGGER_LOWLEVEL: -			set_intr_postackable(XIRQ2IRQ(extnum)); +			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));  			break;  		default:  			break; diff --git a/arch/mn10300/unit-asb2364/Makefile b/arch/mn10300/unit-asb2364/Makefile new file mode 100644 index 00000000000..6dd27d65877 --- /dev/null +++ b/arch/mn10300/unit-asb2364/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +obj-y   := unit-init.o leds.o diff --git a/arch/mn10300/unit-asb2364/include/unit/clock.h b/arch/mn10300/unit-asb2364/include/unit/clock.h new file mode 100644 index 00000000000..d34ac9a7508 --- /dev/null +++ b/arch/mn10300/unit-asb2364/include/unit/clock.h @@ -0,0 +1,29 @@ +/* clock.h: unit-specific clocks + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Modified by Matsushita Electric Industrial Co., Ltd. + * Modifications: + *	23-Feb-2007 MEI Add define for watchdog timer. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_UNIT_CLOCK_H +#define _ASM_UNIT_CLOCK_H + +#ifndef __ASSEMBLY__ + +#define MN10300_IOCLK		100000000UL		/* for DDR800 */ +/*#define MN10300_IOCLK		83333333UL */		/* for DDR667 */ +#define MN10300_IOBCLK		MN10300_IOCLK		/* IOBCLK is equal to IOCLK */ + +#endif /* !__ASSEMBLY__ */ + +#define MN10300_WDCLK		27000000UL + +#endif /* _ASM_UNIT_CLOCK_H */ diff --git a/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h b/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h new file mode 100644 index 00000000000..a039a50c91d --- /dev/null +++ b/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h @@ -0,0 +1,50 @@ +/* ASB2364 FPGA registers + */ + +#ifndef _ASM_UNIT_FPGA_REGS_H +#define _ASM_UNIT_FPGA_REGS_H + +#include <asm/cpu-regs.h> + +#ifdef __KERNEL__ + +#define ASB2364_FPGA_REG_RESET_LAN	__SYSREG(0xa9001300, u16) +#define ASB2364_FPGA_REG_RESET_UART	__SYSREG(0xa9001304, u16) +#define ASB2364_FPGA_REG_RESET_I2C	__SYSREG(0xa9001308, u16) +#define ASB2364_FPGA_REG_RESET_USB	__SYSREG(0xa900130c, u16) +#define ASB2364_FPGA_REG_RESET_AV	__SYSREG(0xa9001310, u16) + +#define ASB2364_FPGA_REG_IRQ_LAN	__SYSREG(0xa9001510, u16) +#define ASB2364_FPGA_REG_IRQ_UART	__SYSREG(0xa9001514, u16) +#define ASB2364_FPGA_REG_IRQ_I2C	__SYSREG(0xa9001518, u16) +#define ASB2364_FPGA_REG_IRQ_USB	__SYSREG(0xa900151c, u16) +#define ASB2364_FPGA_REG_IRQ_FPGA	__SYSREG(0xa9001524, u16) + +#define ASB2364_FPGA_REG_MASK_LAN	__SYSREG(0xa9001590, u16) +#define ASB2364_FPGA_REG_MASK_UART	__SYSREG(0xa9001594, u16) +#define ASB2364_FPGA_REG_MASK_I2C	__SYSREG(0xa9001598, u16) +#define ASB2364_FPGA_REG_MASK_USB	__SYSREG(0xa900159c, u16) +#define ASB2364_FPGA_REG_MASK_FPGA	__SYSREG(0xa90015a4, u16) + +#define ASB2364_FPGA_REG_CPLD5_SET1	__SYSREG(0xa9002500, u16) +#define ASB2364_FPGA_REG_CPLD5_SET2	__SYSREG(0xa9002504, u16) +#define ASB2364_FPGA_REG_CPLD6_SET1	__SYSREG(0xa9002600, u16) +#define ASB2364_FPGA_REG_CPLD6_SET2	__SYSREG(0xa9002604, u16) +#define ASB2364_FPGA_REG_CPLD7_SET1	__SYSREG(0xa9002700, u16) +#define ASB2364_FPGA_REG_CPLD7_SET2	__SYSREG(0xa9002704, u16) +#define ASB2364_FPGA_REG_CPLD8_SET1	__SYSREG(0xa9002800, u16) +#define ASB2364_FPGA_REG_CPLD8_SET2	__SYSREG(0xa9002804, u16) +#define ASB2364_FPGA_REG_CPLD9_SET1	__SYSREG(0xa9002900, u16) +#define ASB2364_FPGA_REG_CPLD9_SET2	__SYSREG(0xa9002904, u16) +#define ASB2364_FPGA_REG_CPLD10_SET1	__SYSREG(0xa9002a00, u16) +#define ASB2364_FPGA_REG_CPLD10_SET2	__SYSREG(0xa9002a04, u16) + +#define SyncExBus()					\ +	do {						\ +		unsigned short w;			\ +		w = *(volatile short *)0xa9000000;	\ +	} while (0) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_UNIT_FPGA_REGS_H */ diff --git a/arch/mn10300/unit-asb2364/include/unit/leds.h b/arch/mn10300/unit-asb2364/include/unit/leds.h new file mode 100644 index 00000000000..03a3933ad32 --- /dev/null +++ b/arch/mn10300/unit-asb2364/include/unit/leds.h @@ -0,0 +1,54 @@ +/* Unit-specific leds + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_UNIT_LEDS_H +#define _ASM_UNIT_LEDS_H + +#include <asm/pio-regs.h> +#include <asm/cpu-regs.h> +#include <asm/exceptions.h> + +#define MN10300_USE_7SEGLEDS	0 + +#define ASB2364_7SEGLEDS	__SYSREG(0xA9001630, u32) + +/* + * use the 7-segment LEDs to indicate states + */ + +#if MN10300_USE_7SEGLEDS +/* flip the 7-segment LEDs between "Gdb-" and "----" */ +#define mn10300_set_gdbleds(ONOFF)					\ +	do {								\ +		ASB2364_7SEGLEDS = (ONOFF) ? 0x8543077f : 0x7f7f7f7f;	\ +	} while (0) +#else +#define mn10300_set_gdbleds(ONOFF) do {} while (0) +#endif + +#if MN10300_USE_7SEGLEDS +/* indicate double-fault by displaying "db-f" on the LEDs */ +#define mn10300_set_dbfleds			\ +	mov	0x43077f1d,d0		;	\ +	mov	d0,(ASB2364_7SEGLEDS) +#else +#define mn10300_set_dbfleds +#endif + +#ifndef __ASSEMBLY__ +extern void peripheral_leds_display_exception(enum exception_code); +extern void peripheral_leds_led_chase(void); +extern void peripheral_leds7x4_display_dec(unsigned int, unsigned int); +extern void peripheral_leds7x4_display_hex(unsigned int, unsigned int); +extern void debug_to_serial(const char *, int); +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_UNIT_LEDS_H */ diff --git a/arch/mn10300/unit-asb2364/include/unit/serial.h b/arch/mn10300/unit-asb2364/include/unit/serial.h new file mode 100644 index 00000000000..7f048bbfdfd --- /dev/null +++ b/arch/mn10300/unit-asb2364/include/unit/serial.h @@ -0,0 +1,151 @@ +/* Unit-specific 8250 serial ports + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_UNIT_SERIAL_H +#define _ASM_UNIT_SERIAL_H + +#include <asm/cpu-regs.h> +#include <proc/irq.h> +#include <unit/fpga-regs.h> +#include <linux/serial_reg.h> + +#define SERIAL_PORT0_BASE_ADDRESS	0xA8200000 + +#define SERIAL_IRQ	XIRQ1	/* single serial (TL16C550C)	(Lo) */ + +/* + * The ASB2364 has an 12.288 MHz clock + * for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD (12288000 / 16) + +/* + * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports + */ +#ifndef CONFIG_GDBSTUB_ON_TTYSx + +#define SERIAL_PORT_DFNS						\ +	{								\ +		.baud_base	= BASE_BAUD,				\ +		.irq		= SERIAL_IRQ,				\ +		.flags		= STD_COM_FLAGS,			\ +		.iomem_base	= (u8 *) SERIAL_PORT0_BASE_ADDRESS,	\ +		.iomem_reg_shift = 1,					\ +		.io_type	= SERIAL_IO_MEM,			\ +	}, + +#ifndef __ASSEMBLY__ + +static inline void __debug_to_serial(const char *p, int n) +{ +} + +#endif /* !__ASSEMBLY__ */ + +#else /* CONFIG_GDBSTUB_ON_TTYSx */ + +#define SERIAL_PORT_DFNS /* stolen by gdb-stub */ + +#if defined(CONFIG_GDBSTUB_ON_TTYS0) +#define GDBPORT_SERIAL_RX	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX  * 4, u8) +#define GDBPORT_SERIAL_TX	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX  * 4, u8) +#define GDBPORT_SERIAL_DLL	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 4, u8) +#define GDBPORT_SERIAL_DLM	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 4, u8) +#define GDBPORT_SERIAL_IER	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 4, u8) +#define GDBPORT_SERIAL_IIR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 4, u8) +#define GDBPORT_SERIAL_FCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 4, u8) +#define GDBPORT_SERIAL_LCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 4, u8) +#define GDBPORT_SERIAL_MCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 4, u8) +#define GDBPORT_SERIAL_LSR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 4, u8) +#define GDBPORT_SERIAL_MSR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 4, u8) +#define GDBPORT_SERIAL_SCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 4, u8) +#define GDBPORT_SERIAL_IRQ	SERIAL_IRQ + +#elif defined(CONFIG_GDBSTUB_ON_TTYS1) +#error The ASB2364 does not have a /dev/ttyS1 +#endif + +#ifndef __ASSEMBLY__ + +static inline void __debug_to_serial(const char *p, int n) +{ +	char ch; + +#define LSR_WAIT_FOR(STATE)	\ +	do {} while (!(GDBPORT_SERIAL_LSR & UART_LSR_##STATE)) +#define FLOWCTL_QUERY(LINE)	\ +	({ GDBPORT_SERIAL_MSR & UART_MSR_##LINE; }) +#define FLOWCTL_WAIT_FOR(LINE)	\ +	do {} while (!(GDBPORT_SERIAL_MSR & UART_MSR_##LINE)) +#define FLOWCTL_CLEAR(LINE)	\ +	do { GDBPORT_SERIAL_MCR &= ~UART_MCR_##LINE; } while (0) +#define FLOWCTL_SET(LINE)	\ +	do { GDBPORT_SERIAL_MCR |= UART_MCR_##LINE; } while (0) + +	FLOWCTL_SET(DTR); + +	for (; n > 0; n--) { +		LSR_WAIT_FOR(THRE); +		FLOWCTL_WAIT_FOR(CTS); + +		ch = *p++; +		if (ch == 0x0a) { +			GDBPORT_SERIAL_TX = 0x0d; +			LSR_WAIT_FOR(THRE); +			FLOWCTL_WAIT_FOR(CTS); +		} +		GDBPORT_SERIAL_TX = ch; +	} + +	FLOWCTL_CLEAR(DTR); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* CONFIG_GDBSTUB_ON_TTYSx */ + +#define SERIAL_INITIALIZE					\ +do {								\ +	/* release reset */					\ +	ASB2364_FPGA_REG_RESET_UART = 0x0001;			\ +	SyncExBus();						\ +} while (0) + +#define SERIAL_CHECK_INTERRUPT					\ +do {								\ +	if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) == 0x0001) {	\ +		return IRQ_NONE;				\ +	}							\ +} while (0) + +#define SERIAL_CLEAR_INTERRUPT					\ +do {								\ +	ASB2364_FPGA_REG_IRQ_UART = 0x0001;			\ +	SyncExBus();						\ +} while (0) + +#define SERIAL_SET_INT_MASK					\ +do {								\ +	ASB2364_FPGA_REG_MASK_UART = 0x0001;			\ +	SyncExBus();						\ +} while (0) + +#define SERIAL_CLEAR_INT_MASK					\ +do {								\ +	ASB2364_FPGA_REG_MASK_UART = 0x0000;			\ +	SyncExBus();						\ +} while (0) + +#endif /* _ASM_UNIT_SERIAL_H */ diff --git a/arch/mn10300/unit-asb2364/include/unit/timex.h b/arch/mn10300/unit-asb2364/include/unit/timex.h new file mode 100644 index 00000000000..b5223f705ef --- /dev/null +++ b/arch/mn10300/unit-asb2364/include/unit/timex.h @@ -0,0 +1,125 @@ +/* timex.h: MN2WS0038 architecture timer specifications + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ASM_UNIT_TIMEX_H +#define _ASM_UNIT_TIMEX_H + +#ifndef __ASSEMBLY__ +#include <linux/irq.h> +#endif /* __ASSEMBLY__ */ + +#include <asm/timer-regs.h> +#include <unit/clock.h> +#include <asm/param.h> + +/* + * jiffies counter specifications + */ + +#define	TMJCBR_MAX		0xffffff	/* 24bit */ +#define	TMJCBC			TMTBC + +#define	TMJCMD			TMTMD +#define	TMJCBR			TMTBR +#define	TMJCIRQ			TMTIRQ +#define	TMJCICR			TMTICR + +#ifndef __ASSEMBLY__ + +#define MN10300_SRC_IOBCLK	MN10300_IOBCLK + +#ifndef HZ +# error HZ undeclared. +#endif /* !HZ */ + +#define MN10300_JCCLK		(MN10300_SRC_IOBCLK) +#define MN10300_TSCCLK		(MN10300_SRC_IOBCLK) + +#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ) +#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ) + +/* Check bit width of MTM interval value that sets base register */ +#if (MN10300_JC_PER_HZ - 1) > TMJCBR_MAX +# error MTM tick timer interval value is overflow. +#endif + + +static inline void startup_jiffies_counter(void) +{ +	u32 sync; + +	TMJCBR = MN10300_JC_PER_HZ - 1; +	sync = TMJCBR; + +	TMJCMD = TMTMD_TMTLDE; +	TMJCMD = TMTMD_TMTCNE; +	sync = TMJCMD; + +	TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; +	sync = TMJCICR; +} + +static inline void shutdown_jiffies_counter(void) +{ +} + +#endif /* !__ASSEMBLY__ */ + + +/* + * timestamp counter specifications + */ + +#define	TMTSCBR_MAX	0xffffffff +#define	TMTSCMD		TMSMD +#define	TMTSCBR		TMSBR +#define	TMTSCBC		TMSBC +#define	TMTSCICR	TMSICR + +#ifndef __ASSEMBLY__ + +static inline void startup_timestamp_counter(void) +{ +	u32 sync; + +	/* set up TMS(Timestamp) 32bit timer register to count real time +	 * - count down from 4Gig-1 to 0 and wrap at IOBCLK rate +	 */ + +	TMTSCBR = TMTSCBR_MAX; +	sync = TMTSCBR; + +	TMTSCICR = 0; +	sync = TMTSCICR; + +	TMTSCMD = TMTMD_TMTLDE; +	TMTSCMD = TMTMD_TMTCNE; +	sync = TMTSCMD; +} + +static inline void shutdown_timestamp_counter(void) +{ +	TMTSCMD = 0; +} + +/* + * we use a cascaded pair of 16-bit down-counting timers to count I/O + * clock cycles for the purposes of time keeping + */ +typedef unsigned long cycles_t; + +static inline cycles_t read_timestamp_counter(void) +{ +	return (cycles_t)TMTSCBC; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_UNIT_TIMEX_H */ diff --git a/arch/mn10300/unit-asb2364/leds.c b/arch/mn10300/unit-asb2364/leds.c new file mode 100644 index 00000000000..1ff830c372b --- /dev/null +++ b/arch/mn10300/unit-asb2364/leds.c @@ -0,0 +1,98 @@ +/* leds.c: ASB2364 peripheral 7seg LEDs x4 support + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/intctl-regs.h> +#include <asm/rtc-regs.h> +#include <unit/leds.h> + +#if MN10300_USE_7SEGLEDS +static const u8 asb2364_led_hex_tbl[16] = { +	0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0, +	0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c +}; + +static const u32 asb2364_led_chase_tbl[6] = { +	~0x02020202,	/* top		- segA */ +	~0x04040404,	/* right top	- segB */ +	~0x08080808,	/* right bottom	- segC */ +	~0x10101010,	/* bottom	- segD */ +	~0x20202020,	/* left bottom	- segE */ +	~0x40404040,	/* left top	- segF */ +}; + +static unsigned asb2364_led_chase; + +void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) +{ +	u32 leds; + +	leds = asb2364_led_hex_tbl[(val/1000) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[(val/100) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[(val/10) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[val % 10]; +	leds |= points^0x01010101; + +	ASB2364_7SEGLEDS = leds; +} + +void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) +{ +	u32 leds; + +	leds = asb2364_led_hex_tbl[(val/1000) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[(val/100) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[(val/10) % 10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[val % 10]; +	leds |= points^0x01010101; + +	ASB2364_7SEGLEDS = leds; +} + +/* display triple horizontal bar and exception code */ +void peripheral_leds_display_exception(enum exception_code code) +{ +	u32 leds; + +	leds = asb2364_led_hex_tbl[(code/0x100) % 0x10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[(code/0x10) % 0x10]; +	leds <<= 8; +	leds |= asb2364_led_hex_tbl[code % 0x10]; +	leds |= 0x6d010101; + +	ASB2364_7SEGLEDS = leds; +} + +void peripheral_leds_led_chase(void) +{ +	ASB2364_7SEGLEDS = asb2364_led_chase_tbl[asb2364_led_chase]; +	asb2364_led_chase++; +	if (asb2364_led_chase >= 6) +		asb2364_led_chase = 0; +} +#else  /* MN10300_USE_7SEGLEDS */ +void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) { } +void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) { } +void peripheral_leds_display_exception(enum exception_code code) { } +void peripheral_leds_led_chase(void) { } +#endif /* MN10300_USE_7SEGLEDS */ diff --git a/arch/mn10300/unit-asb2364/unit-init.c b/arch/mn10300/unit-asb2364/unit-init.c new file mode 100644 index 00000000000..a3fc09b43f8 --- /dev/null +++ b/arch/mn10300/unit-asb2364/unit-init.c @@ -0,0 +1,85 @@ +/* ASB2364 initialisation + * + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/setup.h> +#include <asm/processor.h> +#include <asm/irq.h> +#include <asm/intctl-regs.h> + +/* + * initialise some of the unit hardware before gdbstub is set up + */ +asmlinkage void __init unit_init(void) +{ +	/* set up the external interrupts */ + +	/* XIRQ[0]: NAND RXBY */ +	/* SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_LOWLEVEL); */ + +	/* XIRQ[1]: LAN, UART, I2C, USB, PCI, FPGA */ +	SET_XIRQ_TRIGGER(1, XIRQ_TRIGGER_LOWLEVEL); + +	/* XIRQ[2]: Extend Slot 1-9 */ +	/* SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL); */ + +#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) &&	\ +    defined(CONFIG_ETHERNET_IRQ_LEVEL) &&	\ +    (CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL) +# error CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL +#endif + +#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) +	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL)); +#elif defined(CONFIG_ETHERNET_IRQ_LEVEL) +	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL)); +#endif +} + +/* + * initialise the rest of the unit hardware after gdbstub is ready + */ +asmlinkage void __init unit_setup(void) +{ + +} + +/* + * initialise the external interrupts used by a unit of this type + */ +void __init unit_init_IRQ(void) +{ +	unsigned int extnum; + +	for (extnum = 0 ; extnum < NR_XIRQS ; extnum++) { +		switch (GET_XIRQ_TRIGGER(extnum)) { +			/* LEVEL triggered interrupts should be made +			 * post-ACK'able as they hold their lines until +			 * serviced +			 */ +		case XIRQ_TRIGGER_HILEVEL: +		case XIRQ_TRIGGER_LOWLEVEL: +			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum)); +			break; +		default: +			break; +		} +	} + +#define IRQCTL	__SYSREG(0xd5000090, u32) +	IRQCTL |= 0x02; +}  |