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
This commit is contained in:
@@ -243,6 +243,7 @@ endif
|
||||
cpu-as-$(CONFIG_4xx) += -Wa,-m405
|
||||
cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec)
|
||||
cpu-as-$(CONFIG_E200) += -Wa,-me200
|
||||
cpu-as-$(CONFIG_E500) += -Wa,-me500
|
||||
cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4
|
||||
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(
|
||||
extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
|
||||
unsigned long ua, unsigned long entries);
|
||||
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,
|
||||
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 void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem);
|
||||
#endif
|
||||
|
||||
@@ -144,7 +144,9 @@ power9_restore_additional_sprs:
|
||||
mtspr SPRN_MMCR1, r4
|
||||
|
||||
ld r3, STOP_MMCR2(r13)
|
||||
ld r4, PACA_SPRG_VDSO(r13)
|
||||
mtspr SPRN_MMCR2, r3
|
||||
mtspr SPRN_SPRG3, r4
|
||||
blr
|
||||
|
||||
/*
|
||||
|
||||
@@ -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() */
|
||||
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;
|
||||
|
||||
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,
|
||||
if (!mem)
|
||||
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;
|
||||
|
||||
pua = (void *) vmalloc_to_phys(pua);
|
||||
@@ -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);
|
||||
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) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/swap.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pte-walk.h>
|
||||
|
||||
static DEFINE_MUTEX(mem_list_mutex);
|
||||
|
||||
@@ -27,6 +28,7 @@ struct mm_iommu_table_group_mem_t {
|
||||
struct rcu_head rcu;
|
||||
unsigned long used;
|
||||
atomic64_t mapped;
|
||||
unsigned int pageshift;
|
||||
u64 ua; /* userspace address */
|
||||
u64 entries; /* number of entries in hpas[] */
|
||||
u64 *hpas; /* vmalloc'ed */
|
||||
@@ -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;
|
||||
long i, j, ret = 0, locked_entries = 0;
|
||||
unsigned int pageshift;
|
||||
unsigned long flags;
|
||||
struct page *page = NULL;
|
||||
|
||||
mutex_lock(&mem_list_mutex);
|
||||
@@ -159,6 +163,12 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
|
||||
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])));
|
||||
if (!mem->hpas) {
|
||||
kfree(mem);
|
||||
@@ -199,6 +209,23 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -349,7 +376,7 @@ struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
|
||||
EXPORT_SYMBOL_GPL(mm_iommu_find);
|
||||
|
||||
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;
|
||||
u64 *va = &mem->hpas[entry];
|
||||
@@ -357,6 +384,9 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
|
||||
if (entry >= mem->entries)
|
||||
return -EFAULT;
|
||||
|
||||
if (pageshift > mem->pageshift)
|
||||
return -EFAULT;
|
||||
|
||||
*hpa = *va | (ua & ~PAGE_MASK);
|
||||
|
||||
return 0;
|
||||
@@ -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);
|
||||
|
||||
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;
|
||||
void *va = &mem->hpas[entry];
|
||||
@@ -373,6 +403,9 @@ long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem,
|
||||
if (entry >= mem->entries)
|
||||
return -EFAULT;
|
||||
|
||||
if (pageshift > mem->pageshift)
|
||||
return -EFAULT;
|
||||
|
||||
pa = (void *) vmalloc_to_phys(va);
|
||||
if (!pa)
|
||||
return -EFAULT;
|
||||
|
||||
@@ -2734,7 +2734,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr,
|
||||
{
|
||||
int nr, dotted;
|
||||
unsigned long first_adr;
|
||||
unsigned long inst, last_inst = 0;
|
||||
unsigned int inst, last_inst = 0;
|
||||
unsigned char val[4];
|
||||
|
||||
dotted = 0;
|
||||
@@ -2758,7 +2758,7 @@ generic_inst_dump(unsigned long adr, long count, int praddr,
|
||||
dotted = 0;
|
||||
last_inst = inst;
|
||||
if (praddr)
|
||||
printf(REG" %.8lx", adr, inst);
|
||||
printf(REG" %.8x", adr, inst);
|
||||
printf("\t");
|
||||
dump_func(inst, adr);
|
||||
printf("\n");
|
||||
|
||||
@@ -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,
|
||||
unsigned long tce, unsigned long size,
|
||||
unsigned long tce, unsigned long shift,
|
||||
unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem)
|
||||
{
|
||||
long ret = 0;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
ret = mm_iommu_ua_to_hpa(mem, tce, phpa);
|
||||
ret = mm_iommu_ua_to_hpa(mem, tce, shift, phpa);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -487,7 +487,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container,
|
||||
if (!pua)
|
||||
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);
|
||||
if (ret)
|
||||
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,
|
||||
entry + i);
|
||||
|
||||
ret = tce_iommu_prereg_ua_to_hpa(container,
|
||||
tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem);
|
||||
tce, tbl->it_page_shift, &hpa, &mem);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user