|
@@ -44,9 +44,6 @@ static inline void copy_from_user_page(struct vm_area_struct *vma,
|
|
|
memcpy(dst, src, len);
|
|
|
}
|
|
|
|
|
|
-#define PG_WC PG_arch_1
|
|
|
-PAGEFLAG(WC, WC)
|
|
|
-
|
|
|
#ifdef CONFIG_X86_PAT
|
|
|
/*
|
|
|
* X86 PAT uses page flags WC and Uncached together to keep track of
|
|
@@ -55,16 +52,24 @@ PAGEFLAG(WC, WC)
|
|
|
* _PAGE_CACHE_UC_MINUS and fourth state where page's memory type has not
|
|
|
* been changed from its default (value of -1 used to denote this).
|
|
|
* Note we do not support _PAGE_CACHE_UC here.
|
|
|
- *
|
|
|
- * Caller must hold memtype_lock for atomicity.
|
|
|
*/
|
|
|
+
|
|
|
+#define _PGMT_DEFAULT 0
|
|
|
+#define _PGMT_WC (1UL << PG_arch_1)
|
|
|
+#define _PGMT_UC_MINUS (1UL << PG_uncached)
|
|
|
+#define _PGMT_WB (1UL << PG_uncached | 1UL << PG_arch_1)
|
|
|
+#define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1)
|
|
|
+#define _PGMT_CLEAR_MASK (~_PGMT_MASK)
|
|
|
+
|
|
|
static inline unsigned long get_page_memtype(struct page *pg)
|
|
|
{
|
|
|
- if (!PageUncached(pg) && !PageWC(pg))
|
|
|
+ unsigned long pg_flags = pg->flags & _PGMT_MASK;
|
|
|
+
|
|
|
+ if (pg_flags == _PGMT_DEFAULT)
|
|
|
return -1;
|
|
|
- else if (!PageUncached(pg) && PageWC(pg))
|
|
|
+ else if (pg_flags == _PGMT_WC)
|
|
|
return _PAGE_CACHE_WC;
|
|
|
- else if (PageUncached(pg) && !PageWC(pg))
|
|
|
+ else if (pg_flags == _PGMT_UC_MINUS)
|
|
|
return _PAGE_CACHE_UC_MINUS;
|
|
|
else
|
|
|
return _PAGE_CACHE_WB;
|
|
@@ -72,25 +77,26 @@ static inline unsigned long get_page_memtype(struct page *pg)
|
|
|
|
|
|
static inline void set_page_memtype(struct page *pg, unsigned long memtype)
|
|
|
{
|
|
|
+ unsigned long memtype_flags = _PGMT_DEFAULT;
|
|
|
+ unsigned long old_flags;
|
|
|
+ unsigned long new_flags;
|
|
|
+
|
|
|
switch (memtype) {
|
|
|
case _PAGE_CACHE_WC:
|
|
|
- ClearPageUncached(pg);
|
|
|
- SetPageWC(pg);
|
|
|
+ memtype_flags = _PGMT_WC;
|
|
|
break;
|
|
|
case _PAGE_CACHE_UC_MINUS:
|
|
|
- SetPageUncached(pg);
|
|
|
- ClearPageWC(pg);
|
|
|
+ memtype_flags = _PGMT_UC_MINUS;
|
|
|
break;
|
|
|
case _PAGE_CACHE_WB:
|
|
|
- SetPageUncached(pg);
|
|
|
- SetPageWC(pg);
|
|
|
- break;
|
|
|
- default:
|
|
|
- case -1:
|
|
|
- ClearPageUncached(pg);
|
|
|
- ClearPageWC(pg);
|
|
|
+ memtype_flags = _PGMT_WB;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ do {
|
|
|
+ old_flags = pg->flags;
|
|
|
+ new_flags = (old_flags & _PGMT_CLEAR_MASK) | memtype_flags;
|
|
|
+ } while (cmpxchg(&pg->flags, old_flags, new_flags) != old_flags);
|
|
|
}
|
|
|
#else
|
|
|
static inline unsigned long get_page_memtype(struct page *pg) { return -1; }
|