]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
sparc64 patches from DaveM
authorChris Wright <chrisw@sous-sol.org>
Mon, 5 Jun 2006 19:09:40 +0000 (12:09 -0700)
committerChris Wright <chrisw@sous-sol.org>
Mon, 5 Jun 2006 19:09:40 +0000 (12:09 -0700)
queue-2.6.16/series
queue-2.6.16/sparc64-fix-d-cache-corruption-in-mremap.patch [new file with mode: 0644]
queue-2.6.16/sparc64-fix-missing-fold-at-end-of-checksums.patch [new file with mode: 0644]
queue-2.6.16/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch [new file with mode: 0644]

index 507b183da17ad393a418ec7c8d1ce6a3884ff052..e722024a5ff0e4d83721400263f7277719a36eb0 100644 (file)
@@ -1 +1,4 @@
 usb-whiteheat-fix-firmware-spurious-errors.patch
+sparc64-fix-d-cache-corruption-in-mremap.patch
+sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch
+sparc64-fix-missing-fold-at-end-of-checksums.patch
diff --git a/queue-2.6.16/sparc64-fix-d-cache-corruption-in-mremap.patch b/queue-2.6.16/sparc64-fix-d-cache-corruption-in-mremap.patch
new file mode 100644 (file)
index 0000000..7be4d58
--- /dev/null
@@ -0,0 +1,94 @@
+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];
diff --git a/queue-2.6.16/sparc64-fix-missing-fold-at-end-of-checksums.patch b/queue-2.6.16/sparc64-fix-missing-fold-at-end-of-checksums.patch
new file mode 100644 (file)
index 0000000..a539dba
--- /dev/null
@@ -0,0 +1,55 @@
+From stable-bounces@linux.kernel.org  Mon Jun  5 11:30:48 2006
+Date: Mon, 05 Jun 2006 11:27:10 -0700 (PDT)
+From: David Miller <davem@davemloft.net>
+To: stable@kernel.org
+Cc: 
+Subject: SPARC64: Fix missing fold at end of checksums.
+
+Both csum_partial() and the csum_partial_copy*() family of routines
+forget to do a final fold on the computed checksum value on sparc64.
+So do the standard Sparc "add + set condition codes, add carry"
+sequence, then make sure the high 32-bits of the return value are
+clear.
+
+Based upon some excellent detective work and debugging done by
+Richard Braun and Samuel Thibault.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ arch/sparc64/lib/checksum.S  |    5 +++--
+ arch/sparc64/lib/csum_copy.S |    5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- linux-2.6.16.20.orig/arch/sparc64/lib/checksum.S
++++ linux-2.6.16.20/arch/sparc64/lib/checksum.S
+@@ -165,8 +165,9 @@ csum_partial_end_cruft:
+       sll             %g1, 8, %g1
+       or              %o5, %g1, %o4
+-1:    add             %o2, %o4, %o2
++1:    addcc           %o2, %o4, %o2
++      addc            %g0, %o2, %o2
+ csum_partial_finish:
+       retl
+-       mov            %o2, %o0
++       srl            %o2, 0, %o0
+--- linux-2.6.16.20.orig/arch/sparc64/lib/csum_copy.S
++++ linux-2.6.16.20/arch/sparc64/lib/csum_copy.S
+@@ -221,11 +221,12 @@ FUNC_NAME:               /* %o0=src, %o1=dst, %o2=len
+       sll             %g1, 8, %g1
+       or              %o5, %g1, %o4
+-1:    add             %o3, %o4, %o3
++1:    addcc           %o3, %o4, %o3
++      addc            %g0, %o3, %o3
+ 70:
+       retl
+-       mov            %o3, %o0
++       srl            %o3, 0, %o0
+ 95:   mov             0, GLOBAL_SPARE
+       brlez,pn        %o2, 4f
diff --git a/queue-2.6.16/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch b/queue-2.6.16/sparc64-respect-gfp_t-argument-to-dma_alloc_coherent.patch
new file mode 100644 (file)
index 0000000..73a9d6e
--- /dev/null
@@ -0,0 +1,225 @@
+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,