[XTENSA] Add support for configurable registers and coprocessors

The Xtensa architecture allows to define custom instructions and
registers. Registers that are bound to a coprocessor are only
accessible if the corresponding enable bit is set, which allows
to implement a 'lazy' context switch mechanism. Other registers
needs to be saved and restore at the time of the context switch
or during interrupt handling.

This patch adds support for these additional states:

- save and restore registers that are used by the compiler upon
  interrupt entry and exit.
- context switch additional registers unbound to any coprocessor
- 'lazy' context switch of registers bound to a coprocessor
- ptrace interface to provide access to additional registers
- update configuration files in include/asm-xtensa/variant-fsf

Signed-off-by: Chris Zankel <chris@zankel.net>
diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
index aa21210..e5849bb 100644
--- a/include/asm-xtensa/coprocessor.h
+++ b/include/asm-xtensa/coprocessor.h
@@ -5,81 +5,168 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 - 2005 Tensilica Inc.
+ * Copyright (C) 2003 - 2007 Tensilica Inc.
  */
 
+
 #ifndef _XTENSA_COPROCESSOR_H
 #define _XTENSA_COPROCESSOR_H
 
-#include <asm/variant/core.h>
+#include <linux/stringify.h>
 #include <asm/variant/tie.h>
+#include <asm/types.h>
 
-#if !XCHAL_HAVE_CP
+#ifdef __ASSEMBLY__
+# include <asm/variant/tie-asm.h>
 
-#define XTENSA_CP_EXTRA_OFFSET 	0
-#define XTENSA_CP_EXTRA_ALIGN	1	/* must be a power of 2 */
-#define XTENSA_CP_EXTRA_SIZE	0
+.macro	xchal_sa_start  a b
+	.set .Lxchal_pofs_, 0
+	.set .Lxchal_ofs_, 0
+.endm
 
-#else
+.macro	xchal_sa_align  ptr minofs maxofs ofsalign totalign
+	.set	.Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_ + \totalign - 1
+	.set	.Lxchal_ofs_, (.Lxchal_ofs_ & -\totalign) - .Lxchal_pofs_
+.endm
 
-#define XTOFS(last_start,last_size,align) \
-	((last_start+last_size+align-1) & -align)
+#define _SELECT	(  XTHAL_SAS_TIE | XTHAL_SAS_OPT \
+		 | XTHAL_SAS_CC \
+		 | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB )
 
-#define XTENSA_CP_EXTRA_OFFSET	0
-#define XTENSA_CP_EXTRA_ALIGN	XCHAL_EXTRA_SA_ALIGN
+.macro save_xtregs_opt ptr clb at1 at2 at3 at4 offset
+	.if XTREGS_OPT_SIZE > 0
+		addi	\clb, \ptr, \offset
+		xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT
+	.endif
+.endm
 
-#define XTENSA_CPE_CP0_OFFSET	\
-	XTOFS(XTENSA_CP_EXTRA_OFFSET, XCHAL_EXTRA_SA_SIZE, XCHAL_CP0_SA_ALIGN)
-#define XTENSA_CPE_CP1_OFFSET	\
-	XTOFS(XTENSA_CPE_CP0_OFFSET, XCHAL_CP0_SA_SIZE, XCHAL_CP1_SA_ALIGN)
-#define XTENSA_CPE_CP2_OFFSET	\
-	XTOFS(XTENSA_CPE_CP1_OFFSET, XCHAL_CP1_SA_SIZE, XCHAL_CP2_SA_ALIGN)
-#define XTENSA_CPE_CP3_OFFSET	\
-	XTOFS(XTENSA_CPE_CP2_OFFSET, XCHAL_CP2_SA_SIZE, XCHAL_CP3_SA_ALIGN)
-#define XTENSA_CPE_CP4_OFFSET	\
-	XTOFS(XTENSA_CPE_CP3_OFFSET, XCHAL_CP3_SA_SIZE, XCHAL_CP4_SA_ALIGN)
-#define XTENSA_CPE_CP5_OFFSET	\
-	XTOFS(XTENSA_CPE_CP4_OFFSET, XCHAL_CP4_SA_SIZE, XCHAL_CP5_SA_ALIGN)
-#define XTENSA_CPE_CP6_OFFSET	\
-	XTOFS(XTENSA_CPE_CP5_OFFSET, XCHAL_CP5_SA_SIZE, XCHAL_CP6_SA_ALIGN)
-#define XTENSA_CPE_CP7_OFFSET	\
-	XTOFS(XTENSA_CPE_CP6_OFFSET, XCHAL_CP6_SA_SIZE, XCHAL_CP7_SA_ALIGN)
-#define XTENSA_CP_EXTRA_SIZE	\
-	XTOFS(XTENSA_CPE_CP7_OFFSET, XCHAL_CP7_SA_SIZE, 16)
+.macro load_xtregs_opt ptr clb at1 at2 at3 at4 offset
+	.if XTREGS_OPT_SIZE > 0
+		addi	\clb, \ptr, \offset
+		xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT
+	.endif
+.endm
+#undef _SELECT
 
-#if XCHAL_CP_NUM > 0
-# ifndef __ASSEMBLY__
+#define _SELECT	(  XTHAL_SAS_TIE | XTHAL_SAS_OPT \
+		 | XTHAL_SAS_NOCC \
+		 | XTHAL_SAS_CALR | XTHAL_SAS_CALE | XTHAL_SAS_GLOB )
+
+.macro save_xtregs_user ptr clb at1 at2 at3 at4 offset
+	.if XTREGS_USER_SIZE > 0
+		addi	\clb, \ptr, \offset
+		xchal_ncp_store \clb \at1 \at2 \at3 \at4 select=_SELECT
+	.endif
+.endm
+
+.macro load_xtregs_user ptr clb at1 at2 at3 at4 offset
+	.if XTREGS_USER_SIZE > 0
+		addi	\clb, \ptr, \offset
+		xchal_ncp_load \clb \at1 \at2 \at3 \at4 select=_SELECT
+	.endif
+.endm
+#undef _SELECT
+
+
+
+#endif	/* __ASSEMBLY__ */
+
 /*
- * Tasks that own contents of (last user) each coprocessor.
- * Entries are 0 for not-owned or non-existent coprocessors.
- * Note: The size of this structure is fixed to 8 bytes in entry.S
+ * XTENSA_HAVE_COPROCESSOR(x) returns 1 if coprocessor x is configured.
+ *
+ * XTENSA_HAVE_IO_PORT(x) returns 1 if io-port x is configured.
+ *
  */
-typedef struct {
-	struct task_struct *owner;	/* owner */
-	int offset;			/* offset in cpextra space. */
-} coprocessor_info_t;
-# else
-#  define COPROCESSOR_INFO_OWNER 0
-#  define COPROCESSOR_INFO_OFFSET 4
-#  define COPROCESSOR_INFO_SIZE 8
-# endif
-#endif
-#endif	/* XCHAL_HAVE_CP */
 
+#define XTENSA_HAVE_COPROCESSOR(x)					\
+	((XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK) & (1 << (x)))
+#define XTENSA_HAVE_COPROCESSORS					\
+	(XCHAL_CP_MASK ^ XCHAL_CP_PORT_MASK)
+#define XTENSA_HAVE_IO_PORT(x)						\
+	(XCHAL_CP_PORT_MASK & (1 << (x)))
+#define XTENSA_HAVE_IO_PORTS						\
+	XCHAL_CP_PORT_MASK
 
 #ifndef __ASSEMBLY__
-# if XCHAL_CP_NUM > 0
-struct task_struct;
-extern void release_coprocessors (struct task_struct*);
-extern void save_coprocessor_registers(void*, int);
-# else
-#  define release_coprocessors(task)
-# endif
 
-typedef unsigned char cp_state_t[XTENSA_CP_EXTRA_SIZE]
-	__attribute__ ((aligned (XTENSA_CP_EXTRA_ALIGN)));
+
+#if XCHAL_HAVE_CP
+
+#define RSR_CPENABLE(x)	do {						  \
+	__asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \
+	} while(0);
+#define WSR_CPENABLE(x)	do {						  \
+  	__asm__ __volatile__("wsr %0," __stringify(CPENABLE) "; rsync" 	  \
+	    		     :: "a" (x));				  \
+	} while(0);
+
+#endif /* XCHAL_HAVE_CP */
+
+
+/*
+ * Additional registers.
+ * We define three types of additional registers:
+ *  ext: extra registers that are used by the compiler
+ *  cpn: optional registers that can be used by a user application
+ *  cpX: coprocessor registers that can only be used if the corresponding
+ *       CPENABLE bit is set.
+ */
+
+#define XCHAL_SA_REG(list,compiler,x,type,y,name,z,align,size,...)	\
+	__REG ## list (compiler, type, name, size, align)
+
+#define __REG0(compiler,t,name,s,a)	__REG0_ ## compiler (name)
+#define __REG1(compiler,t,name,s,a)	__REG1_ ## compiler (name)
+#define __REG2(c,type,...)		__REG2_ ## type (__VA_ARGS__)
+
+#define __REG0_0(name)
+#define __REG0_1(name)	__u32 name;
+#define __REG1_0(name)	__u32 name;
+#define __REG1_1(name)
+#define __REG2_0(n,s,a)	__u32 name;
+#define __REG2_1(n,s,a)	unsigned char n[s] __attribute__ ((aligned(a)));
+#define __REG2_2(n,s,a) unsigned char n[s] __attribute__ ((aligned(a)));
+
+typedef struct { XCHAL_NCP_SA_LIST(0) } xtregs_opt_t
+	__attribute__ ((aligned (XCHAL_NCP_SA_ALIGN)));
+typedef struct { XCHAL_NCP_SA_LIST(1) } xtregs_user_t
+	__attribute__ ((aligned (XCHAL_NCP_SA_ALIGN)));
+
+#if XTENSA_HAVE_COPROCESSORS
+
+typedef struct { XCHAL_CP0_SA_LIST(2) } xtregs_cp0_t
+	__attribute__ ((aligned (XCHAL_CP0_SA_ALIGN)));
+typedef struct { XCHAL_CP1_SA_LIST(2) } xtregs_cp1_t
+	__attribute__ ((aligned (XCHAL_CP1_SA_ALIGN)));
+typedef struct { XCHAL_CP2_SA_LIST(2) } xtregs_cp2_t
+	__attribute__ ((aligned (XCHAL_CP2_SA_ALIGN)));
+typedef struct { XCHAL_CP3_SA_LIST(2) } xtregs_cp3_t
+	__attribute__ ((aligned (XCHAL_CP3_SA_ALIGN)));
+typedef struct { XCHAL_CP4_SA_LIST(2) } xtregs_cp4_t
+	__attribute__ ((aligned (XCHAL_CP4_SA_ALIGN)));
+typedef struct { XCHAL_CP5_SA_LIST(2) } xtregs_cp5_t
+	__attribute__ ((aligned (XCHAL_CP5_SA_ALIGN)));
+typedef struct { XCHAL_CP6_SA_LIST(2) } xtregs_cp6_t
+	__attribute__ ((aligned (XCHAL_CP6_SA_ALIGN)));
+typedef struct { XCHAL_CP7_SA_LIST(2) } xtregs_cp7_t
+	__attribute__ ((aligned (XCHAL_CP7_SA_ALIGN)));
+
+extern struct thread_info* coprocessor_owner[XCHAL_CP_MAX];
+extern void coprocessor_save(void*, int);
+extern void coprocessor_load(void*, int);
+extern void coprocessor_flush(struct thread_info*, int);
+extern void coprocessor_restore(struct thread_info*, int);
+
+extern void coprocessor_release_all(struct thread_info*);
+extern void coprocessor_flush_all(struct thread_info*);
+
+static inline void coprocessor_clear_cpenable(void)
+{
+	unsigned long i = 0;
+	WSR_CPENABLE(i);
+}
+
+#endif	/* XTENSA_HAVE_COPROCESSORS */
 
 #endif	/* !__ASSEMBLY__ */
-
-
 #endif	/* _XTENSA_COPROCESSOR_H */
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
index 86479b8..11103e0 100644
--- a/include/asm-xtensa/elf.h
+++ b/include/asm-xtensa/elf.h
@@ -173,6 +173,21 @@
        _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
   } while (0)
 
+typedef struct {
+	xtregs_opt_t	opt;
+	xtregs_user_t	user;
+#if XTENSA_HAVE_COPROCESSORS
+	xtregs_cp0_t	cp0;
+	xtregs_cp1_t	cp1;
+	xtregs_cp2_t	cp2;
+	xtregs_cp3_t	cp3;
+	xtregs_cp4_t	cp4;
+	xtregs_cp5_t	cp5;
+	xtregs_cp6_t	cp6;
+	xtregs_cp7_t	cp7;
+#endif
+} elf_xtregs_t;
+
 #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
 
 struct task_struct;
diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h
index 96408f4..4918a4e 100644
--- a/include/asm-xtensa/processor.h
+++ b/include/asm-xtensa/processor.h
@@ -103,10 +103,6 @@
 	unsigned long dbreaka[XCHAL_NUM_DBREAK];
 	unsigned long dbreakc[XCHAL_NUM_DBREAK];
 
-	/* Allocate storage for extra state and coprocessor state. */
-	unsigned char cp_save[XTENSA_CP_EXTRA_SIZE]
-		__attribute__ ((aligned(XTENSA_CP_EXTRA_ALIGN)));
-
 	/* Make structure 16 bytes aligned. */
 	int align[0] __attribute__ ((aligned(16)));
 };
@@ -162,21 +158,16 @@
 struct task_struct;
 struct mm_struct;
 
-// FIXME: do we need release_thread for CP??
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-// FIXME: do we need prepare_to_copy (lazy status) for CP??
 /* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)	do { } while (0)
+extern void prepare_to_copy(struct task_struct*);
 
-/*
- * create a kernel thread without removing it from tasklists
- */
+/* Create a kernel thread without removing it from tasklists */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
-
 #define copy_segments(p, mm)	do { } while(0)
 #define release_segments(mm)	do { } while(0)
 #define forget_segments()	do { } while (0)
diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h
index 77ff02d..422c73e 100644
--- a/include/asm-xtensa/ptrace.h
+++ b/include/asm-xtensa/ptrace.h
@@ -53,33 +53,30 @@
 
 /* Registers used by strace */
 
-#define REG_A_BASE	0xfc000000
-#define REG_AR_BASE	0x04000000
-#define REG_PC		0x14000000
-#define REG_PS		0x080000e6
-#define REG_WB		0x08000048
-#define REG_WS		0x08000049
-#define REG_LBEG	0x08000000
-#define REG_LEND	0x08000001
-#define REG_LCOUNT	0x08000002
-#define REG_SAR		0x08000003
-#define REG_DEPC	0x080000c0
-#define	REG_EXCCAUSE	0x080000e8
-#define REG_EXCVADDR	0x080000ee
-#define SYSCALL_NR	0x1
+#define REG_A_BASE	0x0000
+#define REG_AR_BASE	0x0100
+#define REG_PC		0x0020
+#define REG_PS		0x02e6
+#define REG_WB		0x0248
+#define REG_WS		0x0249
+#define REG_LBEG	0x0200
+#define REG_LEND	0x0201
+#define REG_LCOUNT	0x0202
+#define REG_SAR		0x0203
 
-#define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1)
+#define SYSCALL_NR	0x00ff
 
 /* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */
 
-#define PTRACE_GETREGS            12
-#define PTRACE_SETREGS            13
-#define PTRACE_GETFPREGS          14
-#define PTRACE_SETFPREGS          15
-#define PTRACE_GETFPREGSIZE       18
+#define PTRACE_GETREGS		12
+#define PTRACE_SETREGS		13
+#define PTRACE_GETXTREGS	18
+#define PTRACE_SETXTREGS	19
 
 #ifndef __ASSEMBLY__
 
+#ifdef __KERNEL__
+
 /*
  * This struct defines the way the registers are stored on the
  * kernel stack during a system call or other kernel entry.
@@ -102,6 +99,9 @@
 	unsigned long icountlevel;	/*  60 */
 	int reserved[1];		/*  64 */
 
+	/* Additional configurable registers that are used by the compiler. */
+	xtregs_opt_t xtregs_opt;
+
 	/* Make sure the areg field is 16 bytes aligned. */
 	int align[0] __attribute__ ((aligned(16)));
 
@@ -111,8 +111,6 @@
 	unsigned long areg[16];		/* 128 (64) */
 };
 
-#ifdef __KERNEL__
-
 #include <asm/variant/core.h>
 
 # define task_pt_regs(tsk) ((struct pt_regs*) \
diff --git a/include/asm-xtensa/regs.h b/include/asm-xtensa/regs.h
index c913d25..d4baed2 100644
--- a/include/asm-xtensa/regs.h
+++ b/include/asm-xtensa/regs.h
@@ -100,7 +100,14 @@
 #define EXCCAUSE_DTLB_SIZE_RESTRICTION		27
 #define EXCCAUSE_LOAD_CACHE_ATTRIBUTE		28
 #define EXCCAUSE_STORE_CACHE_ATTRIBUTE		29
-#define EXCCAUSE_FLOATING_POINT			40
+#define EXCCAUSE_COPROCESSOR0_DISABLED		32
+#define EXCCAUSE_COPROCESSOR1_DISABLED		33
+#define EXCCAUSE_COPROCESSOR2_DISABLED		34
+#define EXCCAUSE_COPROCESSOR3_DISABLED		35
+#define EXCCAUSE_COPROCESSOR4_DISABLED		36
+#define EXCCAUSE_COPROCESSOR5_DISABLED		37
+#define EXCCAUSE_COPROCESSOR6_DISABLED		38
+#define EXCCAUSE_COPROCESSOR7_DISABLED		39
 
 /*  PS register fields.  */
 
diff --git a/include/asm-xtensa/sigcontext.h b/include/asm-xtensa/sigcontext.h
index dff3c54..03383af 100644
--- a/include/asm-xtensa/sigcontext.h
+++ b/include/asm-xtensa/sigcontext.h
@@ -22,6 +22,7 @@
 	unsigned long sc_acclo;
 	unsigned long sc_acchi;
 	unsigned long sc_a[16];
+	void *sc_xtregs;
 };
 
 #endif /* _XTENSA_SIGCONTEXT_H */
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index e0cb911..62b1e8f 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -46,42 +46,6 @@
 	return flags & 0xf;
 }
 
-#define RSR_CPENABLE(x)	do {						  \
-	__asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \
-	} while(0);
-#define WSR_CPENABLE(x)	do {						  \
-  	__asm__ __volatile__("wsr %0," __stringify(CPENABLE)";rsync" 	  \
-	    		     :: "a" (x));} while(0);
-
-#define clear_cpenable() __clear_cpenable()
-
-static inline void __clear_cpenable(void)
-{
-#if XCHAL_HAVE_CP
-	unsigned long i = 0;
-	WSR_CPENABLE(i);
-#endif
-}
-
-static inline void enable_coprocessor(int i)
-{
-#if XCHAL_HAVE_CP
-	int cp;
-	RSR_CPENABLE(cp);
-	cp |= 1 << i;
-	WSR_CPENABLE(cp);
-#endif
-}
-
-static inline void disable_coprocessor(int i)
-{
-#if XCHAL_HAVE_CP
-	int cp;
-	RSR_CPENABLE(cp);
-	cp &= ~(1 << i);
-	WSR_CPENABLE(cp);
-#endif
-}
 
 #define smp_read_barrier_depends() do { } while(0)
 #define read_barrier_depends() do { } while(0)
@@ -111,7 +75,6 @@
 
 #define switch_to(prev,next,last)		\
 do {						\
-	clear_cpenable();			\
 	(last) = _switch_to(prev, next);	\
 } while(0)
 
@@ -244,7 +207,7 @@
 		"wsr	a13," __stringify(SAR) "\n\t"
 		"wsr	a14," __stringify(PS) "\n\t"
 		:: "a" (&a0), "a" (&ps)
-		: "a2", "a3", "a12", "a13", "a14", "a15", "memory");
+		: "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory");
 }
 
 #define arch_align_stack(x) (x)
diff --git a/include/asm-xtensa/thread_info.h b/include/asm-xtensa/thread_info.h
index 52c9582..a2c6406 100644
--- a/include/asm-xtensa/thread_info.h
+++ b/include/asm-xtensa/thread_info.h
@@ -27,6 +27,21 @@
 
 #ifndef __ASSEMBLY__
 
+#if XTENSA_HAVE_COPROCESSORS
+
+typedef struct xtregs_coprocessor {
+	xtregs_cp0_t cp0;
+	xtregs_cp1_t cp1;
+	xtregs_cp2_t cp2;
+	xtregs_cp3_t cp3;
+	xtregs_cp4_t cp4;
+	xtregs_cp5_t cp5;
+	xtregs_cp6_t cp6;
+	xtregs_cp7_t cp7;
+} xtregs_coprocessor_t;
+
+#endif
+
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
@@ -38,7 +53,13 @@
 	mm_segment_t		addr_limit;	/* thread address space */
 	struct restart_block    restart_block;
 
+	unsigned long		cpenable;
 
+	/* Allocate storage for extra user states and coprocessor states. */
+#if XTENSA_HAVE_COPROCESSORS
+	xtregs_coprocessor_t	xtregs_cp;
+#endif
+	xtregs_user_t		xtregs_user;
 };
 
 #else /* !__ASSEMBLY__ */
diff --git a/include/asm-xtensa/variant-fsf/tie-asm.h b/include/asm-xtensa/variant-fsf/tie-asm.h
new file mode 100644
index 0000000..68a73bf
--- /dev/null
+++ b/include/asm-xtensa/variant-fsf/tie-asm.h
@@ -0,0 +1,70 @@
+/*
+ * This header file contains assembly-language definitions (assembly
+ * macros, etc.) for this specific Xtensa processor's TIE extensions
+ * and options.  It is customized to this Xtensa processor configuration.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2008 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_TIE_ASM_H
+#define _XTENSA_CORE_TIE_ASM_H
+
+/*  Selection parameter values for save-area save/restore macros:  */
+/*  Option vs. TIE:  */
+#define XTHAL_SAS_TIE	0x0001	/* custom extension or coprocessor */
+#define XTHAL_SAS_OPT	0x0002	/* optional (and not a coprocessor) */
+/*  Whether used automatically by compiler:  */
+#define XTHAL_SAS_NOCC	0x0004	/* not used by compiler w/o special opts/code */
+#define XTHAL_SAS_CC	0x0008	/* used by compiler without special opts/code */
+/*  ABI handling across function calls:  */
+#define XTHAL_SAS_CALR	0x0010	/* caller-saved */
+#define XTHAL_SAS_CALE	0x0020	/* callee-saved */
+#define XTHAL_SAS_GLOB	0x0040	/* global across function calls (in thread) */
+/*  Misc  */
+#define XTHAL_SAS_ALL	0xFFFF	/* include all default NCP contents */
+
+
+
+/* Macro to save all non-coprocessor (extra) custom TIE and optional state
+ * (not including zero-overhead loop registers).
+ * Save area ptr (clobbered):  ptr  (1 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)
+ */
+	.macro xchal_ncp_store  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+	xchal_sa_start	\continue, \ofs
+	.ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select
+	xchal_sa_align	\ptr, 0, 1024-4, 4, 4
+	rur	\at1, THREADPTR		// threadptr option
+	s32i	\at1, \ptr, .Lxchal_ofs_ + 0
+	.set	.Lxchal_ofs_, .Lxchal_ofs_ + 4
+	.endif
+	.endm	// xchal_ncp_store
+
+/* Macro to save all non-coprocessor (extra) custom TIE and optional state
+ * (not including zero-overhead loop registers).
+ * Save area ptr (clobbered):  ptr  (1 byte aligned)
+ * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)
+ */
+	.macro xchal_ncp_load  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL
+	xchal_sa_start	\continue, \ofs
+	.ifeq (XTHAL_SAS_OPT | XTHAL_SAS_CC | XTHAL_SAS_GLOB) & ~\select
+	xchal_sa_align	\ptr, 0, 1024-4, 4, 4
+	l32i	\at1, \ptr, .Lxchal_ofs_ + 0
+	wur	\at1, THREADPTR		// threadptr option
+	.set	.Lxchal_ofs_, .Lxchal_ofs_ + 4
+	.endif
+	.endm	// xchal_ncp_load
+
+
+
+#define XCHAL_NCP_NUM_ATMPS	1
+
+
+#define XCHAL_SA_NUM_ATMPS	1
+
+#endif /*_XTENSA_CORE_TIE_ASM_H*/
+
diff --git a/include/asm-xtensa/variant-fsf/tie.h b/include/asm-xtensa/variant-fsf/tie.h
index a73c716..bf40201 100644
--- a/include/asm-xtensa/variant-fsf/tie.h
+++ b/include/asm-xtensa/variant-fsf/tie.h
@@ -1,22 +1,77 @@
 /*
- * Xtensa processor core configuration information.
+ * This header file describes this specific Xtensa processor's TIE extensions
+ * that extend basic Xtensa core functionality.  It is customized to this
+ * Xtensa processor configuration.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999-2006 Tensilica Inc.
+ * Copyright (C) 1999-2007 Tensilica Inc.
  */
 
-#ifndef XTENSA_TIE_H
-#define XTENSA_TIE_H
-
-/*----------------------------------------------------------------------
-			COPROCESSORS and EXTRA STATE
-  ----------------------------------------------------------------------*/
+#ifndef _XTENSA_CORE_TIE_H
+#define _XTENSA_CORE_TIE_H
 
 #define XCHAL_CP_NUM			0	/* number of coprocessors */
-#define XCHAL_CP_MASK			0x00
+#define XCHAL_CP_MAX			0	/* max CP ID + 1 (0 if none) */
+#define XCHAL_CP_MASK			0x00	/* bitmask of all CPs by ID */
+#define XCHAL_CP_PORT_MASK		0x00	/* bitmask of only port CPs */
 
-#endif /*XTENSA_CONFIG_TIE_H*/
+/*  Basic parameters of each coprocessor:  */
+#define XCHAL_CP7_NAME			"XTIOP"
+#define XCHAL_CP7_IDENT			XTIOP
+#define XCHAL_CP7_SA_SIZE		0	/* size of state save area */
+#define XCHAL_CP7_SA_ALIGN		1	/* min alignment of save area */
+#define XCHAL_CP_ID_XTIOP		7	/* coprocessor ID (0..7) */
+
+/*  Filler info for unassigned coprocessors, to simplify arrays etc:  */
+#define XCHAL_NCP_SA_SIZE		0
+#define XCHAL_NCP_SA_ALIGN		1
+#define XCHAL_CP0_SA_SIZE		0
+#define XCHAL_CP0_SA_ALIGN		1
+#define XCHAL_CP1_SA_SIZE		0
+#define XCHAL_CP1_SA_ALIGN		1
+#define XCHAL_CP2_SA_SIZE		0
+#define XCHAL_CP2_SA_ALIGN		1
+#define XCHAL_CP3_SA_SIZE		0
+#define XCHAL_CP3_SA_ALIGN		1
+#define XCHAL_CP4_SA_SIZE		0
+#define XCHAL_CP4_SA_ALIGN		1
+#define XCHAL_CP5_SA_SIZE		0
+#define XCHAL_CP5_SA_ALIGN		1
+#define XCHAL_CP6_SA_SIZE		0
+#define XCHAL_CP6_SA_ALIGN		1
+
+/*  Save area for non-coprocessor optional and custom (TIE) state:  */
+#define XCHAL_NCP_SA_SIZE		0
+#define XCHAL_NCP_SA_ALIGN		1
+
+/*  Total save area for optional and custom state (NCP + CPn):  */
+#define XCHAL_TOTAL_SA_SIZE		0	/* with 16-byte align padding */
+#define XCHAL_TOTAL_SA_ALIGN		1	/* actual minimum alignment */
+
+#define XCHAL_NCP_SA_NUM	0
+#define XCHAL_NCP_SA_LIST(s)
+#define XCHAL_CP0_SA_NUM	0
+#define XCHAL_CP0_SA_LIST(s)
+#define XCHAL_CP1_SA_NUM	0
+#define XCHAL_CP1_SA_LIST(s)
+#define XCHAL_CP2_SA_NUM	0
+#define XCHAL_CP2_SA_LIST(s)
+#define XCHAL_CP3_SA_NUM	0
+#define XCHAL_CP3_SA_LIST(s)
+#define XCHAL_CP4_SA_NUM	0
+#define XCHAL_CP4_SA_LIST(s)
+#define XCHAL_CP5_SA_NUM	0
+#define XCHAL_CP5_SA_LIST(s)
+#define XCHAL_CP6_SA_NUM	0
+#define XCHAL_CP6_SA_LIST(s)
+#define XCHAL_CP7_SA_NUM	0
+#define XCHAL_CP7_SA_LIST(s)
+
+/* Byte length of instruction from its first nibble (op0 field), per FLIX.  */
+#define XCHAL_OP0_FORMAT_LENGTHS	3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3
+
+#endif /*_XTENSA_CORE_TIE_H*/