aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-06-13 14:46:40 -0400
committerChris Metcalf <cmetcalf@tilera.com>2012-07-18 16:40:05 -0400
commitbbaa22c3a0d0be4406d26e5a73d1e8e504787986 (patch)
tree4d00f1bda85d9735c60d7db1cdbdd215d5317ae4 /arch/tile/kernel
parent3e219b91533058e242b78ac08aaa91024dd6f369 (diff)
tilegx pci: support I/O to arbitrarily-cached pages
The tilegx PCI root complex support (currently only in linux-next) is limited to pages that are homed on cached in the default manner, i.e. "hash-for-home". This change supports delivery of I/O data to pages that are cached in other ways (locally on a particular core, uncached, user-managed incoherent, etc.). A large part of the change is supporting flushing pages from cache on particular homes so that we can transition the data that we are delivering to or from the device appropriately. The new homecache_finv* routines handle this. Some changes to page_table_range_init() were also required to make the fixmap code work correctly on tilegx; it hadn't been used there before. We also remove some stub mark_caches_evicted_*() routines that were just no-ops anyway. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/pci-dma.c182
1 files changed, 143 insertions, 39 deletions
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
index b3ed19f8779c..9814d7082f24 100644
--- a/arch/tile/kernel/pci-dma.c
+++ b/arch/tile/kernel/pci-dma.c
@@ -22,9 +22,15 @@
22/* Generic DMA mapping functions: */ 22/* Generic DMA mapping functions: */
23 23
24/* 24/*
25 * Allocate what Linux calls "coherent" memory, which for us just 25 * Allocate what Linux calls "coherent" memory. On TILEPro this is
26 * means uncached. 26 * uncached memory; on TILE-Gx it is hash-for-home memory.
27 */ 27 */
28#ifdef __tilepro__
29#define PAGE_HOME_DMA PAGE_HOME_UNCACHED
30#else
31#define PAGE_HOME_DMA PAGE_HOME_HASH
32#endif
33
28void *dma_alloc_coherent(struct device *dev, 34void *dma_alloc_coherent(struct device *dev,
29 size_t size, 35 size_t size,
30 dma_addr_t *dma_handle, 36 dma_addr_t *dma_handle,
@@ -48,13 +54,13 @@ void *dma_alloc_coherent(struct device *dev,
48 if (dma_mask <= DMA_BIT_MASK(32)) 54 if (dma_mask <= DMA_BIT_MASK(32))
49 node = 0; 55 node = 0;
50 56
51 pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_UNCACHED); 57 pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_DMA);
52 if (pg == NULL) 58 if (pg == NULL)
53 return NULL; 59 return NULL;
54 60
55 addr = page_to_phys(pg); 61 addr = page_to_phys(pg);
56 if (addr + size > dma_mask) { 62 if (addr + size > dma_mask) {
57 homecache_free_pages(addr, order); 63 __homecache_free_pages(pg, order);
58 return NULL; 64 return NULL;
59 } 65 }
60 66
@@ -87,22 +93,110 @@ EXPORT_SYMBOL(dma_free_coherent);
87 * can count on nothing having been touched. 93 * can count on nothing having been touched.
88 */ 94 */
89 95
90/* Flush a PA range from cache page by page. */ 96/* Set up a single page for DMA access. */
91static void __dma_map_pa_range(dma_addr_t dma_addr, size_t size) 97static void __dma_prep_page(struct page *page, unsigned long offset,
98 size_t size, enum dma_data_direction direction)
92{ 99{
93 struct page *page = pfn_to_page(PFN_DOWN(dma_addr)); 100 /*
94 size_t bytesleft = PAGE_SIZE - (dma_addr & (PAGE_SIZE - 1)); 101 * Flush the page from cache if necessary.
102 * On tilegx, data is delivered to hash-for-home L3; on tilepro,
103 * data is delivered direct to memory.
104 *
105 * NOTE: If we were just doing DMA_TO_DEVICE we could optimize
106 * this to be a "flush" not a "finv" and keep some of the
107 * state in cache across the DMA operation, but it doesn't seem
108 * worth creating the necessary flush_buffer_xxx() infrastructure.
109 */
110 int home = page_home(page);
111 switch (home) {
112 case PAGE_HOME_HASH:
113#ifdef __tilegx__
114 return;
115#endif
116 break;
117 case PAGE_HOME_UNCACHED:
118#ifdef __tilepro__
119 return;
120#endif
121 break;
122 case PAGE_HOME_IMMUTABLE:
123 /* Should be going to the device only. */
124 BUG_ON(direction == DMA_FROM_DEVICE ||
125 direction == DMA_BIDIRECTIONAL);
126 return;
127 case PAGE_HOME_INCOHERENT:
128 /* Incoherent anyway, so no need to work hard here. */
129 return;
130 default:
131 BUG_ON(home < 0 || home >= NR_CPUS);
132 break;
133 }
134 homecache_finv_page(page);
135
136#ifdef DEBUG_ALIGNMENT
137 /* Warn if the region isn't cacheline aligned. */
138 if (offset & (L2_CACHE_BYTES - 1) || (size & (L2_CACHE_BYTES - 1)))
139 pr_warn("Unaligned DMA to non-hfh memory: PA %#llx/%#lx\n",
140 PFN_PHYS(page_to_pfn(page)) + offset, size);
141#endif
142}
95 143
96 while ((ssize_t)size > 0) { 144/* Make the page ready to be read by the core. */
97 /* Flush the page. */ 145static void __dma_complete_page(struct page *page, unsigned long offset,
98 homecache_flush_cache(page++, 0); 146 size_t size, enum dma_data_direction direction)
147{
148#ifdef __tilegx__
149 switch (page_home(page)) {
150 case PAGE_HOME_HASH:
151 /* I/O device delivered data the way the cpu wanted it. */
152 break;
153 case PAGE_HOME_INCOHERENT:
154 /* Incoherent anyway, so no need to work hard here. */
155 break;
156 case PAGE_HOME_IMMUTABLE:
157 /* Extra read-only copies are not a problem. */
158 break;
159 default:
160 /* Flush the bogus hash-for-home I/O entries to memory. */
161 homecache_finv_map_page(page, PAGE_HOME_HASH);
162 break;
163 }
164#endif
165}
99 166
100 /* Figure out if we need to continue on the next page. */ 167static void __dma_prep_pa_range(dma_addr_t dma_addr, size_t size,
101 size -= bytesleft; 168 enum dma_data_direction direction)
102 bytesleft = PAGE_SIZE; 169{
170 struct page *page = pfn_to_page(PFN_DOWN(dma_addr));
171 unsigned long offset = dma_addr & (PAGE_SIZE - 1);
172 size_t bytes = min(size, (size_t)(PAGE_SIZE - offset));
173
174 while (size != 0) {
175 __dma_prep_page(page, offset, bytes, direction);
176 size -= bytes;
177 ++page;
178 offset = 0;
179 bytes = min((size_t)PAGE_SIZE, size);
180 }
181}
182
183static void __dma_complete_pa_range(dma_addr_t dma_addr, size_t size,
184 enum dma_data_direction direction)
185{
186 struct page *page = pfn_to_page(PFN_DOWN(dma_addr));
187 unsigned long offset = dma_addr & (PAGE_SIZE - 1);
188 size_t bytes = min(size, (size_t)(PAGE_SIZE - offset));
189
190 while (size != 0) {
191 __dma_complete_page(page, offset, bytes, direction);
192 size -= bytes;
193 ++page;
194 offset = 0;
195 bytes = min((size_t)PAGE_SIZE, size);
103 } 196 }
104} 197}
105 198
199
106/* 200/*
107 * dma_map_single can be passed any memory address, and there appear 201 * dma_map_single can be passed any memory address, and there appear
108 * to be no alignment constraints. 202 * to be no alignment constraints.
@@ -111,28 +205,29 @@ static void __dma_map_pa_range(dma_addr_t dma_addr, size_t size)
111 * line with some other data that has been touched in the meantime. 205 * line with some other data that has been touched in the meantime.
112 */ 206 */
113dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, 207dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
114 enum dma_data_direction direction) 208 enum dma_data_direction direction)
115{ 209{
116 dma_addr_t dma_addr = __pa(ptr); 210 dma_addr_t dma_addr = __pa(ptr);
117 211
118 BUG_ON(!valid_dma_direction(direction)); 212 BUG_ON(!valid_dma_direction(direction));
119 WARN_ON(size == 0); 213 WARN_ON(size == 0);
120 214
121 __dma_map_pa_range(dma_addr, size); 215 __dma_prep_pa_range(dma_addr, size, direction);
122 216
123 return dma_addr; 217 return dma_addr;
124} 218}
125EXPORT_SYMBOL(dma_map_single); 219EXPORT_SYMBOL(dma_map_single);
126 220
127void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, 221void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
128 enum dma_data_direction direction) 222 enum dma_data_direction direction)
129{ 223{
130 BUG_ON(!valid_dma_direction(direction)); 224 BUG_ON(!valid_dma_direction(direction));
225 __dma_complete_pa_range(dma_addr, size, direction);
131} 226}
132EXPORT_SYMBOL(dma_unmap_single); 227EXPORT_SYMBOL(dma_unmap_single);
133 228
134int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents, 229int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
135 enum dma_data_direction direction) 230 enum dma_data_direction direction)
136{ 231{
137 struct scatterlist *sg; 232 struct scatterlist *sg;
138 int i; 233 int i;
@@ -143,17 +238,25 @@ int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
143 238
144 for_each_sg(sglist, sg, nents, i) { 239 for_each_sg(sglist, sg, nents, i) {
145 sg->dma_address = sg_phys(sg); 240 sg->dma_address = sg_phys(sg);
146 __dma_map_pa_range(sg->dma_address, sg->length); 241 __dma_prep_pa_range(sg->dma_address, sg->length, direction);
147 } 242 }
148 243
149 return nents; 244 return nents;
150} 245}
151EXPORT_SYMBOL(dma_map_sg); 246EXPORT_SYMBOL(dma_map_sg);
152 247
153void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, 248void dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
154 enum dma_data_direction direction) 249 enum dma_data_direction direction)
155{ 250{
251 struct scatterlist *sg;
252 int i;
253
156 BUG_ON(!valid_dma_direction(direction)); 254 BUG_ON(!valid_dma_direction(direction));
255 for_each_sg(sglist, sg, nents, i) {
256 sg->dma_address = sg_phys(sg);
257 __dma_complete_pa_range(sg->dma_address, sg->length,
258 direction);
259 }
157} 260}
158EXPORT_SYMBOL(dma_unmap_sg); 261EXPORT_SYMBOL(dma_unmap_sg);
159 262
@@ -164,16 +267,17 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
164 BUG_ON(!valid_dma_direction(direction)); 267 BUG_ON(!valid_dma_direction(direction));
165 268
166 BUG_ON(offset + size > PAGE_SIZE); 269 BUG_ON(offset + size > PAGE_SIZE);
167 homecache_flush_cache(page, 0); 270 __dma_prep_page(page, offset, size, direction);
168
169 return page_to_pa(page) + offset; 271 return page_to_pa(page) + offset;
170} 272}
171EXPORT_SYMBOL(dma_map_page); 273EXPORT_SYMBOL(dma_map_page);
172 274
173void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, 275void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
174 enum dma_data_direction direction) 276 enum dma_data_direction direction)
175{ 277{
176 BUG_ON(!valid_dma_direction(direction)); 278 BUG_ON(!valid_dma_direction(direction));
279 __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
280 dma_address & PAGE_OFFSET, size, direction);
177} 281}
178EXPORT_SYMBOL(dma_unmap_page); 282EXPORT_SYMBOL(dma_unmap_page);
179 283
@@ -181,33 +285,33 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
181 size_t size, enum dma_data_direction direction) 285 size_t size, enum dma_data_direction direction)
182{ 286{
183 BUG_ON(!valid_dma_direction(direction)); 287 BUG_ON(!valid_dma_direction(direction));
288 __dma_complete_pa_range(dma_handle, size, direction);
184} 289}
185EXPORT_SYMBOL(dma_sync_single_for_cpu); 290EXPORT_SYMBOL(dma_sync_single_for_cpu);
186 291
187void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, 292void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
188 size_t size, enum dma_data_direction direction) 293 size_t size, enum dma_data_direction direction)
189{ 294{
190 unsigned long start = PFN_DOWN(dma_handle); 295 __dma_prep_pa_range(dma_handle, size, direction);
191 unsigned long end = PFN_DOWN(dma_handle + size - 1);
192 unsigned long i;
193
194 BUG_ON(!valid_dma_direction(direction));
195 for (i = start; i <= end; ++i)
196 homecache_flush_cache(pfn_to_page(i), 0);
197} 296}
198EXPORT_SYMBOL(dma_sync_single_for_device); 297EXPORT_SYMBOL(dma_sync_single_for_device);
199 298
200void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, 299void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist,
201 enum dma_data_direction direction) 300 int nelems, enum dma_data_direction direction)
202{ 301{
302 struct scatterlist *sg;
303 int i;
304
203 BUG_ON(!valid_dma_direction(direction)); 305 BUG_ON(!valid_dma_direction(direction));
204 WARN_ON(nelems == 0 || sg[0].length == 0); 306 WARN_ON(nelems == 0 || sglist->length == 0);
307
308 for_each_sg(sglist, sg, nelems, i) {
309 dma_sync_single_for_cpu(dev, sg->dma_address,
310 sg_dma_len(sg), direction);
311 }
205} 312}
206EXPORT_SYMBOL(dma_sync_sg_for_cpu); 313EXPORT_SYMBOL(dma_sync_sg_for_cpu);
207 314
208/*
209 * Flush and invalidate cache for scatterlist.
210 */
211void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, 315void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
212 int nelems, enum dma_data_direction direction) 316 int nelems, enum dma_data_direction direction)
213{ 317{
@@ -242,8 +346,8 @@ void dma_sync_single_range_for_device(struct device *dev,
242EXPORT_SYMBOL(dma_sync_single_range_for_device); 346EXPORT_SYMBOL(dma_sync_single_range_for_device);
243 347
244/* 348/*
245 * dma_alloc_noncoherent() returns non-cacheable memory, so there's no 349 * dma_alloc_noncoherent() is #defined to return coherent memory,
246 * need to do any flushing here. 350 * so there's no need to do any flushing here.
247 */ 351 */
248void dma_cache_sync(struct device *dev, void *vaddr, size_t size, 352void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
249 enum dma_data_direction direction) 353 enum dma_data_direction direction)