linux-headers/arch/e2k/include/asm/machdep.h

705 lines
26 KiB
C

#ifndef _E2K_MACHDEP_H_
#define _E2K_MACHDEP_H_
#include <linux/init.h>
#include <linux/types.h>
#include <uapi/asm/iset_ver.h>
#include <asm/sections.h>
#include <asm/aau_regs_types.h>
#include <asm/mmu_types.h>
#include <asm/mlt.h>
#ifdef __KERNEL__
enum {
CPU_HWBUG_LARGE_PAGES,
CPU_HWBUG_LAPIC_TIMER,
CPU_HWBUG_PIO_READS,
CPU_HWBUG_ATOMIC,
CPU_HWBUG_CLW,
CPU_HWBUG_PAGE_A,
CPU_HWBUG_SPURIOUS_EXC_ILL_INSTR_ADDR,
CPU_HWBUG_UNALIGNED_LOADS,
CPU_HWBUG_CANNOT_DO_DMA_IN_NEIGHBOUR_NODE,
CPU_HWBUG_DMA_AT_APIC_ADDR,
CPU_HWBUG_KERNEL_DATA_MONITOR,
CPU_HWBUG_WRITE_MEMORY_BARRIER,
CPU_HWBUG_BAD_RESET,
CPU_HWBUG_BREAKPOINT_INSTR,
CPU_HWBUG_E8C_WATCHDOG,
CPU_HWBUG_IOMMU,
CPU_HWBUG_WC_DAM,
CPU_HWBUG_TRAP_CELLAR_S_F,
CPU_HWBUG_SS,
CPU_HWBUG_AAU_AALDV,
CPU_HWBUG_LEVEL_EOI,
CPU_HWBUG_FALSE_SS,
CPU_HWBUG_SPURIOUS_EXC_DATA_DEBUG,
CPU_HWBUG_TLB_FLUSH_L1D,
CPU_HWBUG_GUEST_ASYNC_PM,
CPU_HWBUG_E16C_SLEEP,
CPU_HWBUG_L1I_STOPS_WORKING,
CPU_HWBUG_CLW_STALE_L1_ENTRY,
CPU_HWBUG_C3_WAIT_MA_C,
CPU_HWBUG_VIRT_SCLKM3_INTC,
CPU_HWBUG_VIRT_PSIZE_INTERCEPTION,
CPU_HWBUG_USD_ALIGNMENT,
CPU_FEAT_WC_PCI_PREFETCH,
CPU_FEAT_FLUSH_DC_IC,
CPU_FEAT_EPIC,
CPU_FEAT_TRAP_V5,
CPU_FEAT_TRAP_V6,
CPU_FEAT_QPREG,
CPU_FEAT_ISET_V3,
CPU_FEAT_ISET_V5,
CPU_FEAT_ISET_V6,
NR_CPU_FEATURES
};
struct cpuinfo_e2k;
struct pt_regs;
struct seq_file;
struct global_regs;
struct kernel_gregs;
struct local_gregs;
struct e2k_aau_context;
struct kvm_vcpu_arch;
struct e2k_dimtp;
struct thread_info;
#include <asm/kvm/machdep.h> /* virtualization support */
typedef struct machdep {
int native_id; /* machine Id */
int native_rev; /* cpu revision */
e2k_iset_ver_t native_iset_ver; /* Instruction set version */
bool cmdline_iset_ver; /* iset specified in cmdline */
bool mmu_pt_v6; /* MMU is setting up to use */
/* new page table structures */
bool mmu_separate_pt; /* MMU was set to use */
/* separate PTs for kernel */
/* and users */
bool L3_enable; /* cache L3 is enable */
bool gmi; /* is hardware virtualized */
/* guest VM */
e2k_addr_t x86_io_area_base;
e2k_addr_t x86_io_area_size;
u8 max_nr_node_cpus;
u8 nr_node_cpus;
u8 node_iolinks;
e2k_addr_t pcicfg_area_phys_base;
e2k_size_t pcicfg_area_size;
e2k_addr_t nsr_area_phys_base;
e2k_size_t nbsr_area_offset;
e2k_size_t nbsr_area_size;
e2k_addr_t copsr_area_phys_base;
e2k_size_t copsr_area_size;
u8 mlt_size;
u8 tlb_lines_bits_num;
u64 tlb_addr_line_num;
u64 tlb_addr_line_num2;
u8 tlb_addr_line_num_shift2;
u8 tlb_addr_set_num;
u8 tlb_addr_set_num_shift;
e2k_size_t sic_mc_size;
u8 sic_mc_count;
u32 sic_mc1_ecc;
u32 sic_io_str1;
u32 clock_tick_rate;
unsigned long cpu_features[(NR_CPU_FEATURES + 63) / 64];
e2k_addr_t (*get_nsr_area_phys_base)(void);
void (*setup_apic_vector_handlers)(void);
#ifdef CONFIG_SMP
void (*clk_off)(void);
void (*clk_on)(int);
#endif
void (*C1_enter)(void);
void (*C3_enter)(void);
/* Often used pointers are placed close to each other */
void (*save_kernel_gregs)(struct kernel_gregs *);
void (*save_gregs)(struct global_regs *);
void (*save_local_gregs)(struct local_gregs *, bool is_signal);
void (*save_gregs_dirty_bgr)(struct global_regs *);
void (*save_gregs_on_mask)(struct global_regs *, bool dirty_bgr,
unsigned long not_save_gregs_mask);
void (*restore_gregs)(const struct global_regs *);
void (*restore_local_gregs)(const struct local_gregs *, bool is_signal);
void (*restore_gregs_on_mask)(struct global_regs *, bool dirty_bgr,
unsigned long not_restore_gregs_mask);
void (*save_dimtp)(e2k_dimtp_t *);
void (*restore_dimtp)(const e2k_dimtp_t *);
void (*save_kvm_context)(struct kvm_vcpu_arch *);
void (*restore_kvm_context)(const struct kvm_vcpu_arch *);
void (*calculate_aau_aaldis_aaldas)(const struct pt_regs *regs,
struct thread_info *ti, struct e2k_aau_context *context);
void (*do_aau_fault)(int aa_field, struct pt_regs *regs);
void (*save_aaldi)(u64 *aaldis);
void (*get_aau_context)(struct e2k_aau_context *);
unsigned long (*rrd)(int reg);
void (*rwd)(int reg, unsigned long value);
unsigned long (*boot_rrd)(int reg);
void (*boot_rwd)(int reg, unsigned long value);
u64 (*get_cu_hw1)(void);
void (*set_cu_hw1)(u64);
#ifdef CONFIG_MLT_STORAGE
void (*invalidate_MLT)(void);
void (*get_and_invalidate_MLT_context)(e2k_mlt_t *mlt_state);
#endif
void (*flushts)(void);
void (*setup_arch)(void);
void (*setup_cpu_info)(struct cpuinfo_e2k *c);
int (*show_cpuinfo)(struct seq_file *m, void *v);
void (*init_IRQ)(void);
int (*set_wallclock)(unsigned long nowtime);
unsigned long (*get_wallclock)(void);
void (*restart)(char *cmd);
void (*power_off)(void);
void (*halt)(void);
void (*arch_reset)(char *cmd);
void (*arch_halt)(void);
int (*get_irq_vector)(void);
/* virtualization support: guest kernel and host/hypervisor */
host_machdep_t host; /* host additional fields (used only by */
/* host at arch/e2k/kvm/xxx) */
guest_machdep_t guest; /* guest additional fields (used only by */
/* guest at arch/e2k/kvm/guest/xxx) */
} machdep_t;
/*
* When executing on pure guest kernel, guest_cpu will be set to
* 'machine.guest.id', i.e. to what hardware guest *thinks* it's
* being executed on.
*/
typedef void (*cpuhas_initcall_t)(int cpu, int revision, int iset_ver,
int guest_cpu, struct machdep *machine);
extern cpuhas_initcall_t __cpuhas_initcalls[], __cpuhas_initcalls_end[];
/*
* feature =
* if ('is_static')
* 'static_cond' checked at build time;
* else
* 'dynamic_cond' checked in runtime;
*/
#ifndef BUILD_CPUHAS_INITIALIZERS
# define CPUHAS(feat, is_static, static_cond, dynamic_cond) \
static const char feat##_is_static = !!(is_static); \
static const char feat##_is_set_statically = !!(static_cond);
#else /* #ifdef BUILD_CPUHAS_INITIALIZERS */
# include <linux/bitops.h>
# define CPUHAS(feat, _is_static, static_cond, dynamic_cond) \
__init \
static void feat##_initializer(const int cpu, const int revision, \
const int iset_ver, const int guest_cpu, \
struct machdep *const machine) { \
bool is_static = (_is_static); \
if (is_static && (static_cond) || !is_static && (dynamic_cond)) \
set_bit(feat, (machine)->cpu_features); \
} \
static cpuhas_initcall_t __cpuhas_initcall_##feat __used \
__section(".cpuhas_initcall") = &feat##_initializer;
#endif
/* Most of these bugs are not emulated on simulator but
* set them anyway to make kernel running on a simulator
* behave in the same way as on real hardware. */
/* #47176 - Large pages do not work.
* Workaround - do not use them. */
CPUHAS(CPU_HWBUG_LARGE_PAGES,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL && revision < 1);
/* #56947 - lapic timer can lose interrupts.
* Workaround - do not use oneshot mode. */
CPUHAS(CPU_HWBUG_LAPIC_TIMER,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL && revision < 1);
/* #69194 - PIO reads can hang processor.
* Workaround - serialize PIO reads on every CPU. */
CPUHAS(CPU_HWBUG_PIO_READS,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL && (revision <= 1 || revision == 6) ||
cpu == IDR_ES2_RU_MDL && revision <= 1);
/* #71610 - Atomic operations can be non-atomic
* Workaround - flush data cache line.
* This workaround increases the count of DCACHE flushes,
* Turmalin has hardware bug with flushes so don't use
* this workaround on it. */
CPUHAS(CPU_HWBUG_ATOMIC,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL);
/* #58397, #76626 - CLW does not work.
* Workaround - do not use it. */
CPUHAS(CPU_HWBUG_CLW,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S),
false,
cpu == IDR_ES2_DSP_MDL && (revision <= 1 || revision == 6) ||
cpu == IDR_ES2_RU_MDL && revision <= 1 ||
cpu == IDR_E2S_MDL && revision == 0);
/* #76626 - "Page accessed" bit in PTE does not work.
* Workaround - always set it. */
CPUHAS(CPU_HWBUG_PAGE_A,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL && (revision <= 1 || revision == 6) ||
cpu == IDR_ES2_RU_MDL && revision <= 1);
/* #78411 - Sometimes exc_illegal_instr_addr is generated
* instead of exc_instr_page_miss.
* Workaround - always return to user from exc_illegal_instr_addr. */
CPUHAS(CPU_HWBUG_SPURIOUS_EXC_ILL_INSTR_ADDR,
!IS_ENABLED(CONFIG_CPU_E2S),
false,
cpu == IDR_E2S_MDL && revision <= 1);
/* #83160 - unaligned loads do not work
* Workaround - limit the stream of unaligned loads to less
* than 32 bytes per cycle and put "wait ld_c" before it. */
CPUHAS(CPU_HWBUG_UNALIGNED_LOADS,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL && (revision <= 1 || revision == 6) ||
cpu == IDR_ES2_RU_MDL && revision <= 1)
/* #83884 - es2 deadlocks on DMA to neighbour node.
* #100984 - # DMA to neighbour node slows down.
* Workaround - allocate DMA buffers only in the device node. */
CPUHAS(CPU_HWBUG_CANNOT_DO_DMA_IN_NEIGHBOUR_NODE,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E8C),
false,
cpu == IDR_ES2_DSP_MDL && (revision <= 1 || revision == 6) ||
cpu == IDR_ES2_RU_MDL && revision <= 1 ||
cpu == IDR_E8C_MDL && revision <= 2);
/* #83884 - es2 deadlock on DMA at
* (APIC_DEFAULT_PHYS_BASE & 0x7fffFFFF) address.
* Workaround - reserve the 4K page at this address. */
CPUHAS(CPU_HWBUG_DMA_AT_APIC_ADDR,
!IS_ENABLED(CONFIG_CPU_ES2),
false,
cpu == IDR_ES2_DSP_MDL);
/* #88644 - data profiling events are lost if overflow happens
* under closed NM interrupts; also DDMCR writing does not clear
* pending exc_data_debug exceptions.
* Workaround - disable data monitor profiling in kernel. */
CPUHAS(CPU_HWBUG_KERNEL_DATA_MONITOR,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL);
/* #89495 - write barrier does not work (even for atomics).
* Workaround - special command sequence after every read-acquire. */
CPUHAS(CPU_HWBUG_WRITE_MEMORY_BARRIER,
!IS_ENABLED(CONFIG_CPU_E8C),
false,
cpu == IDR_E8C_MDL && revision <= 1);
/* On some processor's revisions writecombine memory
* in prefetchable PCI area is not allowed. */
CPUHAS(CPU_FEAT_WC_PCI_PREFETCH,
!IS_ENABLED(CONFIG_CPU_ES2),
true,
!((cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL) &&
revision == 0));
/* #82499 - Instruction Cache must be handled carefully
* when flush_dc_line also flushes IC by physical address. */
CPUHAS(CPU_FEAT_FLUSH_DC_IC,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 3,
iset_ver >= E2K_ISET_V3);
/* #89653 - some hw counter won't reset, which may cause corruption of DMA.
* Workaround - reset machine until the counter sets in good value */
CPUHAS(CPU_HWBUG_BAD_RESET,
!IS_ENABLED(CONFIG_CPU_E8C),
false,
cpu == IDR_E8C_MDL && revision <= 1);
/* #90514 - hardware hangs after modifying code with a breakpoint.
* Workaround - use HS.lng from the instruction being replaced. */
CPUHAS(CPU_HWBUG_BREAKPOINT_INSTR,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E8C2_MDL);
/* #92834, #96516 - hang because of hardware problems.
* Workaround - boot activates watchdog, kernel should disable it */
CPUHAS(CPU_HWBUG_E8C_WATCHDOG,
!IS_ENABLED(CONFIG_CPU_E8C),
false,
cpu == IDR_E8C_MDL && revision <= 1);
/* #94466 */
CPUHAS(CPU_HWBUG_IOMMU,
!IS_ENABLED(CONFIG_CPU_E2S),
false,
cpu == IDR_E2S_MDL && revision <= 2);
/* #95860 - WC memory conflicts with DAM.
* Workaround - "wait st_c" between WC writes and cacheable loads */
CPUHAS(CPU_HWBUG_WC_DAM,
!IS_ENABLED(CONFIG_CPU_E2S) && !IS_ENABLED(CONFIG_CPU_E8C) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_E2S_MDL && revision <= 2 ||
cpu == IDR_E8C_MDL && revision <= 1 ||
cpu == IDR_E8C2_MDL && revision == 0);
/* 96719 - combination of flags s_f=0, store=1, sru=1 is possible
* Workaround - treat it as s_f=1, store=1, sru=1 */
CPUHAS(CPU_HWBUG_TRAP_CELLAR_S_F,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL && revision == 0);
/* #97594 - %cr1_lo.ss flag is lost if ext. interrupt arrives faster.
* Workaround - manually set %cr1_lo.ss again in interrupt handler */
CPUHAS(CPU_HWBUG_SS,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL && revision <= 2 ||
cpu == IDR_E8C_MDL && revision <= 2 ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL && revision == 0);
/* #99302 - %aaldv sometimes is not restored properly.
* Workaround - insert 'wait ma_c' barrier */
CPUHAS(CPU_HWBUG_AAU_AALDV,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL && revision == 0);
/* #103223 - LAPIC does not send EoI to IO_APIC for level interrupts.
* Workaround - wait under closed interrupts until APIC_ISR clears */
CPUHAS(CPU_HWBUG_LEVEL_EOI,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL);
/* #104865 - hardware might generate a false single step interrupt
* Workaround - clean frame 0 of PCS during the allocation */
CPUHAS(CPU_HWBUG_FALSE_SS,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL && revision <= 2 ||
cpu == IDR_E8C_MDL && revision <= 2 ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL);
/* #117649 - false exc_data_debug are generated based on _previous_
* values in ld/st address registers.
* Workaround - forbid data breakpoint on the first 31 bytes
* (hardware prefetch works with 32 bytes blocks). */
CPUHAS(CPU_HWBUG_SPURIOUS_EXC_DATA_DEBUG,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2) && !IS_ENABLED(CONFIG_CPU_E12C) &&
!IS_ENABLED(CONFIG_CPU_E16C) && !IS_ENABLED(CONFIG_CPU_E2C3),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL ||
cpu == IDR_E12C_MDL && revision == 0 ||
cpu == IDR_E16C_MDL && revision == 0 ||
cpu == IDR_E2C3_MDL && revision == 0);
/* #119084 - several TBL flushes in a row might fail to flush L1D.
* Workaround - insert "wait fl_c" immediately after every TLB flush */
CPUHAS(CPU_HWBUG_TLB_FLUSH_L1D,
!IS_ENABLED(CONFIG_CPU_E8C2),
false,
cpu == IDR_E8C2_MDL);
/* #121311 - asynchronous entries in INTC_INFO_MU always have "pm" bit set.
* Workaround - use "pm" bit saved in guest's chain stack. */
CPUHAS(CPU_HWBUG_GUEST_ASYNC_PM,
!IS_ENABLED(CONFIG_CPU_E12C) && !IS_ENABLED(CONFIG_CPU_E16C) &&
!IS_ENABLED(CONFIG_CPU_E2C3),
false,
cpu == IDR_E12C_MDL || cpu == IDR_E16C_MDL ||
cpu == IDR_E2C3_MDL);
/* #122946 - conflict new interrupt while sync signal turning off.
* Workaround - wating for C0 after E2K_WAIT_V6 */
CPUHAS(CPU_HWBUG_E16C_SLEEP,
!IS_ENABLED(CONFIG_CPU_E16C),
false,
cpu == IDR_E16C_MDL && revision == 0);
/* #124206 - instruction buffer stops working
* Workaround - prepare %ctpr's in glaunch/trap handler entry;
* avoid rbranch in glaunch/trap handler entry and exit. */
CPUHAS(CPU_HWBUG_L1I_STOPS_WORKING,
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2) && !IS_ENABLED(CONFIG_CPU_E12C) &&
!IS_ENABLED(CONFIG_CPU_E16C) && !IS_ENABLED(CONFIG_CPU_E2C3),
false,
cpu == IDR_ES2_DSP_MDL || cpu == IDR_ES2_RU_MDL ||
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL ||
cpu == IDR_E1CP_MDL || cpu == IDR_E8C2_MDL ||
cpu == IDR_E12C_MDL || cpu == IDR_E16C_MDL ||
cpu == IDR_E2C3_MDL);
/* #124947 - CLW clearing by OS must be done on the same CPU that started the
* hardware clearing operation to avoid creating a stale L1 entry.
* Workaround - forbid migration until CLW clearing is finished in software. */
CPUHAS(CPU_HWBUG_CLW_STALE_L1_ENTRY,
IS_ENABLED(CONFIG_E2K_MACHINE) && !IS_ENABLED(CONFIG_CPU_E12C) &&
!IS_ENABLED(CONFIG_CPU_E16C),
IS_ENABLED(CONFIG_CPU_E2S) || IS_ENABLED(CONFIG_CPU_E8C) ||
IS_ENABLED(CONFIG_CPU_E8C2),
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL || cpu == IDR_E8C2_MDL ||
cpu == IDR_E12C_MDL && revision == 0 ||
cpu == IDR_E16C_MDL && revision == 0);
/* #126587 - "wait ma_c=1" does not wait for all L2$ writebacks to complete
* when disabling CPU core with "wait trap=1" algorithm.
* Workaround - manually insert 66 NOPs before "wait trap=1" */
CPUHAS(CPU_HWBUG_C3_WAIT_MA_C,
IS_ENABLED(CONFIG_E2K_MACHINE),
IS_ENABLED(CONFIG_CPU_E2S) || IS_ENABLED(CONFIG_CPU_E8C) ||
IS_ENABLED(CONFIG_CPU_E1CP),
cpu == IDR_E2S_MDL || cpu == IDR_E8C_MDL || cpu == IDR_E1CP_MDL);
/* #128127 - Intercepting SCLKM3 write does not prevent guest from writing it.
* Workaround - Update SH_SCLKM3 in intercept handler */
CPUHAS(CPU_HWBUG_VIRT_SCLKM3_INTC,
!IS_ENABLED(CONFIG_CPU_E16C) && !IS_ENABLED(CONFIG_CPU_E2C3) &&
!IS_ENABLED(CONFIG_CPU_E12C),
false,
cpu == IDR_E16C_MDL && revision == 0 ||
cpu == IDR_E12C_MDL && revision == 0 ||
cpu == IDR_E2C3_MDL && revision == 0);
/* #130039 - intercepting some specific sequences of call/return/setwd
* (that change WD.psize in a specific way) does not work.
* Workaround - avoid those sequences. */
CPUHAS(CPU_HWBUG_VIRT_PSIZE_INTERCEPTION,
IS_ENABLED(CONFIG_E2K_MACHINE),
IS_ENABLED(CONFIG_CPU_E16C) || IS_ENABLED(CONFIG_CPU_E2C3),
(cpu == IDR_E16C_MDL || cpu == IDR_E2C3_MDL) && revision == 0);
/* #129848 - alignment of usd_hi write depends on current usd_lo.p
* Workaround - write usd_lo before usd_hi, while keeping 2 tact distance from sbr write.
* Valid sequences are: sbr, nop, usd.lo, usd.hi OR sbr, usd.lo, usd.hi, usd.lo */
CPUHAS(CPU_HWBUG_USD_ALIGNMENT,
IS_ENABLED(CONFIG_E2K_MACHINE) && !IS_ENABLED(CONFIG_CPU_E16C) &&
!IS_ENABLED(CONFIG_CPU_E2C3),
!IS_ENABLED(CONFIG_CPU_E12C),
cpu == IDR_E16C_MDL && revision <= 1 ||
cpu == IDR_E2C3_MDL && revision <= 1);
/* Rely on IDR instead of iset version to choose between APIC and EPIC.
* For guest we use it's own fake IDR so that we choose between APIC and
* EPIC based on what hardware guest *thinks* it's being executed on. */
CPUHAS(CPU_FEAT_EPIC,
IS_ENABLED(CONFIG_E2K_MACHINE) &&
!IS_ENABLED(CONFIG_KVM_GUEST_KERNEL),
!IS_ENABLED(CONFIG_CPU_ES2) && !IS_ENABLED(CONFIG_CPU_E2S) &&
!IS_ENABLED(CONFIG_CPU_E8C) && !IS_ENABLED(CONFIG_CPU_E1CP) &&
!IS_ENABLED(CONFIG_CPU_E8C2),
guest_cpu != IDR_ES2_DSP_MDL && guest_cpu != IDR_ES2_RU_MDL &&
guest_cpu != IDR_E2S_MDL && guest_cpu != IDR_E8C_MDL &&
guest_cpu != IDR_E1CP_MDL && guest_cpu != IDR_E8C2_MDL);
/* Shows which user registers must be saved upon trap entry/exit */
CPUHAS(CPU_FEAT_TRAP_V5,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET == 5,
iset_ver == E2K_ISET_V5);
CPUHAS(CPU_FEAT_TRAP_V6,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 6,
iset_ver >= E2K_ISET_V6);
/* QP registers: only since iset V5 */
CPUHAS(CPU_FEAT_QPREG,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 5,
iset_ver >= E2K_ISET_V5);
/* Optimized version of machine.iset check */
CPUHAS(CPU_FEAT_ISET_V3,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 3,
iset_ver >= E2K_ISET_V3);
CPUHAS(CPU_FEAT_ISET_V5,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 5,
iset_ver >= E2K_ISET_V5);
CPUHAS(CPU_FEAT_ISET_V6,
CONFIG_CPU_ISET != 0,
CONFIG_CPU_ISET >= 6,
iset_ver >= E2K_ISET_V6);
static inline unsigned long test_feature_dynamic(struct machdep *machine, int feature)
{
unsigned long *addr = machine->cpu_features;
return 1UL & (addr[feature / 64] >> (feature & 63));
}
#define test_feature(machine, feature) \
((feature##_is_static) ? \
(feature##_is_set_statically) : \
test_feature_dynamic(machine, feature))
#define boot_machine_has(machine_p, feature) \
test_feature(machine_p, feature)
#define boot_cpu_has(feature) boot_machine_has(&boot_machine, feature)
#ifndef E2K_P2V
# define cpu_has(feature) test_feature(&machine, feature)
#else
# define cpu_has(feature) boot_cpu_has(feature)
#endif
/* Normally cpu_has() is passed symbolic name of feature (e.g. CPU_FEAT_*),
* use this one instead if only numeric value of feature is known. */
#define cpu_has_by_value(feature) test_feature_dynamic(&machine, feature)
extern void cpu_set_feature(struct machdep *machine, int feature);
extern void cpu_clear_feature(struct machdep *machine, int feature);
extern __nodedata machdep_t machine;
extern __nodedata pt_struct_t pgtable_struct;
#define boot_machine (boot_get_vo_value(machine))
#define boot_pgtable_struct ((pt_struct_t)boot_get_vo_value(pgtable_struct))
#define boot_pgtable_struct_p boot_vp_to_pp(&pgtable_struct)
#if CONFIG_CPU_ISET >= 6
# define IS_CPU_ISET_V6() true
#elif CONFIG_CPU_ISET >= 1
# define IS_CPU_ISET_V6() false
#elif CONFIG_CPU_ISET == 0
# ifdef E2K_P2V
# define IS_CPU_ISET_V6() \
(boot_machine.native_iset_ver >= E2K_ISET_V6)
# else /* ! E2K_P2V */
# define IS_CPU_ISET_V6() \
(machine.native_iset_ver >= E2K_ISET_V6)
# endif /* E2K_P2V */
#else /* CONFIG_CPU_ISET undefined or negative */
# warning "Undefined CPU ISET VERSION #, IS_CPU_ISET_V6 is defined dinamicaly"
# ifdef E2K_P2V
# define IS_CPU_ISET_V6() \
(boot_machine.native_iset_ver >= E2K_ISET_V6)
# else /* ! E2K_P2V */
# define IS_CPU_ISET_V6() \
(machine.native_iset_ver >= E2K_ISET_V6)
# endif /* E2K_P2V */
#endif /* CONFIG_CPU_ISET 0-6 */
#define IS_HV_GM() (machine.gmi)
extern void save_kernel_gregs_v2(struct kernel_gregs *);
extern void save_kernel_gregs_v5(struct kernel_gregs *);
extern void save_gregs_v2(struct global_regs *);
extern void save_gregs_v5(struct global_regs *);
extern void save_local_gregs_v2(struct local_gregs *, bool is_signal);
extern void save_local_gregs_v5(struct local_gregs *, bool is_signal);
extern void save_gregs_dirty_bgr_v2(struct global_regs *);
extern void save_gregs_dirty_bgr_v5(struct global_regs *);
extern void save_gregs_on_mask_v2(struct global_regs *, bool dirty_bgr,
unsigned long mask_not_save);
extern void save_gregs_on_mask_v5(struct global_regs *, bool dirty_bgr,
unsigned long mask_not_save);
extern void restore_gregs_v2(const struct global_regs *);
extern void restore_gregs_v5(const struct global_regs *);
extern void restore_local_gregs_v2(const struct local_gregs *, bool is_signal);
extern void restore_local_gregs_v5(const struct local_gregs *, bool is_signal);
extern void restore_gregs_on_mask_v2(struct global_regs *, bool dirty_bgr,
unsigned long mask_not_restore);
extern void restore_gregs_on_mask_v5(struct global_regs *, bool dirty_bgr,
unsigned long mask_not_restore);
extern void save_dimtp_v6(e2k_dimtp_t *);
extern void restore_dimtp_v6(const e2k_dimtp_t *);
extern void save_kvm_context_v6(struct kvm_vcpu_arch *);
extern void restore_kvm_context_v6(const struct kvm_vcpu_arch *);
extern void qpswitchd_sm(int);
extern void calculate_aau_aaldis_aaldas_v2(const struct pt_regs *regs,
struct thread_info *ti, struct e2k_aau_context *context);
extern void calculate_aau_aaldis_aaldas_v5(const struct pt_regs *regs,
struct thread_info *ti, struct e2k_aau_context *context);
extern void calculate_aau_aaldis_aaldas_v6(const struct pt_regs *regs,
struct thread_info *ti, struct e2k_aau_context *context);
extern void do_aau_fault_v2(int aa_field, struct pt_regs *regs);
extern void do_aau_fault_v5(int aa_field, struct pt_regs *regs);
extern void do_aau_fault_v6(int aa_field, struct pt_regs *regs);
extern void save_aaldi_v2(u64 *aaldis);
extern void save_aaldi_v5(u64 *aaldis);
extern void get_aau_context_v2(struct e2k_aau_context *);
extern void get_aau_context_v5(struct e2k_aau_context *);
extern void flushts_v3(void);
extern unsigned long boot_native_read_IDR_reg_value(void);
unsigned long rrd_v2(int);
unsigned long rrd_v3(int);
unsigned long rrd_v6(int);
void rwd_v2(int reg, unsigned long value);
void rwd_v3(int reg, unsigned long value);
void rwd_v6(int reg, unsigned long value);
unsigned long boot_rrd_v2(int);
unsigned long boot_rrd_v3(int);
unsigned long boot_rrd_v6(int);
void boot_rwd_v2(int reg, unsigned long value);
void boot_rwd_v3(int reg, unsigned long value);
void boot_rwd_v6(int reg, unsigned long value);
/* Supported registers for machine->rrd()/rwd() */
enum {
E2K_REG_CORE_MODE,
E2K_REG_HCEM,
E2K_REG_HCEB,
E2K_REG_OSCUTD,
E2K_REG_OSCUIR,
};
u64 native_get_cu_hw1_v2(void);
u64 native_get_cu_hw1_v5(void);
void native_set_cu_hw1_v2(u64);
void native_set_cu_hw1_v5(u64);
void invalidate_MLT_v2(void);
void invalidate_MLT_v3(void);
void get_and_invalidate_MLT_context_v2(e2k_mlt_t *mlt_state);
void get_and_invalidate_MLT_context_v3(e2k_mlt_t *mlt_state);
void get_and_invalidate_MLT_context_v6(e2k_mlt_t *mlt_state);
#ifdef CONFIG_SMP
void clock_off_v3(void);
void clock_on_v3(int cpu);
#endif
void C1_enter_v2(void);
void C1_enter_v6(void);
void C3_enter_v3(void);
void C3_enter_v6(void);
#endif /* __KERNEL__ */
#endif /* _E2K_MACHDEP_H_ */