[RFC PATCH 10/10] powerpc/powernv: OPAL V4 Implement vm_map/unmap service

Nicholas Piggin npiggin at gmail.com
Sat May 2 21:19:14 AEST 2020


This implements os_vm_map, os_vm_unmap. OPAL uses EA regions that
is specifies in OPAL_FIND_VM_AREA for these mappings, so provided
the page tables are allocated at init-time and not freed, these
services can be provided without memory allocation / blocking.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 arch/powerpc/include/asm/opal-api.h   |  2 +
 arch/powerpc/platforms/powernv/opal.c | 57 +++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 1b2f176677fc..97c5e5423827 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -1205,6 +1205,8 @@ struct opal_vm_area {
 
 struct opal_os_ops {
 	__be64  os_printf; /* void printf(int32_t level, const char *str) */
+	__be64  os_vm_map; /* int64_t os_vm_map(uint64_t ea, uint64_t pa, uint64_t flags) */
+	__be64  os_vm_unmap; /* void os_vm_unmap(uint64_t ea) */
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 0fbfcd088c58..93b9afaf33b3 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -1095,6 +1095,61 @@ static pgprot_t opal_vm_flags_to_prot(uint64_t flags)
 	return prot;
 }
 
+static int64_t os_vm_map(uint64_t ea, uint64_t pa, uint64_t flags)
+{
+	struct mm_struct *mm = opal_mm;
+	spinlock_t *ptl;
+	pte_t pte, *ptep;
+	pgprot_t prot;
+
+	if (WARN_ON_ONCE(!opal_mm_enabled))
+		return -EINVAL;
+
+	if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+		return -EINVAL;
+
+	/* mm should be active_mm if MMU is on here */
+
+//	printk("os_vm_map 0x%llx->0x%llx flags=0x%llx\n", ea, pa, flags);
+
+	prot = opal_vm_flags_to_prot(flags);
+
+	pte = pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL_X);
+
+	ptep = get_locked_pte(mm, ea, &ptl);
+	set_pte_at(mm, ea, ptep, pte);
+	pte_unmap_unlock(ptep, ptl);
+
+	return 0;
+}
+
+static void os_vm_unmap(uint64_t ea)
+{
+	struct mm_struct *mm = opal_mm;
+	spinlock_t *ptl;
+	pte_t *ptep;
+
+	if (WARN_ON_ONCE(!opal_mm_enabled))
+		return;
+
+	if (WARN_ON_ONCE(!(mfmsr() & (MSR_IR|MSR_DR))))
+		return;
+
+//	printk("os_vm_unmap 0x%llx\n", ea);
+
+	/* mm should be active_mm if MMU is on here */
+
+	ptep = get_locked_pte(mm, ea, &ptl);
+	pte_clear(mm, ea, ptep);
+	pte_unmap_unlock(ptep, ptl);
+
+	/*
+	 * This leaves potential TLBs in other CPUs for this EA, but it is
+	 * only used by this CPU. Can't do a broadcast flush here, no IPIs.
+	 */
+	local_flush_tlb_mm(mm);
+}
+
 static int __init opal_init_mm(void)
 {
 	struct mm_struct *mm;
@@ -1174,6 +1229,8 @@ static int __init opal_init_early(void)
 
 		memset(&opal_os_ops, 0, sizeof(opal_os_ops));
 		opal_os_ops.os_printf = cpu_to_be64(&os_printf);
+		opal_os_ops.os_vm_map = cpu_to_be64(&os_vm_map);
+		opal_os_ops.os_vm_unmap = cpu_to_be64(&os_vm_unmap);
 		if (opal_register_os_ops(&opal_os_ops, sizeof(opal_os_ops))) {
 			pr_warn("OPAL register OS ops failed, firmware will run in v3 mode.\n");
 		} else {
-- 
2.23.0



More information about the Linuxppc-dev mailing list