diff options
author | David S. Miller <davem@davemloft.net> | 2006-05-23 05:07:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-05-23 05:07:22 -0400 |
commit | 42f142371e48fbc44956d57b4e506bb6ce673cd7 (patch) | |
tree | cbcf77d8bf8adc923c50e1fd53a8becd81952beb | |
parent | 353b28bafd1b962359a866ff263a7fad833d29a1 (diff) |
[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.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/kernel/pci_iommu.c | 4 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 4 | ||||
-rw-r--r-- | include/asm-sparc64/dma-mapping.h | 141 | ||||
-rw-r--r-- | include/asm-sparc64/pci.h | 4 |
4 files changed, 146 insertions, 7 deletions
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 8efbc139769d..82e5455134c6 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c | |||
@@ -218,7 +218,7 @@ static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) | |||
218 | * DMA for PCI device PDEV. Return non-NULL cpu-side address if | 218 | * DMA for PCI device PDEV. Return non-NULL cpu-side address if |
219 | * successful and set *DMA_ADDRP to the PCI side dma address. | 219 | * successful and set *DMA_ADDRP to the PCI side dma address. |
220 | */ | 220 | */ |
221 | static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) | 221 | static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) |
222 | { | 222 | { |
223 | struct pcidev_cookie *pcp; | 223 | struct pcidev_cookie *pcp; |
224 | struct pci_iommu *iommu; | 224 | struct pci_iommu *iommu; |
@@ -232,7 +232,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr | |||
232 | if (order >= 10) | 232 | if (order >= 10) |
233 | return NULL; | 233 | return NULL; |
234 | 234 | ||
235 | first_page = __get_free_pages(GFP_ATOMIC, order); | 235 | first_page = __get_free_pages(gfp, order); |
236 | if (first_page == 0UL) | 236 | if (first_page == 0UL) |
237 | return NULL; | 237 | return NULL; |
238 | memset((char *)first_page, 0, PAGE_SIZE << order); | 238 | memset((char *)first_page, 0, PAGE_SIZE << order); |
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 9e94db2573a2..2b7a1f316a93 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
@@ -154,7 +154,7 @@ static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, un | |||
154 | __clear_bit(i, arena->map); | 154 | __clear_bit(i, arena->map); |
155 | } | 155 | } |
156 | 156 | ||
157 | static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) | 157 | static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) |
158 | { | 158 | { |
159 | struct pcidev_cookie *pcp; | 159 | struct pcidev_cookie *pcp; |
160 | struct pci_iommu *iommu; | 160 | struct pci_iommu *iommu; |
@@ -169,7 +169,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr | |||
169 | 169 | ||
170 | npages = size >> IO_PAGE_SHIFT; | 170 | npages = size >> IO_PAGE_SHIFT; |
171 | 171 | ||
172 | first_page = __get_free_pages(GFP_ATOMIC, order); | 172 | first_page = __get_free_pages(gfp, order); |
173 | if (unlikely(first_page == 0UL)) | 173 | if (unlikely(first_page == 0UL)) |
174 | return NULL; | 174 | return NULL; |
175 | 175 | ||
diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index c7d5804ba76d..a8d39f23d43b 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h | |||
@@ -4,7 +4,146 @@ | |||
4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
5 | 5 | ||
6 | #ifdef CONFIG_PCI | 6 | #ifdef CONFIG_PCI |
7 | #include <asm-generic/dma-mapping.h> | 7 | |
8 | /* we implement the API below in terms of the existing PCI one, | ||
9 | * so include it */ | ||
10 | #include <linux/pci.h> | ||
11 | /* need struct page definitions */ | ||
12 | #include <linux/mm.h> | ||
13 | |||
14 | static inline int | ||
15 | dma_supported(struct device *dev, u64 mask) | ||
16 | { | ||
17 | BUG_ON(dev->bus != &pci_bus_type); | ||
18 | |||
19 | return pci_dma_supported(to_pci_dev(dev), mask); | ||
20 | } | ||
21 | |||
22 | static inline int | ||
23 | dma_set_mask(struct device *dev, u64 dma_mask) | ||
24 | { | ||
25 | BUG_ON(dev->bus != &pci_bus_type); | ||
26 | |||
27 | return pci_set_dma_mask(to_pci_dev(dev), dma_mask); | ||
28 | } | ||
29 | |||
30 | static inline void * | ||
31 | dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, | ||
32 | gfp_t flag) | ||
33 | { | ||
34 | BUG_ON(dev->bus != &pci_bus_type); | ||
35 | |||
36 | return pci_iommu_ops->alloc_consistent(to_pci_dev(dev), size, dma_handle, flag); | ||
37 | } | ||
38 | |||
39 | static inline void | ||
40 | dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, | ||
41 | dma_addr_t dma_handle) | ||
42 | { | ||
43 | BUG_ON(dev->bus != &pci_bus_type); | ||
44 | |||
45 | pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); | ||
46 | } | ||
47 | |||
48 | static inline dma_addr_t | ||
49 | dma_map_single(struct device *dev, void *cpu_addr, size_t size, | ||
50 | enum dma_data_direction direction) | ||
51 | { | ||
52 | BUG_ON(dev->bus != &pci_bus_type); | ||
53 | |||
54 | return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); | ||
55 | } | ||
56 | |||
57 | static inline void | ||
58 | dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | ||
59 | enum dma_data_direction direction) | ||
60 | { | ||
61 | BUG_ON(dev->bus != &pci_bus_type); | ||
62 | |||
63 | pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); | ||
64 | } | ||
65 | |||
66 | static inline dma_addr_t | ||
67 | dma_map_page(struct device *dev, struct page *page, | ||
68 | unsigned long offset, size_t size, | ||
69 | enum dma_data_direction direction) | ||
70 | { | ||
71 | BUG_ON(dev->bus != &pci_bus_type); | ||
72 | |||
73 | return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); | ||
74 | } | ||
75 | |||
76 | static inline void | ||
77 | dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, | ||
78 | enum dma_data_direction direction) | ||
79 | { | ||
80 | BUG_ON(dev->bus != &pci_bus_type); | ||
81 | |||
82 | pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); | ||
83 | } | ||
84 | |||
85 | static inline int | ||
86 | dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | ||
87 | enum dma_data_direction direction) | ||
88 | { | ||
89 | BUG_ON(dev->bus != &pci_bus_type); | ||
90 | |||
91 | return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); | ||
92 | } | ||
93 | |||
94 | static inline void | ||
95 | dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | ||
96 | enum dma_data_direction direction) | ||
97 | { | ||
98 | BUG_ON(dev->bus != &pci_bus_type); | ||
99 | |||
100 | pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); | ||
101 | } | ||
102 | |||
103 | static inline void | ||
104 | dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, | ||
105 | enum dma_data_direction direction) | ||
106 | { | ||
107 | BUG_ON(dev->bus != &pci_bus_type); | ||
108 | |||
109 | pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, | ||
110 | size, (int)direction); | ||
111 | } | ||
112 | |||
113 | static inline void | ||
114 | dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, | ||
115 | enum dma_data_direction direction) | ||
116 | { | ||
117 | BUG_ON(dev->bus != &pci_bus_type); | ||
118 | |||
119 | pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, | ||
120 | size, (int)direction); | ||
121 | } | ||
122 | |||
123 | static inline void | ||
124 | dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, | ||
125 | enum dma_data_direction direction) | ||
126 | { | ||
127 | BUG_ON(dev->bus != &pci_bus_type); | ||
128 | |||
129 | pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); | ||
130 | } | ||
131 | |||
132 | static inline void | ||
133 | dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, | ||
134 | enum dma_data_direction direction) | ||
135 | { | ||
136 | BUG_ON(dev->bus != &pci_bus_type); | ||
137 | |||
138 | pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); | ||
139 | } | ||
140 | |||
141 | static inline int | ||
142 | dma_mapping_error(dma_addr_t dma_addr) | ||
143 | { | ||
144 | return pci_dma_mapping_error(dma_addr); | ||
145 | } | ||
146 | |||
8 | #else | 147 | #else |
9 | 148 | ||
10 | struct device; | 149 | struct device; |
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 7c5a589ea437..e1ea67bc32f2 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h | |||
@@ -42,7 +42,7 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) | |||
42 | struct pci_dev; | 42 | struct pci_dev; |
43 | 43 | ||
44 | struct pci_iommu_ops { | 44 | struct pci_iommu_ops { |
45 | void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *); | 45 | void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *, gfp_t); |
46 | void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t); | 46 | void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t); |
47 | dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int); | 47 | dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int); |
48 | void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int); | 48 | void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int); |
@@ -59,7 +59,7 @@ extern struct pci_iommu_ops *pci_iommu_ops; | |||
59 | */ | 59 | */ |
60 | static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) | 60 | static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) |
61 | { | 61 | { |
62 | return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle); | 62 | return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle, GFP_ATOMIC); |
63 | } | 63 | } |
64 | 64 | ||
65 | /* Free and unmap a consistent DMA buffer. | 65 | /* Free and unmap a consistent DMA buffer. |