]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/mm/kmmio.c
Merge branch 'for-2.6.28' of git://git.kernel.dk/linux-2.6-block
[linux-2.6-omap-h63xx.git] / arch / x86 / mm / kmmio.c
index 3ad27b8504a5554bccf404744a4b97e79dcd474b..93d82038af4b541853420a48502df0fc4c9c2407 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <linux/list.h>
+#include <linux/rculist.h>
 #include <linux/spinlock.h>
 #include <linux/hash.h>
 #include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/kdebug.h>
 #include <linux/mutex.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/debugreg.h>
 #include <linux/mmiotrace.h>
 
@@ -104,11 +105,12 @@ static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
        return NULL;
 }
 
-static void set_page_present(unsigned long addr, bool present, int *pglevel)
+static void set_page_present(unsigned long addr, bool present,
+                                                       unsigned int *pglevel)
 {
        pteval_t pteval;
        pmdval_t pmdval;
-       int level;
+       unsigned int level;
        pmd_t *pmd;
        pte_t *pte = lookup_address(addr, &level);
 
@@ -145,15 +147,15 @@ static void set_page_present(unsigned long addr, bool present, int *pglevel)
 }
 
 /** Mark the given page as not present. Access to it will trigger a fault. */
-static void arm_kmmio_fault_page(unsigned long page, int *page_level)
+static void arm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
 {
-       set_page_present(page & PAGE_MASK, false, page_level);
+       set_page_present(page & PAGE_MASK, false, pglevel);
 }
 
 /** Mark the given page as present. */
-static void disarm_kmmio_fault_page(unsigned long page, int *page_level)
+static void disarm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
 {
-       set_page_present(page & PAGE_MASK, true, page_level);
+       set_page_present(page & PAGE_MASK, true, pglevel);
 }
 
 /*
@@ -351,11 +353,19 @@ static void release_kmmio_fault_page(unsigned long page,
        }
 }
 
+/*
+ * With page-unaligned ioremaps, one or two armed pages may contain
+ * addresses from outside the intended mapping. Events for these addresses
+ * are currently silently dropped. The events may result only from programming
+ * mistakes by accessing addresses before the beginning or past the end of a
+ * mapping.
+ */
 int register_kmmio_probe(struct kmmio_probe *p)
 {
        unsigned long flags;
        int ret = 0;
        unsigned long size = 0;
+       const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
 
        spin_lock_irqsave(&kmmio_lock, flags);
        if (get_kmmio_probe(p->addr)) {
@@ -364,7 +374,7 @@ int register_kmmio_probe(struct kmmio_probe *p)
        }
        kmmio_count++;
        list_add_rcu(&p->list, &kmmio_probes);
-       while (size < p->len) {
+       while (size < size_lim) {
                if (add_kmmio_fault_page(p->addr + size))
                        pr_err("kmmio: Unable to set page fault.\n");
                size += PAGE_SIZE;
@@ -436,11 +446,12 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
 {
        unsigned long flags;
        unsigned long size = 0;
+       const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
        struct kmmio_fault_page *release_list = NULL;
        struct kmmio_delayed_release *drelease;
 
        spin_lock_irqsave(&kmmio_lock, flags);
-       while (size < p->len) {
+       while (size < size_lim) {
                release_kmmio_fault_page(p->addr + size, &release_list);
                size += PAGE_SIZE;
        }