Merge tag 'stable/for-linus-3.19-rc0b-tag' of git://git.kernel.org/pub/scm/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 21:23:03 +0000 (13:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 21:23:03 +0000 (13:23 -0800)
Pull additional xen update from David Vrabel:
 "Xen: additional features for 3.19-rc0

   - Linear p2m for x86 PV guests which simplifies the p2m code,
     improves performance and will allow for > 512 GB PV guests in the
     future.

  A last-minute, configuration specific issue was discovered with this
  change which is why it was not included in my previous pull request.
  This is now been fixed and tested"

* tag 'stable/for-linus-3.19-rc0b-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen: switch to post-init routines in xen mmu.c earlier
  Revert "swiotlb-xen: pass dev_addr to swiotlb_tbl_unmap_single"
  xen: annotate xen_set_identity_and_remap_chunk() with __init
  xen: introduce helper functions to do safe read and write accesses
  xen: Speed up set_phys_to_machine() by using read-only mappings
  xen: switch to linear virtual mapped sparse p2m list
  xen: Hide get_phys_to_machine() to be able to tune common path
  x86: Introduce function to get pmd entry pointer
  xen: Delay invalidating extra memory
  xen: Delay m2p_override initialization
  xen: Delay remapping memory of pv-domain
  xen: use common page allocation function in p2m.c
  xen: Make functions static
  xen: fix some style issues in p2m.c

1  2 
arch/x86/include/asm/pgtable_types.h
arch/x86/mm/pageattr.c
arch/x86/xen/mmu.c
arch/x86/xen/xen-ops.h

                         _PAGE_SOFT_DIRTY | _PAGE_NUMA)
  #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_NUMA)
  
 -#define _PAGE_CACHE_MASK      (_PAGE_PCD | _PAGE_PWT)
 -#define _PAGE_CACHE_WB                (0)
 -#define _PAGE_CACHE_WC                (_PAGE_PWT)
 -#define _PAGE_CACHE_UC_MINUS  (_PAGE_PCD)
 -#define _PAGE_CACHE_UC                (_PAGE_PCD | _PAGE_PWT)
 +/*
 + * The cache modes defined here are used to translate between pure SW usage
 + * and the HW defined cache mode bits and/or PAT entries.
 + *
 + * The resulting bits for PWT, PCD and PAT should be chosen in a way
 + * to have the WB mode at index 0 (all bits clear). This is the default
 + * right now and likely would break too much if changed.
 + */
 +#ifndef __ASSEMBLY__
 +enum page_cache_mode {
 +      _PAGE_CACHE_MODE_WB = 0,
 +      _PAGE_CACHE_MODE_WC = 1,
 +      _PAGE_CACHE_MODE_UC_MINUS = 2,
 +      _PAGE_CACHE_MODE_UC = 3,
 +      _PAGE_CACHE_MODE_WT = 4,
 +      _PAGE_CACHE_MODE_WP = 5,
 +      _PAGE_CACHE_MODE_NUM = 8
 +};
 +#endif
 +
 +#define _PAGE_CACHE_MASK      (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)
 +#define _PAGE_NOCACHE         (cachemode2protval(_PAGE_CACHE_MODE_UC))
  
  #define PAGE_NONE     __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
  #define PAGE_SHARED   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
  
  #define __PAGE_KERNEL_RO              (__PAGE_KERNEL & ~_PAGE_RW)
  #define __PAGE_KERNEL_RX              (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
 -#define __PAGE_KERNEL_EXEC_NOCACHE    (__PAGE_KERNEL_EXEC | _PAGE_PCD | _PAGE_PWT)
 -#define __PAGE_KERNEL_WC              (__PAGE_KERNEL | _PAGE_CACHE_WC)
 -#define __PAGE_KERNEL_NOCACHE         (__PAGE_KERNEL | _PAGE_PCD | _PAGE_PWT)
 -#define __PAGE_KERNEL_UC_MINUS                (__PAGE_KERNEL | _PAGE_PCD)
 +#define __PAGE_KERNEL_NOCACHE         (__PAGE_KERNEL | _PAGE_NOCACHE)
  #define __PAGE_KERNEL_VSYSCALL                (__PAGE_KERNEL_RX | _PAGE_USER)
  #define __PAGE_KERNEL_VVAR            (__PAGE_KERNEL_RO | _PAGE_USER)
 -#define __PAGE_KERNEL_VVAR_NOCACHE    (__PAGE_KERNEL_VVAR | _PAGE_PCD | _PAGE_PWT)
  #define __PAGE_KERNEL_LARGE           (__PAGE_KERNEL | _PAGE_PSE)
 -#define __PAGE_KERNEL_LARGE_NOCACHE   (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
  #define __PAGE_KERNEL_LARGE_EXEC      (__PAGE_KERNEL_EXEC | _PAGE_PSE)
  
  #define __PAGE_KERNEL_IO              (__PAGE_KERNEL)
  #define __PAGE_KERNEL_IO_NOCACHE      (__PAGE_KERNEL_NOCACHE)
 -#define __PAGE_KERNEL_IO_UC_MINUS     (__PAGE_KERNEL_UC_MINUS)
 -#define __PAGE_KERNEL_IO_WC           (__PAGE_KERNEL_WC)
  
  #define PAGE_KERNEL                   __pgprot(__PAGE_KERNEL)
  #define PAGE_KERNEL_RO                        __pgprot(__PAGE_KERNEL_RO)
  #define PAGE_KERNEL_EXEC              __pgprot(__PAGE_KERNEL_EXEC)
  #define PAGE_KERNEL_RX                        __pgprot(__PAGE_KERNEL_RX)
 -#define PAGE_KERNEL_WC                        __pgprot(__PAGE_KERNEL_WC)
  #define PAGE_KERNEL_NOCACHE           __pgprot(__PAGE_KERNEL_NOCACHE)
 -#define PAGE_KERNEL_UC_MINUS          __pgprot(__PAGE_KERNEL_UC_MINUS)
 -#define PAGE_KERNEL_EXEC_NOCACHE      __pgprot(__PAGE_KERNEL_EXEC_NOCACHE)
  #define PAGE_KERNEL_LARGE             __pgprot(__PAGE_KERNEL_LARGE)
 -#define PAGE_KERNEL_LARGE_NOCACHE     __pgprot(__PAGE_KERNEL_LARGE_NOCACHE)
  #define PAGE_KERNEL_LARGE_EXEC                __pgprot(__PAGE_KERNEL_LARGE_EXEC)
  #define PAGE_KERNEL_VSYSCALL          __pgprot(__PAGE_KERNEL_VSYSCALL)
  #define PAGE_KERNEL_VVAR              __pgprot(__PAGE_KERNEL_VVAR)
 -#define PAGE_KERNEL_VVAR_NOCACHE      __pgprot(__PAGE_KERNEL_VVAR_NOCACHE)
  
  #define PAGE_KERNEL_IO                        __pgprot(__PAGE_KERNEL_IO)
  #define PAGE_KERNEL_IO_NOCACHE                __pgprot(__PAGE_KERNEL_IO_NOCACHE)
 -#define PAGE_KERNEL_IO_UC_MINUS               __pgprot(__PAGE_KERNEL_IO_UC_MINUS)
 -#define PAGE_KERNEL_IO_WC             __pgprot(__PAGE_KERNEL_IO_WC)
  
  /*         xwr */
  #define __P000        PAGE_NONE
@@@ -344,59 -341,6 +344,59 @@@ static inline pmdval_t pmdnuma_flags(pm
  #define pgprot_val(x) ((x).pgprot)
  #define __pgprot(x)   ((pgprot_t) { (x) } )
  
 +extern uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM];
 +extern uint8_t __pte2cachemode_tbl[8];
 +
 +#define __pte2cm_idx(cb)                              \
 +      ((((cb) >> (_PAGE_BIT_PAT - 2)) & 4) |          \
 +       (((cb) >> (_PAGE_BIT_PCD - 1)) & 2) |          \
 +       (((cb) >> _PAGE_BIT_PWT) & 1))
 +#define __cm_idx2pte(i)                                       \
 +      ((((i) & 4) << (_PAGE_BIT_PAT - 2)) |           \
 +       (((i) & 2) << (_PAGE_BIT_PCD - 1)) |           \
 +       (((i) & 1) << _PAGE_BIT_PWT))
 +
 +static inline unsigned long cachemode2protval(enum page_cache_mode pcm)
 +{
 +      if (likely(pcm == 0))
 +              return 0;
 +      return __cachemode2pte_tbl[pcm];
 +}
 +static inline pgprot_t cachemode2pgprot(enum page_cache_mode pcm)
 +{
 +      return __pgprot(cachemode2protval(pcm));
 +}
 +static inline enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
 +{
 +      unsigned long masked;
 +
 +      masked = pgprot_val(pgprot) & _PAGE_CACHE_MASK;
 +      if (likely(masked == 0))
 +              return 0;
 +      return __pte2cachemode_tbl[__pte2cm_idx(masked)];
 +}
 +static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot)
 +{
 +      pgprot_t new;
 +      unsigned long val;
 +
 +      val = pgprot_val(pgprot);
 +      pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
 +              ((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
 +      return new;
 +}
 +static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot)
 +{
 +      pgprot_t new;
 +      unsigned long val;
 +
 +      val = pgprot_val(pgprot);
 +      pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
 +                        ((val & _PAGE_PAT_LARGE) >>
 +                         (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
 +      return new;
 +}
 +
  
  typedef struct page *pgtable_t;
  
@@@ -452,6 -396,7 +452,7 @@@ static inline void update_page_count(in
  extern pte_t *lookup_address(unsigned long address, unsigned int *level);
  extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
                                    unsigned int *level);
+ extern pmd_t *lookup_pmd_address(unsigned long address);
  extern phys_addr_t slow_virt_to_phys(void *__address);
  extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
                                   unsigned numpages, unsigned long page_flags);
diff --combined arch/x86/mm/pageattr.c
@@@ -383,6 -383,26 +383,26 @@@ static pte_t *_lookup_address_cpa(struc
          return lookup_address(address, level);
  }
  
+ /*
+  * Lookup the PMD entry for a virtual address. Return a pointer to the entry
+  * or NULL if not present.
+  */
+ pmd_t *lookup_pmd_address(unsigned long address)
+ {
+       pgd_t *pgd;
+       pud_t *pud;
+       pgd = pgd_offset_k(address);
+       if (pgd_none(*pgd))
+               return NULL;
+       pud = pud_offset(pgd, address);
+       if (pud_none(*pud) || pud_large(*pud) || !pud_present(*pud))
+               return NULL;
+       return pmd_offset(pud, address);
+ }
  /*
   * This is necessary because __pa() does not work on some
   * kinds of memory, like vmalloc() or the alloc_remap()
@@@ -485,22 -505,13 +505,22 @@@ try_preserve_large_page(pte_t *kpte, un
  
        /*
         * We are safe now. Check whether the new pgprot is the same:
 +       * Convert protection attributes to 4k-format, as cpa->mask* are set
 +       * up accordingly.
         */
        old_pte = *kpte;
 -      old_prot = req_prot = pte_pgprot(old_pte);
 +      old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte));
  
        pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
        pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);
  
 +      /*
 +       * req_prot is in format of 4k pages. It must be converted to large
 +       * page format: the caching mode includes the PAT bit located at
 +       * different bit positions in the two formats.
 +       */
 +      req_prot = pgprot_4k_2_large(req_prot);
 +
        /*
         * Set the PSE and GLOBAL flags only if the PRESENT flag is
         * set otherwise pmd_present/pmd_huge will return true even on
@@@ -594,10 -605,13 +614,10 @@@ __split_large_page(struct cpa_data *cpa
  
        paravirt_alloc_pte(&init_mm, page_to_pfn(base));
        ref_prot = pte_pgprot(pte_clrhuge(*kpte));
 -      /*
 -       * If we ever want to utilize the PAT bit, we need to
 -       * update this function to make sure it's converted from
 -       * bit 12 to bit 7 when we cross from the 2MB level to
 -       * the 4K level:
 -       */
 -      WARN_ON_ONCE(pgprot_val(ref_prot) & _PAGE_PAT_LARGE);
 +
 +      /* promote PAT bit to correct position */
 +      if (level == PG_LEVEL_2M)
 +              ref_prot = pgprot_large_2_4k(ref_prot);
  
  #ifdef CONFIG_X86_64
        if (level == PG_LEVEL_1G) {
@@@ -885,7 -899,6 +905,7 @@@ static int populate_pmd(struct cpa_dat
  {
        unsigned int cur_pages = 0;
        pmd_t *pmd;
 +      pgprot_t pmd_pgprot;
  
        /*
         * Not on a 2M boundary?
        if (num_pages == cur_pages)
                return cur_pages;
  
 +      pmd_pgprot = pgprot_4k_2_large(pgprot);
 +
        while (end - start >= PMD_SIZE) {
  
                /*
  
                pmd = pmd_offset(pud, start);
  
 -              set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot)));
 +              set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE |
 +                                 massage_pgprot(pmd_pgprot)));
  
                start     += PMD_SIZE;
                cpa->pfn  += PMD_SIZE;
@@@ -959,7 -969,6 +979,7 @@@ static int populate_pud(struct cpa_dat
        pud_t *pud;
        unsigned long end;
        int cur_pages = 0;
 +      pgprot_t pud_pgprot;
  
        end = start + (cpa->numpages << PAGE_SHIFT);
  
                return cur_pages;
  
        pud = pud_offset(pgd, start);
 +      pud_pgprot = pgprot_4k_2_large(pgprot);
  
        /*
         * Map everything starting from the Gb boundary, possibly with 1G pages
         */
        while (end - start >= PUD_SIZE) {
 -              set_pud(pud, __pud(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot)));
 +              set_pud(pud, __pud(cpa->pfn | _PAGE_PSE |
 +                                 massage_pgprot(pud_pgprot)));
  
                start     += PUD_SIZE;
                cpa->pfn  += PUD_SIZE;
@@@ -1317,6 -1324,12 +1337,6 @@@ static int __change_page_attr_set_clr(s
        return 0;
  }
  
 -static inline int cache_attr(pgprot_t attr)
 -{
 -      return pgprot_val(attr) &
 -              (_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
 -}
 -
  static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                                    pgprot_t mask_set, pgprot_t mask_clr,
                                    int force_split, int in_flag,
         * No need to flush, when we did not set any of the caching
         * attributes:
         */
 -      cache = cache_attr(mask_set);
 +      cache = !!pgprot2cachemode(mask_set);
  
        /*
         * On success we use CLFLUSH, when the CPU supports it to
@@@ -1452,8 -1465,7 +1472,8 @@@ int _set_memory_uc(unsigned long addr, 
         * for now UC MINUS. see comments in ioremap_nocache()
         */
        return change_page_attr_set(&addr, numpages,
 -                                  __pgprot(_PAGE_CACHE_UC_MINUS), 0);
 +                                  cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
 +                                  0);
  }
  
  int set_memory_uc(unsigned long addr, int numpages)
         * for now UC MINUS. see comments in ioremap_nocache()
         */
        ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
 -                          _PAGE_CACHE_UC_MINUS, NULL);
 +                            _PAGE_CACHE_MODE_UC_MINUS, NULL);
        if (ret)
                goto out_err;
  
@@@ -1482,7 -1494,7 +1502,7 @@@ out_err
  EXPORT_SYMBOL(set_memory_uc);
  
  static int _set_memory_array(unsigned long *addr, int addrinarray,
 -              unsigned long new_type)
 +              enum page_cache_mode new_type)
  {
        int i, j;
        int ret;
        }
  
        ret = change_page_attr_set(addr, addrinarray,
 -                                  __pgprot(_PAGE_CACHE_UC_MINUS), 1);
 +                                 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
 +                                 1);
  
 -      if (!ret && new_type == _PAGE_CACHE_WC)
 +      if (!ret && new_type == _PAGE_CACHE_MODE_WC)
                ret = change_page_attr_set_clr(addr, addrinarray,
 -                                             __pgprot(_PAGE_CACHE_WC),
 +                                             cachemode2pgprot(
 +                                              _PAGE_CACHE_MODE_WC),
                                               __pgprot(_PAGE_CACHE_MASK),
                                               0, CPA_ARRAY, NULL);
        if (ret)
@@@ -1521,13 -1531,13 +1541,13 @@@ out_free
  
  int set_memory_array_uc(unsigned long *addr, int addrinarray)
  {
 -      return _set_memory_array(addr, addrinarray, _PAGE_CACHE_UC_MINUS);
 +      return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_UC_MINUS);
  }
  EXPORT_SYMBOL(set_memory_array_uc);
  
  int set_memory_array_wc(unsigned long *addr, int addrinarray)
  {
 -      return _set_memory_array(addr, addrinarray, _PAGE_CACHE_WC);
 +      return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WC);
  }
  EXPORT_SYMBOL(set_memory_array_wc);
  
@@@ -1537,12 -1547,10 +1557,12 @@@ int _set_memory_wc(unsigned long addr, 
        unsigned long addr_copy = addr;
  
        ret = change_page_attr_set(&addr, numpages,
 -                                  __pgprot(_PAGE_CACHE_UC_MINUS), 0);
 +                                 cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
 +                                 0);
        if (!ret) {
                ret = change_page_attr_set_clr(&addr_copy, numpages,
 -                                             __pgprot(_PAGE_CACHE_WC),
 +                                             cachemode2pgprot(
 +                                              _PAGE_CACHE_MODE_WC),
                                               __pgprot(_PAGE_CACHE_MASK),
                                               0, 0, NULL);
        }
@@@ -1557,7 -1565,7 +1577,7 @@@ int set_memory_wc(unsigned long addr, i
                return set_memory_uc(addr, numpages);
  
        ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
 -              _PAGE_CACHE_WC, NULL);
 +              _PAGE_CACHE_MODE_WC, NULL);
        if (ret)
                goto out_err;
  
@@@ -1576,7 -1584,6 +1596,7 @@@ EXPORT_SYMBOL(set_memory_wc)
  
  int _set_memory_wb(unsigned long addr, int numpages)
  {
 +      /* WB cache mode is hard wired to all cache attribute bits being 0 */
        return change_page_attr_clear(&addr, numpages,
                                      __pgprot(_PAGE_CACHE_MASK), 0);
  }
@@@ -1599,7 -1606,6 +1619,7 @@@ int set_memory_array_wb(unsigned long *
        int i;
        int ret;
  
 +      /* WB cache mode is hard wired to all cache attribute bits being 0 */
        ret = change_page_attr_clear(addr, addrinarray,
                                      __pgprot(_PAGE_CACHE_MASK), 1);
        if (ret)
@@@ -1662,7 -1668,7 +1682,7 @@@ int set_pages_uc(struct page *page, in
  EXPORT_SYMBOL(set_pages_uc);
  
  static int _set_pages_array(struct page **pages, int addrinarray,
 -              unsigned long new_type)
 +              enum page_cache_mode new_type)
  {
        unsigned long start;
        unsigned long end;
        }
  
        ret = cpa_set_pages_array(pages, addrinarray,
 -                      __pgprot(_PAGE_CACHE_UC_MINUS));
 -      if (!ret && new_type == _PAGE_CACHE_WC)
 +                      cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS));
 +      if (!ret && new_type == _PAGE_CACHE_MODE_WC)
                ret = change_page_attr_set_clr(NULL, addrinarray,
 -                                             __pgprot(_PAGE_CACHE_WC),
 +                                             cachemode2pgprot(
 +                                              _PAGE_CACHE_MODE_WC),
                                               __pgprot(_PAGE_CACHE_MASK),
                                               0, CPA_PAGES_ARRAY, pages);
        if (ret)
@@@ -1704,13 -1709,13 +1724,13 @@@ err_out
  
  int set_pages_array_uc(struct page **pages, int addrinarray)
  {
 -      return _set_pages_array(pages, addrinarray, _PAGE_CACHE_UC_MINUS);
 +      return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_UC_MINUS);
  }
  EXPORT_SYMBOL(set_pages_array_uc);
  
  int set_pages_array_wc(struct page **pages, int addrinarray)
  {
 -      return _set_pages_array(pages, addrinarray, _PAGE_CACHE_WC);
 +      return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WC);
  }
  EXPORT_SYMBOL(set_pages_array_wc);
  
@@@ -1729,7 -1734,6 +1749,7 @@@ int set_pages_array_wb(struct page **pa
        unsigned long end;
        int i;
  
 +      /* WB cache mode is hard wired to all cache attribute bits being 0 */
        retval = cpa_clear_pages_array(pages, addrinarray,
                        __pgprot(_PAGE_CACHE_MASK));
        if (retval)
@@@ -1817,7 -1821,7 +1837,7 @@@ static int __set_pages_np(struct page *
        return __change_page_attr_set_clr(&cpa, 0);
  }
  
 -void kernel_map_pages(struct page *page, int numpages, int enable)
 +void __kernel_map_pages(struct page *page, int numpages, int enable)
  {
        if (PageHighMem(page))
                return;
diff --combined arch/x86/xen/mmu.c
@@@ -387,7 -387,7 +387,7 @@@ static pteval_t pte_pfn_to_mfn(pteval_
                unsigned long mfn;
  
                if (!xen_feature(XENFEAT_auto_translated_physmap))
-                       mfn = get_phys_to_machine(pfn);
+                       mfn = __pfn_to_mfn(pfn);
                else
                        mfn = pfn;
                /*
  __visible pteval_t xen_pte_val(pte_t pte)
  {
        pteval_t pteval = pte.pte;
 -#if 0
 -      /* If this is a WC pte, convert back from Xen WC to Linux WC */
 -      if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
 -              WARN_ON(!pat_enabled);
 -              pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
 -      }
 -#endif
 +
        return pte_mfn_to_pfn(pteval);
  }
  PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
@@@ -421,8 -427,47 +421,8 @@@ __visible pgdval_t xen_pgd_val(pgd_t pg
  }
  PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val);
  
 -/*
 - * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7
 - * are reserved for now, to correspond to the Intel-reserved PAT
 - * types.
 - *
 - * We expect Linux's PAT set as follows:
 - *
 - * Idx  PTE flags        Linux    Xen    Default
 - * 0                     WB       WB     WB
 - * 1            PWT      WC       WT     WT
 - * 2        PCD          UC-      UC-    UC-
 - * 3        PCD PWT      UC       UC     UC
 - * 4    PAT              WB       WC     WB
 - * 5    PAT     PWT      WC       WP     WT
 - * 6    PAT PCD          UC-      rsv    UC-
 - * 7    PAT PCD PWT      UC       rsv    UC
 - */
 -
 -void xen_set_pat(u64 pat)
 -{
 -      /* We expect Linux to use a PAT setting of
 -       * UC UC- WC WB (ignoring the PAT flag) */
 -      WARN_ON(pat != 0x0007010600070106ull);
 -}
 -
  __visible pte_t xen_make_pte(pteval_t pte)
  {
 -#if 0
 -      /* If Linux is trying to set a WC pte, then map to the Xen WC.
 -       * If _PAGE_PAT is set, then it probably means it is really
 -       * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
 -       * things work out OK...
 -       *
 -       * (We should never see kernel mappings with _PAGE_PSE set,
 -       * but we could see hugetlbfs mappings, I think.).
 -       */
 -      if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) {
 -              if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
 -                      pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
 -      }
 -#endif
        pte = pte_pfn_to_mfn(pte);
  
        return native_make_pte(pte);
@@@ -1113,20 -1158,16 +1113,16 @@@ static void __init xen_cleanhighmap(uns
         * instead of somewhere later and be confusing. */
        xen_mc_flush();
  }
- static void __init xen_pagetable_p2m_copy(void)
+ static void __init xen_pagetable_p2m_free(void)
  {
        unsigned long size;
        unsigned long addr;
-       unsigned long new_mfn_list;
-       if (xen_feature(XENFEAT_auto_translated_physmap))
-               return;
  
        size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
  
-       new_mfn_list = xen_revector_p2m_tree();
        /* No memory or already called. */
-       if (!new_mfn_list || new_mfn_list == xen_start_info->mfn_list)
+       if ((unsigned long)xen_p2m_addr == xen_start_info->mfn_list)
                return;
  
        /* using __ka address and sticking INVALID_P2M_ENTRY! */
  
        size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
        memblock_free(__pa(xen_start_info->mfn_list), size);
-       /* And revector! Bye bye old array */
-       xen_start_info->mfn_list = new_mfn_list;
  
        /* At this stage, cleanup_highmap has already cleaned __ka space
         * from _brk_limit way up to the max_pfn_mapped (which is the end of
  }
  #endif
  
- static void __init xen_pagetable_init(void)
+ static void __init xen_pagetable_p2m_setup(void)
  {
-       paging_init();
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return;
+       xen_vmalloc_p2m_tree();
  #ifdef CONFIG_X86_64
-       xen_pagetable_p2m_copy();
+       xen_pagetable_p2m_free();
  #endif
+       /* And revector! Bye bye old array */
+       xen_start_info->mfn_list = (unsigned long)xen_p2m_addr;
+ }
+ static void __init xen_pagetable_init(void)
+ {
+       paging_init();
+       xen_post_allocator_init();
+       xen_pagetable_p2m_setup();
        /* Allocate and initialize top and mid mfn levels for p2m structure */
        xen_build_mfn_list_list();
  
+       /* Remap memory freed due to conflicts with E820 map */
+       if (!xen_feature(XENFEAT_auto_translated_physmap))
+               xen_remap_memory();
        xen_setup_shared_info();
-       xen_post_allocator_init();
  }
  static void xen_write_cr2(unsigned long cr2)
  {
@@@ -1412,10 -1469,8 +1424,10 @@@ static int xen_pgd_alloc(struct mm_stru
                page->private = (unsigned long)user_pgd;
  
                if (user_pgd != NULL) {
 +#ifdef CONFIG_X86_VSYSCALL_EMULATION
                        user_pgd[pgd_index(VSYSCALL_ADDR)] =
                                __pgd(__pa(level3_user_vsyscall) | _PAGE_TABLE);
 +#endif
                        ret = 0;
                }
  
@@@ -1978,7 -2033,7 +1990,7 @@@ static void xen_set_fixmap(unsigned idx
  # ifdef CONFIG_HIGHMEM
        case FIX_KMAP_BEGIN ... FIX_KMAP_END:
  # endif
 -#else
 +#elif defined(CONFIG_X86_VSYSCALL_EMULATION)
        case VSYSCALL_PAGE:
  #endif
        case FIX_TEXT_POKE0:
  
        __native_set_fixmap(idx, pte);
  
 -#ifdef CONFIG_X86_64
 +#ifdef CONFIG_X86_VSYSCALL_EMULATION
        /* Replicate changes to map the vsyscall page into the user
           pagetable vsyscall mapping. */
        if (idx == VSYSCALL_PAGE) {
diff --combined arch/x86/xen/xen-ops.h
@@@ -29,11 -29,14 +29,13 @@@ void xen_build_mfn_list_list(void)
  void xen_setup_machphys_mapping(void);
  void xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
  void xen_reserve_top(void);
- extern unsigned long xen_max_p2m_pfn;
  
  void xen_mm_pin_all(void);
  void xen_mm_unpin_all(void);
 -void xen_set_pat(u64);
  
+ unsigned long __ref xen_chk_extra_mem(unsigned long pfn);
+ void __init xen_inv_extra_mem(void);
+ void __init xen_remap_memory(void);
  char * __init xen_memory_setup(void);
  char * xen_auto_xlated_memory_setup(void);
  void __init xen_arch_setup(void);
@@@ -46,7 -49,7 +48,7 @@@ void xen_hvm_init_shared_info(void)
  void xen_unplug_emulated_devices(void);
  
  void __init xen_build_dynamic_phys_to_machine(void);
unsigned long __init xen_revector_p2m_tree(void);
void __init xen_vmalloc_p2m_tree(void);
  
  void xen_init_irq_ops(void);
  void xen_setup_timer(int cpu);