Commit 1b3a6e97 authored by Thiemo Seufer's avatar Thiemo Seufer Committed by Ralf Baechle
Browse files

Fix 64bit SMP TLB handler and stack frame handling, optimize 32bit SMP


TLB handlers a bit, match definitions in pgtable-{32,64}.h better.

Signed-off-by: default avatarThiemo Seufer <ths@networkno.de>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 7c2740f1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
	LONG_S		a2, fw_arg2
	LONG_S		a3, fw_arg3

	MTC0		zero, CP0_CONTEXT	# clear context register
	PTR_LA		$28, init_thread_union
	PTR_ADDIU	sp, $28, _THREAD_SIZE - 32
	set_saved_sp	sp, t0, t1
+21 −29
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ enum opcode {
	insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
	insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
	insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
	insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
	insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
	insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
	insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
	insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
@@ -134,7 +134,6 @@ static __initdata struct insn insn_table[] = {
	{ insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
	{ insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
	{ insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE },
	{ insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE },
	{ insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD },
	{ insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 },
	{ insn_j, M(j_op,0,0,0,0,0), JIMM },
@@ -366,7 +365,6 @@ I_u2u1u3(_dsll);
I_u2u1u3(_dsll32);
I_u2u1u3(_dsra);
I_u2u1u3(_dsrl);
I_u2u1u3(_dsrl32);
I_u3u1u2(_dsubu);
I_0(_eret);
I_u1(_j);
@@ -944,34 +942,29 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
	/* No i_nop needed here, since the next insn doesn't touch TMP. */

#ifdef CONFIG_SMP
# ifdef CONFIG_BUILD_ELF64
	/*
	 * 64 bit SMP has the lower part of &pgd_current[smp_processor_id()]
	 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
	 * stored in CONTEXT.
	 */
	if (in_compat_space_p(pgdc)) {
		i_dmfc0(p, ptr, C0_CONTEXT);
		i_dsra(p, ptr, ptr, 23);
		i_ld(p, ptr, 0, ptr);
	} else {
#ifdef CONFIG_BUILD_ELF64
	i_dmfc0(p, ptr, C0_CONTEXT);
	i_dsrl(p, ptr, ptr, 23);
		i_dsll(p, ptr, ptr, 3);
	i_LA_mostly(p, tmp, pgdc);
	i_daddu(p, ptr, ptr, tmp);
	i_dmfc0(p, tmp, C0_BADVADDR);
	i_ld(p, ptr, rel_lo(pgdc), ptr);
# else
	/*
	 * 64 bit SMP running in compat space has the lower part of
	 * &pgd_current[smp_processor_id()] stored in CONTEXT.
	 */
	if (!in_compat_space_p(pgdc))
		panic("Invalid page directory address!");

	i_dmfc0(p, ptr, C0_CONTEXT);
		i_lui(p, tmp, rel_highest(pgdc));
		i_dsll(p, ptr, ptr, 9);
		i_daddiu(p, tmp, tmp, rel_higher(pgdc));
		i_dsrl32(p, ptr, ptr, 0);
		i_and(p, ptr, ptr, tmp);
		i_dmfc0(p, tmp, C0_BADVADDR);
	i_dsra(p, ptr, ptr, 23);
	i_ld(p, ptr, 0, ptr);
# endif
	}
#else
	i_LA_mostly(p, ptr, pgdc);
	i_ld(p, ptr, rel_lo(pgdc), ptr);
@@ -1028,7 +1021,6 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
	i_mfc0(p, ptr, C0_CONTEXT);
	i_LA_mostly(p, tmp, pgdc);
	i_srl(p, ptr, ptr, 23);
	i_sll(p, ptr, ptr, 2);
	i_addu(p, ptr, tmp, ptr);
#else
	i_LA_mostly(p, ptr, pgdc);
+2 −2
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ extern unsigned long pgd_current[];

#ifdef CONFIG_32BIT
#define TLBMISS_HANDLER_SETUP()						\
	write_c0_context((unsigned long) smp_processor_id() << 23);	\
	write_c0_context((unsigned long) smp_processor_id() << 25);	\
	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif
#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
@@ -40,7 +40,7 @@ extern unsigned long pgd_current[];
#endif
#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
#define TLBMISS_HANDLER_SETUP()						\
	write_c0_context((unsigned long) smp_processor_id() << 23);	\
	write_c0_context((unsigned long) smp_processor_id() << 26);	\
	TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
#endif

+6 −4
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ extern pmd_t invalid_pmd_table[PTRS_PER_PMD];
extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD];

/*
 * Empty pmd entries point to the invalid_pte_table.
 * Empty pgd/pmd entries point to the invalid_pte_table.
 */
static inline int pmd_none(pmd_t pmd)
{
@@ -156,7 +156,8 @@ static inline void pud_clear(pud_t *pudp)
	pud_val(*pudp) = ((unsigned long) invalid_pmd_table);
}

#define pte_page(x)		pfn_to_page((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
#define pte_page(x)		pfn_to_page(pte_pfn(x))

#ifdef CONFIG_CPU_VR41XX
#define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
#define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
@@ -167,12 +168,14 @@ static inline void pud_clear(pud_t *pudp)

#define __pgd_offset(address)	pgd_index(address)
#define __pud_offset(address)	(((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
#define __pmd_offset(address)	pmd_index(address)
#define page_pte(page) page_pte_prot(page, __pgprot(0))

/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, 0)

#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
#define pmd_index(address)	(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))

/* to find an entry in a page-table-directory */
#define pgd_offset(mm,addr)	((mm)->pgd + pgd_index(addr))
@@ -185,8 +188,7 @@ static inline unsigned long pud_page(pud_t pud)
/* Find an entry in the second-level page table.. */
static inline pmd_t *pmd_offset(pud_t * pud, unsigned long address)
{
	return (pmd_t *) pud_page(*pud) +
	       ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
	return (pmd_t *) pud_page(*pud) + pmd_index(address);
}

/* Find an entry in the third-level page table.. */
+4 −6
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@
		mfc0	k0, CP0_CONTEXT
		lui	k1, %hi(kernelsp)
		srl	k0, k0, 23
		sll	k0, k0, 2
		addu	k1, k0
		LONG_L	k1, %lo(kernelsp)(k1)
#endif
@@ -76,12 +75,12 @@
#endif
#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
		MFC0	k1, CP0_CONTEXT
		dsrl	k1, 23
		dsll	k1, k1, 3
		lui	k0, %highest(kernelsp)
		dsrl	k1, 23
		daddiu	k0, %higher(kernelsp)
		dsll	k0, k0, 16
		daddiu	k0, %hi(kernelsp)
		dsll	k0, k0, 16
		daddu	k1, k1, k0
		LONG_L	k1, %lo(kernelsp)(k1)
#endif
@@ -91,7 +90,6 @@
#ifdef CONFIG_32BIT
		mfc0	\temp, CP0_CONTEXT
		srl	\temp, 23
		sll	\temp, 2
		LONG_S	\stackp, kernelsp(\temp)
#endif
#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
@@ -102,8 +100,8 @@
		LONG_S	\stackp, %lo(kernelsp)(\temp)
#endif
#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
		lw	\temp, TI_CPU(gp)
		dsll	\temp, 3
		MFC0	\temp, CP0_CONTEXT
		dsrl	\temp, 23
		LONG_S	\stackp, kernelsp(\temp)
#endif
		.endm