backports: backport some memory functions
authorHauke Mehrtens <hauke@hauke-m.de>
Thu, 6 Jun 2013 11:48:04 +0000 (13:48 +0200)
committerLuis R. Rodriguez <mcgrof@do-not-panic.com>
Wed, 12 Jun 2013 21:50:29 +0000 (14:50 -0700)
This includes the following functions needed by some drm drivers:
arch_phys_wc_add()
arch_phys_wc_del()
phys_wc_to_mtrr_index()

This backports the following commit form mainline kernel:
commit d0d98eedee2178c803dd824bb09f52b0e2ac1811
Author: Andy Lutomirski <luto@amacapital.net>
Date:   Mon May 13 23:58:40 2013 +0000

    Add arch_phys_wc_{add, del} to manipulate WC MTRRs if needed

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
backport/backport-include/asm/mtrr.h [new file with mode: 0644]
backport/backport-include/linux/io.h [new file with mode: 0644]
backport/compat/Makefile
backport/compat/backport-3.11.c [new file with mode: 0644]

diff --git a/backport/backport-include/asm/mtrr.h b/backport/backport-include/asm/mtrr.h
new file mode 100644 (file)
index 0000000..cf0f6fd
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __BACKPORT_ASM_MTRR_H
+#define __BACKPORT_ASM_MTRR_H
+#include_next <asm/mtrr.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
+/*
+ * The following functions are for use by other drivers that cannot use
+ * arch_phys_wc_add and arch_phys_wc_del.
+ */
+#ifdef CONFIG_MTRR
+extern int phys_wc_to_mtrr_index(int handle);
+#else
+static inline int phys_wc_to_mtrr_index(int handle)
+{
+       return -1;
+}
+#endif /* CONFIG_MTRR */
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)) */
+
+#endif /* __BACKPORT_ASM_MTRR_H */
diff --git a/backport/backport-include/linux/io.h b/backport/backport-include/linux/io.h
new file mode 100644 (file)
index 0000000..9a5b308
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __BACKPORT_LINUX_IO_H
+#define __BACKPORT_LINUX_IO_H
+#include_next <linux/io.h>
+
+/*
+ * Some systems (x86 without PAT) have a somewhat reliable way to mark a
+ * physical address range such that uncached mappings will actually
+ * end up write-combining.  This facility should be used in conjunction
+ * with pgprot_writecombine, ioremap-wc, or set_memory_wc, since it has
+ * no effect if the per-page mechanisms are functional.
+ * (On x86 without PAT, these functions manipulate MTRRs.)
+ *
+ * arch_phys_del_wc(0) or arch_phys_del_wc(any error code) is guaranteed
+ * to have no effect.
+ */
+#ifndef arch_phys_wc_add
+#ifdef CONFIG_MTRR
+extern int __must_check arch_phys_wc_add(unsigned long base,
+                                        unsigned long size);
+extern void arch_phys_wc_del(int handle);
+#else
+static inline int __must_check arch_phys_wc_add(unsigned long base,
+                                               unsigned long size)
+{
+       return 0;  /* It worked (i.e. did nothing). */
+}
+
+static inline void arch_phys_wc_del(int handle)
+{
+}
+#endif /* CONFIG_MTRR */
+
+#define arch_phys_wc_add arch_phys_wc_add
+#endif
+
+#endif /* __BACKPORT_LINUX_IO_H */
index 18df1561121d27e2950e30b2f3e0134584b43401..252290e315c53057c75679c30fdb6dca34175e8f 100644 (file)
@@ -35,6 +35,7 @@ compat-$(CPTCFG_BACKPORT_KERNEL_3_7) += compat-3.7.o
 compat-$(CPTCFG_BACKPORT_KERNEL_3_8) += compat-3.8.o
 compat-$(CPTCFG_BACKPORT_KERNEL_3_9) += compat-3.9.o
 compat-$(CPTCFG_BACKPORT_KERNEL_3_10) += backport-3.10.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_11) += backport-3.11.o
 
 compat-$(CPTCFG_BACKPORT_BUILD_KFIFO) += kfifo.o
 compat-$(CPTCFG_BACKPORT_BUILD_GENERIC_ATOMIC64) += compat_atomic.o
diff --git a/backport/compat/backport-3.11.c b/backport/compat/backport-3.11.c
new file mode 100644 (file)
index 0000000..72e0800
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013  Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Compatibility file for Linux wireless for kernels 3.11.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+
+#ifdef CONFIG_MTRR
+
+#include <asm/mtrr.h>
+#include <asm/cpufeature.h>
+#include <linux/io.h>
+
+/* arch_phys_wc_add returns an MTRR register index plus this offset. */
+#define MTRR_TO_PHYS_WC_OFFSET 1000
+
+/**
+ * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable
+ * @base: Physical base address
+ * @size: Size of region
+ *
+ * If PAT is available, this does nothing.  If PAT is unavailable, it
+ * attempts to add a WC MTRR covering size bytes starting at base and
+ * logs an error if this fails.
+ *
+ * Drivers must store the return value to pass to mtrr_del_wc_if_needed,
+ * but drivers should not try to interpret that return value.
+ */
+int arch_phys_wc_add(unsigned long base, unsigned long size)
+{
+       int ret;
+
+#if defined(CONFIG_X86_PAT)
+       if (cpu_has_pat)
+               return 0;
+#endif
+
+       ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
+       if (ret < 0) {
+               pr_warn("Failed to add WC MTRR for [%p-%p]; performance may suffer.",
+                       (void *)base, (void *)(base + size - 1));
+               return ret;
+       }
+       return ret + MTRR_TO_PHYS_WC_OFFSET;
+}
+EXPORT_SYMBOL(arch_phys_wc_add);
+
+/*
+ * arch_phys_wc_del - undoes arch_phys_wc_add
+ * @handle: Return value from arch_phys_wc_add
+ *
+ * This cleans up after mtrr_add_wc_if_needed.
+ *
+ * The API guarantees that mtrr_del_wc_if_needed(error code) and
+ * mtrr_del_wc_if_needed(0) do nothing.
+ */
+void arch_phys_wc_del(int handle)
+{
+       if (handle >= 1) {
+               WARN_ON(handle < MTRR_TO_PHYS_WC_OFFSET);
+               mtrr_del(handle - MTRR_TO_PHYS_WC_OFFSET, 0, 0);
+       }
+}
+EXPORT_SYMBOL(arch_phys_wc_del);
+
+/*
+ * phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value
+ * @handle: Return value from arch_phys_wc_add
+ *
+ * This will turn the return value from arch_phys_wc_add into an mtrr
+ * index suitable for debugging.
+ *
+ * Note: There is no legitimate use for this function, except possibly
+ * in printk line.  Alas there is an illegitimate use in some ancient
+ * drm ioctls.
+ */
+int phys_wc_to_mtrr_index(int handle)
+{
+       if (handle < MTRR_TO_PHYS_WC_OFFSET)
+               return -1;
+       else
+               return handle - MTRR_TO_PHYS_WC_OFFSET;
+}
+EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index);
+
+#endif /* CONFIG_MTRR */