Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bd29c56 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sparc fixes from David Miller:
 "I've been auditing the THP support on sparc64 and found several bugs,
  hopefully most of which are fixed completely here.

  Also an RT kernel locking fix from Kirill Tkhai"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc64: Give more detailed information in {pgd,pmd}_ERROR() and kill pte_ERROR().
  sparc64: Add basic validations to {pud,pmd}_bad().
  sparc64: Use 'ILOG2_4MB' instead of constant '22'.
  sparc64: Fix range check in kern_addr_valid().
  sparc64: Fix top-level fault handling bugs.
  sparc64: Handle 32-bit tasks properly in compute_effective_address().
  sparc64: Don't use _PAGE_PRESENT in pte_modify() mask.
  sparc64: Fix hex values in comment above pte_modify().
  sparc64: Fix bugs in get_user_pages_fast() wrt. THP.
  sparc64: Fix huge PMD invalidation.
  sparc64: Fix executable bit testing in set_pmd_at() paths.
  sparc64: Normalize NMI watchdog logging and behavior.
  sparc64: Make itc_sync_lock raw
  sparc64: Fix argument sign extension for compat_sys_futex().
parents 30321c7b fe866433
Loading
Loading
Loading
Loading
+46 −37
Original line number Diff line number Diff line
@@ -71,6 +71,23 @@

#include <linux/sched.h>

extern unsigned long sparc64_valid_addr_bitmap[];

/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
static inline bool __kern_addr_valid(unsigned long paddr)
{
	if ((paddr >> MAX_PHYS_ADDRESS_BITS) != 0UL)
		return false;
	return test_bit(paddr >> ILOG2_4MB, sparc64_valid_addr_bitmap);
}

static inline bool kern_addr_valid(unsigned long addr)
{
	unsigned long paddr = __pa(addr);

	return __kern_addr_valid(paddr);
}

/* Entries per page directory level. */
#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
#define PTRS_PER_PMD	(1UL << PMD_BITS)
@@ -79,9 +96,12 @@
/* Kernel has a separate 44bit address space. */
#define FIRST_USER_ADDRESS	0

#define pte_ERROR(e)	__builtin_trap()
#define pmd_ERROR(e)	__builtin_trap()
#define pgd_ERROR(e)	__builtin_trap()
#define pmd_ERROR(e)							\
	pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n",		\
	       __FILE__, __LINE__, &(e), pmd_val(e), __builtin_return_address(0))
#define pgd_ERROR(e)							\
	pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n",		\
	       __FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0))

#endif /* !(__ASSEMBLY__) */

@@ -258,8 +278,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
{
	unsigned long mask, tmp;

	/* SUN4U: 0x600307ffffffecb8 (negated == 0x9ffcf80000001347)
	 * SUN4V: 0x30ffffffffffee17 (negated == 0xcf000000000011e8)
	/* SUN4U: 0x630107ffffffec38 (negated == 0x9cfef800000013c7)
	 * SUN4V: 0x33ffffffffffee07 (negated == 0xcc000000000011f8)
	 *
	 * Even if we use negation tricks the result is still a 6
	 * instruction sequence, so don't try to play fancy and just
@@ -289,10 +309,10 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t prot)
	"	.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_CP_4U | _PAGE_CV_4U | _PAGE_E_4U |
	       _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4U),
	  "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V |
	       _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | _PAGE_PRESENT_4V |
	       _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V |
	       _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V));

	return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask));
@@ -633,7 +653,7 @@ static inline unsigned long pmd_large(pmd_t pmd)
{
	pte_t pte = __pte(pmd_val(pmd));

	return (pte_val(pte) & _PAGE_PMD_HUGE) && pte_present(pte);
	return pte_val(pte) & _PAGE_PMD_HUGE;
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -719,20 +739,6 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
	return __pmd(pte_val(pte));
}

static inline pmd_t pmd_mknotpresent(pmd_t pmd)
{
	unsigned long mask;

	if (tlb_type == hypervisor)
		mask = _PAGE_PRESENT_4V;
	else
		mask = _PAGE_PRESENT_4U;

	pmd_val(pmd) &= ~mask;

	return pmd;
}

static inline pmd_t pmd_mksplitting(pmd_t pmd)
{
	pte_t pte = __pte(pmd_val(pmd));
@@ -757,6 +763,20 @@ static inline int pmd_present(pmd_t pmd)

#define pmd_none(pmd)			(!pmd_val(pmd))

/* pmd_bad() is only called on non-trans-huge PMDs.  Our encoding is
 * very simple, it's just the physical address.  PTE tables are of
 * size PAGE_SIZE so make sure the sub-PAGE_SIZE bits are clear and
 * the top bits outside of the range of any physical address size we
 * support are clear as well.  We also validate the physical itself.
 */
#define pmd_bad(pmd)			((pmd_val(pmd) & ~PAGE_MASK) || \
					 !__kern_addr_valid(pmd_val(pmd)))

#define pud_none(pud)			(!pud_val(pud))

#define pud_bad(pud)			((pud_val(pud) & ~PAGE_MASK) || \
					 !__kern_addr_valid(pud_val(pud)))

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
		       pmd_t *pmdp, pmd_t pmd);
@@ -790,10 +810,7 @@ static inline unsigned long __pmd_page(pmd_t pmd)
#define pud_page_vaddr(pud)		\
	((unsigned long) __va(pud_val(pud)))
#define pud_page(pud) 			virt_to_page((void *)pud_page_vaddr(pud))
#define pmd_bad(pmd)			(0)
#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0UL)
#define pud_none(pud)			(!pud_val(pud))
#define pud_bad(pud)			(0)
#define pud_present(pud)		(pud_val(pud) != 0U)
#define pud_clear(pudp)			(pud_val(*(pudp)) = 0UL)

@@ -893,6 +910,10 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
				 pmd_t *pmd);

#define __HAVE_ARCH_PMDP_INVALIDATE
extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
			    pmd_t *pmdp);

#define __HAVE_ARCH_PGTABLE_DEPOSIT
extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
				       pgtable_t pgtable);
@@ -919,18 +940,6 @@ extern unsigned long pte_file(pte_t);
extern pte_t pgoff_to_pte(unsigned long);
#define PTE_FILE_MAX_BITS	(64UL - PAGE_SHIFT - 1UL)

extern unsigned long sparc64_valid_addr_bitmap[];

/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
static inline bool kern_addr_valid(unsigned long addr)
{
	unsigned long paddr = __pa(addr);

	if ((paddr >> 41UL) != 0UL)
		return false;
	return test_bit(paddr >> 22, sparc64_valid_addr_bitmap);
}

extern int page_in_phys_avail(unsigned long paddr);

/*
+2 −1
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
	andcc		REG1, REG2, %g0;		\
	be,pt		%xcc, 700f;			\
	 sethi		%hi(4 * 1024 * 1024), REG2;	\
	brgez,pn	REG1, FAIL_LABEL;		\
	 andn		REG1, REG2, REG1;		\
	and		VADDR, REG2, REG2;		\
	brlz,pt		REG1, PTE_LABEL;		\
+2 −2
Original line number Diff line number Diff line
@@ -282,8 +282,8 @@ sun4v_chip_type:
	stx	%l2, [%l4 + 0x0]
	ldx	[%sp + 2047 + 128 + 0x50], %l3	! physaddr low
	/* 4MB align */
	srlx	%l3, 22, %l3
	sllx	%l3, 22, %l3
	srlx	%l3, ILOG2_4MB, %l3
	sllx	%l3, ILOG2_4MB, %l3
	stx	%l3, [%l4 + 0x8]

	/* Leave service as-is, "call-method" */
+1 −1
Original line number Diff line number Diff line
@@ -277,7 +277,7 @@ kvmap_dtlb_load:
#ifdef CONFIG_SPARSEMEM_VMEMMAP
kvmap_vmemmap:
	sub		%g4, %g5, %g5
	srlx		%g5, 22, %g5
	srlx		%g5, ILOG2_4MB, %g5
	sethi		%hi(vmemmap_table), %g1
	sllx		%g5, 3, %g5
	or		%g1, %lo(vmemmap_table), %g1
+5 −16
Original line number Diff line number Diff line
@@ -68,27 +68,16 @@ EXPORT_SYMBOL(touch_nmi_watchdog);

static void die_nmi(const char *str, struct pt_regs *regs, int do_panic)
{
	int this_cpu = smp_processor_id();

	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0,
		       pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP)
		return;

	console_verbose();
	bust_spinlocks(1);

	printk(KERN_EMERG "%s", str);
	printk(" on CPU%d, ip %08lx, registers:\n",
	       smp_processor_id(), regs->tpc);
	show_regs(regs);
	dump_stack();

	bust_spinlocks(0);

	if (do_panic || panic_on_oops)
		panic("Non maskable interrupt");

	nmi_exit();
	local_irq_enable();
	do_exit(SIGBUS);
		panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
	else
		WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
}

notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
Loading