Commit fffad3e1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xtensa-next-20160320' of git://github.com/czankel/xtensa-linux

Pull Xtensa updates from Chris Zankel:
 "Xtensa improvements for 4.6:

   - control whether perf IRQ is treated as NMI from Kconfig
   - implement ioremap for regions outside KIO segment
   - fix ISS serial port behaviour when EOF is reached
   - fix preemption in {clear,copy}_user_highpage
   - fix endianness issues for XTFPGA devices, big-endian cores are now
     fully functional
   - clean up debug infrastructure and add support for hardware
     breakpoints and watchpoints
   - add processor configurations for Three Core HiFi-2 MX and HiFi3
     cpus"

* tag 'xtensa-next-20160320' of git://github.com/czankel/xtensa-linux:
  xtensa: add test_kc705_hifi variant
  xtensa: add Three Core HiFi-2 MX Variant.
  xtensa: support hardware breakpoints/watchpoints
  xtensa: use context structure for debug exceptions
  xtensa: remove remaining non-functional KGDB bits
  xtensa: clear all DBREAKC registers on start
  xtensa: xtfpga: fix earlycon endianness
  xtensa: xtfpga: fix i2c controller register width and endianness
  xtensa: xtfpga: fix ethernet controller endianness
  xtensa: xtfpga: fix serial port register width and endianness
  xtensa: define CONFIG_CPU_{BIG,LITTLE}_ENDIAN
  xtensa: fix preemption in {clear,copy}_user_highpage
  xtensa: ISS: don't hang if stdin EOF is reached
  xtensa: support ioremap for memory outside KIO region
  xtensa: use XTENSA_INT_LEVEL macro in asm/timex.h
  xtensa: make fake NMI configurable
parents 1e75a9f3 9da8320b
......@@ -17,6 +17,7 @@ config XTENSA
select HAVE_DMA_API_DEBUG
select HAVE_FUNCTION_TRACER
select HAVE_FUTEX_CMPXCHG if !MMU
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
......@@ -138,6 +139,22 @@ config XTENSA_VARIANT_HAVE_PERF_EVENTS
If unsure, say N.
config XTENSA_FAKE_NMI
bool "Treat PMM IRQ as NMI"
depends on XTENSA_VARIANT_HAVE_PERF_EVENTS
default n
help
If PMM IRQ is the only IRQ at EXCM level it is safe to
treat it as NMI, which improves accuracy of profiling.
If there are other interrupts at or above PMM IRQ priority level
but not above the EXCM level, PMM IRQ still may be treated as NMI,
but only if these IRQs are not used. There will be a build warning
saying that this is not safe, and a bugcheck if one of these IRQs
actually fire.
If unsure, say N.
config XTENSA_UNALIGNED_USER
bool "Unaligned memory access in use space"
help
......
......@@ -53,9 +53,11 @@ endif
ifeq ($(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1)
CHECKFLAGS += -D__XTENSA_EB__
KBUILD_CPPFLAGS += -DCONFIG_CPU_BIG_ENDIAN
endif
ifeq ($(shell echo __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1)
CHECKFLAGS += -D__XTENSA_EL__
KBUILD_CPPFLAGS += -DCONFIG_CPU_LITTLE_ENDIAN
endif
vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y))
......
......@@ -5,7 +5,7 @@
/ {
compatible = "cdns,xtensa-kc705";
chosen {
bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000";
bootargs = "earlycon=uart8250,mmio32native,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000";
};
memory@0 {
device_type = "memory";
......
......@@ -5,7 +5,7 @@ / {
interrupt-parent = <&pic>;
chosen {
bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug";
bootargs = "earlycon=uart8250,mmio32native,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug";
};
memory@0 {
......@@ -60,6 +60,8 @@ serial0: serial@0d050020 {
no-loopback-test;
reg = <0x0d050020 0x20>;
reg-shift = <2>;
reg-io-width = <4>;
native-endian;
interrupts = <0 1>; /* external irq 0 */
clocks = <&osc>;
};
......@@ -67,6 +69,7 @@ serial0: serial@0d050020 {
enet0: ethoc@0d030000 {
compatible = "opencores,ethoc";
reg = <0x0d030000 0x4000 0x0d800000 0x4000>;
native-endian;
interrupts = <1 1>; /* external irq 1 */
local-mac-address = [00 50 c2 13 6f 00];
clocks = <&osc>;
......@@ -86,7 +89,8 @@ i2c0: i2c-master@0d090000 {
#size-cells = <0>;
reg = <0x0d090000 0x20>;
reg-shift = <2>;
reg-io-width = <1>;
reg-io-width = <4>;
native-endian;
interrupts = <4 1>;
clocks = <&osc>;
......
/*
* Xtensa hardware breakpoints/watchpoints handling functions
*
* 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) 2016 Cadence Design Systems Inc.
*/
#ifndef __ASM_XTENSA_HW_BREAKPOINT_H
#define __ASM_XTENSA_HW_BREAKPOINT_H
#ifdef CONFIG_HAVE_HW_BREAKPOINT
#include <linux/kdebug.h>
#include <linux/types.h>
#include <uapi/linux/hw_breakpoint.h>
/* Breakpoint */
#define XTENSA_BREAKPOINT_EXECUTE 0
/* Watchpoints */
#define XTENSA_BREAKPOINT_LOAD 1
#define XTENSA_BREAKPOINT_STORE 2
struct arch_hw_breakpoint {
unsigned long address;
u16 len;
u16 type;
};
struct perf_event;
struct pt_regs;
struct task_struct;
int hw_breakpoint_slots(int type);
int arch_check_bp_in_kernelspace(struct perf_event *bp);
int arch_validate_hwbkpt_settings(struct perf_event *bp);
int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);
int arch_install_hw_breakpoint(struct perf_event *bp);
void arch_uninstall_hw_breakpoint(struct perf_event *bp);
void hw_breakpoint_pmu_read(struct perf_event *bp);
int check_hw_breakpoint(struct pt_regs *regs);
void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
#else
struct task_struct;
static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
{
}
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif /* __ASM_XTENSA_HW_BREAKPOINT_H */
......@@ -25,9 +25,12 @@
#ifdef CONFIG_MMU
void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size);
void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size);
void xtensa_iounmap(volatile void __iomem *addr);
/*
* Return the virtual address for the specified bus memory.
* Note that we currently don't support any address outside the KIO segment.
*/
static inline void __iomem *ioremap_nocache(unsigned long offset,
unsigned long size)
......@@ -36,7 +39,7 @@ static inline void __iomem *ioremap_nocache(unsigned long offset,
&& offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE)
return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR);
else
BUG();
return xtensa_ioremap_nocache(offset, size);
}
static inline void __iomem *ioremap_cache(unsigned long offset,
......@@ -46,7 +49,7 @@ static inline void __iomem *ioremap_cache(unsigned long offset,
&& offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE)
return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR);
else
BUG();
return xtensa_ioremap_cache(offset, size);
}
#define ioremap_cache ioremap_cache
......@@ -60,6 +63,13 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
static inline void iounmap(volatile void __iomem *addr)
{
unsigned long va = (unsigned long) addr;
if (!(va >= XCHAL_KIO_CACHED_VADDR &&
va - XCHAL_KIO_CACHED_VADDR < XCHAL_KIO_SIZE) &&
!(va >= XCHAL_KIO_BYPASS_VADDR &&
va - XCHAL_KIO_BYPASS_VADDR < XCHAL_KIO_SIZE))
xtensa_iounmap(addr);
}
#define virt_to_bus virt_to_phys
......
......@@ -13,6 +13,7 @@
#define _XTENSA_IRQFLAGS_H
#include <linux/types.h>
#include <asm/processor.h>
static inline unsigned long arch_local_save_flags(void)
{
......
......@@ -78,22 +78,20 @@
#define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level)
#define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK)
#define IS_POW2(v) (((v) & ((v) - 1)) == 0)
#define XTENSA_INTLEVEL_ANDBELOW_MASK(l) _XTENSA_INTLEVEL_ANDBELOW_MASK(l)
#define _XTENSA_INTLEVEL_ANDBELOW_MASK(l) (XCHAL_INTLEVEL##l##_ANDBELOW_MASK)
#define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT)
/* LOCKLEVEL defines the interrupt level that masks all
* general-purpose interrupts.
*/
#if defined(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) && \
defined(XCHAL_PROFILING_INTERRUPT) && \
PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \
XCHAL_EXCM_LEVEL > 1 && \
IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL))
#define LOCKLEVEL (XCHAL_EXCM_LEVEL - 1)
#if defined(CONFIG_XTENSA_FAKE_NMI) && defined(XCHAL_PROFILING_INTERRUPT)
#define LOCKLEVEL (PROFILING_INTLEVEL - 1)
#else
#define LOCKLEVEL XCHAL_EXCM_LEVEL
#endif
#define TOPLEVEL XCHAL_EXCM_LEVEL
#define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL)
......@@ -132,11 +130,10 @@ struct thread_struct {
unsigned long bad_vaddr; /* last user fault */
unsigned long bad_uaddr; /* last kernel fault accessing user space */
unsigned long error_code;
unsigned long ibreak[XCHAL_NUM_IBREAK];
unsigned long dbreaka[XCHAL_NUM_DBREAK];
unsigned long dbreakc[XCHAL_NUM_DBREAK];
#ifdef CONFIG_HAVE_HW_BREAKPOINT
struct perf_event *ptrace_bp[XCHAL_NUM_IBREAK];
struct perf_event *ptrace_wp[XCHAL_NUM_DBREAK];
#endif
/* Make structure 16 bytes aligned. */
int align[0] __attribute__ ((aligned(16)));
};
......
......@@ -28,6 +28,7 @@
/* Special registers. */
#define SREG_MR 32
#define SREG_IBREAKENABLE 96
#define SREG_IBREAKA 128
#define SREG_DBREAKA 144
#define SREG_DBREAKC 160
......@@ -103,6 +104,8 @@
/* DEBUGCAUSE register fields. */
#define DEBUGCAUSE_DBNUM_MASK 0xf00
#define DEBUGCAUSE_DBNUM_SHIFT 8 /* First bit of DBNUM field */
#define DEBUGCAUSE_DEBUGINT_BIT 5 /* External debug interrupt */
#define DEBUGCAUSE_BREAKN_BIT 4 /* BREAK.N instruction */
#define DEBUGCAUSE_BREAK_BIT 3 /* BREAK instruction */
......
......@@ -111,6 +111,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
#define TIF_DB_DISABLED 8 /* debug trap disabled for syscall */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
......
......@@ -12,19 +12,16 @@
#include <asm/processor.h>
#include <linux/stringify.h>
#define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL
#define INTLEVEL(x) _INTLEVEL(x)
#if XCHAL_NUM_TIMERS > 0 && \
INTLEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL
XTENSA_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL
# define LINUX_TIMER 0
# define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT
#elif XCHAL_NUM_TIMERS > 1 && \
INTLEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL
XTENSA_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL
# define LINUX_TIMER 1
# define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT
#elif XCHAL_NUM_TIMERS > 2 && \
INTLEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL
XTENSA_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL
# define LINUX_TIMER 2
# define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT
#else
......
......@@ -65,4 +65,21 @@ static inline void spill_registers(void)
#endif
}
struct debug_table {
/* Pointer to debug exception handler */
void (*debug_exception)(void);
/* Temporary register save area */
unsigned long debug_save[1];
#ifdef CONFIG_HAVE_HW_BREAKPOINT
/* Save area for DBREAKC registers */
unsigned long dbreakc_save[XCHAL_NUM_DBREAK];
/* Saved ICOUNT register */
unsigned long icount_save;
/* Saved ICOUNTLEVEL register */
unsigned long icount_level_save;
#endif
};
void debug_exception(void);
#endif /* _XTENSA_TRAPS_H */
......@@ -72,6 +72,8 @@
#define PTRACE_SETREGS 13
#define PTRACE_GETXTREGS 18
#define PTRACE_SETXTREGS 19
#define PTRACE_GETHBPREGS 20
#define PTRACE_SETHBPREGS 21
#endif /* _UAPI_XTENSA_PTRACE_H */
......@@ -8,12 +8,12 @@ obj-y := align.o coprocessor.o entry.o irq.o pci-dma.o platform.o process.o \
ptrace.o setup.o signal.o stacktrace.o syscall.o time.o traps.o \
vectors.o
obj-$(CONFIG_KGDB) += xtensa-stub.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
obj-$(CONFIG_SMP) += smp.o mxhead.o
obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
AFLAGS_head.o += -mtext-section-literals
AFLAGS_mxhead.o += -mtext-section-literals
......
......@@ -23,6 +23,7 @@
#include <linux/kbuild.h>
#include <asm/ptrace.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
int main(void)
......@@ -117,5 +118,16 @@ int main(void)
DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
DEFINE(PG_ARCH_1, PG_arch_1);
/* struct debug_table */
DEFINE(DT_DEBUG_EXCEPTION,
offsetof(struct debug_table, debug_exception));
DEFINE(DT_DEBUG_SAVE, offsetof(struct debug_table, debug_save));
#ifdef CONFIG_HAVE_HW_BREAKPOINT
DEFINE(DT_DBREAKC_SAVE, offsetof(struct debug_table, dbreakc_save));
DEFINE(DT_ICOUNT_SAVE, offsetof(struct debug_table, icount_save));
DEFINE(DT_ICOUNT_LEVEL_SAVE,
offsetof(struct debug_table, icount_level_save));
#endif
return 0;
}
......@@ -543,6 +543,12 @@ common_exception_return:
#endif
5:
#ifdef CONFIG_HAVE_HW_BREAKPOINT
_bbci.l a4, TIF_DB_DISABLED, 7f
movi a4, restore_dbreak
callx4 a4
7:
#endif
#ifdef CONFIG_DEBUG_TLB_SANITY
l32i a4, a1, PT_DEPC
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
......@@ -789,39 +795,99 @@ ENTRY(debug_exception)
movi a2, 1 << PS_EXCM_BIT
or a2, a0, a2
movi a0, debug_exception # restore a3, debug jump vector
wsr a2, ps
xsr a0, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
/* Switch to kernel/user stack, restore jump vector, and save a0 */
bbsi.l a2, PS_UM_BIT, 2f # jump if user mode
addi a2, a1, -16-PT_SIZE # assume kernel stack
3:
l32i a0, a3, DT_DEBUG_SAVE
s32i a1, a2, PT_AREG1
s32i a0, a2, PT_AREG0
movi a0, 0
s32i a1, a2, PT_AREG1
s32i a0, a2, PT_DEPC # mark it as a regular exception
xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
xsr a0, depc
s32i a3, a2, PT_AREG3
s32i a0, a2, PT_AREG2
mov a1, a2
/* Debug exception is handled as an exception, so interrupts will
* likely be enabled in the common exception handler. Disable
* preemption if we have HW breakpoints to preserve DEBUGCAUSE.DBNUM
* meaning.
*/
#if defined(CONFIG_PREEMPT_COUNT) && defined(CONFIG_HAVE_HW_BREAKPOINT)
GET_THREAD_INFO(a2, a1)
l32i a3, a2, TI_PRE_COUNT
addi a3, a3, 1
s32i a3, a2, TI_PRE_COUNT
#endif
rsr a2, ps
bbsi.l a2, PS_UM_BIT, _user_exception
j _kernel_exception
2: rsr a2, excsave1
l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer
s32i a0, a2, PT_AREG0
j 3b
#ifdef CONFIG_HAVE_HW_BREAKPOINT
/* Debug exception while in exception mode. This may happen when
* window overflow/underflow handler or fast exception handler hits
* data breakpoint, in which case save and disable all data
* breakpoints, single-step faulting instruction and restore data
* breakpoints.
*/
1:
bbci.l a0, PS_UM_BIT, 1b # jump if kernel mode
rsr a0, debugcause
bbsi.l a0, DEBUGCAUSE_DBREAK_BIT, .Ldebug_save_dbreak
.set _index, 0
.rept XCHAL_NUM_DBREAK
l32i a0, a3, DT_DBREAKC_SAVE + _index * 4
wsr a0, SREG_DBREAKC + _index
.set _index, _index + 1
.endr
l32i a0, a3, DT_ICOUNT_LEVEL_SAVE
wsr a0, icountlevel
l32i a0, a3, DT_ICOUNT_SAVE
xsr a0, icount
l32i a0, a3, DT_DEBUG_SAVE
xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
rfi XCHAL_DEBUGLEVEL
.Ldebug_save_dbreak:
.set _index, 0
.rept XCHAL_NUM_DBREAK
movi a0, 0
s32i a1, a2, PT_AREG1
s32i a0, a2, PT_DEPC
xsr a0, depc
s32i a3, a2, PT_AREG3
s32i a0, a2, PT_AREG2
mov a1, a2
j _user_exception
xsr a0, SREG_DBREAKC + _index
s32i a0, a3, DT_DBREAKC_SAVE + _index * 4
.set _index, _index + 1
.endr
/* Debug exception while in exception mode. */
movi a0, XCHAL_EXCM_LEVEL + 1
xsr a0, icountlevel
s32i a0, a3, DT_ICOUNT_LEVEL_SAVE
movi a0, 0xfffffffe
xsr a0, icount
s32i a0, a3, DT_ICOUNT_SAVE
l32i a0, a3, DT_DEBUG_SAVE
xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
rfi XCHAL_DEBUGLEVEL
#else
/* Debug exception while in exception mode. Should not happen. */
1: j 1b // FIXME!!
#endif
ENDPROC(debug_exception)
......
......@@ -128,7 +128,7 @@ ENTRY(_startup)
wsr a0, icountlevel
.set _index, 0
.rept XCHAL_NUM_DBREAK - 1
.rept XCHAL_NUM_DBREAK
wsr a0, SREG_DBREAKC + _index
.set _index, _index + 1
.endr
......@@ -197,11 +197,6 @@ ENTRY(_startup)
wsr a2, ps # (enable reg-windows; progmode stack)
rsync
/* Set up EXCSAVE[DEBUGLEVEL] to point to the Debug Exception Handler.*/
movi a2, debug_exception
wsr a2, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
#ifdef CONFIG_SMP
/*
* Notice that we assume with SMP that cores have PRID
......
/*
* Xtensa hardware breakpoints/watchpoints handling functions
*
* 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) 2016 Cadence Design Systems Inc.
*/
#include <linux/hw_breakpoint.h>
#include <linux/log2.h>
#include <linux/percpu.h>
#include <linux/perf_event.h>
#include <variant/core.h>
/* Breakpoint currently in use for each IBREAKA. */
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[XCHAL_NUM_IBREAK]);
/* Watchpoint currently in use for each DBREAKA. */
static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[XCHAL_NUM_DBREAK]);
int hw_breakpoint_slots(int type)
{
switch (type) {
case TYPE_INST:
return XCHAL_NUM_IBREAK;
case TYPE_DATA:
return XCHAL_NUM_DBREAK;
default:
pr_warn("unknown slot type: %d\n", type);
return 0;
}
}
int arch_check_bp_in_kernelspace(struct perf_event *bp)
{
unsigned int len;
unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
va = info->address;
len = bp->attr.bp_len;
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
}
/*
* Construct an arch_hw_breakpoint from a perf_event.
*/
static int arch_build_bp_info(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
/* Type */
switch (bp->attr.bp_type) {
case HW_BREAKPOINT_X:
info->type = XTENSA_BREAKPOINT_EXECUTE;
break;
case HW_BREAKPOINT_R:
info->type = XTENSA_BREAKPOINT_LOAD;
break;
case HW_BREAKPOINT_W:
info->type = XTENSA_BREAKPOINT_STORE;
break;
case HW_BREAKPOINT_RW:
info->type = XTENSA_BREAKPOINT_LOAD | XTENSA_BREAKPOINT_STORE;
break;
default:
return -EINVAL;
}
/* Len */
info->len = bp->attr.bp_len;
if (info->len < 1 || info->len > 64 || !is_power_of_2(info->len))
return -EINVAL;
/* Address */
info->address = bp->attr.bp_addr;
if (info->address & (info->len - 1))
return -EINVAL;
return 0;
}
int arch_validate_hwbkpt_settings(struct perf_event *bp)
{
int ret;
/* Build the arch_hw_breakpoint. */
ret = arch_build_bp_info(bp);
return ret;
}
int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data)
{
return NOTIFY_DONE;
}
static void xtensa_wsr(unsigned long v, u8 sr)
{
/* We don't have indexed wsr and creating instruction dynamically
* doesn't seem worth it given how small XCHAL_NUM_IBREAK and
* XCHAL_NUM_DBREAK are. Thus the switch. In case build breaks here
* the switch below needs to be extended.
*/
BUILD_BUG_ON(XCHAL_NUM_IBREAK > 2);
BUILD_BUG_ON(XCHAL_NUM_DBREAK > 2);
switch (sr) {
#if XCHAL_NUM_IBREAK > 0
case SREG_IBREAKA + 0:
WSR(v, SREG_IBREAKA + 0);
break;
#endif
#if XCHAL_NUM_IBREAK > 1
case SREG_IBREAKA + 1:
WSR(v, SREG_IBREAKA + 1);
break;
#endif
#if XCHAL_NUM_DBREAK > 0
case SREG_DBREAKA + 0:
WSR(v, SREG_DBREAKA + 0);
break;
case SREG_DBREAKC + 0:
WSR(v, SREG_DBREAKC + 0);
break;
#endif
#if XCHAL_NUM_DBREAK > 1
case SREG_DBREAKA + 1:
WSR(v, SREG_DBREAKA + 1);
break;
case SREG_DBREAKC + 1:
WSR(v, SREG_DBREAKC + 1);
break;
#endif
}
}
static int alloc_slot(struct perf_event **slot, size_t n,
struct perf_event *bp)
{
size_t i;
for (i = 0; i < n; ++i) {
if (!slot[i]) {
slot[i] = bp;
return i;
}
}
return -EBUSY;
}
static void set_ibreak_regs(int reg, struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned long ibreakenable;
xtensa_wsr(info->address, SREG_IBREAKA + reg);
RSR(ibreakenable, SREG_IBREAKENABLE);
WSR(ibreakenable | (1 << reg), SREG_IBREAKENABLE);
}
static void set_dbreak_regs(int reg, struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned long dbreakc = DBREAKC_MASK_MASK & -info->len;
if (info->type & XTENSA_BREAKPOINT_LOAD)
dbreakc |= DBREAKC_LOAD_MASK;
if (info->type & XTENSA_BREAKPOINT_STORE)
dbreakc |= DBREAKC_STOR_MASK;
xtensa_wsr(info->address, SREG_DBREAKA + reg);
xtensa_wsr(dbreakc, SREG_DBREAKC + reg);
}
int arch_install_hw_breakpoint(struct perf_event *bp)
{
int i;
if (counter_arch_bp(bp)->type == XTENSA_BREAKPOINT_EXECUTE) {
/* Breakpoint */
i = alloc_slot(this_cpu_ptr(bp_on_reg), XCHAL_NUM_IBREAK, bp);
if (i < 0)
return i;
set_ibreak_regs(i, bp);
} else {
/* Watchpoint */
i = alloc_slot(this_cpu_ptr(wp_on_reg), XCHAL_NUM_DBREAK, bp);
if (i < 0)
return i;
set_dbreak_regs(i, bp);
}
return 0;
}
static int free_slot(struct perf_event **slot, size_t n,
struct perf_event *bp)
{
size_t i;
for (i = 0; i < n; ++i) {
if (slot[i] == bp) {
slot[i] = NULL;
return i;
}
}
return -EBUSY;
}
void arch_uninstall_hw_breakpoint(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
int i;
if (info->type == XTENSA_BREAKPOINT_EXECUTE) {
unsigned long ibreakenable;
/* Breakpoint */
i = free_slot(this_cpu_ptr(bp_on_reg), XCHAL_NUM_IBREAK, bp);
if (i >= 0) {
RSR(ibreakenable, SREG_IBREAKENABLE);
WSR(ibreakenable & ~(1 << i), SREG_IBREAKENABLE);
}
} else {
/* Watchpoint */
i = free_slot(this_cpu_ptr(wp_on_reg), XCHAL_NUM_DBREAK, bp);
if (i >= 0)
xtensa_wsr(0, SREG_DBREAKC + i);
}
}
void hw_breakpoint_pmu_read(struct perf_event *bp)
{
}
void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
{
int i;
struct thread_struct *t = &tsk->thread;
for (i = 0; i < XCHAL_NUM_IBREAK; ++i) {
if (t->ptrace_bp[i]) {
unregister_hw_breakpoint(t->ptrace_bp[i]);
t->ptrace_bp[i] = NULL;
}
}
for (i = 0; i < XCHAL_NUM_DBREAK; ++i) {
if (t->ptrace_wp[i]) {
unregister_hw_breakpoint(t->ptrace_wp[i]);
t->ptrace_wp[i] = NULL;
}
}
}
/*
* Set ptrace breakpoint pointers to zero for this task.
* This is required in order to prevent child processes from unregistering
* breakpoints held by their parent.
*/
void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
{
memset(tsk->thread.ptrace_bp, 0, sizeof(tsk->thread.ptrace_bp));
memset(tsk->thread.ptrace_wp, 0, sizeof(tsk->thread.ptrace_wp));
}
void restore_dbreak(void)
{
int i;
for (i = 0; i < XCHAL_NUM_DBREAK; ++i) {
struct perf_event *bp = this_cpu_ptr(wp_on_reg)[i];
if (bp)
set_dbreak_regs(i, bp);
}
clear_thread_flag(TIF_DB_DISABLED);
}
int check_hw_breakpoint(struct pt_regs *regs)
{
if (regs->debugcause & BIT(DEBUGCAUSE_IBREAK_BIT)) {
int i;
struct perf_event **bp = this_cpu_ptr(bp_on_reg);
for (i = 0; i < XCHAL_NUM_IBREAK; ++i) {
if (bp[i] && !bp[i]->attr.disabled &&
regs->pc == bp[i]->attr.bp_addr)
perf_bp_event(bp[i], regs);
}
return 0;
} else if (regs->debugcause & BIT(DEBUGCAUSE_DBREAK_BIT)) {
struct perf_event **bp = this_cpu_ptr(wp_on_reg);
int dbnum = (regs->debugcause & DEBUGCAUSE_DBNUM_MASK) >>
DEBUGCAUSE_DBNUM_SHIFT;
if (dbnum < XCHAL_NUM_DBREAK && bp[dbnum]) {
if (user_mode(regs)) {
perf_bp_event(bp[dbnum], regs);
} else {
set_thread_flag(TIF_DB_DISABLED);
xtensa_wsr(0, SREG_DBREAKC + dbnum);
}
} else {
WARN_ONCE(1,
"Wrong/unconfigured DBNUM reported in DEBUGCAUSE: %d\n",
dbnum);
}
return 0;
}
return -ENOENT;
}
......@@ -24,6 +24,7 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/elf.h>
#include <linux/hw_breakpoint.h>
#include <linux/init.h>
#include <linux/prctl.h>
#include <linux/init_task.h>
......@@ -43,6 +44,7 @@
#include <linux/atomic.h>
#include <asm/asm-offsets.h>
#include <asm/regs.h>
#include <asm/hw_breakpoint.h>
extern void ret_from_fork(void);
extern void ret_from_kernel_thread(void);
......@@ -131,6 +133,7 @@ void flush_thread(void)
coprocessor_flush_all(ti);
coprocessor_release_all(ti);
#endif
flush_ptrace_hw_breakpoint(current);
}
/*
......@@ -273,6 +276,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
ti->cpenable = 0;
#endif
clear_ptrace_hw_breakpoint(p);
return 0;
}
......
......@@ -13,21 +13,23 @@
* Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
*/
#include <linux/errno.h>
#include <linux/hw_breakpoint.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/perf_event.h>
#include <linux/ptrace.h>
#include <linux/smp.h>
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/smp.h>
#include <asm/pgtable.h>
#include <asm/coprocessor.h>
#include <asm/elf.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/elf.h>
#include <asm/coprocessor.h>
#include <asm/uaccess.h>
void user_enable_single_step(struct task_struct *child)
......@@ -267,6 +269,146 @@ int ptrace_pokeusr(struct task_struct *child, long regno, long val)
return 0;
}
#ifdef CONFIG_HAVE_HW_BREAKPOINT
static void ptrace_hbptriggered(struct perf_event *bp,
struct perf_sample_data *data,
struct pt_regs *regs)
{
int i;
siginfo_t info;
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
if (bp->attr.bp_type & HW_BREAKPOINT_X) {
for (i = 0; i < XCHAL_NUM_IBREAK; ++i)
if (current->thread.ptrace_bp[i] == bp)
break;
i <<= 1;
} else {
for (i = 0; i < XCHAL_NUM_DBREAK; ++i)
if (current->thread.ptrace_wp[i] == bp)
break;
i = (i << 1) | 1;
}
info.si_signo = SIGTRAP;
info.si_errno = i;
info.si_code = TRAP_HWBKPT;
info.si_addr = (void __user *)bkpt->address;
force_sig_info(SIGTRAP, &info, current);
}
static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
{
struct perf_event_attr attr;
ptrace_breakpoint_init(&attr);
/* Initialise fields to sane defaults. */
attr.bp_addr = 0;
attr.bp_len = 1;
attr.bp_type = type;
attr.disabled = 1;
return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL,
tsk);
}
/*
* Address bit 0 choose instruction (0) or data (1) break register, bits
* 31..1 are the register number.
* Both PTRACE_GETHBPREGS and PTRACE_SETHBPREGS transfer two 32-bit words:
* address (0) and control (1).
* Instruction breakpoint contorl word is 0 to clear breakpoint, 1 to set.
* Data breakpoint control word bit 31 is 'trigger on store', bit 30 is
* 'trigger on load, bits 29..0 are length. Length 0 is used to clear a
* breakpoint. To set a breakpoint length must be a power of 2 in the range
* 1..64 and the address must be length-aligned.
*/
static long ptrace_gethbpregs(struct task_struct *child, long addr,
long __user *datap)
{
struct perf_event *bp;
u32 user_data[2] = {0};
bool dbreak = addr & 1;
unsigned idx = addr >> 1;
if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
(dbreak && idx >= XCHAL_NUM_DBREAK))
return -EINVAL;
if (dbreak)
bp = child->thread.ptrace_wp[idx];
else
bp = child->thread.ptrace_bp[idx];
if (bp) {
user_data[0] = bp->attr.bp_addr;
user_data[1] = bp->attr.disabled ? 0 : bp->attr.bp_len;
if (dbreak) {
if (bp->attr.bp_type & HW_BREAKPOINT_R)
user_data[1] |= DBREAKC_LOAD_MASK;
if (bp->attr.bp_type & HW_BREAKPOINT_W)
user_data[1] |= DBREAKC_STOR_MASK;
}
}
if (copy_to_user(datap, user_data, sizeof(user_data)))
return -EFAULT;
return 0;
}
static long ptrace_sethbpregs(struct task_struct *child, long addr,
long __user *datap)
{
struct perf_event *bp;
struct perf_event_attr attr;
u32 user_data[2];
bool dbreak = addr & 1;
unsigned idx = addr >> 1;
int bp_type = 0;
if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
(dbreak && idx >= XCHAL_NUM_DBREAK))
return -EINVAL;
if (copy_from_user(user_data, datap, sizeof(user_data)))
return -EFAULT;
if (dbreak) {
bp = child->thread.ptrace_wp[idx];
if (user_data[1] & DBREAKC_LOAD_MASK)
bp_type |= HW_BREAKPOINT_R;
if (user_data[1] & DBREAKC_STOR_MASK)
bp_type |= HW_BREAKPOINT_W;
} else {
bp = child->thread.ptrace_bp[idx];
bp_type = HW_BREAKPOINT_X;
}
if (!bp) {
bp = ptrace_hbp_create(child,
bp_type ? bp_type : HW_BREAKPOINT_RW);
if (IS_ERR(bp))
return PTR_ERR(bp);
if (dbreak)
child->thread.ptrace_wp[idx] = bp;
else
child->thread.ptrace_bp[idx] = bp;
}
attr = bp->attr;
attr.bp_addr = user_data[0];
attr.bp_len = user_data[1] & ~(DBREAKC_LOAD_MASK | DBREAKC_STOR_MASK);
attr.bp_type = bp_type;
attr.disabled = !attr.bp_len;
return modify_user_hw_breakpoint(bp, &attr);
}
#endif
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
......@@ -307,7 +449,15 @@ long arch_ptrace(struct task_struct *child, long request,
case PTRACE_SETXTREGS:
ret = ptrace_setxregs(child, datap);
break;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
case PTRACE_GETHBPREGS:
ret = ptrace_gethbpregs(child, addr, datap);
break;
case PTRACE_SETHBPREGS:
ret = ptrace_sethbpregs(child, addr, datap);
break;
#endif
default:
ret = ptrace_request(child, request, addr, data);
break;
......
......@@ -39,11 +39,7 @@
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/traps.h>
#ifdef CONFIG_KGDB
extern int gdb_enter;
extern int return_from_debug_flag;
#endif
#include <asm/hw_breakpoint.h>
/*
* Machine specific interrupt handlers
......@@ -162,6 +158,8 @@ COPROCESSOR(7),
DEFINE_PER_CPU(unsigned long, exc_table[EXC_TABLE_SIZE/4]);
DEFINE_PER_CPU(struct debug_table, debug_table);
void die(const char*, struct pt_regs*, long);
static inline void
......@@ -205,6 +203,32 @@ extern void do_IRQ(int, struct pt_regs *);
#if XTENSA_FAKE_NMI
#define IS_POW2(v) (((v) & ((v) - 1)) == 0)
#if !(PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \
IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL)))
#warning "Fake NMI is requested for PMM, but there are other IRQs at or above its level."
#warning "Fake NMI will be used, but there will be a bugcheck if one of those IRQs fire."
static inline void check_valid_nmi(void)
{
unsigned intread = get_sr(interrupt);
unsigned intenable = get_sr(intenable);
BUG_ON(intread & intenable &
~(XTENSA_INTLEVEL_ANDBELOW_MASK(PROFILING_INTLEVEL) ^
XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL) ^
BIT(XCHAL_PROFILING_INTERRUPT)));
}
#else
static inline void check_valid_nmi(void)
{
}
#endif
irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id);
DEFINE_PER_CPU(unsigned long, nmi_count);
......@@ -219,6 +243,7 @@ void do_nmi(struct pt_regs *regs)
old_regs = set_irq_regs(regs);
nmi_enter();
++*this_cpu_ptr(&nmi_count);
check_valid_nmi();
xtensa_pmu_irq_handler(0, NULL);
nmi_exit();
set_irq_regs(old_regs);
......@@ -314,23 +339,22 @@ do_unaligned_user (struct pt_regs *regs)
}
#endif
/* Handle debug events.
* When CONFIG_HAVE_HW_BREAKPOINT is on this handler is called with
* preemption disabled to avoid rescheduling and keep mapping of hardware
* breakpoint structures to debug registers intact, so that
* DEBUGCAUSE.DBNUM could be used in case of data breakpoint hit.
*/
void
do_debug(struct pt_regs *regs)
{
#ifdef CONFIG_KGDB
/* If remote debugging is configured AND enabled, we give control to
* kgdb. Otherwise, we fall through, perhaps giving control to the
* native debugger.
*/
#ifdef CONFIG_HAVE_HW_BREAKPOINT
int ret = check_hw_breakpoint(regs);
if (gdb_enter) {
extern void gdb_handle_exception(struct pt_regs *);
gdb_handle_exception(regs);
return_from_debug_flag = 1;
preempt_enable();
if (ret == 0)
return;
}
#endif
__die_if_kernel("Breakpoint in kernel", regs, SIGKILL);
/* If in user mode, send SIGTRAP signal to current process */
......@@ -364,6 +388,15 @@ static void trap_init_excsave(void)
__asm__ __volatile__("wsr %0, excsave1\n" : : "a" (excsave1));
}
static void trap_init_debug(void)
{
unsigned long debugsave = (unsigned long)this_cpu_ptr(&debug_table);
this_cpu_ptr(&debug_table)->debug_exception = debug_exception;
__asm__ __volatile__("wsr %0, excsave" __stringify(XCHAL_DEBUGLEVEL)
:: "a"(debugsave));
}
/*
* Initialize dispatch tables.
*
......@@ -407,12 +440,14 @@ void __init trap_init(void)
/* Initialize EXCSAVE_1 to hold the address of the exception table. */
trap_init_excsave();
trap_init_debug();
}
#ifdef CONFIG_SMP
void secondary_trap_init(void)
{
trap_init_excsave();
trap_init_debug();
}
#endif
......
......@@ -601,7 +601,9 @@ ENDPROC(window_overflow_restore_a0_fixup)
ENTRY(_DebugInterruptVector)
xsr a0, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
s32i a0, a3, DT_DEBUG_SAVE
l32i a0, a3, DT_DEBUG_EXCEPTION
jx a0
ENDPROC(_DebugInterruptVector)
......
......@@ -3,5 +3,5 @@
#
obj-y := init.o misc.o
obj-$(CONFIG_MMU) += cache.o fault.o mmu.o tlb.o
obj-$(CONFIG_MMU) += cache.o fault.o ioremap.o mmu.o tlb.o
obj-$(CONFIG_HIGHMEM) += highmem.o
......@@ -97,11 +97,11 @@ void clear_user_highpage(struct page *page, unsigned long vaddr)
unsigned long paddr;
void *kvaddr = coherent_kvaddr(page, TLBTEMP_BASE_1, vaddr, &paddr);
pagefault_disable();
preempt_disable();
kmap_invalidate_coherent(page, vaddr);
set_bit(PG_arch_1, &page->flags);
clear_page_alias(kvaddr, paddr);
pagefault_enable();
preempt_enable();
}
void copy_user_highpage(struct page *dst, struct page *src,
......@@ -113,11 +113,11 @@ void copy_user_highpage(struct page *dst, struct page *src,
void *src_vaddr = coherent_kvaddr(src, TLBTEMP_BASE_2, vaddr,
&src_paddr);
pagefault_disable();
preempt_disable();
kmap_invalidate_coherent(dst, vaddr);
set_bit(PG_arch_1, &dst->flags);
copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
pagefault_enable();
preempt_enable();
}
#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
......
/*
* ioremap implementation.
*
* Copyright (C) 2015 Cadence Design Systems Inc.
*
* 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.
*/
#include <linux/io.h>
#include <linux/vmalloc.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
#include <asm/pgtable.h>
static void __iomem *xtensa_ioremap(unsigned long paddr, unsigned long size,
pgprot_t prot)
{
unsigned long offset = paddr & ~PAGE_MASK;
unsigned long pfn = __phys_to_pfn(paddr);
struct vm_struct *area;
unsigned long vaddr;
int err;
paddr &= PAGE_MASK;
WARN_ON(pfn_valid(pfn));
size = PAGE_ALIGN(offset + size);
area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
vaddr = (unsigned long)area->addr;
area->phys_addr = paddr;
err = ioremap_page_range(vaddr, vaddr + size, paddr, prot);
if (err) {
vunmap((void *)vaddr);
return NULL;
}
flush_cache_vmap(vaddr, vaddr + size);
return (void __iomem *)(offset + vaddr);
}
void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size)
{
return xtensa_ioremap(addr, size, pgprot_noncached(PAGE_KERNEL));
}
EXPORT_SYMBOL(xtensa_ioremap_nocache);
void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size)
{
return xtensa_ioremap(addr, size, PAGE_KERNEL);
}
EXPORT_SYMBOL(xtensa_ioremap_cache);
void xtensa_iounmap(volatile void __iomem *io_addr)
{
void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
vunmap(addr);
}
EXPORT_SYMBOL(xtensa_iounmap);
......@@ -96,20 +96,22 @@ static void rs_poll(unsigned long priv)
{
struct tty_port *port = (struct tty_port *)priv;
int i = 0;
int rd = 1;
unsigned char c;
spin_lock(&timer_lock);
while (simc_poll(0)) {
simc_read(0, &c, 1);
rd = simc_read(0, &c, 1);
if (rd <= 0)
break;
tty_insert_flip_char(port, c, TTY_NORMAL);
i++;
}
if (i)
tty_flip_buffer_push(port);
if (rd)
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
spin_unlock(&timer_lock);
}
......
......@@ -223,6 +223,7 @@ static struct ethoc_platform_data ethoc_pdata = {
*/
.hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 },
.phy_id = -1,
.big_endian = XCHAL_HAVE_BE,
};
static struct platform_device ethoc_device = {
......@@ -283,7 +284,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
.irq = DUART16552_INTNUM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
UPF_IOREMAP,
.iotype = UPIO_MEM32,
.iotype = XCHAL_HAVE_BE ? UPIO_MEM32BE : UPIO_MEM32,
.regshift = 2,
.uartclk = 0, /* set in xtavnet_init() */
},
......
This diff is collapsed.
This diff is collapsed.
/*
* tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration
*
* NOTE: This header file is not meant to be included directly.
*/
/* 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.
Copyright (c) 1999-2014 Tensilica Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef _XTENSA_CORE_TIE_H
#define _XTENSA_CORE_TIE_H
#define XCHAL_CP_NUM 2 /* number of coprocessors */
#define XCHAL_CP_MAX 8 /* max CP ID + 1 (0 if none) */
#define XCHAL_CP_MASK 0x82 /* bitmask of all CPs by ID */
#define XCHAL_CP_PORT_MASK 0x80 /* bitmask of only port CPs */
/* Basic parameters of each coprocessor: */
#define XCHAL_CP1_NAME "AudioEngineLX"
#define XCHAL_CP1_IDENT AudioEngineLX
#define XCHAL_CP1_SA_SIZE 184 /* size of state save area */
#define XCHAL_CP1_SA_ALIGN 8 /* min alignment of save area */
#define XCHAL_CP_ID_AUDIOENGINELX 1 /* coprocessor ID (0..7) */
#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_CP0_SA_SIZE 0
#define XCHAL_CP0_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 36
#define XCHAL_NCP_SA_ALIGN 4
/* Total save area for optional and custom state (NCP + CPn): */
#define XCHAL_TOTAL_SA_SIZE 240 /* with 16-byte align padding */
#define XCHAL_TOTAL_SA_ALIGN 8 /* actual minimum alignment */
/*
* Detailed contents of save areas.
* NOTE: caller must define the XCHAL_SA_REG macro (not defined here)
* before expanding the XCHAL_xxx_SA_LIST() macros.
*
* XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize,
* dbnum,base,regnum,bitsz,gapsz,reset,x...)
*
* s = passed from XCHAL_*_LIST(s), eg. to select how to expand
* ccused = set if used by compiler without special options or code
* abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global)
* kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg)
* opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg)
* name = lowercase reg name (no quotes)
* galign = group byte alignment (power of 2) (galign >= align)
* align = register byte alignment (power of 2)
* asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz)
* (not including any pad bytes required to galign this or next reg)
* dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>)
* base = reg shortname w/o index (or sr=special, ur=TIE user reg)
* regnum = reg index in regfile, or special/TIE-user reg number
* bitsz = number of significant bits (regfile width, or ur/sr mask bits)
* gapsz = intervening bits, if bitsz bits not stored contiguously
* (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize)
* reset = register reset value (or 0 if undefined at reset)
* x = reserved for future use (0 until then)
*
* To filter out certain registers, e.g. to expand only the non-global
* registers used by the compiler, you can do something like this:
*
* #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p)
* #define SELCC0(p...)
* #define SELCC1(abikind,p...) SELAK##abikind(p)
* #define SELAK0(p...) REG(p)
* #define SELAK1(p...) REG(p)
* #define SELAK2(p...)
* #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \
* ...what you want to expand...
*/
#define XCHAL_NCP_SA_NUM 9
#define XCHAL_NCP_SA_LIST(s) \
XCHAL_SA_REG(s,1,2,1,1, threadptr, 4, 4, 4,0x03E7, ur,231, 32,0,0,0) \
XCHAL_SA_REG(s,1,0,0,1, acclo, 4, 4, 4,0x0210, sr,16 , 32,0,0,0) \
XCHAL_SA_REG(s,1,0,0,1, acchi, 4, 4, 4,0x0211, sr,17 , 8,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, m0, 4, 4, 4,0x0220, sr,32 , 32,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, m1, 4, 4, 4,0x0221, sr,33 , 32,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, m2, 4, 4, 4,0x0222, sr,34 , 32,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, m3, 4, 4, 4,0x0223, sr,35 , 32,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, br, 4, 4, 4,0x0204, sr,4 , 16,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, scompare1, 4, 4, 4,0x020C, sr,12 , 32,0,0,0)
#define XCHAL_CP0_SA_NUM 0
#define XCHAL_CP0_SA_LIST(s) /* empty */
#define XCHAL_CP1_SA_NUM 26
#define XCHAL_CP1_SA_LIST(s) \
XCHAL_SA_REG(s,0,0,1,0, ae_ovf_sar, 8, 4, 4,0x03F0, ur,240, 8,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_bithead, 4, 4, 4,0x03F1, ur,241, 32,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0,ae_ts_fts_bu_bp, 4, 4, 4,0x03F2, ur,242, 16,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_cw_sd_no, 4, 4, 4,0x03F3, ur,243, 29,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_cbegin0, 4, 4, 4,0x03F6, ur,246, 32,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_cend0, 4, 4, 4,0x03F7, ur,247, 32,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed0, 8, 8, 8,0x1010, aed,0 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed1, 8, 8, 8,0x1011, aed,1 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed2, 8, 8, 8,0x1012, aed,2 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed3, 8, 8, 8,0x1013, aed,3 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed4, 8, 8, 8,0x1014, aed,4 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed5, 8, 8, 8,0x1015, aed,5 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed6, 8, 8, 8,0x1016, aed,6 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed7, 8, 8, 8,0x1017, aed,7 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed8, 8, 8, 8,0x1018, aed,8 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed9, 8, 8, 8,0x1019, aed,9 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed10, 8, 8, 8,0x101A, aed,10 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed11, 8, 8, 8,0x101B, aed,11 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed12, 8, 8, 8,0x101C, aed,12 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed13, 8, 8, 8,0x101D, aed,13 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed14, 8, 8, 8,0x101E, aed,14 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aed15, 8, 8, 8,0x101F, aed,15 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, u0, 8, 8, 8,0x1020, u,0 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, u1, 8, 8, 8,0x1021, u,1 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, u2, 8, 8, 8,0x1022, u,2 , 64,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, u3, 8, 8, 8,0x1023, u,3 , 64,0,0,0)
#define XCHAL_CP2_SA_NUM 0
#define XCHAL_CP2_SA_LIST(s) /* empty */
#define XCHAL_CP3_SA_NUM 0
#define XCHAL_CP3_SA_LIST(s) /* empty */
#define XCHAL_CP4_SA_NUM 0
#define XCHAL_CP4_SA_LIST(s) /* empty */
#define XCHAL_CP5_SA_NUM 0
#define XCHAL_CP5_SA_LIST(s) /* empty */
#define XCHAL_CP6_SA_NUM 0
#define XCHAL_CP6_SA_LIST(s) /* empty */
#define XCHAL_CP7_SA_NUM 0
#define XCHAL_CP7_SA_LIST(s) /* empty */
/* 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,8,8
/* Byte length of instruction from its first byte, per FLIX. */
#define XCHAL_BYTE0_FORMAT_LENGTHS \
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8,\
3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8, 3,3,3,3,3,3,3,3,2,2,2,2,2,2,8,8
#endif /*_XTENSA_CORE_TIE_H*/
This diff is collapsed.
/*
* 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 version 2.1 of the GNU
* Lesser General Public License as published by the Free Software Foundation.
*
* Copyright (C) 1999-2009 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 (8 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_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 1024-4, 4, 4
rsr \at1, BR // boolean option
s32i \at1, \ptr, .Lxchal_ofs_ + 0
.set .Lxchal_ofs_, .Lxchal_ofs_ + 4
.endif
.ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 1024-4, 4, 4
rsr \at1, SCOMPARE1 // conditional store option
s32i \at1, \ptr, .Lxchal_ofs_ + 0
.set .Lxchal_ofs_, .Lxchal_ofs_ + 4
.endif
.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 (8 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_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 1024-4, 4, 4
l32i \at1, \ptr, .Lxchal_ofs_ + 0
wsr \at1, BR // boolean option
.set .Lxchal_ofs_, .Lxchal_ofs_ + 4
.endif
.ifeq (XTHAL_SAS_OPT | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 1024-4, 4, 4
l32i \at1, \ptr, .Lxchal_ofs_ + 0
wsr \at1, SCOMPARE1 // conditional store option
.set .Lxchal_ofs_, .Lxchal_ofs_ + 4
.endif
.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
/* Macro to save the state of TIE coprocessor AudioEngineLX.
* Save area ptr (clobbered): ptr (8 byte aligned)
* Scratch regs (clobbered): at1..at4 (only first XCHAL_CP1_NUM_ATMPS needed)
*/
#define xchal_cp_AudioEngineLX_store xchal_cp1_store
/* #define xchal_cp_AudioEngineLX_store_a2 xchal_cp1_store a2 a3 a4 a5 a6 */
.macro xchal_cp1_store ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL
xchal_sa_start \continue, \ofs
.ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 0, 1, 8
rur240 \at1 // AE_OVF_SAR
s32i \at1, \ptr, 0
rur241 \at1 // AE_BITHEAD
s32i \at1, \ptr, 4
rur242 \at1 // AE_TS_FTS_BU_BP
s32i \at1, \ptr, 8
rur243 \at1 // AE_SD_NO
s32i \at1, \ptr, 12
AE_SP24X2S.I aep0, \ptr, 16
AE_SP24X2S.I aep1, \ptr, 24
AE_SP24X2S.I aep2, \ptr, 32
AE_SP24X2S.I aep3, \ptr, 40
AE_SP24X2S.I aep4, \ptr, 48
AE_SP24X2S.I aep5, \ptr, 56
addi \ptr, \ptr, 64
AE_SP24X2S.I aep6, \ptr, 0
AE_SP24X2S.I aep7, \ptr, 8
AE_SQ56S.I aeq0, \ptr, 16
AE_SQ56S.I aeq1, \ptr, 24
AE_SQ56S.I aeq2, \ptr, 32
AE_SQ56S.I aeq3, \ptr, 40
.set .Lxchal_pofs_, .Lxchal_pofs_ + 64
.set .Lxchal_ofs_, .Lxchal_ofs_ + 112
.endif
.endm // xchal_cp1_store
/* Macro to restore the state of TIE coprocessor AudioEngineLX.
* Save area ptr (clobbered): ptr (8 byte aligned)
* Scratch regs (clobbered): at1..at4 (only first XCHAL_CP1_NUM_ATMPS needed)
*/
#define xchal_cp_AudioEngineLX_load xchal_cp1_load
/* #define xchal_cp_AudioEngineLX_load_a2 xchal_cp1_load a2 a3 a4 a5 a6 */
.macro xchal_cp1_load ptr at1 at2 at3 at4 continue=0 ofs=-1 select=XTHAL_SAS_ALL
xchal_sa_start \continue, \ofs
.ifeq (XTHAL_SAS_TIE | XTHAL_SAS_NOCC | XTHAL_SAS_CALR) & ~\select
xchal_sa_align \ptr, 0, 0, 1, 8
l32i \at1, \ptr, 0
wur240 \at1 // AE_OVF_SAR
l32i \at1, \ptr, 4
wur241 \at1 // AE_BITHEAD
l32i \at1, \ptr, 8
wur242 \at1 // AE_TS_FTS_BU_BP
l32i \at1, \ptr, 12
wur243 \at1 // AE_SD_NO
addi \ptr, \ptr, 80
AE_LQ56.I aeq0, \ptr, 0
AE_LQ56.I aeq1, \ptr, 8
AE_LQ56.I aeq2, \ptr, 16
AE_LQ56.I aeq3, \ptr, 24
AE_LP24X2.I aep0, \ptr, -64
AE_LP24X2.I aep1, \ptr, -56
AE_LP24X2.I aep2, \ptr, -48
AE_LP24X2.I aep3, \ptr, -40
AE_LP24X2.I aep4, \ptr, -32
AE_LP24X2.I aep5, \ptr, -24
AE_LP24X2.I aep6, \ptr, -16
AE_LP24X2.I aep7, \ptr, -8
.set .Lxchal_pofs_, .Lxchal_pofs_ + 80
.set .Lxchal_ofs_, .Lxchal_ofs_ + 112
.endif
.endm // xchal_cp1_load
#define XCHAL_CP1_NUM_ATMPS 1
#define XCHAL_SA_NUM_ATMPS 1
/* Empty macros for unconfigured coprocessors: */
.macro xchal_cp0_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp0_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp2_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp2_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp3_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp3_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp4_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp4_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp5_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp5_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp6_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp6_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp7_store p a b c d continue=0 ofs=-1 select=-1 ; .endm
.macro xchal_cp7_load p a b c d continue=0 ofs=-1 select=-1 ; .endm
#endif /*_XTENSA_CORE_TIE_ASM_H*/
/*
* 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 version 2.1 of the GNU
* Lesser General Public License as published by the Free Software Foundation.
*
* Copyright (C) 1999-2009 Tensilica Inc.
*/
#ifndef _XTENSA_CORE_TIE_H
#define _XTENSA_CORE_TIE_H
#define XCHAL_CP_NUM 1 /* number of coprocessors */
#define XCHAL_CP_MAX 2 /* max CP ID + 1 (0 if none) */
#define XCHAL_CP_MASK 0x02 /* bitmask of all CPs by ID */
#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */
/* Basic parameters of each coprocessor: */
#define XCHAL_CP1_NAME "AudioEngineLX"
#define XCHAL_CP1_IDENT AudioEngineLX
#define XCHAL_CP1_SA_SIZE 112 /* size of state save area */
#define XCHAL_CP1_SA_ALIGN 8 /* min alignment of save area */
#define XCHAL_CP_ID_AUDIOENGINELX 1 /* coprocessor ID (0..7) */
/* Filler info for unassigned coprocessors, to simplify arrays etc: */
#define XCHAL_CP0_SA_SIZE 0
#define XCHAL_CP0_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
#define XCHAL_CP7_SA_SIZE 0
#define XCHAL_CP7_SA_ALIGN 1
/* Save area for non-coprocessor optional and custom (TIE) state: */
#define XCHAL_NCP_SA_SIZE 12
#define XCHAL_NCP_SA_ALIGN 4
/* Total save area for optional and custom state (NCP + CPn): */
#define XCHAL_TOTAL_SA_SIZE 128 /* with 16-byte align padding */
#define XCHAL_TOTAL_SA_ALIGN 8 /* actual minimum alignment */
/*
* Detailed contents of save areas.
* NOTE: caller must define the XCHAL_SA_REG macro (not defined here)
* before expanding the XCHAL_xxx_SA_LIST() macros.
*
* XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize,
* dbnum,base,regnum,bitsz,gapsz,reset,x...)
*
* s = passed from XCHAL_*_LIST(s), eg. to select how to expand
* ccused = set if used by compiler without special options or code
* abikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global)
* kind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg)
* opt = 0 (custom TIE extension or coprocessor), or 1 (optional reg)
* name = lowercase reg name (no quotes)
* galign = group byte alignment (power of 2) (galign >= align)
* align = register byte alignment (power of 2)
* asize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz)
* (not including any pad bytes required to galign this or next reg)
* dbnum = unique target number f/debug (see <xtensa-libdb-macros.h>)
* base = reg shortname w/o index (or sr=special, ur=TIE user reg)
* regnum = reg index in regfile, or special/TIE-user reg number
* bitsz = number of significant bits (regfile width, or ur/sr mask bits)
* gapsz = intervening bits, if bitsz bits not stored contiguously
* (padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize)
* reset = register reset value (or 0 if undefined at reset)
* x = reserved for future use (0 until then)
*
* To filter out certain registers, e.g. to expand only the non-global
* registers used by the compiler, you can do something like this:
*
* #define XCHAL_SA_REG(s,ccused,p...) SELCC##ccused(p)
* #define SELCC0(p...)
* #define SELCC1(abikind,p...) SELAK##abikind(p)
* #define SELAK0(p...) REG(p)
* #define SELAK1(p...) REG(p)
* #define SELAK2(p...)
* #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \
* ...what you want to expand...
*/
#define XCHAL_NCP_SA_NUM 3
#define XCHAL_NCP_SA_LIST(s) \
XCHAL_SA_REG(s,0,0,0,1, br, 4, 4, 4,0x0204, sr,4 , 16,0,0,0) \
XCHAL_SA_REG(s,0,0,0,1, scompare1, 4, 4, 4,0x020C, sr,12 , 32,0,0,0) \
XCHAL_SA_REG(s,1,2,1,1, threadptr, 4, 4, 4,0x03E7, ur,231, 32,0,0,0)
#define XCHAL_CP0_SA_NUM 0
#define XCHAL_CP0_SA_LIST(s) /* empty */
#define XCHAL_CP1_SA_NUM 16
#define XCHAL_CP1_SA_LIST(s) \
XCHAL_SA_REG(s,0,0,1,0, ae_ovf_sar, 8, 4, 4,0x03F0, ur,240, 7,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_bithead, 4, 4, 4,0x03F1, ur,241, 32,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0,ae_ts_fts_bu_bp, 4, 4, 4,0x03F2, ur,242, 16,0,0,0) \
XCHAL_SA_REG(s,0,0,1,0, ae_sd_no, 4, 4, 4,0x03F3, ur,243, 28,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep0, 8, 8, 8,0x0060, aep,0 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep1, 8, 8, 8,0x0061, aep,1 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep2, 8, 8, 8,0x0062, aep,2 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep3, 8, 8, 8,0x0063, aep,3 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep4, 8, 8, 8,0x0064, aep,4 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep5, 8, 8, 8,0x0065, aep,5 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep6, 8, 8, 8,0x0066, aep,6 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aep7, 8, 8, 8,0x0067, aep,7 , 48,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aeq0, 8, 8, 8,0x0068, aeq,0 , 56,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aeq1, 8, 8, 8,0x0069, aeq,1 , 56,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aeq2, 8, 8, 8,0x006A, aeq,2 , 56,0,0,0) \
XCHAL_SA_REG(s,0,0,2,0, aeq3, 8, 8, 8,0x006B, aeq,3 , 56,0,0,0)
#define XCHAL_CP2_SA_NUM 0
#define XCHAL_CP2_SA_LIST(s) /* empty */
#define XCHAL_CP3_SA_NUM 0
#define XCHAL_CP3_SA_LIST(s) /* empty */
#define XCHAL_CP4_SA_NUM 0
#define XCHAL_CP4_SA_LIST(s) /* empty */
#define XCHAL_CP5_SA_NUM 0
#define XCHAL_CP5_SA_LIST(s) /* empty */
#define XCHAL_CP6_SA_NUM 0
#define XCHAL_CP6_SA_LIST(s) /* empty */
#define XCHAL_CP7_SA_NUM 0
#define XCHAL_CP7_SA_LIST(s) /* empty */
/* 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,8
#endif /*_XTENSA_CORE_TIE_H*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment