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

Commit 10ce13bb authored by Laura Abbott's avatar Laura Abbott Committed by Vijayanand Jitta
Browse files

arm: highmem: Add support for flushing kmap_atomic mappings



The highmem code provides kmap_flush_unused to ensure all kmap
mappings are really removed if they are unused. This code does not
handle kmap_atomic mappings since they are managed separately.
This prevents an issue for any code which relies on having absolutely
no mappings for a particular page. Rather than pay the penalty of
having CONFIG_DEBUG_HIGHMEM on all the time, add functionality
to remove the kmap_atomic mappings in a similar way to kmap_flush_unused.

Change-Id: I9d73abad693c18f2daa1647353e7592b255475b0
Signed-off-by: default avatarLaura Abbott <lauraa@codeaurora.org>
parent 98055d18
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -230,6 +230,9 @@ config NEED_RET_TO_USER
config ARCH_MTD_XIP
	bool

config ARCH_WANT_KMAP_ATOMIC_FLUSH
	bool

config VECTORS_BASE
	hex
	default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -567,6 +570,7 @@ config ARCH_QCOM
       select SPARSE_IRQ
       select USE_OF
       select PINCTRL
       select ARCH_WANT_KMAP_ATOMIC_FLUSH
       help
         Support for Qualcomm MSM/QSD based systems.  This runs on the
         apps processor of the MSM/QSD and depends on a shared memory
+56 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 * published by the Free Software Foundation.
 */

#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
@@ -147,3 +148,58 @@ void *kmap_atomic_pfn(unsigned long pfn)

	return (void *)vaddr;
}

#ifdef CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH
static void kmap_remove_unused_cpu(int cpu)
{
	int start_idx, idx, type;

	pagefault_disable();
	type = kmap_atomic_idx();
	start_idx = type + 1 + KM_TYPE_NR * cpu;

	for (idx = start_idx; idx < KM_TYPE_NR + KM_TYPE_NR * cpu; idx++) {
		unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
		pte_t ptep;

		ptep = get_top_pte(vaddr);
		if (ptep)
			set_top_pte(vaddr, __pte(0));
	}
	pagefault_enable();
}

static void kmap_remove_unused(void *unused)
{
	kmap_remove_unused_cpu(smp_processor_id());
}

void kmap_atomic_flush_unused(void)
{
	on_each_cpu(kmap_remove_unused, NULL, 1);
}

static int hotplug_kmap_atomic_callback(struct notifier_block *nfb,
					unsigned long action, void *hcpu)
{
	switch (action & (~CPU_TASKS_FROZEN)) {
	case CPU_DYING:
		kmap_remove_unused_cpu((int)hcpu);
		break;
	default:
		break;
	}

	return NOTIFY_OK;
}

static struct notifier_block hotplug_kmap_atomic_notifier = {
	.notifier_call = hotplug_kmap_atomic_callback,
};

static int __init init_kmap_atomic(void)
{
	return register_hotcpu_notifier(&hotplug_kmap_atomic_notifier);
}
early_initcall(init_kmap_atomic);
#endif