--- /dev/null
+From stable-bounces@linux.kernel.org Fri Jun 2 18:34:53 2006
+Date: Fri, 02 Jun 2006 18:30:58 -0700 (PDT)
+From: David Miller <davem@davemloft.net>
+To: stable@kernel.org
+Cc:
+Subject: SPARC64: Fix D-cache corruption in mremap
+
+If we move a mapping from one virtual address to another,
+and this changes the virtual color of the mapping to those
+pages, we can see corrupt data due to D-cache aliasing.
+
+Check for and deal with this by overriding the move_pte()
+macro. Set things up so that other platforms can cleanly
+override the move_pte() macro too.
+
+This long standing bug corrupts user memory, and in particular
+has been notorious for corrupting Debian package database
+files on sparc64 boxes.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ include/asm-generic/pgtable.h | 11 +----------
+ include/asm-mips/pgtable.h | 10 +++++++++-
+ include/asm-sparc64/pgtable.h | 17 +++++++++++++++++
+ 3 files changed, 27 insertions(+), 11 deletions(-)
+
+--- linux-2.6.16.20.orig/include/asm-generic/pgtable.h
++++ linux-2.6.16.20/include/asm-generic/pgtable.h
+@@ -159,17 +159,8 @@ static inline void ptep_set_wrprotect(st
+ #define lazy_mmu_prot_update(pte) do { } while (0)
+ #endif
+
+-#ifndef __HAVE_ARCH_MULTIPLE_ZERO_PAGE
++#ifndef __HAVE_ARCH_MOVE_PTE
+ #define move_pte(pte, prot, old_addr, new_addr) (pte)
+-#else
+-#define move_pte(pte, prot, old_addr, new_addr) \
+-({ \
+- pte_t newpte = (pte); \
+- if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \
+- pte_page(pte) == ZERO_PAGE(old_addr)) \
+- newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \
+- newpte; \
+-})
+ #endif
+
+ /*
+--- linux-2.6.16.20.orig/include/asm-mips/pgtable.h
++++ linux-2.6.16.20/include/asm-mips/pgtable.h
+@@ -70,7 +70,15 @@ extern unsigned long zero_page_mask;
+ #define ZERO_PAGE(vaddr) \
+ (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask)))
+
+-#define __HAVE_ARCH_MULTIPLE_ZERO_PAGE
++#define __HAVE_ARCH_MOVE_PTE
++#define move_pte(pte, prot, old_addr, new_addr) \
++({ \
++ pte_t newpte = (pte); \
++ if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \
++ pte_page(pte) == ZERO_PAGE(old_addr)) \
++ newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \
++ newpte; \
++})
+
+ extern void paging_init(void);
+
+--- linux-2.6.16.20.orig/include/asm-sparc64/pgtable.h
++++ linux-2.6.16.20/include/asm-sparc64/pgtable.h
+@@ -335,6 +335,23 @@ static inline void set_pte_at(struct mm_
+ #define pte_clear(mm,addr,ptep) \
+ set_pte_at((mm), (addr), (ptep), __pte(0UL))
+
++#ifdef DCACHE_ALIASING_POSSIBLE
++#define __HAVE_ARCH_MOVE_PTE
++#define move_pte(pte, prot, old_addr, new_addr) \
++({ \
++ pte_t newpte = (pte); \
++ if (pte_present(pte)) { \
++ unsigned long this_pfn = pte_pfn(pte); \
++ \
++ if (pfn_valid(this_pfn) && \
++ (((old_addr) ^ (new_addr)) & (1 << 13))) \
++ flush_dcache_page_all(current->mm, \
++ pfn_to_page(this_pfn)); \
++ } \
++ newpte; \
++})
++#endif
++
+ extern pgd_t swapper_pg_dir[2048];
+ extern pmd_t swapper_low_pmd_dir[2048];
+
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Jun 4 20:44:37 2006
+Date: Sun, 04 Jun 2006 20:41:00 -0700 (PDT)
+From: David Miller <davem@davemloft.net>
+To: stable@kernel.org
+Cc:
+Subject: SPARC64: Respect gfp_t argument to dma_alloc_coherent().
+
+Using asm-generic/dma-mapping.h does not work because pushing
+the call down to pci_alloc_coherent() causes the gfp_t argument
+of dma_alloc_coherent() to be ignored.
+
+Fix this by implementing things directly, and adding a gfp_t
+argument we can use in the internal call down to the PCI DMA
+implementation of pci_alloc_coherent().
+
+This fixes massive memory corruption when using the sound driver
+layer, which passes things like __GFP_COMP down into these
+routines and (correctly) expects that to work.
+
+This is a disk eater when sound is used, so it's pretty critical.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ arch/sparc64/kernel/pci_iommu.c | 4 -
+ arch/sparc64/kernel/sparc64_ksyms.c | 2
+ include/asm-sparc64/dma-mapping.h | 141 +++++++++++++++++++++++++++++++++++-
+ include/asm-sparc64/pci.h | 4 -
+ 4 files changed, 146 insertions(+), 5 deletions(-)
+
+--- linux-2.6.16.20.orig/arch/sparc64/kernel/pci_iommu.c
++++ linux-2.6.16.20/arch/sparc64/kernel/pci_iommu.c
+@@ -219,7 +219,7 @@ static inline void iommu_free_ctx(struct
+ * DMA for PCI device PDEV. Return non-NULL cpu-side address if
+ * successful and set *DMA_ADDRP to the PCI side dma address.
+ */
+-void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
++void *__pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
+ {
+ struct pcidev_cookie *pcp;
+ struct pci_iommu *iommu;
+@@ -233,7 +233,7 @@ void *pci_alloc_consistent(struct pci_de
+ if (order >= 10)
+ return NULL;
+
+- first_page = __get_free_pages(GFP_ATOMIC, order);
++ first_page = __get_free_pages(gfp, order);
+ if (first_page == 0UL)
+ return NULL;
+ memset((char *)first_page, 0, PAGE_SIZE << order);
+--- linux-2.6.16.20.orig/arch/sparc64/kernel/sparc64_ksyms.c
++++ linux-2.6.16.20/arch/sparc64/kernel/sparc64_ksyms.c
+@@ -221,7 +221,7 @@ EXPORT_SYMBOL(insl);
+ EXPORT_SYMBOL(ebus_chain);
+ EXPORT_SYMBOL(isa_chain);
+ EXPORT_SYMBOL(pci_memspace_mask);
+-EXPORT_SYMBOL(pci_alloc_consistent);
++EXPORT_SYMBOL(__pci_alloc_consistent);
+ EXPORT_SYMBOL(pci_free_consistent);
+ EXPORT_SYMBOL(pci_map_single);
+ EXPORT_SYMBOL(pci_unmap_single);
+--- linux-2.6.16.20.orig/include/asm-sparc64/dma-mapping.h
++++ linux-2.6.16.20/include/asm-sparc64/dma-mapping.h
+@@ -4,7 +4,146 @@
+ #include <linux/config.h>
+
+ #ifdef CONFIG_PCI
+-#include <asm-generic/dma-mapping.h>
++
++/* we implement the API below in terms of the existing PCI one,
++ * so include it */
++#include <linux/pci.h>
++/* need struct page definitions */
++#include <linux/mm.h>
++
++static inline int
++dma_supported(struct device *dev, u64 mask)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return pci_dma_supported(to_pci_dev(dev), mask);
++}
++
++static inline int
++dma_set_mask(struct device *dev, u64 dma_mask)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
++}
++
++static inline void *
++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
++ gfp_t flag)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return __pci_alloc_consistent(to_pci_dev(dev), size, dma_handle, flag);
++}
++
++static inline void
++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
++ dma_addr_t dma_handle)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
++}
++
++static inline dma_addr_t
++dma_map_single(struct device *dev, void *cpu_addr, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
++}
++
++static inline void
++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
++}
++
++static inline dma_addr_t
++dma_map_page(struct device *dev, struct page *page,
++ unsigned long offset, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
++}
++
++static inline void
++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
++}
++
++static inline int
++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
++}
++
++static inline void
++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
++}
++
++static inline void
++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
++ size, (int)direction);
++}
++
++static inline void
++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
++ size, (int)direction);
++}
++
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
++ enum dma_data_direction direction)
++{
++ BUG_ON(dev->bus != &pci_bus_type);
++
++ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
++}
++
++static inline int
++dma_mapping_error(dma_addr_t dma_addr)
++{
++ return pci_dma_mapping_error(dma_addr);
++}
++
+ #else
+
+ struct device;
+--- linux-2.6.16.20.orig/include/asm-sparc64/pci.h
++++ linux-2.6.16.20/include/asm-sparc64/pci.h
+@@ -44,7 +44,9 @@ struct pci_dev;
+ /* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices.
+ */
+-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle);
++extern void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp);
++#define pci_alloc_consistent(DEV,SZ,HANDLE) \
++ __pci_alloc_consistent(DEV,SZ,HANDLE,GFP_ATOMIC)
+
+ /* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,