Commit ffb48e79 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-4.18-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Michael Ellerman:
 "Two regression fixes, one for xmon disassembly formatting and the
  other to fix the E500 build.

  Two commits to fix a potential security issue in the VFIO code under
  obscure circumstances.

  And finally a fix to the Power9 idle code to restore SPRG3, which is
  user visible and used for sched_getcpu().

  Thanks to: Alexey Kardashevskiy, David Gibson. Gautham R. Shenoy,
  James Clarke"

* tag 'powerpc-4.18-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/powernv: Fix save/restore of SPRG3 on entry/exit from stop (idle)
  powerpc/Makefile: Assemble with -me500 when building for E500
  KVM: PPC: Check if IOMMU page is contained in the pinned physical page
  vfio/spapr: Use IOMMU pageshift rather than pagesize
  powerpc/xmon: Fix disassembly since printf changes
parents 55b636b4 b03897cf
...@@ -243,6 +243,7 @@ endif ...@@ -243,6 +243,7 @@ endif
cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_4xx) += -Wa,-m405
cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec)
cpu-as-$(CONFIG_E200) += -Wa,-me200 cpu-as-$(CONFIG_E200) += -Wa,-me200
cpu-as-$(CONFIG_E500) += -Wa,-me500
cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4 cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4
cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc) cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc)
......
...@@ -35,9 +35,9 @@ extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup_rm( ...@@ -35,9 +35,9 @@ extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup_rm(
extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
unsigned long ua, unsigned long entries); unsigned long ua, unsigned long entries);
extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
unsigned long ua, unsigned long *hpa); unsigned long ua, unsigned int pageshift, unsigned long *hpa);
extern long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, extern long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem,
unsigned long ua, unsigned long *hpa); unsigned long ua, unsigned int pageshift, unsigned long *hpa);
extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem); extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem);
extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem); extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem);
#endif #endif
......
...@@ -144,7 +144,9 @@ power9_restore_additional_sprs: ...@@ -144,7 +144,9 @@ power9_restore_additional_sprs:
mtspr SPRN_MMCR1, r4 mtspr SPRN_MMCR1, r4
ld r3, STOP_MMCR2(r13) ld r3, STOP_MMCR2(r13)
ld r4, PACA_SPRG_VDSO(r13)
mtspr SPRN_MMCR2, r3 mtspr SPRN_MMCR2, r3
mtspr SPRN_SPRG3, r4
blr blr
/* /*
......
...@@ -449,7 +449,7 @@ long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, ...@@ -449,7 +449,7 @@ long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
/* This only handles v2 IOMMU type, v1 is handled via ioctl() */ /* This only handles v2 IOMMU type, v1 is handled via ioctl() */
return H_TOO_HARD; return H_TOO_HARD;
if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, &hpa))) if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, tbl->it_page_shift, &hpa)))
return H_HARDWARE; return H_HARDWARE;
if (mm_iommu_mapped_inc(mem)) if (mm_iommu_mapped_inc(mem))
......
...@@ -279,7 +279,8 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, ...@@ -279,7 +279,8 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
if (!mem) if (!mem)
return H_TOO_HARD; return H_TOO_HARD;
if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, &hpa))) if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, tbl->it_page_shift,
&hpa)))
return H_HARDWARE; return H_HARDWARE;
pua = (void *) vmalloc_to_phys(pua); pua = (void *) vmalloc_to_phys(pua);
...@@ -469,7 +470,8 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, ...@@ -469,7 +470,8 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K); mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K);
if (mem) if (mem)
prereg = mm_iommu_ua_to_hpa_rm(mem, ua, &tces) == 0; prereg = mm_iommu_ua_to_hpa_rm(mem, ua,
IOMMU_PAGE_SHIFT_4K, &tces) == 0;
} }
if (!prereg) { if (!prereg) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pte-walk.h>
static DEFINE_MUTEX(mem_list_mutex); static DEFINE_MUTEX(mem_list_mutex);
...@@ -27,6 +28,7 @@ struct mm_iommu_table_group_mem_t { ...@@ -27,6 +28,7 @@ struct mm_iommu_table_group_mem_t {
struct rcu_head rcu; struct rcu_head rcu;
unsigned long used; unsigned long used;
atomic64_t mapped; atomic64_t mapped;
unsigned int pageshift;
u64 ua; /* userspace address */ u64 ua; /* userspace address */
u64 entries; /* number of entries in hpas[] */ u64 entries; /* number of entries in hpas[] */
u64 *hpas; /* vmalloc'ed */ u64 *hpas; /* vmalloc'ed */
...@@ -125,6 +127,8 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, ...@@ -125,6 +127,8 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
{ {
struct mm_iommu_table_group_mem_t *mem; struct mm_iommu_table_group_mem_t *mem;
long i, j, ret = 0, locked_entries = 0; long i, j, ret = 0, locked_entries = 0;
unsigned int pageshift;
unsigned long flags;
struct page *page = NULL; struct page *page = NULL;
mutex_lock(&mem_list_mutex); mutex_lock(&mem_list_mutex);
...@@ -159,6 +163,12 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, ...@@ -159,6 +163,12 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
goto unlock_exit; goto unlock_exit;
} }
/*
* For a starting point for a maximum page size calculation
* we use @ua and @entries natural alignment to allow IOMMU pages
* smaller than huge pages but still bigger than PAGE_SIZE.
*/
mem->pageshift = __ffs(ua | (entries << PAGE_SHIFT));
mem->hpas = vzalloc(array_size(entries, sizeof(mem->hpas[0]))); mem->hpas = vzalloc(array_size(entries, sizeof(mem->hpas[0])));
if (!mem->hpas) { if (!mem->hpas) {
kfree(mem); kfree(mem);
...@@ -199,6 +209,23 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, ...@@ -199,6 +209,23 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
} }
} }
populate: populate:
pageshift = PAGE_SHIFT;
if (PageCompound(page)) {
pte_t *pte;
struct page *head = compound_head(page);
unsigned int compshift = compound_order(head);
local_irq_save(flags); /* disables as well */
pte = find_linux_pte(mm->pgd, ua, NULL, &pageshift);
local_irq_restore(flags);
/* Double check it is still the same pinned page */
if (pte && pte_page(*pte) == head &&
pageshift == compshift)
pageshift = max_t(unsigned int, pageshift,
PAGE_SHIFT);
}
mem->pageshift = min(mem->pageshift, pageshift);
mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
} }
...@@ -349,7 +376,7 @@ struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, ...@@ -349,7 +376,7 @@ struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
EXPORT_SYMBOL_GPL(mm_iommu_find); EXPORT_SYMBOL_GPL(mm_iommu_find);
long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
unsigned long ua, unsigned long *hpa) unsigned long ua, unsigned int pageshift, unsigned long *hpa)
{ {
const long entry = (ua - mem->ua) >> PAGE_SHIFT; const long entry = (ua - mem->ua) >> PAGE_SHIFT;
u64 *va = &mem->hpas[entry]; u64 *va = &mem->hpas[entry];
...@@ -357,6 +384,9 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, ...@@ -357,6 +384,9 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
if (entry >= mem->entries) if (entry >= mem->entries)
return -EFAULT; return -EFAULT;
if (pageshift > mem->pageshift)
return -EFAULT;
*hpa = *va | (ua & ~PAGE_MASK); *hpa = *va | (ua & ~PAGE_MASK);
return 0; return 0;
...@@ -364,7 +394,7 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, ...@@ -364,7 +394,7 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
EXPORT_SYMBOL_GPL(mm_iommu_ua_to_hpa); EXPORT_SYMBOL_GPL(mm_iommu_ua_to_hpa);
long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem,
unsigned long ua, unsigned long *hpa) unsigned long ua, unsigned int pageshift, unsigned long *hpa)
{ {
const long entry = (ua - mem->ua) >> PAGE_SHIFT; const long entry = (ua - mem->ua) >> PAGE_SHIFT;
void *va = &mem->hpas[entry]; void *va = &mem->hpas[entry];
...@@ -373,6 +403,9 @@ long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, ...@@ -373,6 +403,9 @@ long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem,
if (entry >= mem->entries) if (entry >= mem->entries)
return -EFAULT; return -EFAULT;
if (pageshift > mem->pageshift)
return -EFAULT;
pa = (void *) vmalloc_to_phys(va); pa = (void *) vmalloc_to_phys(va);
if (!pa) if (!pa)
return -EFAULT; return -EFAULT;
......
...@@ -2734,7 +2734,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr, ...@@ -2734,7 +2734,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr,
{ {
int nr, dotted; int nr, dotted;
unsigned long first_adr; unsigned long first_adr;
unsigned long inst, last_inst = 0; unsigned int inst, last_inst = 0;
unsigned char val[4]; unsigned char val[4];
dotted = 0; dotted = 0;
...@@ -2758,7 +2758,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr, ...@@ -2758,7 +2758,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr,
dotted = 0; dotted = 0;
last_inst = inst; last_inst = inst;
if (praddr) if (praddr)
printf(REG" %.8lx", adr, inst); printf(REG" %.8x", adr, inst);
printf("\t"); printf("\t");
dump_func(inst, adr); dump_func(inst, adr);
printf("\n"); printf("\n");
......
...@@ -457,17 +457,17 @@ static void tce_iommu_unuse_page(struct tce_container *container, ...@@ -457,17 +457,17 @@ static void tce_iommu_unuse_page(struct tce_container *container,
} }
static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container, static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container,
unsigned long tce, unsigned long size, unsigned long tce, unsigned long shift,
unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem) unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem)
{ {
long ret = 0; long ret = 0;
struct mm_iommu_table_group_mem_t *mem; struct mm_iommu_table_group_mem_t *mem;
mem = mm_iommu_lookup(container->mm, tce, size); mem = mm_iommu_lookup(container->mm, tce, 1ULL << shift);
if (!mem) if (!mem)
return -EINVAL; return -EINVAL;
ret = mm_iommu_ua_to_hpa(mem, tce, phpa); ret = mm_iommu_ua_to_hpa(mem, tce, shift, phpa);
if (ret) if (ret)
return -EINVAL; return -EINVAL;
...@@ -487,7 +487,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container, ...@@ -487,7 +487,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container,
if (!pua) if (!pua)
return; return;
ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl), ret = tce_iommu_prereg_ua_to_hpa(container, *pua, tbl->it_page_shift,
&hpa, &mem); &hpa, &mem);
if (ret) if (ret)
pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n", pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n",
...@@ -611,7 +611,7 @@ static long tce_iommu_build_v2(struct tce_container *container, ...@@ -611,7 +611,7 @@ static long tce_iommu_build_v2(struct tce_container *container,
entry + i); entry + i);
ret = tce_iommu_prereg_ua_to_hpa(container, ret = tce_iommu_prereg_ua_to_hpa(container,
tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); tce, tbl->it_page_shift, &hpa, &mem);
if (ret) if (ret)
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment