Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (230 commits)
  [SPARC64]: Update defconfig.
  [SPARC64]: Fix 2 bugs in huge page support.
  [SPARC64]: CONFIG_BLK_DEV_RAM fix
  [SPARC64]: Optimized TSB table initialization.
  [SPARC64]: Allow CONFIG_MEMORY_HOTPLUG to build.
  [SPARC64]: Use SLAB caches for TSB tables.
  [SPARC64]: Don't kill the page allocator when growing a TSB.
  [SPARC64]: Randomize mm->mmap_base when PF_RANDOMIZE is set.
  [SPARC64]: Increase top of 32-bit process stack.
  [SPARC64]: Top-down address space allocation for 32-bit tasks.
  [SPARC64] bbc_i2c: Fix cpu check and add missing module license.
  [SPARC64]: Fix and re-enable dynamic TSB sizing.
  [SUNSU]: Fix missing spinlock initialization.
  [TG3]: Do not try to access NIC_SRAM_DATA_SIG on Sun parts.
  [SPARC64]: First cut at VIS simulator for Niagara.
  [SPARC64]: Fix system type in /proc/cpuinfo and remove bogus OBP check.
  [SPARC64]: Add SMT scheduling support for Niagara.
  [SPARC64]: Fix 32-bit truncation which broke sparsemem.
  [SPARC64]: Move over to sparsemem.
  [SPARC64]: Fix new context version SMP handling.
  ...
This commit is contained in:
Linus Torvalds
2006-03-20 11:57:50 -08:00
125 changed files with 14207 additions and 4039 deletions
+9 -17
View File
@@ -7,27 +7,19 @@
#ifndef _SPARC_IDPROM_H
#define _SPARC_IDPROM_H
/* Offset into the EEPROM where the id PROM is located on the 4c */
#define IDPROM_OFFSET 0x7d8
#include <linux/types.h>
/* On sun4m; physical. */
/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
#define IDPROM_OFFSET_M 0xfd8
struct idprom
{
unsigned char id_format; /* Format identifier (always 0x01) */
unsigned char id_machtype; /* Machine type */
unsigned char id_ethaddr[6]; /* Hardware ethernet address */
long id_date; /* Date of manufacture */
unsigned int id_sernum:24; /* Unique serial number */
unsigned char id_cksum; /* Checksum - xor of the data bytes */
unsigned char reserved[16];
struct idprom {
u8 id_format; /* Format identifier (always 0x01) */
u8 id_machtype; /* Machine type */
u8 id_ethaddr[6]; /* Hardware ethernet address */
s32 id_date; /* Date of manufacture */
u32 id_sernum:24; /* Unique serial number */
u8 id_cksum; /* Checksum - xor of the data bytes */
u8 reserved[16];
};
extern struct idprom *idprom;
extern void idprom_init(void);
#define IDPROM_SIZE (sizeof(struct idprom))
#endif /* !(_SPARC_IDPROM_H) */
+2
View File
@@ -165,6 +165,7 @@ enum prom_input_device {
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
@@ -177,6 +178,7 @@ enum prom_output_device {
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
-47
View File
@@ -120,17 +120,6 @@ case 8: __put_user_asm(x,d,addr,__pu_ret); break; \
default: __pu_ret = __put_user_bad(); break; \
} } else { __pu_ret = -EFAULT; } __pu_ret; })
#define __put_user_check_ret(x,addr,size,retval) ({ \
register int __foo __asm__ ("l1"); \
if (__access_ok(addr,size)) { \
switch (size) { \
case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \
default: if (__put_user_bad()) return retval; break; \
} } else return retval; })
#define __put_user_nocheck(x,addr,size) ({ \
register int __pu_ret; \
switch (size) { \
@@ -141,16 +130,6 @@ case 8: __put_user_asm(x,d,addr,__pu_ret); break; \
default: __pu_ret = __put_user_bad(); break; \
} __pu_ret; })
#define __put_user_nocheck_ret(x,addr,size,retval) ({ \
register int __foo __asm__ ("l1"); \
switch (size) { \
case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
case 8: __put_user_asm_ret(x,d,addr,retval,__foo); break; \
default: if (__put_user_bad()) return retval; break; \
} })
#define __put_user_asm(x,size,addr,ret) \
__asm__ __volatile__( \
"/* Put user asm, inline. */\n" \
@@ -170,32 +149,6 @@ __asm__ __volatile__( \
: "=&r" (ret) : "r" (x), "m" (*__m(addr)), \
"i" (-EFAULT))
#define __put_user_asm_ret(x,size,addr,ret,foo) \
if (__builtin_constant_p(ret) && ret == -EFAULT) \
__asm__ __volatile__( \
"/* Put user asm ret, inline. */\n" \
"1:\t" "st"#size " %1, %2\n\n\t" \
".section __ex_table,#alloc\n\t" \
".align 4\n\t" \
".word 1b, __ret_efault\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "m" (*__m(addr))); \
else \
__asm__ __volatile( \
"/* Put user asm ret, inline. */\n" \
"1:\t" "st"#size " %1, %2\n\n\t" \
".section .fixup,#alloc,#execinstr\n\t" \
".align 4\n" \
"3:\n\t" \
"ret\n\t" \
" restore %%g0, %3, %%o0\n\t" \
".previous\n\n\t" \
".section __ex_table,#alloc\n\t" \
".align 4\n\t" \
".word 1b, 3b\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "m" (*__m(addr)), "i" (ret))
extern int __put_user_bad(void);
#define __get_user_check(x,addr,size,type) ({ \
+5 -1
View File
@@ -95,7 +95,11 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
#ifdef __KERNEL__
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? 0xf0000000 : 0x80000000000L)
#define STACK_TOP32 ((1UL << 32UL) - PAGE_SIZE)
#define STACK_TOP64 (0x0000080000000000UL - (1UL << 32UL))
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
STACK_TOP32 : STACK_TOP64)
#endif
+17 -1
View File
@@ -25,14 +25,27 @@
/* SpitFire and later extended ASIs. The "(III)" marker designates
* UltraSparc-III and later specific ASIs. The "(CMT)" marker designates
* Chip Multi Threading specific ASIs.
* Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific
* ASIs, "(4V)" designates SUN4V specific ASIs.
*/
#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */
#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */
#define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */
#define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */
#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/
#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */
#define ASI_BLK_AIUP_L_4V 0x1e /* (4V) Prim, user, block, l-endian*/
#define ASI_BLK_AIUS_L_4V 0x1f /* (4V) Sec, user, block, l-endian */
#define ASI_SCRATCHPAD 0x20 /* (4V) Scratch Pad Registers */
#define ASI_MMU 0x21 /* (4V) MMU Context Registers */
#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
* secondary, user
*/
#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */
#define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */
#define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */
#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */
#define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */
#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */
#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */
#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */
@@ -137,6 +150,9 @@
#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */
#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */
#define ASI_BLK_INIT_QUAD_LDD_P 0xe2 /* (NG) init-store, twin load,
* primary, implicit
*/
#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */
#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */
#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */
+193 -10
View File
@@ -1,41 +1,224 @@
/* cpudata.h: Per-cpu parameters.
*
* Copyright (C) 2003, 2005 David S. Miller (davem@redhat.com)
* Copyright (C) 2003, 2005, 2006 David S. Miller (davem@davemloft.net)
*/
#ifndef _SPARC64_CPUDATA_H
#define _SPARC64_CPUDATA_H
#include <asm/hypervisor.h>
#include <asm/asi.h>
#ifndef __ASSEMBLY__
#include <linux/percpu.h>
#include <linux/threads.h>
typedef struct {
/* Dcache line 1 */
unsigned int __softirq_pending; /* must be 1st, see rtrap.S */
unsigned int multiplier;
unsigned int counter;
unsigned int idle_volume;
unsigned int __pad1;
unsigned long clock_tick; /* %tick's per second */
unsigned long udelay_val;
/* Dcache line 2 */
unsigned int pgcache_size;
unsigned int __pad1;
unsigned long *pte_cache[2];
unsigned long *pgd_cache;
/* Dcache line 3, rarely used */
/* Dcache line 2, rarely used */
unsigned int dcache_size;
unsigned int dcache_line_size;
unsigned int icache_size;
unsigned int icache_line_size;
unsigned int ecache_size;
unsigned int ecache_line_size;
unsigned int __pad2;
unsigned int __pad3;
unsigned int __pad4;
} cpuinfo_sparc;
DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
#define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu))
#define local_cpu_data() __get_cpu_var(__cpu_data)
/* Trap handling code needs to get at a few critical values upon
* trap entry and to process TSB misses. These cannot be in the
* per_cpu() area as we really need to lock them into the TLB and
* thus make them part of the main kernel image. As a result we
* try to make this as small as possible.
*
* This is padded out and aligned to 64-bytes to avoid false sharing
* on SMP.
*/
/* If you modify the size of this structure, please update
* TRAP_BLOCK_SZ_SHIFT below.
*/
struct thread_info;
struct trap_per_cpu {
/* D-cache line 1: Basic thread information, cpu and device mondo queues */
struct thread_info *thread;
unsigned long pgd_paddr;
unsigned long cpu_mondo_pa;
unsigned long dev_mondo_pa;
/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
unsigned long resum_mondo_pa;
unsigned long resum_kernel_buf_pa;
unsigned long nonresum_mondo_pa;
unsigned long nonresum_kernel_buf_pa;
/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
struct hv_fault_status fault_info;
/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */
unsigned long cpu_mondo_block_pa;
unsigned long cpu_list_pa;
unsigned long __pad1[2];
/* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size. */
unsigned long __pad2[4];
} __attribute__((aligned(64)));
extern struct trap_per_cpu trap_block[NR_CPUS];
extern void init_cur_cpu_trap(struct thread_info *);
extern void setup_tba(void);
struct cpuid_patch_entry {
unsigned int addr;
unsigned int cheetah_safari[4];
unsigned int cheetah_jbus[4];
unsigned int starfire[4];
unsigned int sun4v[4];
};
extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
struct sun4v_1insn_patch_entry {
unsigned int addr;
unsigned int insn;
};
extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
__sun4v_1insn_patch_end;
struct sun4v_2insn_patch_entry {
unsigned int addr;
unsigned int insns[2];
};
extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
__sun4v_2insn_patch_end;
#endif /* !(__ASSEMBLY__) */
#define TRAP_PER_CPU_THREAD 0x00
#define TRAP_PER_CPU_PGD_PADDR 0x08
#define TRAP_PER_CPU_CPU_MONDO_PA 0x10
#define TRAP_PER_CPU_DEV_MONDO_PA 0x18
#define TRAP_PER_CPU_RESUM_MONDO_PA 0x20
#define TRAP_PER_CPU_RESUM_KBUF_PA 0x28
#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38
#define TRAP_PER_CPU_FAULT_INFO 0x40
#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0
#define TRAP_PER_CPU_CPU_LIST_PA 0xc8
#define TRAP_BLOCK_SZ_SHIFT 8
#include <asm/scratchpad.h>
#define __GET_CPUID(REG) \
/* Spitfire implementation (default). */ \
661: ldxa [%g0] ASI_UPA_CONFIG, REG; \
srlx REG, 17, REG; \
and REG, 0x1f, REG; \
nop; \
.section .cpuid_patch, "ax"; \
/* Instruction location. */ \
.word 661b; \
/* Cheetah Safari implementation. */ \
ldxa [%g0] ASI_SAFARI_CONFIG, REG; \
srlx REG, 17, REG; \
and REG, 0x3ff, REG; \
nop; \
/* Cheetah JBUS implementation. */ \
ldxa [%g0] ASI_JBUS_CONFIG, REG; \
srlx REG, 17, REG; \
and REG, 0x1f, REG; \
nop; \
/* Starfire implementation. */ \
sethi %hi(0x1fff40000d0 >> 9), REG; \
sllx REG, 9, REG; \
or REG, 0xd0, REG; \
lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\
/* sun4v implementation. */ \
mov SCRATCHPAD_CPUID, REG; \
ldxa [REG] ASI_SCRATCHPAD, REG; \
nop; \
nop; \
.previous;
#ifdef CONFIG_SMP
#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
__GET_CPUID(TMP) \
sethi %hi(trap_block), DEST; \
sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \
or DEST, %lo(trap_block), DEST; \
add DEST, TMP, DEST; \
/* Clobbers TMP, current address space PGD phys address into DEST. */
#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
/* Clobbers TMP, loads local processor's IRQ work area into DEST. */
#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \
__GET_CPUID(TMP) \
sethi %hi(__irq_work), DEST; \
sllx TMP, 6, TMP; \
or DEST, %lo(__irq_work), DEST; \
add DEST, TMP, DEST;
/* Clobbers TMP, loads DEST with current thread info pointer. */
#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
ldx [DEST + TRAP_PER_CPU_THREAD], DEST;
/* Given the current thread info pointer in THR, load the per-cpu
* area base of the current processor into DEST. REG1, REG2, and REG3 are
* clobbered.
*
* You absolutely cannot use DEST as a temporary in this code. The
* reason is that traps can happen during execution, and return from
* trap will load the fully resolved DEST per-cpu base. This can corrupt
* the calculations done by the macro mid-stream.
*/
#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \
ldub [THR + TI_CPU], REG1; \
sethi %hi(__per_cpu_shift), REG3; \
sethi %hi(__per_cpu_base), REG2; \
ldx [REG3 + %lo(__per_cpu_shift)], REG3; \
ldx [REG2 + %lo(__per_cpu_base)], REG2; \
sllx REG1, REG3, REG3; \
add REG3, REG2, DEST;
#else
#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
sethi %hi(trap_block), DEST; \
or DEST, %lo(trap_block), DEST; \
/* Uniprocessor versions, we know the cpuid is zero. */
#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \
sethi %hi(__irq_work), DEST; \
or DEST, %lo(__irq_work), DEST;
#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
ldx [DEST + TRAP_PER_CPU_THREAD], DEST;
/* No per-cpu areas on uniprocessor, so no need to load DEST. */
#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
#endif /* !(CONFIG_SMP) */
#endif /* _SPARC64_CPUDATA_H */
+17 -5
View File
@@ -10,6 +10,7 @@
#ifdef __KERNEL__
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/spitfire.h>
#endif
/*
@@ -68,6 +69,7 @@
#define HWCAP_SPARC_MULDIV 8
#define HWCAP_SPARC_V9 16
#define HWCAP_SPARC_ULTRA3 32
#define HWCAP_SPARC_BLKINIT 64
/*
* These are used to set parameters in the core dumps.
@@ -145,11 +147,21 @@ typedef struct {
instruction set this cpu supports. */
/* On Ultra, we support all of the v8 capabilities. */
#define ELF_HWCAP ((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
HWCAP_SPARC_V9) | \
((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
HWCAP_SPARC_ULTRA3 : 0))
static inline unsigned int sparc64_elf_hwcap(void)
{
unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
HWCAP_SPARC_V9);
if (tlb_type == cheetah || tlb_type == cheetah_plus)
cap |= HWCAP_SPARC_ULTRA3;
else if (tlb_type == hypervisor)
cap |= HWCAP_SPARC_BLKINIT;
return cap;
}
#define ELF_HWCAP sparc64_elf_hwcap();
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
+15
View File
@@ -4,12 +4,21 @@
#include <asm/pstate.h>
/* wrpr %g0, val, %gl */
#define SET_GL(val) \
.word 0xa1902000 | val
/* rdpr %gl, %gN */
#define GET_GL_GLOBAL(N) \
.word 0x81540000 | (N << 25)
#define KERNBASE 0x400000
#define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ)
#define __CHEETAH_ID 0x003e0014
#define __JALAPENO_ID 0x003e0016
#define __SERRANO_ID 0x003e0022
#define CHEETAH_MANUF 0x003e
#define CHEETAH_IMPL 0x0014 /* Ultra-III */
@@ -19,6 +28,12 @@
#define PANTHER_IMPL 0x0019 /* Ultra-IV+ */
#define SERRANO_IMPL 0x0022 /* Ultra-IIIi+ */
#define BRANCH_IF_SUN4V(tmp1,label) \
sethi %hi(is_sun4v), %tmp1; \
lduw [%tmp1 + %lo(is_sun4v)], %tmp1; \
brnz,pn %tmp1, label; \
nop
#define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label) \
rdpr %ver, %tmp1; \
sethi %hi(__CHEETAH_ID), %tmp2; \
File diff suppressed because it is too large Load Diff
+1 -11
View File
@@ -9,15 +9,7 @@
#include <linux/types.h>
/* Offset into the EEPROM where the id PROM is located on the 4c */
#define IDPROM_OFFSET 0x7d8
/* On sun4m; physical. */
/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
#define IDPROM_OFFSET_M 0xfd8
struct idprom
{
struct idprom {
u8 id_format; /* Format identifier (always 0x01) */
u8 id_machtype; /* Machine type */
u8 id_ethaddr[6]; /* Hardware ethernet address */
@@ -30,6 +22,4 @@ struct idprom
extern struct idprom *idprom;
extern void idprom_init(void);
#define IDPROM_SIZE (sizeof(struct idprom))
#endif /* !(_SPARC_IDPROM_H) */
+15
View File
@@ -0,0 +1,15 @@
#ifndef _SPARC64_INTR_QUEUE_H
#define _SPARC64_INTR_QUEUE_H
/* Sun4v interrupt queue registers, accessed via ASI_QUEUE. */
#define INTRQ_CPU_MONDO_HEAD 0x3c0 /* CPU mondo head */
#define INTRQ_CPU_MONDO_TAIL 0x3c8 /* CPU mondo tail */
#define INTRQ_DEVICE_MONDO_HEAD 0x3d0 /* Device mondo head */
#define INTRQ_DEVICE_MONDO_TAIL 0x3d8 /* Device mondo tail */
#define INTRQ_RESUM_MONDO_HEAD 0x3e0 /* Resumable error mondo head */
#define INTRQ_RESUM_MONDO_TAIL 0x3e8 /* Resumable error mondo tail */
#define INTRQ_NONRESUM_MONDO_HEAD 0x3f0 /* Non-resumable error mondo head */
#define INTRQ_NONRESUM_MONDO_TAIL 0x3f8 /* Non-resumable error mondo head */
#endif /* !(_SPARC64_INTR_QUEUE_H) */
+4
View File
@@ -72,8 +72,11 @@ struct ino_bucket {
#define IMAP_VALID 0x80000000 /* IRQ Enabled */
#define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */
#define IMAP_TID_JBUS 0x7c000000 /* JBUS TargetID */
#define IMAP_TID_SHIFT 26
#define IMAP_AID_SAFARI 0x7c000000 /* Safari AgentID */
#define IMAP_AID_SHIFT 26
#define IMAP_NID_SAFARI 0x03e00000 /* Safari NodeID */
#define IMAP_NID_SHIFT 21
#define IMAP_IGN 0x000007c0 /* IRQ Group Number */
#define IMAP_INO 0x0000003f /* IRQ Number */
#define IMAP_INR 0x000007ff /* Full interrupt number*/
@@ -111,6 +114,7 @@ extern void disable_irq(unsigned int);
#define disable_irq_nosync disable_irq
extern void enable_irq(unsigned int);
extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
static __inline__ void set_softint(unsigned long bits)
+22 -14
View File
@@ -4,20 +4,9 @@
#include <linux/config.h>
#include <asm/page.h>
#include <asm/const.h>
#include <asm/hypervisor.h>
/*
* For the 8k pagesize kernel, use only 10 hw context bits to optimize some
* shifts in the fast tlbmiss handlers, instead of all 13 bits (specifically
* for vpte offset calculation). For other pagesizes, this optimization in
* the tlbhandlers can not be done; but still, all 13 bits can not be used
* because the tlb handlers use "andcc" instruction which sign extends 13
* bit arguments.
*/
#if PAGE_SHIFT == 13
#define CTX_NR_BITS 10
#else
#define CTX_NR_BITS 12
#endif
#define CTX_NR_BITS 13
#define TAG_CONTEXT_BITS ((_AC(1,UL) << CTX_NR_BITS) - _AC(1,UL))
@@ -90,8 +79,27 @@
#ifndef __ASSEMBLY__
#define TSB_ENTRY_ALIGNMENT 16
struct tsb {
unsigned long tag;
unsigned long pte;
} __attribute__((aligned(TSB_ENTRY_ALIGNMENT)));
extern void __tsb_insert(unsigned long ent, unsigned long tag, unsigned long pte);
extern void tsb_flush(unsigned long ent, unsigned long tag);
extern void tsb_init(struct tsb *tsb, unsigned long size);
typedef struct {
unsigned long sparc64_ctx_val;
spinlock_t lock;
unsigned long sparc64_ctx_val;
struct tsb *tsb;
unsigned long tsb_rss_limit;
unsigned long tsb_nentries;
unsigned long tsb_reg_val;
unsigned long tsb_map_vaddr;
unsigned long tsb_map_pte;
struct hv_tsb_descr tsb_descr;
} mm_context_t;
#endif /* !__ASSEMBLY__ */
+79 -79
View File
@@ -19,96 +19,98 @@ extern unsigned long tlb_context_cache;
extern unsigned long mmu_context_bmap[];
extern void get_new_mmu_context(struct mm_struct *mm);
#ifdef CONFIG_SMP
extern void smp_new_mmu_context_version(void);
#else
#define smp_new_mmu_context_version() do { } while (0)
#endif
/* Initialize a new mmu context. This is invoked when a new
* address space instance (unique or shared) is instantiated.
* This just needs to set mm->context to an invalid context.
*/
#define init_new_context(__tsk, __mm) \
(((__mm)->context.sparc64_ctx_val = 0UL), 0)
extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
extern void destroy_context(struct mm_struct *mm);
/* Destroy a dead context. This occurs when mmput drops the
* mm_users count to zero, the mmaps have been released, and
* all the page tables have been flushed. Our job is to destroy
* any remaining processor-specific state, and in the sparc64
* case this just means freeing up the mmu context ID held by
* this task if valid.
*/
#define destroy_context(__mm) \
do { spin_lock(&ctx_alloc_lock); \
if (CTX_VALID((__mm)->context)) { \
unsigned long nr = CTX_NRBITS((__mm)->context); \
mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); \
} \
spin_unlock(&ctx_alloc_lock); \
} while(0)
extern void __tsb_context_switch(unsigned long pgd_pa,
unsigned long tsb_reg,
unsigned long tsb_vaddr,
unsigned long tsb_pte,
unsigned long tsb_descr_pa);
/* Reload the two core values used by TLB miss handler
* processing on sparc64. They are:
* 1) The physical address of mm->pgd, when full page
* table walks are necessary, this is where the
* search begins.
* 2) A "PGD cache". For 32-bit tasks only pgd[0] is
* ever used since that maps the entire low 4GB
* completely. To speed up TLB miss processing we
* make this value available to the handlers. This
* decreases the amount of memory traffic incurred.
*/
#define reload_tlbmiss_state(__tsk, __mm) \
do { \
register unsigned long paddr asm("o5"); \
register unsigned long pgd_cache asm("o4"); \
paddr = __pa((__mm)->pgd); \
pgd_cache = 0UL; \
if (task_thread_info(__tsk)->flags & _TIF_32BIT) \
pgd_cache = get_pgd_cache((__mm)->pgd); \
__asm__ __volatile__("wrpr %%g0, 0x494, %%pstate\n\t" \
"mov %3, %%g4\n\t" \
"mov %0, %%g7\n\t" \
"stxa %1, [%%g4] %2\n\t" \
"membar #Sync\n\t" \
"wrpr %%g0, 0x096, %%pstate" \
: /* no outputs */ \
: "r" (paddr), "r" (pgd_cache),\
"i" (ASI_DMMU), "i" (TSB_REG)); \
} while(0)
static inline void tsb_context_switch(struct mm_struct *mm)
{
__tsb_context_switch(__pa(mm->pgd), mm->context.tsb_reg_val,
mm->context.tsb_map_vaddr,
mm->context.tsb_map_pte,
__pa(&mm->context.tsb_descr));
}
extern void tsb_grow(struct mm_struct *mm, unsigned long mm_rss);
#ifdef CONFIG_SMP
extern void smp_tsb_sync(struct mm_struct *mm);
#else
#define smp_tsb_sync(__mm) do { } while (0)
#endif
/* Set MMU context in the actual hardware. */
#define load_secondary_context(__mm) \
__asm__ __volatile__("stxa %0, [%1] %2\n\t" \
"flush %%g6" \
: /* No outputs */ \
: "r" (CTX_HWBITS((__mm)->context)), \
"r" (SECONDARY_CONTEXT), "i" (ASI_DMMU))
__asm__ __volatile__( \
"\n661: stxa %0, [%1] %2\n" \
" .section .sun4v_1insn_patch, \"ax\"\n" \
" .word 661b\n" \
" stxa %0, [%1] %3\n" \
" .previous\n" \
" flush %%g6\n" \
: /* No outputs */ \
: "r" (CTX_HWBITS((__mm)->context)), \
"r" (SECONDARY_CONTEXT), "i" (ASI_DMMU), "i" (ASI_MMU))
extern void __flush_tlb_mm(unsigned long, unsigned long);
/* Switch the current MM context. */
/* Switch the current MM context. Interrupts are disabled. */
static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)
{
unsigned long ctx_valid;
unsigned long ctx_valid, flags;
int cpu;
/* Note: page_table_lock is used here to serialize switch_mm
* and activate_mm, and their calls to get_new_mmu_context.
* This use of page_table_lock is unrelated to its other uses.
*/
spin_lock(&mm->page_table_lock);
spin_lock_irqsave(&mm->context.lock, flags);
ctx_valid = CTX_VALID(mm->context);
if (!ctx_valid)
get_new_mmu_context(mm);
spin_unlock(&mm->page_table_lock);
if (!ctx_valid || (old_mm != mm)) {
load_secondary_context(mm);
reload_tlbmiss_state(tsk, mm);
}
/* We have to be extremely careful here or else we will miss
* a TSB grow if we switch back and forth between a kernel
* thread and an address space which has it's TSB size increased
* on another processor.
*
* It is possible to play some games in order to optimize the
* switch, but the safest thing to do is to unconditionally
* perform the secondary context load and the TSB context switch.
*
* For reference the bad case is, for address space "A":
*
* CPU 0 CPU 1
* run address space A
* set cpu0's bits in cpu_vm_mask
* switch to kernel thread, borrow
* address space A via entry_lazy_tlb
* run address space A
* set cpu1's bit in cpu_vm_mask
* flush_tlb_pending()
* reset cpu_vm_mask to just cpu1
* TSB grow
* run address space A
* context was valid, so skip
* TSB context switch
*
* At that point cpu0 continues to use a stale TSB, the one from
* before the TSB grow performed on cpu1. cpu1 did not cross-call
* cpu0 to update it's TSB because at that point the cpu_vm_mask
* only had cpu1 set in it.
*/
load_secondary_context(mm);
tsb_context_switch(mm);
/* Even if (mm == old_mm) we _must_ check
* the cpu_vm_mask. If we do not we could
* corrupt the TLB state because of how
* smp_flush_tlb_{page,range,mm} on sparc64
* and lazy tlb switches work. -DaveM
/* Any time a processor runs a context on an address space
* for the first time, we must flush that context out of the
* local TLB.
*/
cpu = smp_processor_id();
if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) {
@@ -116,6 +118,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
__flush_tlb_mm(CTX_HWBITS(mm->context),
SECONDARY_CONTEXT);
}
spin_unlock_irqrestore(&mm->context.lock, flags);
}
#define deactivate_mm(tsk,mm) do { } while (0)
@@ -123,23 +126,20 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
/* Activate a new MM instance for the current task. */
static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
{
unsigned long flags;
int cpu;
/* Note: page_table_lock is used here to serialize switch_mm
* and activate_mm, and their calls to get_new_mmu_context.
* This use of page_table_lock is unrelated to its other uses.
*/
spin_lock(&mm->page_table_lock);
spin_lock_irqsave(&mm->context.lock, flags);
if (!CTX_VALID(mm->context))
get_new_mmu_context(mm);
cpu = smp_processor_id();
if (!cpu_isset(cpu, mm->cpu_vm_mask))
cpu_set(cpu, mm->cpu_vm_mask);
spin_unlock(&mm->page_table_lock);
load_secondary_context(mm);
__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
reload_tlbmiss_state(current, mm);
tsb_context_switch(mm);
spin_unlock_irqrestore(&mm->context.lock, flags);
}
#endif /* !(__ASSEMBLY__) */
+6
View File
@@ -0,0 +1,6 @@
#ifndef _SPARC64_NUMNODES_H
#define _SPARC64_NUMNODES_H
#define NODES_SHIFT 0
#endif /* !(_SPARC64_NUMNODES_H) */
+19 -24
View File
@@ -12,18 +12,8 @@
#include <linux/config.h>
#include <asm/openprom.h>
/* Enumeration to describe the prom major version we have detected. */
enum prom_major_version {
PROM_V0, /* Original sun4c V0 prom */
PROM_V2, /* sun4c and early sun4m V2 prom */
PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */
PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */
PROM_AP1000, /* actually no prom at all */
};
extern enum prom_major_version prom_vers;
/* Revision, and firmware revision. */
extern unsigned int prom_rev, prom_prev;
/* OBP version string. */
extern char prom_version[];
/* Root node of the prom device tree, this stays constant after
* initialization is complete.
@@ -39,6 +29,9 @@ extern int prom_stdin, prom_stdout;
extern int prom_chosen_node;
/* Helper values and strings in arch/sparc64/kernel/head.S */
extern const char prom_peer_name[];
extern const char prom_compatible_name[];
extern const char prom_root_compatible[];
extern const char prom_finddev_name[];
extern const char prom_chosen_path[];
extern const char prom_getprop_name[];
@@ -130,15 +123,6 @@ extern void prom_setcallback(callback_func_t func_ptr);
*/
extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size);
/* Get the prom major version. */
extern int prom_version(void);
/* Get the prom plugin revision. */
extern int prom_getrev(void);
/* Get the prom firmware revision. */
extern int prom_getprev(void);
/* Character operations to/from the console.... */
/* Non-blocking get character from console. */
@@ -164,6 +148,7 @@ enum prom_input_device {
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
@@ -176,6 +161,7 @@ enum prom_output_device {
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
@@ -183,10 +169,18 @@ extern enum prom_output_device prom_query_output_device(void);
/* Multiprocessor operations... */
#ifdef CONFIG_SMP
/* Start the CPU with the given device tree node, context table, and context
* at the passed program counter.
/* Start the CPU with the given device tree node at the passed program
* counter with the given arg passed in via register %o0.
*/
extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg);
/* Start the CPU with the given cpu ID at the passed program
* counter with the given arg passed in via register %o0.
*/
extern void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg);
/* Stop the CPU with the given cpu ID. */
extern void prom_stopcpu_cpuid(int cpuid);
/* Stop the current CPU. */
extern void prom_stopself(void);
@@ -335,6 +329,7 @@ int cpu_find_by_mid(int mid, int *prom_node);
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);
extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
extern long p1275_cmd(const char *, long, ...);
+4 -9
View File
@@ -104,10 +104,12 @@ typedef unsigned long pgprot_t;
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#define ARCH_HAS_SETCLEAR_HUGE_PTE
#define ARCH_HAS_HUGETLB_PREFAULT_HOOK
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#endif
#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \
(_AC(0x0000000070000000,UL)) : (PAGE_OFFSET))
(_AC(0x0000000070000000,UL)) : \
(_AC(0xfffff80000000000,UL) + (1UL << 32UL)))
#endif /* !(__ASSEMBLY__) */
@@ -124,17 +126,10 @@ typedef unsigned long pgprot_t;
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
/* PFNs are real physical page numbers. However, mem_map only begins to record
* per-page information starting at pfn_base. This is to handle systems where
* the first physical page in the machine is at some huge physical address,
* such as 4GB. This is common on a partitioned E10000, for example.
*/
extern struct page *pfn_to_page(unsigned long pfn);
extern unsigned long page_to_pfn(struct page *);
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr)>>PAGE_SHIFT)
#define pfn_valid(pfn) (((pfn)-(pfn_base)) < max_mapnr)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define virt_to_phys __pa
+3
View File
@@ -139,6 +139,9 @@ struct pci_pbm_info {
/* Opaque 32-bit system bus Port ID. */
u32 portid;
/* Opaque 32-bit handle used for hypervisor calls. */
u32 devhandle;
/* Chipset version information. */
int chip_type;
#define PBM_CHIP_TYPE_SABRE 1
+45 -11
View File
@@ -41,10 +41,26 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
struct pci_dev;
struct pci_iommu_ops {
void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *);
void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t);
dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int);
void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int);
int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int);
void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int);
void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int);
void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
};
extern struct pci_iommu_ops *pci_iommu_ops;
/* Allocate and map kernel buffer using consistent mode DMA for a device.
* hwdev should be valid struct pci_dev pointer for PCI devices.
*/
extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle);
static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
{
return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle);
}
/* Free and unmap a consistent DMA buffer.
* cpu_addr is what was returned from pci_alloc_consistent,
@@ -54,7 +70,10 @@ extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t
* References to the memory and mappings associated with cpu_addr/dma_addr
* past this call are illegal.
*/
extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle);
static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
{
return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle);
}
/* Map a single buffer of the indicated size for DMA in streaming mode.
* The 32-bit bus address to use is returned.
@@ -62,7 +81,10 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
* Once the device is given the dma address, the device owns this memory
* until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
*/
extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction);
static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
return pci_iommu_ops->map_single(hwdev, ptr, size, direction);
}
/* Unmap a single streaming mode DMA translation. The dma_addr and size
* must match what was provided for in a previous pci_map_single call. All
@@ -71,7 +93,10 @@ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
* After this call, reads by the cpu to the buffer are guaranteed to see
* whatever the device wrote there.
*/
extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
{
pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction);
}
/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */
#define pci_map_page(dev, page, off, size, dir) \
@@ -107,15 +132,19 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction);
static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
return pci_iommu_ops->map_sg(hwdev, sg, nents, direction);
}
/* Unmap a set of streaming mode DMA translations.
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nhwents, int direction);
static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction)
{
pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction);
}
/* Make physical memory consistent for a single
* streaming mode DMA translation after a transfer.
@@ -127,8 +156,10 @@ extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
* must first perform a pci_dma_sync_for_device, and then the
* device again owns the buffer.
*/
extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
size_t size, int direction);
static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
{
pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction);
}
static inline void
pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
@@ -144,7 +175,10 @@ pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
* The same as pci_dma_sync_single_* but for a scatter-gather list,
* same rules and usage.
*/
extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction);
static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
{
pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction);
}
static inline void
pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
+30 -142
View File
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/spitfire.h>
#include <asm/cpudata.h>
@@ -13,172 +14,59 @@
#include <asm/page.h>
/* Page table allocation/freeing. */
#ifdef CONFIG_SMP
/* Sliiiicck */
#define pgt_quicklists local_cpu_data()
#else
extern struct pgtable_cache_struct {
unsigned long *pgd_cache;
unsigned long *pte_cache[2];
unsigned int pgcache_size;
} pgt_quicklists;
#endif
#define pgd_quicklist (pgt_quicklists.pgd_cache)
#define pmd_quicklist ((unsigned long *)0)
#define pte_quicklist (pgt_quicklists.pte_cache)
#define pgtable_cache_size (pgt_quicklists.pgcache_size)
extern kmem_cache_t *pgtable_cache;
static __inline__ void free_pgd_fast(pgd_t *pgd)
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
preempt_disable();
*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
pgtable_cache_size++;
preempt_enable();
return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
}
static __inline__ pgd_t *get_pgd_fast(void)
static inline void pgd_free(pgd_t *pgd)
{
unsigned long *ret;
preempt_disable();
if((ret = pgd_quicklist) != NULL) {
pgd_quicklist = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
preempt_enable();
} else {
preempt_enable();
ret = (unsigned long *) __get_free_page(GFP_KERNEL|__GFP_REPEAT);
if(ret)
memset(ret, 0, PAGE_SIZE);
}
return (pgd_t *)ret;
kmem_cache_free(pgtable_cache, pgd);
}
static __inline__ void free_pgd_slow(pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
#ifdef DCACHE_ALIASING_POSSIBLE
#define VPTE_COLOR(address) (((address) >> (PAGE_SHIFT + 10)) & 1UL)
#define DCACHE_COLOR(address) (((address) >> PAGE_SHIFT) & 1UL)
#else
#define VPTE_COLOR(address) 0
#define DCACHE_COLOR(address) 0
#endif
#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD)
static __inline__ pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
unsigned long *ret;
int color = 0;
preempt_disable();
if (pte_quicklist[color] == NULL)
color = 1;
if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
pte_quicklist[color] = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
}
preempt_enable();
return (pmd_t *)ret;
return kmem_cache_alloc(pgtable_cache,
GFP_KERNEL|__GFP_REPEAT);
}
static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
static inline void pmd_free(pmd_t *pmd)
{
pmd_t *pmd;
pmd = pmd_alloc_one_fast(mm, address);
if (!pmd) {
pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
if (pmd)
memset(pmd, 0, PAGE_SIZE);
}
return pmd;
kmem_cache_free(pgtable_cache, pmd);
}
static __inline__ void free_pmd_fast(pmd_t *pmd)
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
unsigned long address)
{
unsigned long color = DCACHE_COLOR((unsigned long)pmd);
preempt_disable();
*(unsigned long *)pmd = (unsigned long) pte_quicklist[color];
pte_quicklist[color] = (unsigned long *) pmd;
pgtable_cache_size++;
preempt_enable();
return kmem_cache_alloc(pgtable_cache,
GFP_KERNEL|__GFP_REPEAT);
}
static __inline__ void free_pmd_slow(pmd_t *pmd)
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long address)
{
free_page((unsigned long)pmd);
return virt_to_page(pte_alloc_one_kernel(mm, address));
}
static inline void pte_free_kernel(pte_t *pte)
{
kmem_cache_free(pgtable_cache, pte);
}
static inline void pte_free(struct page *ptepage)
{
pte_free_kernel(page_address(ptepage));
}
#define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE)
#define pmd_populate(MM,PMD,PTE_PAGE) \
pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address);
static inline struct page *
pte_alloc_one(struct mm_struct *mm, unsigned long addr)
{
pte_t *pte = pte_alloc_one_kernel(mm, addr);
if (pte)
return virt_to_page(pte);
return NULL;
}
static __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
{
unsigned long color = VPTE_COLOR(address);
unsigned long *ret;
preempt_disable();
if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
pte_quicklist[color] = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
}
preempt_enable();
return (pte_t *)ret;
}
static __inline__ void free_pte_fast(pte_t *pte)
{
unsigned long color = DCACHE_COLOR((unsigned long)pte);
preempt_disable();
*(unsigned long *)pte = (unsigned long) pte_quicklist[color];
pte_quicklist[color] = (unsigned long *) pte;
pgtable_cache_size++;
preempt_enable();
}
static __inline__ void free_pte_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
static inline void pte_free_kernel(pte_t *pte)
{
free_pte_fast(pte);
}
static inline void pte_free(struct page *ptepage)
{
free_pte_fast(page_address(ptepage));
}
#define pmd_free(pmd) free_pmd_fast(pmd)
#define pgd_free(pgd) free_pgd_fast(pgd)
#define pgd_alloc(mm) get_pgd_fast()
#define check_pgt_cache() do { } while (0)
#endif /* _SPARC64_PGALLOC_H */
+520 -192
View File
@@ -25,7 +25,8 @@
#include <asm/const.h>
/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB).
* The page copy blockops can use 0x2000000 to 0x10000000.
* The page copy blockops can use 0x2000000 to 0x4000000.
* The TSB is mapped in the 0x4000000 to 0x6000000 range.
* The PROM resides in an area spanning 0xf0000000 to 0x100000000.
* The vmalloc area spans 0x100000000 to 0x200000000.
* Since modules need to be in the lowest 32-bits of the address space,
@@ -34,6 +35,7 @@
* 0x400000000.
*/
#define TLBTEMP_BASE _AC(0x0000000002000000,UL)
#define TSBMAP_BASE _AC(0x0000000004000000,UL)
#define MODULES_VADDR _AC(0x0000000010000000,UL)
#define MODULES_LEN _AC(0x00000000e0000000,UL)
#define MODULES_END _AC(0x00000000f0000000,UL)
@@ -88,132 +90,132 @@
#endif /* !(__ASSEMBLY__) */
/* Spitfire/Cheetah TTE bits. */
#define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */
#define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit up to date*/
#define _PAGE_SZ4MB _AC(0x6000000000000000,UL) /* 4MB Page */
#define _PAGE_SZ512K _AC(0x4000000000000000,UL) /* 512K Page */
#define _PAGE_SZ64K _AC(0x2000000000000000,UL) /* 64K Page */
#define _PAGE_SZ8K _AC(0x0000000000000000,UL) /* 8K Page */
#define _PAGE_NFO _AC(0x1000000000000000,UL) /* No Fault Only */
#define _PAGE_IE _AC(0x0800000000000000,UL) /* Invert Endianness */
#define _PAGE_SOFT2 _AC(0x07FC000000000000,UL) /* Software bits, set 2 */
#define _PAGE_RES1 _AC(0x0002000000000000,UL) /* Reserved */
#define _PAGE_SZ32MB _AC(0x0001000000000000,UL) /* (Panther) 32MB page */
#define _PAGE_SZ256MB _AC(0x2001000000000000,UL) /* (Panther) 256MB page */
#define _PAGE_SN _AC(0x0000800000000000,UL) /* (Cheetah) Snoop */
#define _PAGE_RES2 _AC(0x0000780000000000,UL) /* Reserved */
#define _PAGE_PADDR_SF _AC(0x000001FFFFFFE000,UL) /* (Spitfire) paddr[40:13]*/
#define _PAGE_PADDR _AC(0x000007FFFFFFE000,UL) /* (Cheetah) paddr[42:13] */
#define _PAGE_SOFT _AC(0x0000000000001F80,UL) /* Software bits */
#define _PAGE_L _AC(0x0000000000000040,UL) /* Locked TTE */
#define _PAGE_CP _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */
#define _PAGE_CV _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */
#define _PAGE_E _AC(0x0000000000000008,UL) /* side-Effect */
#define _PAGE_P _AC(0x0000000000000004,UL) /* Privileged Page */
#define _PAGE_W _AC(0x0000000000000002,UL) /* Writable */
#define _PAGE_G _AC(0x0000000000000001,UL) /* Global */
/* PTE bits which are the same in SUN4U and SUN4V format. */
#define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */
#define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/
/* Here are the SpitFire software bits we use in the TTE's.
*
* WARNING: If you are going to try and start using some
* of the soft2 bits, you will need to make
* modifications to the swap entry implementation.
* For example, one thing that could happen is that
* swp_entry_to_pte() would BUG_ON() if you tried
* to use one of the soft2 bits for _PAGE_FILE.
*
* Like other architectures, I have aliased _PAGE_FILE with
* _PAGE_MODIFIED. This works because _PAGE_FILE is never
* interpreted that way unless _PAGE_PRESENT is clear.
*/
#define _PAGE_EXEC _AC(0x0000000000001000,UL) /* Executable SW bit */
#define _PAGE_MODIFIED _AC(0x0000000000000800,UL) /* Modified (dirty) */
#define _PAGE_FILE _AC(0x0000000000000800,UL) /* Pagecache page */
#define _PAGE_ACCESSED _AC(0x0000000000000400,UL) /* Accessed (ref'd) */
#define _PAGE_READ _AC(0x0000000000000200,UL) /* Readable SW Bit */
#define _PAGE_WRITE _AC(0x0000000000000100,UL) /* Writable SW Bit */
#define _PAGE_PRESENT _AC(0x0000000000000080,UL) /* Present */
/* SUN4U pte bits... */
#define _PAGE_SZ4MB_4U _AC(0x6000000000000000,UL) /* 4MB Page */
#define _PAGE_SZ512K_4U _AC(0x4000000000000000,UL) /* 512K Page */
#define _PAGE_SZ64K_4U _AC(0x2000000000000000,UL) /* 64K Page */
#define _PAGE_SZ8K_4U _AC(0x0000000000000000,UL) /* 8K Page */
#define _PAGE_NFO_4U _AC(0x1000000000000000,UL) /* No Fault Only */
#define _PAGE_IE_4U _AC(0x0800000000000000,UL) /* Invert Endianness */
#define _PAGE_SOFT2_4U _AC(0x07FC000000000000,UL) /* Software bits, set 2 */
#define _PAGE_RES1_4U _AC(0x0002000000000000,UL) /* Reserved */
#define _PAGE_SZ32MB_4U _AC(0x0001000000000000,UL) /* (Panther) 32MB page */
#define _PAGE_SZ256MB_4U _AC(0x2001000000000000,UL) /* (Panther) 256MB page */
#define _PAGE_SN_4U _AC(0x0000800000000000,UL) /* (Cheetah) Snoop */
#define _PAGE_RES2_4U _AC(0x0000780000000000,UL) /* Reserved */
#define _PAGE_PADDR_4U _AC(0x000007FFFFFFE000,UL) /* (Cheetah) pa[42:13] */
#define _PAGE_SOFT_4U _AC(0x0000000000001F80,UL) /* Software bits: */
#define _PAGE_EXEC_4U _AC(0x0000000000001000,UL) /* Executable SW bit */
#define _PAGE_MODIFIED_4U _AC(0x0000000000000800,UL) /* Modified (dirty) */
#define _PAGE_FILE_4U _AC(0x0000000000000800,UL) /* Pagecache page */
#define _PAGE_ACCESSED_4U _AC(0x0000000000000400,UL) /* Accessed (ref'd) */
#define _PAGE_READ_4U _AC(0x0000000000000200,UL) /* Readable SW Bit */
#define _PAGE_WRITE_4U _AC(0x0000000000000100,UL) /* Writable SW Bit */
#define _PAGE_PRESENT_4U _AC(0x0000000000000080,UL) /* Present */
#define _PAGE_L_4U _AC(0x0000000000000040,UL) /* Locked TTE */
#define _PAGE_CP_4U _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */
#define _PAGE_CV_4U _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */
#define _PAGE_E_4U _AC(0x0000000000000008,UL) /* side-Effect */
#define _PAGE_P_4U _AC(0x0000000000000004,UL) /* Privileged Page */
#define _PAGE_W_4U _AC(0x0000000000000002,UL) /* Writable */
/* SUN4V pte bits... */
#define _PAGE_NFO_4V _AC(0x4000000000000000,UL) /* No Fault Only */
#define _PAGE_SOFT2_4V _AC(0x3F00000000000000,UL) /* Software bits, set 2 */
#define _PAGE_MODIFIED_4V _AC(0x2000000000000000,UL) /* Modified (dirty) */
#define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd) */
#define _PAGE_READ_4V _AC(0x0800000000000000,UL) /* Readable SW Bit */
#define _PAGE_WRITE_4V _AC(0x0400000000000000,UL) /* Writable SW Bit */
#define _PAGE_PADDR_4V _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13] */
#define _PAGE_IE_4V _AC(0x0000000000001000,UL) /* Invert Endianness */
#define _PAGE_E_4V _AC(0x0000000000000800,UL) /* side-Effect */
#define _PAGE_CP_4V _AC(0x0000000000000400,UL) /* Cacheable in P-Cache */
#define _PAGE_CV_4V _AC(0x0000000000000200,UL) /* Cacheable in V-Cache */
#define _PAGE_P_4V _AC(0x0000000000000100,UL) /* Privileged Page */
#define _PAGE_EXEC_4V _AC(0x0000000000000080,UL) /* Executable Page */
#define _PAGE_W_4V _AC(0x0000000000000040,UL) /* Writable */
#define _PAGE_SOFT_4V _AC(0x0000000000000030,UL) /* Software bits */
#define _PAGE_FILE_4V _AC(0x0000000000000020,UL) /* Pagecache page */
#define _PAGE_PRESENT_4V _AC(0x0000000000000010,UL) /* Present */
#define _PAGE_RESV_4V _AC(0x0000000000000008,UL) /* Reserved */
#define _PAGE_SZ16GB_4V _AC(0x0000000000000007,UL) /* 16GB Page */
#define _PAGE_SZ2GB_4V _AC(0x0000000000000006,UL) /* 2GB Page */
#define _PAGE_SZ256MB_4V _AC(0x0000000000000005,UL) /* 256MB Page */
#define _PAGE_SZ32MB_4V _AC(0x0000000000000004,UL) /* 32MB Page */
#define _PAGE_SZ4MB_4V _AC(0x0000000000000003,UL) /* 4MB Page */
#define _PAGE_SZ512K_4V _AC(0x0000000000000002,UL) /* 512K Page */
#define _PAGE_SZ64K_4V _AC(0x0000000000000001,UL) /* 64K Page */
#define _PAGE_SZ8K_4V _AC(0x0000000000000000,UL) /* 8K Page */
#if PAGE_SHIFT == 13
#define _PAGE_SZBITS _PAGE_SZ8K
#define _PAGE_SZBITS_4U _PAGE_SZ8K_4U
#define _PAGE_SZBITS_4V _PAGE_SZ8K_4V
#elif PAGE_SHIFT == 16
#define _PAGE_SZBITS _PAGE_SZ64K
#define _PAGE_SZBITS_4U _PAGE_SZ64K_4U
#define _PAGE_SZBITS_4V _PAGE_SZ64K_4V
#elif PAGE_SHIFT == 19
#define _PAGE_SZBITS _PAGE_SZ512K
#define _PAGE_SZBITS_4U _PAGE_SZ512K_4U
#define _PAGE_SZBITS_4V _PAGE_SZ512K_4V
#elif PAGE_SHIFT == 22
#define _PAGE_SZBITS _PAGE_SZ4MB
#define _PAGE_SZBITS_4U _PAGE_SZ4MB_4U
#define _PAGE_SZBITS_4V _PAGE_SZ4MB_4V
#else
#error Wrong PAGE_SHIFT specified
#endif
#if defined(CONFIG_HUGETLB_PAGE_SIZE_4MB)
#define _PAGE_SZHUGE _PAGE_SZ4MB
#define _PAGE_SZHUGE_4U _PAGE_SZ4MB_4U
#define _PAGE_SZHUGE_4V _PAGE_SZ4MB_4V
#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K)
#define _PAGE_SZHUGE _PAGE_SZ512K
#define _PAGE_SZHUGE_4U _PAGE_SZ512K_4U
#define _PAGE_SZHUGE_4V _PAGE_SZ512K_4V
#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
#define _PAGE_SZHUGE _PAGE_SZ64K
#define _PAGE_SZHUGE_4U _PAGE_SZ64K_4U
#define _PAGE_SZHUGE_4V _PAGE_SZ64K_4V
#endif
#define _PAGE_CACHE (_PAGE_CP | _PAGE_CV)
/* These are actually filled in at boot time by sun4{u,v}_pgprot_init() */
#define __P000 __pgprot(0)
#define __P001 __pgprot(0)
#define __P010 __pgprot(0)
#define __P011 __pgprot(0)
#define __P100 __pgprot(0)
#define __P101 __pgprot(0)
#define __P110 __pgprot(0)
#define __P111 __pgprot(0)
#define __DIRTY_BITS (_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W)
#define __ACCESS_BITS (_PAGE_ACCESSED | _PAGE_READ | _PAGE_R)
#define __PRIV_BITS _PAGE_P
#define PAGE_NONE __pgprot (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE)
/* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */
#define PAGE_SHARED __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
__ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC)
#define PAGE_COPY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
__ACCESS_BITS | _PAGE_EXEC)
#define PAGE_READONLY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
__ACCESS_BITS | _PAGE_EXEC)
#define PAGE_KERNEL __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
__PRIV_BITS | \
__ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC)
#define PAGE_SHARED_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \
_PAGE_CACHE | \
__ACCESS_BITS | _PAGE_WRITE)
#define PAGE_COPY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \
_PAGE_CACHE | __ACCESS_BITS)
#define PAGE_READONLY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \
_PAGE_CACHE | __ACCESS_BITS)
#define _PFN_MASK _PAGE_PADDR
#define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | \
__ACCESS_BITS | _PAGE_E)
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY_NOEXEC
#define __P010 PAGE_COPY_NOEXEC
#define __P011 PAGE_COPY_NOEXEC
#define __P100 PAGE_READONLY
#define __P101 PAGE_READONLY
#define __P110 PAGE_COPY
#define __P111 PAGE_COPY
#define __S000 PAGE_NONE
#define __S001 PAGE_READONLY_NOEXEC
#define __S010 PAGE_SHARED_NOEXEC
#define __S011 PAGE_SHARED_NOEXEC
#define __S100 PAGE_READONLY
#define __S101 PAGE_READONLY
#define __S110 PAGE_SHARED
#define __S111 PAGE_SHARED
#define __S000 __pgprot(0)
#define __S001 __pgprot(0)
#define __S010 __pgprot(0)
#define __S011 __pgprot(0)
#define __S100 __pgprot(0)
#define __S101 __pgprot(0)
#define __S110 __pgprot(0)
#define __S111 __pgprot(0)
#ifndef __ASSEMBLY__
extern unsigned long phys_base;
extern unsigned long pfn_base;
extern pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long);
extern unsigned long pte_sz_bits(unsigned long size);
extern pgprot_t PAGE_KERNEL;
extern pgprot_t PAGE_KERNEL_LOCKED;
extern pgprot_t PAGE_COPY;
extern pgprot_t PAGE_SHARED;
/* XXX This uglyness is for the atyfb driver's sparc mmap() support. XXX */
extern unsigned long _PAGE_IE;
extern unsigned long _PAGE_E;
extern unsigned long _PAGE_CACHE;
extern unsigned long pg_iobits;
extern unsigned long _PAGE_ALL_SZ_BITS;
extern unsigned long _PAGE_SZBITS;
extern struct page *mem_map_zero;
#define ZERO_PAGE(vaddr) (mem_map_zero)
@@ -223,27 +225,403 @@ extern struct page *mem_map_zero;
* the first physical page in the machine is at some huge physical address,
* such as 4GB. This is common on a partitioned E10000, for example.
*/
static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
{
unsigned long paddr = pfn << PAGE_SHIFT;
unsigned long sz_bits;
#define pfn_pte(pfn, prot) \
__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot) | _PAGE_SZBITS)
sz_bits = 0UL;
if (_PAGE_SZBITS_4U != 0UL || _PAGE_SZBITS_4V != 0UL) {
__asm__ __volatile__(
"\n661: sethi %uhi(%1), %0\n"
" sllx %0, 32, %0\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" mov %2, %0\n"
" nop\n"
" .previous\n"
: "=r" (sz_bits)
: "i" (_PAGE_SZBITS_4U), "i" (_PAGE_SZBITS_4V));
}
return __pte(paddr | sz_bits | pgprot_val(prot));
}
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
#define pte_pfn(x) ((pte_val(x) & _PAGE_PADDR)>>PAGE_SHIFT)
#define pte_page(x) pfn_to_page(pte_pfn(x))
static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
/* This one can be done with two shifts. */
static inline unsigned long pte_pfn(pte_t pte)
{
pte_t __pte;
const unsigned long preserve_mask = (_PFN_MASK |
_PAGE_MODIFIED | _PAGE_ACCESSED |
_PAGE_CACHE | _PAGE_E |
_PAGE_PRESENT | _PAGE_SZBITS);
unsigned long ret;
pte_val(__pte) = (pte_val(orig_pte) & preserve_mask) |
(pgprot_val(new_prot) & ~preserve_mask);
__asm__ __volatile__(
"\n661: sllx %1, %2, %0\n"
" srlx %0, %3, %0\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sllx %1, %4, %0\n"
" srlx %0, %5, %0\n"
" .previous\n"
: "=r" (ret)
: "r" (pte_val(pte)),
"i" (21), "i" (21 + PAGE_SHIFT),
"i" (8), "i" (8 + PAGE_SHIFT));
return __pte;
return ret;
}
#define pte_page(x) pfn_to_page(pte_pfn(x))
static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
{
unsigned long mask, tmp;
/* SUN4U: 0x600307ffffffecb8 (negated == 0x9ffcf80000001347)
* SUN4V: 0x30ffffffffffee17 (negated == 0xcf000000000011e8)
*
* Even if we use negation tricks the result is still a 6
* instruction sequence, so don't try to play fancy and just
* do the most straightforward implementation.
*
* Note: We encode this into 3 sun4v 2-insn patch sequences.
*/
__asm__ __volatile__(
"\n661: sethi %%uhi(%2), %1\n"
" sethi %%hi(%2), %0\n"
"\n662: or %1, %%ulo(%2), %1\n"
" or %0, %%lo(%2), %0\n"
"\n663: sllx %1, 32, %1\n"
" or %0, %1, %0\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%3), %1\n"
" sethi %%hi(%3), %0\n"
" .word 662b\n"
" or %1, %%ulo(%3), %1\n"
" or %0, %%lo(%3), %0\n"
" .word 663b\n"
" sllx %1, 32, %1\n"
" or %0, %1, %0\n"
" .previous\n"
: "=r" (mask), "=r" (tmp)
: "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U |
_PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | _PAGE_PRESENT_4U |
_PAGE_SZBITS_4U),
"i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
_PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V |
_PAGE_SZBITS_4V));
return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask));
}
static inline pte_t pgoff_to_pte(unsigned long off)
{
off <<= PAGE_SHIFT;
__asm__ __volatile__(
"\n661: or %0, %2, %0\n"
" .section .sun4v_1insn_patch, \"ax\"\n"
" .word 661b\n"
" or %0, %3, %0\n"
" .previous\n"
: "=r" (off)
: "0" (off), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V));
return __pte(off);
}
static inline pgprot_t pgprot_noncached(pgprot_t prot)
{
unsigned long val = pgprot_val(prot);
__asm__ __volatile__(
"\n661: andn %0, %2, %0\n"
" or %0, %3, %0\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" andn %0, %4, %0\n"
" or %0, %3, %0\n"
" .previous\n"
: "=r" (val)
: "0" (val), "i" (_PAGE_CP_4U | _PAGE_CV_4U), "i" (_PAGE_E_4U),
"i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V));
return __pgprot(val);
}
/* Various pieces of code check for platform support by ifdef testing
* on "pgprot_noncached". That's broken and should be fixed, but for
* now...
*/
#define pgprot_noncached pgprot_noncached
#ifdef CONFIG_HUGETLB_PAGE
static inline pte_t pte_mkhuge(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: sethi %%uhi(%1), %0\n"
" sllx %0, 32, %0\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" mov %2, %0\n"
" nop\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V));
return __pte(pte_val(pte) | mask);
}
#endif
static inline pte_t pte_mkdirty(pte_t pte)
{
unsigned long val = pte_val(pte), tmp;
__asm__ __volatile__(
"\n661: or %0, %3, %0\n"
" nop\n"
"\n662: nop\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%4), %1\n"
" sllx %1, 32, %1\n"
" .word 662b\n"
" or %1, %%lo(%4), %1\n"
" or %0, %1, %0\n"
" .previous\n"
: "=r" (val), "=r" (tmp)
: "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U),
"i" (_PAGE_MODIFIED_4V | _PAGE_W_4V));
return __pte(val);
}
static inline pte_t pte_mkclean(pte_t pte)
{
unsigned long val = pte_val(pte), tmp;
__asm__ __volatile__(
"\n661: andn %0, %3, %0\n"
" nop\n"
"\n662: nop\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%4), %1\n"
" sllx %1, 32, %1\n"
" .word 662b\n"
" or %1, %%lo(%4), %1\n"
" andn %0, %1, %0\n"
" .previous\n"
: "=r" (val), "=r" (tmp)
: "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U),
"i" (_PAGE_MODIFIED_4V | _PAGE_W_4V));
return __pte(val);
}
static inline pte_t pte_mkwrite(pte_t pte)
{
unsigned long val = pte_val(pte), mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V));
return __pte(val | mask);
}
static inline pte_t pte_wrprotect(pte_t pte)
{
unsigned long val = pte_val(pte), tmp;
__asm__ __volatile__(
"\n661: andn %0, %3, %0\n"
" nop\n"
"\n662: nop\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%4), %1\n"
" sllx %1, 32, %1\n"
" .word 662b\n"
" or %1, %%lo(%4), %1\n"
" andn %0, %1, %0\n"
" .previous\n"
: "=r" (val), "=r" (tmp)
: "0" (val), "i" (_PAGE_WRITE_4U | _PAGE_W_4U),
"i" (_PAGE_WRITE_4V | _PAGE_W_4V));
return __pte(val);
}
static inline pte_t pte_mkold(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
mask |= _PAGE_R;
return __pte(pte_val(pte) & ~mask);
}
static inline pte_t pte_mkyoung(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
mask |= _PAGE_R;
return __pte(pte_val(pte) | mask);
}
static inline unsigned long pte_young(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V));
return (pte_val(pte) & mask);
}
static inline unsigned long pte_dirty(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V));
return (pte_val(pte) & mask);
}
static inline unsigned long pte_write(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V));
return (pte_val(pte) & mask);
}
static inline unsigned long pte_exec(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: sethi %%hi(%1), %0\n"
" .section .sun4v_1insn_patch, \"ax\"\n"
" .word 661b\n"
" mov %2, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_EXEC_4U), "i" (_PAGE_EXEC_4V));
return (pte_val(pte) & mask);
}
static inline unsigned long pte_read(pte_t pte)
{
unsigned long mask;
__asm__ __volatile__(
"\n661: mov %1, %0\n"
" nop\n"
" .section .sun4v_2insn_patch, \"ax\"\n"
" .word 661b\n"
" sethi %%uhi(%2), %0\n"
" sllx %0, 32, %0\n"
" .previous\n"
: "=r" (mask)
: "i" (_PAGE_READ_4U), "i" (_PAGE_READ_4V));
return (pte_val(pte) & mask);
}
static inline unsigned long pte_file(pte_t pte)
{
unsigned long val = pte_val(pte);
__asm__ __volatile__(
"\n661: and %0, %2, %0\n"
" .section .sun4v_1insn_patch, \"ax\"\n"
" .word 661b\n"
" and %0, %3, %0\n"
" .previous\n"
: "=r" (val)
: "0" (val), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V));
return val;
}
static inline unsigned long pte_present(pte_t pte)
{
unsigned long val = pte_val(pte);
__asm__ __volatile__(
"\n661: and %0, %2, %0\n"
" .section .sun4v_1insn_patch, \"ax\"\n"
" .word 661b\n"
" and %0, %3, %0\n"
" .previous\n"
: "=r" (val)
: "0" (val), "i" (_PAGE_PRESENT_4U), "i" (_PAGE_PRESENT_4V));
return val;
}
#define pmd_set(pmdp, ptep) \
(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
#define pud_set(pudp, pmdp) \
@@ -253,8 +631,6 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
#define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd))
#define pud_page(pud) \
((unsigned long) __va((((unsigned long)pud_val(pud))<<11UL)))
#define pte_none(pte) (!pte_val(pte))
#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (0)
#define pmd_present(pmd) (pmd_val(pmd) != 0U)
@@ -264,30 +640,8 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
#define pud_present(pud) (pud_val(pud) != 0U)
#define pud_clear(pudp) (pud_val(*(pudp)) = 0U)
/* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
#define pte_read(pte) (pte_val(pte) & _PAGE_READ)
#define pte_exec(pte) (pte_val(pte) & _PAGE_EXEC)
#define pte_write(pte) (pte_val(pte) & _PAGE_WRITE)
#define pte_dirty(pte) (pte_val(pte) & _PAGE_MODIFIED)
#define pte_young(pte) (pte_val(pte) & _PAGE_ACCESSED)
#define pte_wrprotect(pte) (__pte(pte_val(pte) & ~(_PAGE_WRITE|_PAGE_W)))
#define pte_rdprotect(pte) \
(__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_READ))
#define pte_mkclean(pte) \
(__pte(pte_val(pte) & ~(_PAGE_MODIFIED|_PAGE_W)))
#define pte_mkold(pte) \
(__pte(((pte_val(pte)<<1UL)>>1UL) & ~_PAGE_ACCESSED))
/* Permanent address of a page. */
#define __page_address(page) page_address(page)
/* Be very careful when you change these three, they are delicate. */
#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_WRITE))
#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_MODIFIED | _PAGE_W))
#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_SZHUGE))
/* Same in both SUN4V and SUN4U. */
#define pte_none(pte) (!pte_val(pte))
/* to find an entry in a page-table-directory. */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
@@ -296,11 +650,6 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* extract the pgd cache used for optimizing the tlb miss
* slow path when executing 32-bit compat processes
*/
#define get_pgd_cache(pgd) ((unsigned long) pgd_val(*pgd) << 11)
/* Find an entry in the second-level page table.. */
#define pmd_offset(pudp, address) \
((pmd_t *) pud_page(*(pudp)) + \
@@ -327,6 +676,9 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
/* It is more efficient to let flush_tlb_kernel_range()
* handle init_mm tlb flushes.
*
* SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
* and SUN4V pte layout, so this inline test is fine.
*/
if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
tlb_batch_add(mm, addr, ptep, orig);
@@ -361,42 +713,23 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
/* File offset in PTE support. */
#define pte_file(pte) (pte_val(pte) & _PAGE_FILE)
extern unsigned long pte_file(pte_t);
#define pte_to_pgoff(pte) (pte_val(pte) >> PAGE_SHIFT)
#define pgoff_to_pte(off) (__pte(((off) << PAGE_SHIFT) | _PAGE_FILE))
extern pte_t pgoff_to_pte(unsigned long);
#define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL)
extern unsigned long prom_virt_to_phys(unsigned long, int *);
static __inline__ unsigned long
sun4u_get_pte (unsigned long addr)
{
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
pte_t *ptep;
extern unsigned long sun4u_get_pte(unsigned long);
if (addr >= PAGE_OFFSET)
return addr & _PAGE_PADDR;
if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS))
return prom_virt_to_phys(addr, NULL);
pgdp = pgd_offset_k(addr);
pudp = pud_offset(pgdp, addr);
pmdp = pmd_offset(pudp, addr);
ptep = pte_offset_kernel(pmdp, addr);
return pte_val(*ptep) & _PAGE_PADDR;
static inline unsigned long __get_phys(unsigned long addr)
{
return sun4u_get_pte(addr);
}
static __inline__ unsigned long
__get_phys (unsigned long addr)
static inline int __get_iospace(unsigned long addr)
{
return sun4u_get_pte (addr);
}
static __inline__ int
__get_iospace (unsigned long addr)
{
return ((sun4u_get_pte (addr) & 0xf0000000) >> 28);
return ((sun4u_get_pte(addr) & 0xf0000000) >> 28);
}
extern unsigned long *sparc64_valid_addr_bitmap;
@@ -409,11 +742,6 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn,
unsigned long size, pgprot_t prot);
/* Clear virtual and physical cachability, set side-effect bit. */
#define pgprot_noncached(prot) \
(__pgprot((pgprot_val(prot) & ~(_PAGE_CP | _PAGE_CV)) | \
_PAGE_E))
/*
* For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
* its high 4 bits. These macros/functions put it there or get it from there.
@@ -424,8 +752,11 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
#include <asm-generic/pgtable.h>
/* We provide our own get_unmapped_area to cope with VA holes for userland */
/* We provide our own get_unmapped_area to cope with VA holes and
* SHM area cache aliasing for userland.
*/
#define HAVE_ARCH_UNMAPPED_AREA
#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
/* We provide a special get_unmapped_area for framebuffer mmaps to try and use
* the largest alignment possible such that larget PTEs can be used.
@@ -435,12 +766,9 @@ extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long,
unsigned long);
#define HAVE_ARCH_FB_UNMAPPED_AREA
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
extern void check_pgt_cache(void);
extern void pgtable_cache_init(void);
extern void sun4v_register_fault_status(void);
extern void sun4v_ktsb_register(void);
#endif /* !(__ASSEMBLY__) */
+3 -1
View File
@@ -16,11 +16,13 @@
#define PIL_SMP_CALL_FUNC 1
#define PIL_SMP_RECEIVE_SIGNAL 2
#define PIL_SMP_CAPTURE 3
#define PIL_SMP_CTX_NEW_VERSION 4
#ifndef __ASSEMBLY__
#define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \
(PIL) == PIL_SMP_RECEIVE_SIGNAL || \
(PIL) == PIL_SMP_CAPTURE)
(PIL) == PIL_SMP_CAPTURE || \
(PIL) == PIL_SMP_CTX_NEW_VERSION)
#endif
#endif /* !(_SPARC64_PIL_H) */
+8 -15
View File
@@ -28,6 +28,8 @@
* User lives in his very own context, and cannot reference us. Note
* that TASK_SIZE is a misnomer, it really gives maximum user virtual
* address that the kernel will allocate out.
*
* XXX No longer using virtual page tables, kill this upper limit...
*/
#define VA_BITS 44
#ifndef __ASSEMBLY__
@@ -37,18 +39,6 @@
#endif
#define TASK_SIZE ((unsigned long)-VPTE_SIZE)
/*
* The vpte base must be able to hold the entire vpte, half
* of which lives above, and half below, the base. And it
* is placed as close to the highest address range as possible.
*/
#define VPTE_BASE_SPITFIRE (-(VPTE_SIZE/2))
#if 1
#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
#else
#define VPTE_BASE_CHEETAH 0xffe0000000000000
#endif
#ifndef __ASSEMBLY__
typedef struct {
@@ -101,7 +91,8 @@ extern unsigned long thread_saved_pc(struct task_struct *);
/* Do necessary setup to start up a newly executed thread. */
#define start_thread(regs, pc, sp) \
do { \
regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (ASI_PNF << 24); \
unsigned long __asi = ASI_PNF; \
regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_INITIAL_MM|TSTATE_IE) | (__asi << 24UL); \
regs->tpc = ((pc & (~3)) - 4); \
regs->tnpc = regs->tpc + 4; \
regs->y = 0; \
@@ -138,10 +129,10 @@ do { \
#define start_thread32(regs, pc, sp) \
do { \
unsigned long __asi = ASI_PNF; \
pc &= 0x00000000ffffffffUL; \
sp &= 0x00000000ffffffffUL; \
\
regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM); \
regs->tstate = (regs->tstate & (TSTATE_CWP))|(TSTATE_INITIAL_MM|TSTATE_IE|TSTATE_AM) | (__asi << 24UL); \
regs->tpc = ((pc & (~3)) - 4); \
regs->tnpc = regs->tpc + 4; \
regs->y = 0; \
@@ -226,6 +217,8 @@ static inline void prefetchw(const void *x)
#define spin_lock_prefetch(x) prefetchw(x)
#define HAVE_ARCH_PICK_MMAP_LAYOUT
#endif /* !(__ASSEMBLY__) */
#endif /* !(__ASM_SPARC64_PROCESSOR_H) */
+5 -4
View File
@@ -28,11 +28,12 @@
/* The V9 TSTATE Register (with SpitFire and Linux extensions).
*
* ---------------------------------------------------------------
* | Resv | CCR | ASI | %pil | PSTATE | Resv | CWP |
* ---------------------------------------------------------------
* 63 40 39 32 31 24 23 20 19 8 7 5 4 0
* ---------------------------------------------------------------------
* | Resv | GL | CCR | ASI | %pil | PSTATE | Resv | CWP |
* ---------------------------------------------------------------------
* 63 43 42 40 39 32 31 24 23 20 19 8 7 5 4 0
*/
#define TSTATE_GL _AC(0x0000070000000000,UL) /* Global reg level */
#define TSTATE_CCR _AC(0x000000ff00000000,UL) /* Condition Codes. */
#define TSTATE_XCC _AC(0x000000f000000000,UL) /* Condition Codes. */
#define TSTATE_XNEG _AC(0x0000008000000000,UL) /* %xcc Negative. */
+14
View File
@@ -0,0 +1,14 @@
#ifndef _SPARC64_SCRATCHPAD_H
#define _SPARC64_SCRATCHPAD_H
/* Sun4v scratchpad registers, accessed via ASI_SCRATCHPAD. */
#define SCRATCHPAD_MMU_MISS 0x00 /* Shared with OBP - set by OBP */
#define SCRATCHPAD_CPUID 0x08 /* Shared with OBP - set by hypervisor */
#define SCRATCHPAD_UTSBREG1 0x10
#define SCRATCHPAD_UTSBREG2 0x18
/* 0x20 and 0x28, hypervisor only... */
#define SCRATCHPAD_UNUSED1 0x30
#define SCRATCHPAD_UNUSED2 0x38 /* Reserved for OBP */
#endif /* !(_SPARC64_SCRATCHPAD_H) */
+3 -27
View File
@@ -33,37 +33,13 @@
extern cpumask_t phys_cpu_present_map;
#define cpu_possible_map phys_cpu_present_map
extern cpumask_t cpu_sibling_map[NR_CPUS];
/*
* General functions that each host system must provide.
*/
static __inline__ int hard_smp_processor_id(void)
{
if (tlb_type == cheetah || tlb_type == cheetah_plus) {
unsigned long cfg, ver;
__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
if ((ver >> 32) == 0x003e0016) {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (cfg)
: "i" (ASI_JBUS_CONFIG));
return ((cfg >> 17) & 0x1f);
} else {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (cfg)
: "i" (ASI_SAFARI_CONFIG));
return ((cfg >> 17) & 0x3ff);
}
} else if (this_is_starfire != 0) {
return starfire_hard_smp_processor_id();
} else {
unsigned long upaconfig;
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (upaconfig)
: "i" (ASI_UPA_CONFIG));
return ((upaconfig >> 17) & 0x1f);
}
}
extern int hard_smp_processor_id(void);
#define raw_smp_processor_id() (current_thread_info()->cpu)
extern void smp_setup_cpu_possible_map(void);
+12
View File
@@ -0,0 +1,12 @@
#ifndef _SPARC64_SPARSEMEM_H
#define _SPARC64_SPARSEMEM_H
#ifdef __KERNEL__
#define SECTION_SIZE_BITS 26
#define MAX_PHYSADDR_BITS 42
#define MAX_PHYSMEM_BITS 42
#endif /* !(__KERNEL__) */
#endif /* !(_SPARC64_SPARSEMEM_H) */
+1
View File
@@ -44,6 +44,7 @@ enum ultra_tlb_layout {
spitfire = 0,
cheetah = 1,
cheetah_plus = 2,
hypervisor = 3,
};
extern enum ultra_tlb_layout tlb_type;
+2 -5
View File
@@ -209,9 +209,10 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
/* so that ASI is only written if it changes, think again. */ \
__asm__ __volatile__("wr %%g0, %0, %%asi" \
: : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\
trap_block[current_thread_info()->cpu].thread = \
task_thread_info(next); \
__asm__ __volatile__( \
"mov %%g4, %%g7\n\t" \
"wrpr %%g0, 0x95, %%pstate\n\t" \
"stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
"stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
"rdpr %%wstate, %%o5\n\t" \
@@ -225,14 +226,10 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
"ldx [%%g6 + %3], %%o6\n\t" \
"ldub [%%g6 + %2], %%o5\n\t" \
"ldub [%%g6 + %4], %%o7\n\t" \
"mov %%g6, %%l2\n\t" \
"wrpr %%o5, 0x0, %%wstate\n\t" \
"ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
"ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
"wrpr %%g0, 0x94, %%pstate\n\t" \
"mov %%l2, %%g6\n\t" \
"ldx [%%g6 + %6], %%g4\n\t" \
"wrpr %%g0, 0x96, %%pstate\n\t" \
"brz,pt %%o7, 1f\n\t" \
" mov %%g7, %0\n\t" \
"b,a ret_from_syscall\n\t" \
+3 -6
View File
@@ -64,8 +64,6 @@ struct thread_info {
__u64 kernel_cntd0, kernel_cntd1;
__u64 pcr_reg;
__u64 cee_stuff;
struct restart_block restart_block;
struct pt_regs *kern_una_regs;
@@ -104,10 +102,9 @@ struct thread_info {
#define TI_KERN_CNTD0 0x00000480
#define TI_KERN_CNTD1 0x00000488
#define TI_PCR 0x00000490
#define TI_CEE_STUFF 0x00000498
#define TI_RESTART_BLOCK 0x000004a0
#define TI_KUNA_REGS 0x000004c8
#define TI_KUNA_INSN 0x000004d0
#define TI_RESTART_BLOCK 0x00000498
#define TI_KUNA_REGS 0x000004c0
#define TI_KUNA_INSN 0x000004c8
#define TI_FPREGS 0x00000500
/* We embed this in the uppermost byte of thread_info->flags */
+6
View File
@@ -14,4 +14,10 @@
typedef unsigned long cycles_t;
#define get_cycles() tick_ops->get_tick()
#define ARCH_HAS_READ_CURRENT_TIMER 1
#define read_current_timer(timer_val_p) \
({ *timer_val_p = tick_ops->get_tick(); \
0; \
})
#endif
+19 -6
View File
@@ -5,6 +5,11 @@
#include <linux/mm.h>
#include <asm/mmu_context.h>
/* TSB flush operations. */
struct mmu_gather;
extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
extern void flush_tsb_user(struct mmu_gather *mp);
/* TLB flush operations. */
extern void flush_tlb_pending(void);
@@ -14,28 +19,36 @@ extern void flush_tlb_pending(void);
#define flush_tlb_page(vma,addr) flush_tlb_pending()
#define flush_tlb_mm(mm) flush_tlb_pending()
/* Local cpu only. */
extern void __flush_tlb_all(void);
extern void __flush_tlb_page(unsigned long context, unsigned long page, unsigned long r);
extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
#ifndef CONFIG_SMP
#define flush_tlb_all() __flush_tlb_all()
#define flush_tlb_kernel_range(start,end) \
__flush_tlb_kernel_range(start,end)
do { flush_tsb_kernel_range(start,end); \
__flush_tlb_kernel_range(start,end); \
} while (0)
#else /* CONFIG_SMP */
extern void smp_flush_tlb_all(void);
extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
#define flush_tlb_all() smp_flush_tlb_all()
#define flush_tlb_kernel_range(start, end) \
smp_flush_tlb_kernel_range(start, end)
do { flush_tsb_kernel_range(start,end); \
smp_flush_tlb_kernel_range(start, end); \
} while (0)
#endif /* ! CONFIG_SMP */
extern void flush_tlb_pgtables(struct mm_struct *, unsigned long, unsigned long);
static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
{
/* We don't use virtual page tables for TLB miss processing
* any more. Nowadays we use the TSB.
*/
}
#endif /* _SPARC64_TLBFLUSH_H */
+281
View File
@@ -0,0 +1,281 @@
#ifndef _SPARC64_TSB_H
#define _SPARC64_TSB_H
/* The sparc64 TSB is similar to the powerpc hashtables. It's a
* power-of-2 sized table of TAG/PTE pairs. The cpu precomputes
* pointers into this table for 8K and 64K page sizes, and also a
* comparison TAG based upon the virtual address and context which
* faults.
*
* TLB miss trap handler software does the actual lookup via something
* of the form:
*
* ldxa [%g0] ASI_{D,I}MMU_TSB_8KB_PTR, %g1
* ldxa [%g0] ASI_{D,I}MMU, %g6
* sllx %g6, 22, %g6
* srlx %g6, 22, %g6
* ldda [%g1] ASI_NUCLEUS_QUAD_LDD, %g4
* cmp %g4, %g6
* bne,pn %xcc, tsb_miss_{d,i}tlb
* mov FAULT_CODE_{D,I}TLB, %g3
* stxa %g5, [%g0] ASI_{D,I}TLB_DATA_IN
* retry
*
*
* Each 16-byte slot of the TSB is the 8-byte tag and then the 8-byte
* PTE. The TAG is of the same layout as the TLB TAG TARGET mmu
* register which is:
*
* -------------------------------------------------
* | - | CONTEXT | - | VADDR bits 63:22 |
* -------------------------------------------------
* 63 61 60 48 47 42 41 0
*
* But actually, since we use per-mm TSB's, we zero out the CONTEXT
* field.
*
* Like the powerpc hashtables we need to use locking in order to
* synchronize while we update the entries. PTE updates need locking
* as well.
*
* We need to carefully choose a lock bits for the TSB entry. We
* choose to use bit 47 in the tag. Also, since we never map anything
* at page zero in context zero, we use zero as an invalid tag entry.
* When the lock bit is set, this forces a tag comparison failure.
*/
#define TSB_TAG_LOCK_BIT 47
#define TSB_TAG_LOCK_HIGH (1 << (TSB_TAG_LOCK_BIT - 32))
#define TSB_TAG_INVALID_BIT 46
#define TSB_TAG_INVALID_HIGH (1 << (TSB_TAG_INVALID_BIT - 32))
#define TSB_MEMBAR membar #StoreStore
/* Some cpus support physical address quad loads. We want to use
* those if possible so we don't need to hard-lock the TSB mapping
* into the TLB. We encode some instruction patching in order to
* support this.
*
* The kernel TSB is locked into the TLB by virtue of being in the
* kernel image, so we don't play these games for swapper_tsb access.
*/
#ifndef __ASSEMBLY__
struct tsb_ldquad_phys_patch_entry {
unsigned int addr;
unsigned int sun4u_insn;
unsigned int sun4v_insn;
};
extern struct tsb_ldquad_phys_patch_entry __tsb_ldquad_phys_patch,
__tsb_ldquad_phys_patch_end;
struct tsb_phys_patch_entry {
unsigned int addr;
unsigned int insn;
};
extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
#endif
#define TSB_LOAD_QUAD(TSB, REG) \
661: ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG; \
.section .tsb_ldquad_phys_patch, "ax"; \
.word 661b; \
ldda [TSB] ASI_QUAD_LDD_PHYS, REG; \
ldda [TSB] ASI_QUAD_LDD_PHYS_4V, REG; \
.previous
#define TSB_LOAD_TAG_HIGH(TSB, REG) \
661: lduwa [TSB] ASI_N, REG; \
.section .tsb_phys_patch, "ax"; \
.word 661b; \
lduwa [TSB] ASI_PHYS_USE_EC, REG; \
.previous
#define TSB_LOAD_TAG(TSB, REG) \
661: ldxa [TSB] ASI_N, REG; \
.section .tsb_phys_patch, "ax"; \
.word 661b; \
ldxa [TSB] ASI_PHYS_USE_EC, REG; \
.previous
#define TSB_CAS_TAG_HIGH(TSB, REG1, REG2) \
661: casa [TSB] ASI_N, REG1, REG2; \
.section .tsb_phys_patch, "ax"; \
.word 661b; \
casa [TSB] ASI_PHYS_USE_EC, REG1, REG2; \
.previous
#define TSB_CAS_TAG(TSB, REG1, REG2) \
661: casxa [TSB] ASI_N, REG1, REG2; \
.section .tsb_phys_patch, "ax"; \
.word 661b; \
casxa [TSB] ASI_PHYS_USE_EC, REG1, REG2; \
.previous
#define TSB_STORE(ADDR, VAL) \
661: stxa VAL, [ADDR] ASI_N; \
.section .tsb_phys_patch, "ax"; \
.word 661b; \
stxa VAL, [ADDR] ASI_PHYS_USE_EC; \
.previous
#define TSB_LOCK_TAG(TSB, REG1, REG2) \
99: TSB_LOAD_TAG_HIGH(TSB, REG1); \
sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\
andcc REG1, REG2, %g0; \
bne,pn %icc, 99b; \
nop; \
TSB_CAS_TAG_HIGH(TSB, REG1, REG2); \
cmp REG1, REG2; \
bne,pn %icc, 99b; \
nop; \
TSB_MEMBAR
#define TSB_WRITE(TSB, TTE, TAG) \
add TSB, 0x8, TSB; \
TSB_STORE(TSB, TTE); \
sub TSB, 0x8, TSB; \
TSB_MEMBAR; \
TSB_STORE(TSB, TAG);
#define KTSB_LOAD_QUAD(TSB, REG) \
ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG;
#define KTSB_STORE(ADDR, VAL) \
stxa VAL, [ADDR] ASI_N;
#define KTSB_LOCK_TAG(TSB, REG1, REG2) \
99: lduwa [TSB] ASI_N, REG1; \
sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\
andcc REG1, REG2, %g0; \
bne,pn %icc, 99b; \
nop; \
casa [TSB] ASI_N, REG1, REG2;\
cmp REG1, REG2; \
bne,pn %icc, 99b; \
nop; \
TSB_MEMBAR
#define KTSB_WRITE(TSB, TTE, TAG) \
add TSB, 0x8, TSB; \
stxa TTE, [TSB] ASI_N; \
sub TSB, 0x8, TSB; \
TSB_MEMBAR; \
stxa TAG, [TSB] ASI_N;
/* Do a kernel page table walk. Leaves physical PTE pointer in
* REG1. Jumps to FAIL_LABEL on early page table walk termination.
* VADDR will not be clobbered, but REG2 will.
*/
#define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \
sethi %hi(swapper_pg_dir), REG1; \
or REG1, %lo(swapper_pg_dir), REG1; \
sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x3, REG2; \
lduw [REG1 + REG2], REG1; \
brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
sllx REG1, 11, REG1; \
andn REG2, 0x3, REG2; \
lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - PMD_SHIFT, REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
sllx REG1, 11, REG1; \
andn REG2, 0x7, REG2; \
add REG1, REG2, REG1;
/* Do a user page table walk in MMU globals. Leaves physical PTE
* pointer in REG1. Jumps to FAIL_LABEL on early page table walk
* termination. Physical base of page tables is in PHYS_PGD which
* will not be modified.
*
* VADDR will not be clobbered, but REG1 and REG2 will.
*/
#define USER_PGTABLE_WALK_TL1(VADDR, PHYS_PGD, REG1, REG2, FAIL_LABEL) \
sllx VADDR, 64 - (PGDIR_SHIFT + PGDIR_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x3, REG2; \
lduwa [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
sllx REG1, 11, REG1; \
andn REG2, 0x3, REG2; \
lduwa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - PMD_SHIFT, REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
sllx REG1, 11, REG1; \
andn REG2, 0x7, REG2; \
add REG1, REG2, REG1;
/* Lookup a OBP mapping on VADDR in the prom_trans[] table at TL>0.
* If no entry is found, FAIL_LABEL will be branched to. On success
* the resulting PTE value will be left in REG1. VADDR is preserved
* by this routine.
*/
#define OBP_TRANS_LOOKUP(VADDR, REG1, REG2, REG3, FAIL_LABEL) \
sethi %hi(prom_trans), REG1; \
or REG1, %lo(prom_trans), REG1; \
97: ldx [REG1 + 0x00], REG2; \
brz,pn REG2, FAIL_LABEL; \
nop; \
ldx [REG1 + 0x08], REG3; \
add REG2, REG3, REG3; \
cmp REG2, VADDR; \
bgu,pt %xcc, 98f; \
cmp VADDR, REG3; \
bgeu,pt %xcc, 98f; \
ldx [REG1 + 0x10], REG3; \
sub VADDR, REG2, REG2; \
ba,pt %xcc, 99f; \
add REG3, REG2, REG1; \
98: ba,pt %xcc, 97b; \
add REG1, (3 * 8), REG1; \
99:
/* We use a 32K TSB for the whole kernel, this allows to
* handle about 16MB of modules and vmalloc mappings without
* incurring many hash conflicts.
*/
#define KERNEL_TSB_SIZE_BYTES (32 * 1024)
#define KERNEL_TSB_NENTRIES \
(KERNEL_TSB_SIZE_BYTES / 16)
#define KERNEL_TSB4M_NENTRIES 4096
/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
* on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries
* and the found TTE will be left in REG1. REG3 and REG4 must
* be an even/odd pair of registers.
*
* VADDR and TAG will be preserved and not clobbered by this macro.
*/
#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
sethi %hi(swapper_tsb), REG1; \
or REG1, %lo(swapper_tsb), REG1; \
srlx VADDR, PAGE_SHIFT, REG2; \
and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \
add REG1, REG2, REG2; \
KTSB_LOAD_QUAD(REG2, REG3); \
cmp REG3, TAG; \
be,a,pt %xcc, OK_LABEL; \
mov REG4, REG1;
/* This version uses a trick, the TAG is already (VADDR >> 22) so
* we can make use of that for the index computation.
*/
#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
sethi %hi(swapper_4m_tsb), REG1; \
or REG1, %lo(swapper_4m_tsb), REG1; \
and TAG, (KERNEL_TSB_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \
add REG1, REG2, REG2; \
KTSB_LOAD_QUAD(REG2, REG3); \
cmp REG3, TAG; \
be,a,pt %xcc, OK_LABEL; \
mov REG4, REG1;
#endif /* !(_SPARC64_TSB_H) */
+261 -11
View File
@@ -93,7 +93,7 @@
#define SYSCALL_TRAP(routine, systbl) \
sethi %hi(109f), %g7; \
ba,pt %xcc, scetrap; \
ba,pt %xcc, etrap; \
109: or %g7, %lo(109b), %g7; \
sethi %hi(systbl), %l7; \
ba,pt %xcc, routine; \
@@ -109,14 +109,14 @@
nop;nop;nop;
#define TRAP_UTRAP(handler,lvl) \
ldx [%g6 + TI_UTRAPS], %g1; \
sethi %hi(109f), %g7; \
brz,pn %g1, utrap; \
or %g7, %lo(109f), %g7; \
ba,pt %xcc, utrap; \
109: ldx [%g1 + handler*8], %g1; \
ba,pt %xcc, utrap_ill; \
mov lvl, %o1;
mov handler, %g3; \
ba,pt %xcc, utrap_trap; \
mov lvl, %g4; \
nop; \
nop; \
nop; \
nop; \
nop;
#ifdef CONFIG_SUNOS_EMUL
#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall32, sunos_sys_table)
@@ -136,8 +136,6 @@
#else
#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
#endif
/* FIXME: Write these actually */
#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
#define TRAP_IRQ(routine, level) \
@@ -182,6 +180,26 @@
#define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
#endif
#define SUN4V_ITSB_MISS \
ldxa [%g0] ASI_SCRATCHPAD, %g2; \
ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4; \
ldx [%g2 + HV_FAULT_I_CTX_OFFSET], %g5; \
srlx %g4, 22, %g6; \
ba,pt %xcc, sun4v_itsb_miss; \
nop; \
nop; \
nop;
#define SUN4V_DTSB_MISS \
ldxa [%g0] ASI_SCRATCHPAD, %g2; \
ldx [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4; \
ldx [%g2 + HV_FAULT_D_CTX_OFFSET], %g5; \
srlx %g4, 22, %g6; \
ba,pt %xcc, sun4v_dtsb_miss; \
nop; \
nop; \
nop;
/* Before touching these macros, you owe it to yourself to go and
* see how arch/sparc64/kernel/winfixup.S works... -DaveM
*
@@ -221,6 +239,31 @@
saved; retry; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop;
#define SPILL_0_NORMAL_ETRAP \
etrap_kernel_spill: \
stx %l0, [%sp + STACK_BIAS + 0x00]; \
stx %l1, [%sp + STACK_BIAS + 0x08]; \
stx %l2, [%sp + STACK_BIAS + 0x10]; \
stx %l3, [%sp + STACK_BIAS + 0x18]; \
stx %l4, [%sp + STACK_BIAS + 0x20]; \
stx %l5, [%sp + STACK_BIAS + 0x28]; \
stx %l6, [%sp + STACK_BIAS + 0x30]; \
stx %l7, [%sp + STACK_BIAS + 0x38]; \
stx %i0, [%sp + STACK_BIAS + 0x40]; \
stx %i1, [%sp + STACK_BIAS + 0x48]; \
stx %i2, [%sp + STACK_BIAS + 0x50]; \
stx %i3, [%sp + STACK_BIAS + 0x58]; \
stx %i4, [%sp + STACK_BIAS + 0x60]; \
stx %i5, [%sp + STACK_BIAS + 0x68]; \
stx %i6, [%sp + STACK_BIAS + 0x70]; \
stx %i7, [%sp + STACK_BIAS + 0x78]; \
saved; \
sub %g1, 2, %g1; \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop;
/* Normal 64bit spill */
#define SPILL_1_GENERIC(ASI) \
add %sp, STACK_BIAS + 0x00, %g1; \
@@ -254,6 +297,67 @@
b,a,pt %xcc, spill_fixup_mna; \
b,a,pt %xcc, spill_fixup;
#define SPILL_1_GENERIC_ETRAP \
etrap_user_spill_64bit: \
stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \
stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \
stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \
stxa %l3, [%sp + STACK_BIAS + 0x18] %asi; \
stxa %l4, [%sp + STACK_BIAS + 0x20] %asi; \
stxa %l5, [%sp + STACK_BIAS + 0x28] %asi; \
stxa %l6, [%sp + STACK_BIAS + 0x30] %asi; \
stxa %l7, [%sp + STACK_BIAS + 0x38] %asi; \
stxa %i0, [%sp + STACK_BIAS + 0x40] %asi; \
stxa %i1, [%sp + STACK_BIAS + 0x48] %asi; \
stxa %i2, [%sp + STACK_BIAS + 0x50] %asi; \
stxa %i3, [%sp + STACK_BIAS + 0x58] %asi; \
stxa %i4, [%sp + STACK_BIAS + 0x60] %asi; \
stxa %i5, [%sp + STACK_BIAS + 0x68] %asi; \
stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \
stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \
saved; \
sub %g1, 2, %g1; \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop; nop; nop; \
nop; nop; nop; nop; \
ba,a,pt %xcc, etrap_spill_fixup_64bit; \
ba,a,pt %xcc, etrap_spill_fixup_64bit; \
ba,a,pt %xcc, etrap_spill_fixup_64bit;
#define SPILL_1_GENERIC_ETRAP_FIXUP \
etrap_spill_fixup_64bit: \
ldub [%g6 + TI_WSAVED], %g1; \
sll %g1, 3, %g3; \
add %g6, %g3, %g3; \
stx %sp, [%g3 + TI_RWIN_SPTRS]; \
sll %g1, 7, %g3; \
add %g6, %g3, %g3; \
stx %l0, [%g3 + TI_REG_WINDOW + 0x00]; \
stx %l1, [%g3 + TI_REG_WINDOW + 0x08]; \
stx %l2, [%g3 + TI_REG_WINDOW + 0x10]; \
stx %l3, [%g3 + TI_REG_WINDOW + 0x18]; \
stx %l4, [%g3 + TI_REG_WINDOW + 0x20]; \
stx %l5, [%g3 + TI_REG_WINDOW + 0x28]; \
stx %l6, [%g3 + TI_REG_WINDOW + 0x30]; \
stx %l7, [%g3 + TI_REG_WINDOW + 0x38]; \
stx %i0, [%g3 + TI_REG_WINDOW + 0x40]; \
stx %i1, [%g3 + TI_REG_WINDOW + 0x48]; \
stx %i2, [%g3 + TI_REG_WINDOW + 0x50]; \
stx %i3, [%g3 + TI_REG_WINDOW + 0x58]; \
stx %i4, [%g3 + TI_REG_WINDOW + 0x60]; \
stx %i5, [%g3 + TI_REG_WINDOW + 0x68]; \
stx %i6, [%g3 + TI_REG_WINDOW + 0x70]; \
stx %i7, [%g3 + TI_REG_WINDOW + 0x78]; \
add %g1, 1, %g1; \
stb %g1, [%g6 + TI_WSAVED]; \
saved; \
rdpr %cwp, %g1; \
sub %g1, 2, %g1; \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop
/* Normal 32bit spill */
#define SPILL_2_GENERIC(ASI) \
srl %sp, 0, %sp; \
@@ -287,6 +391,68 @@
b,a,pt %xcc, spill_fixup_mna; \
b,a,pt %xcc, spill_fixup;
#define SPILL_2_GENERIC_ETRAP \
etrap_user_spill_32bit: \
srl %sp, 0, %sp; \
stwa %l0, [%sp + 0x00] %asi; \
stwa %l1, [%sp + 0x04] %asi; \
stwa %l2, [%sp + 0x08] %asi; \
stwa %l3, [%sp + 0x0c] %asi; \
stwa %l4, [%sp + 0x10] %asi; \
stwa %l5, [%sp + 0x14] %asi; \
stwa %l6, [%sp + 0x18] %asi; \
stwa %l7, [%sp + 0x1c] %asi; \
stwa %i0, [%sp + 0x20] %asi; \
stwa %i1, [%sp + 0x24] %asi; \
stwa %i2, [%sp + 0x28] %asi; \
stwa %i3, [%sp + 0x2c] %asi; \
stwa %i4, [%sp + 0x30] %asi; \
stwa %i5, [%sp + 0x34] %asi; \
stwa %i6, [%sp + 0x38] %asi; \
stwa %i7, [%sp + 0x3c] %asi; \
saved; \
sub %g1, 2, %g1; \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop; nop; \
nop; nop; nop; nop; \
ba,a,pt %xcc, etrap_spill_fixup_32bit; \
ba,a,pt %xcc, etrap_spill_fixup_32bit; \
ba,a,pt %xcc, etrap_spill_fixup_32bit;
#define SPILL_2_GENERIC_ETRAP_FIXUP \
etrap_spill_fixup_32bit: \
ldub [%g6 + TI_WSAVED], %g1; \
sll %g1, 3, %g3; \
add %g6, %g3, %g3; \
stx %sp, [%g3 + TI_RWIN_SPTRS]; \
sll %g1, 7, %g3; \
add %g6, %g3, %g3; \
stw %l0, [%g3 + TI_REG_WINDOW + 0x00]; \
stw %l1, [%g3 + TI_REG_WINDOW + 0x04]; \
stw %l2, [%g3 + TI_REG_WINDOW + 0x08]; \
stw %l3, [%g3 + TI_REG_WINDOW + 0x0c]; \
stw %l4, [%g3 + TI_REG_WINDOW + 0x10]; \
stw %l5, [%g3 + TI_REG_WINDOW + 0x14]; \
stw %l6, [%g3 + TI_REG_WINDOW + 0x18]; \
stw %l7, [%g3 + TI_REG_WINDOW + 0x1c]; \
stw %i0, [%g3 + TI_REG_WINDOW + 0x20]; \
stw %i1, [%g3 + TI_REG_WINDOW + 0x24]; \
stw %i2, [%g3 + TI_REG_WINDOW + 0x28]; \
stw %i3, [%g3 + TI_REG_WINDOW + 0x2c]; \
stw %i4, [%g3 + TI_REG_WINDOW + 0x30]; \
stw %i5, [%g3 + TI_REG_WINDOW + 0x34]; \
stw %i6, [%g3 + TI_REG_WINDOW + 0x38]; \
stw %i7, [%g3 + TI_REG_WINDOW + 0x3c]; \
add %g1, 1, %g1; \
stb %g1, [%g6 + TI_WSAVED]; \
saved; \
rdpr %cwp, %g1; \
sub %g1, 2, %g1; \
ba,pt %xcc, etrap_save; \
wrpr %g1, %cwp; \
nop; nop; nop
#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
#define SPILL_3_NORMAL SPILL_0_NORMAL
@@ -325,6 +491,35 @@
restored; retry; nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop;
#define FILL_0_NORMAL_RTRAP \
kern_rtt_fill: \
rdpr %cwp, %g1; \
sub %g1, 1, %g1; \
wrpr %g1, %cwp; \
ldx [%sp + STACK_BIAS + 0x00], %l0; \
ldx [%sp + STACK_BIAS + 0x08], %l1; \
ldx [%sp + STACK_BIAS + 0x10], %l2; \
ldx [%sp + STACK_BIAS + 0x18], %l3; \
ldx [%sp + STACK_BIAS + 0x20], %l4; \
ldx [%sp + STACK_BIAS + 0x28], %l5; \
ldx [%sp + STACK_BIAS + 0x30], %l6; \
ldx [%sp + STACK_BIAS + 0x38], %l7; \
ldx [%sp + STACK_BIAS + 0x40], %i0; \
ldx [%sp + STACK_BIAS + 0x48], %i1; \
ldx [%sp + STACK_BIAS + 0x50], %i2; \
ldx [%sp + STACK_BIAS + 0x58], %i3; \
ldx [%sp + STACK_BIAS + 0x60], %i4; \
ldx [%sp + STACK_BIAS + 0x68], %i5; \
ldx [%sp + STACK_BIAS + 0x70], %i6; \
ldx [%sp + STACK_BIAS + 0x78], %i7; \
restored; \
add %g1, 1, %g1; \
ba,pt %xcc, kern_rtt_restore; \
wrpr %g1, %cwp; \
nop; nop; nop; nop; nop; \
nop; nop; nop; nop;
/* Normal 64bit fill */
#define FILL_1_GENERIC(ASI) \
add %sp, STACK_BIAS + 0x00, %g1; \
@@ -356,6 +551,33 @@
b,a,pt %xcc, fill_fixup_mna; \
b,a,pt %xcc, fill_fixup;
#define FILL_1_GENERIC_RTRAP \
user_rtt_fill_64bit: \
ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \
ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \
ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \
ldxa [%sp + STACK_BIAS + 0x18] %asi, %l3; \
ldxa [%sp + STACK_BIAS + 0x20] %asi, %l4; \
ldxa [%sp + STACK_BIAS + 0x28] %asi, %l5; \
ldxa [%sp + STACK_BIAS + 0x30] %asi, %l6; \
ldxa [%sp + STACK_BIAS + 0x38] %asi, %l7; \
ldxa [%sp + STACK_BIAS + 0x40] %asi, %i0; \
ldxa [%sp + STACK_BIAS + 0x48] %asi, %i1; \
ldxa [%sp + STACK_BIAS + 0x50] %asi, %i2; \
ldxa [%sp + STACK_BIAS + 0x58] %asi, %i3; \
ldxa [%sp + STACK_BIAS + 0x60] %asi, %i4; \
ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \
ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \
ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \
ba,pt %xcc, user_rtt_pre_restore; \
restored; \
nop; nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup;
/* Normal 32bit fill */
#define FILL_2_GENERIC(ASI) \
srl %sp, 0, %sp; \
@@ -387,6 +609,34 @@
b,a,pt %xcc, fill_fixup_mna; \
b,a,pt %xcc, fill_fixup;
#define FILL_2_GENERIC_RTRAP \
user_rtt_fill_32bit: \
srl %sp, 0, %sp; \
lduwa [%sp + 0x00] %asi, %l0; \
lduwa [%sp + 0x04] %asi, %l1; \
lduwa [%sp + 0x08] %asi, %l2; \
lduwa [%sp + 0x0c] %asi, %l3; \
lduwa [%sp + 0x10] %asi, %l4; \
lduwa [%sp + 0x14] %asi, %l5; \
lduwa [%sp + 0x18] %asi, %l6; \
lduwa [%sp + 0x1c] %asi, %l7; \
lduwa [%sp + 0x20] %asi, %i0; \
lduwa [%sp + 0x24] %asi, %i1; \
lduwa [%sp + 0x28] %asi, %i2; \
lduwa [%sp + 0x2c] %asi, %i3; \
lduwa [%sp + 0x30] %asi, %i4; \
lduwa [%sp + 0x34] %asi, %i5; \
lduwa [%sp + 0x38] %asi, %i6; \
lduwa [%sp + 0x3c] %asi, %i7; \
ba,pt %xcc, user_rtt_pre_restore; \
restored; \
nop; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup; \
ba,a,pt %xcc, user_rtt_fill_fixup;
#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
#define FILL_3_NORMAL FILL_0_NORMAL
+1 -45
View File
@@ -114,16 +114,6 @@ case 8: __put_user_asm(data,x,addr,__pu_ret); break; \
default: __pu_ret = __put_user_bad(); break; \
} __pu_ret; })
#define __put_user_nocheck_ret(data,addr,size,retval) ({ \
register int __foo __asm__ ("l1"); \
switch (size) { \
case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \
case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \
case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \
case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \
default: if (__put_user_bad()) return retval; break; \
} })
#define __put_user_asm(x,size,addr,ret) \
__asm__ __volatile__( \
"/* Put user asm, inline. */\n" \
@@ -143,33 +133,6 @@ __asm__ __volatile__( \
: "=r" (ret) : "r" (x), "r" (__m(addr)), \
"i" (-EFAULT))
#define __put_user_asm_ret(x,size,addr,ret,foo) \
if (__builtin_constant_p(ret) && ret == -EFAULT) \
__asm__ __volatile__( \
"/* Put user asm ret, inline. */\n" \
"1:\t" "st"#size "a %1, [%2] %%asi\n\n\t" \
".section __ex_table,\"a\"\n\t" \
".align 4\n\t" \
".word 1b, __ret_efault\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "r" (__m(addr))); \
else \
__asm__ __volatile__( \
"/* Put user asm ret, inline. */\n" \
"1:\t" "st"#size "a %1, [%2] %%asi\n\n\t" \
".section .fixup,#alloc,#execinstr\n\t" \
".align 4\n" \
"3:\n\t" \
"ret\n\t" \
" restore %%g0, %3, %%o0\n\n\t" \
".previous\n\t" \
".section __ex_table,\"a\"\n\t" \
".align 4\n\t" \
".word 1b, 3b\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "r" (__m(addr)), \
"i" (ret))
extern int __put_user_bad(void);
#define __get_user_nocheck(data,addr,size,type) ({ \
@@ -289,14 +252,7 @@ copy_in_user(void __user *to, void __user *from, unsigned long size)
}
#define __copy_in_user copy_in_user
extern unsigned long __must_check __bzero_noasi(void __user *, unsigned long);
static inline unsigned long __must_check
__clear_user(void __user *addr, unsigned long size)
{
return __bzero_noasi(addr, size);
}
extern unsigned long __must_check __clear_user(void __user *, unsigned long);
#define clear_user __clear_user
+16
View File
@@ -0,0 +1,16 @@
/* vdev.h: SUN4V virtual device interfaces and defines.
*
* Copyright (C) 2006 David S. Miller <davem@davemloft.net>
*/
#ifndef _SPARC64_VDEV_H
#define _SPARC64_VDEV_H
#include <linux/types.h>
extern u32 sun4v_vdev_devhandle;
extern int sun4v_vdev_root;
extern unsigned int sun4v_vdev_device_interrupt(unsigned int);
#endif /* !(_SPARC64_VDEV_H) */
+30 -4
View File
@@ -2,9 +2,11 @@
* include/asm-sparc64/xor.h
*
* High speed xor_block operation for RAID4/5 utilizing the
* UltraSparc Visual Instruction Set.
* UltraSparc Visual Instruction Set and Niagara block-init
* twin-load instructions.
*
* Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 2006 David S. Miller <davem@davemloft.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,8 +18,7 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/pstate.h>
#include <asm/asi.h>
#include <asm/spitfire.h>
extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
@@ -37,4 +38,29 @@ static struct xor_block_template xor_block_VIS = {
.do_5 = xor_vis_5,
};
#define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS)
extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *);
extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *,
unsigned long *);
extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *,
unsigned long *, unsigned long *);
extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *,
unsigned long *, unsigned long *, unsigned long *);
static struct xor_block_template xor_block_niagara = {
.name = "Niagara",
.do_2 = xor_niagara_2,
.do_3 = xor_niagara_3,
.do_4 = xor_niagara_4,
.do_5 = xor_niagara_5,
};
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_VIS); \
xor_speed(&xor_block_niagara); \
} while (0)
/* For VIS for everything except Niagara. */
#define XOR_SELECT_TEMPLATE(FASTEST) \
(tlb_type == hypervisor ? &xor_block_niagara : &xor_block_VIS)
+3
View File
@@ -127,6 +127,9 @@
/* Hilscher netx */
#define PORT_NETX 71
/* SUN4V Hypervisor Console */
#define PORT_SUNHV 72
#ifdef __KERNEL__
#include <linux/config.h>