Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 26 Jan 2009 17:47:28 +0000 (09:47 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 26 Jan 2009 17:47:28 +0000 (09:47 -0800)
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (29 commits)
  xen: unitialised return value in xenbus_write_transaction
  x86: fix section mismatch warning
  x86: unmask CPUID levels on Intel CPUs, fix
  x86: work around PAGE_KERNEL_WC not getting WC in iomap_atomic_prot_pfn.
  x86: use standard PIT frequency
  xen: handle highmem pages correctly when shrinking a domain
  x86, mm: fix pte_free()
  xen: actually release memory when shrinking domain
  x86: unmask CPUID levels on Intel CPUs
  x86: add MSR_IA32_MISC_ENABLE bits to <asm/msr-index.h>
  x86: fix PTE corruption issue while mapping RAM using /dev/mem
  x86: mtrr fix debug boot parameter
  x86: fix page attribute corruption with cpa()
  Revert "x86: signal: change type of paramter for sys_rt_sigreturn()"
  x86: use early clobbers in usercopy*.c
  x86: remove kernel_physical_mapping_init() from init section
  fix: crash: IP: __bitmap_intersects+0x48/0x73
  cpufreq: use work_on_cpu in acpi-cpufreq.c for drv_read and drv_write
  work_on_cpu: Use our own workqueue.
  work_on_cpu: don't try to get_online_cpus() in work_on_cpu.
  ...

1  2 
arch/x86/mm/pat.c

diff --combined arch/x86/mm/pat.c
index 8b08fb955274148454a2acaa538c78215322e655,ffc88cc00fda01be5aeabdea047cdd3fc9512d66..7b61036427df69d11a33044d60bc85102931e385
@@@ -333,11 -333,23 +333,23 @@@ int reserve_memtype(u64 start, u64 end
                                              req_type & _PAGE_CACHE_MASK);
        }
  
-       is_range_ram = pagerange_is_ram(start, end);
-       if (is_range_ram == 1)
-               return reserve_ram_pages_type(start, end, req_type, new_type);
-       else if (is_range_ram < 0)
-               return -EINVAL;
+       if (new_type)
+               *new_type = actual_type;
+       /*
+        * For legacy reasons, some parts of the physical address range in the
+        * legacy 1MB region is treated as non-RAM (even when listed as RAM in
+        * the e820 tables).  So we will track the memory attributes of this
+        * legacy 1MB region using the linear memtype_list always.
+        */
+       if (end >= ISA_END_ADDRESS) {
+               is_range_ram = pagerange_is_ram(start, end);
+               if (is_range_ram == 1)
+                       return reserve_ram_pages_type(start, end, req_type,
+                                                     new_type);
+               else if (is_range_ram < 0)
+                       return -EINVAL;
+       }
  
        new  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
        if (!new)
        new->end        = end;
        new->type       = actual_type;
  
-       if (new_type)
-               *new_type = actual_type;
        spin_lock(&memtype_lock);
  
        if (cached_entry && start >= cached_start)
@@@ -437,11 -446,19 +446,19 @@@ int free_memtype(u64 start, u64 end
        if (is_ISA_range(start, end - 1))
                return 0;
  
-       is_range_ram = pagerange_is_ram(start, end);
-       if (is_range_ram == 1)
-               return free_ram_pages_type(start, end);
-       else if (is_range_ram < 0)
-               return -EINVAL;
+       /*
+        * For legacy reasons, some parts of the physical address range in the
+        * legacy 1MB region is treated as non-RAM (even when listed as RAM in
+        * the e820 tables).  So we will track the memory attributes of this
+        * legacy 1MB region using the linear memtype_list always.
+        */
+       if (end >= ISA_END_ADDRESS) {
+               is_range_ram = pagerange_is_ram(start, end);
+               if (is_range_ram == 1)
+                       return free_ram_pages_type(start, end);
+               else if (is_range_ram < 0)
+                       return -EINVAL;
+       }
  
        spin_lock(&memtype_lock);
        list_for_each_entry(entry, &memtype_list, nd) {
@@@ -601,13 -618,12 +618,13 @@@ void unmap_devmem(unsigned long pfn, un
   * Reserved non RAM regions only and after successful reserve_memtype,
   * this func also keeps identity mapping (if any) in sync with this new prot.
   */
 -static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t vma_prot)
 +static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
 +                              int strict_prot)
  {
        int is_ram = 0;
        int id_sz, ret;
        unsigned long flags;
 -      unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
 +      unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK);
  
        is_ram = pagerange_is_ram(paddr, paddr + size);
  
                return ret;
  
        if (flags != want_flags) {
 -              free_memtype(paddr, paddr + size);
 -              printk(KERN_ERR
 -              "%s:%d map pfn expected mapping type %s for %Lx-%Lx, got %s\n",
 -                      current->comm, current->pid,
 -                      cattr_name(want_flags),
 -                      (unsigned long long)paddr,
 -                      (unsigned long long)(paddr + size),
 -                      cattr_name(flags));
 -              return -EINVAL;
 +              if (strict_prot || !is_new_memtype_allowed(want_flags, flags)) {
 +                      free_memtype(paddr, paddr + size);
 +                      printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
 +                              " for %Lx-%Lx, got %s\n",
 +                              current->comm, current->pid,
 +                              cattr_name(want_flags),
 +                              (unsigned long long)paddr,
 +                              (unsigned long long)(paddr + size),
 +                              cattr_name(flags));
 +                      return -EINVAL;
 +              }
 +              /*
 +               * We allow returning different type than the one requested in
 +               * non strict case.
 +               */
 +              *vma_prot = __pgprot((pgprot_val(*vma_prot) &
 +                                    (~_PAGE_CACHE_MASK)) |
 +                                   flags);
        }
  
        /* Need to keep identity mapping in sync */
@@@ -699,7 -706,6 +716,7 @@@ int track_pfn_vma_copy(struct vm_area_s
        unsigned long vma_start = vma->vm_start;
        unsigned long vma_end = vma->vm_end;
        unsigned long vma_size = vma_end - vma_start;
 +      pgprot_t pgprot;
  
        if (!pat_enabled)
                return 0;
                        WARN_ON_ONCE(1);
                        return -EINVAL;
                }
 -              return reserve_pfn_range(paddr, vma_size, __pgprot(prot));
 +              pgprot = __pgprot(prot);
 +              return reserve_pfn_range(paddr, vma_size, &pgprot, 1);
        }
  
        /* reserve entire vma page by page, using pfn and prot from pte */
                if (follow_phys(vma, vma_start + i, 0, &prot, &paddr))
                        continue;
  
 -              retval = reserve_pfn_range(paddr, PAGE_SIZE, __pgprot(prot));
 +              pgprot = __pgprot(prot);
 +              retval = reserve_pfn_range(paddr, PAGE_SIZE, &pgprot, 1);
                if (retval)
                        goto cleanup_ret;
        }
@@@ -754,7 -758,7 +771,7 @@@ cleanup_ret
   * Note that this function can be called with caller trying to map only a
   * subrange/page inside the vma.
   */
 -int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t prot,
 +int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot,
                        unsigned long pfn, unsigned long size)
  {
        int retval = 0;
        if (is_linear_pfn_mapping(vma)) {
                /* reserve the whole chunk starting from vm_pgoff */
                paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
 -              return reserve_pfn_range(paddr, vma_size, prot);
 +              return reserve_pfn_range(paddr, vma_size, prot, 0);
        }
  
        /* reserve page by page using pfn and size */
        base_paddr = (resource_size_t)pfn << PAGE_SHIFT;
        for (i = 0; i < size; i += PAGE_SIZE) {
                paddr = base_paddr + i;
 -              retval = reserve_pfn_range(paddr, PAGE_SIZE, prot);
 +              retval = reserve_pfn_range(paddr, PAGE_SIZE, prot, 0);
                if (retval)
                        goto cleanup_ret;
        }