aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm/pmb.c
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2009-12-14 13:23:03 -0500
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2009-12-14 13:23:03 -0500
commit559300bc0ef7ccd541656f1189d38e7088389559 (patch)
treecd1682881ca4246e9c5a1e8632be4bdd9d9706c6 /arch/sh/mm/pmb.c
parent5416bf33f92a4104dbcd6062bf377c8421ca3cfd (diff)
parent22763c5cf3690a681551162c15d34d935308c8d7 (diff)
Merge commit 'v2.6.32'
Conflicts: arch/avr32/mach-at32ap/include/mach/cpu.h
Diffstat (limited to 'arch/sh/mm/pmb.c')
-rw-r--r--arch/sh/mm/pmb.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index b1a714a92b14..aade31102112 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -33,6 +33,8 @@
33 33
34#define NR_PMB_ENTRIES 16 34#define NR_PMB_ENTRIES 16
35 35
36static void __pmb_unmap(struct pmb_entry *);
37
36static struct kmem_cache *pmb_cache; 38static struct kmem_cache *pmb_cache;
37static unsigned long pmb_map; 39static unsigned long pmb_map;
38 40
@@ -218,9 +220,10 @@ static struct {
218long pmb_remap(unsigned long vaddr, unsigned long phys, 220long pmb_remap(unsigned long vaddr, unsigned long phys,
219 unsigned long size, unsigned long flags) 221 unsigned long size, unsigned long flags)
220{ 222{
221 struct pmb_entry *pmbp; 223 struct pmb_entry *pmbp, *pmbe;
222 unsigned long wanted; 224 unsigned long wanted;
223 int pmb_flags, i; 225 int pmb_flags, i;
226 long err;
224 227
225 /* Convert typical pgprot value to the PMB equivalent */ 228 /* Convert typical pgprot value to the PMB equivalent */
226 if (flags & _PAGE_CACHABLE) { 229 if (flags & _PAGE_CACHABLE) {
@@ -236,20 +239,22 @@ long pmb_remap(unsigned long vaddr, unsigned long phys,
236 239
237again: 240again:
238 for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) { 241 for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
239 struct pmb_entry *pmbe;
240 int ret; 242 int ret;
241 243
242 if (size < pmb_sizes[i].size) 244 if (size < pmb_sizes[i].size)
243 continue; 245 continue;
244 246
245 pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag); 247 pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
246 if (IS_ERR(pmbe)) 248 if (IS_ERR(pmbe)) {
247 return PTR_ERR(pmbe); 249 err = PTR_ERR(pmbe);
250 goto out;
251 }
248 252
249 ret = set_pmb_entry(pmbe); 253 ret = set_pmb_entry(pmbe);
250 if (ret != 0) { 254 if (ret != 0) {
251 pmb_free(pmbe); 255 pmb_free(pmbe);
252 return -EBUSY; 256 err = -EBUSY;
257 goto out;
253 } 258 }
254 259
255 phys += pmb_sizes[i].size; 260 phys += pmb_sizes[i].size;
@@ -264,12 +269,25 @@ again:
264 pmbp->link = pmbe; 269 pmbp->link = pmbe;
265 270
266 pmbp = pmbe; 271 pmbp = pmbe;
272
273 /*
274 * Instead of trying smaller sizes on every iteration
275 * (even if we succeed in allocating space), try using
276 * pmb_sizes[i].size again.
277 */
278 i--;
267 } 279 }
268 280
269 if (size >= 0x1000000) 281 if (size >= 0x1000000)
270 goto again; 282 goto again;
271 283
272 return wanted - size; 284 return wanted - size;
285
286out:
287 if (pmbp)
288 __pmb_unmap(pmbp);
289
290 return err;
273} 291}
274 292
275void pmb_unmap(unsigned long addr) 293void pmb_unmap(unsigned long addr)
@@ -283,12 +301,19 @@ void pmb_unmap(unsigned long addr)
283 if (unlikely(!pmbe)) 301 if (unlikely(!pmbe))
284 return; 302 return;
285 303
304 __pmb_unmap(pmbe);
305}
306
307static void __pmb_unmap(struct pmb_entry *pmbe)
308{
286 WARN_ON(!test_bit(pmbe->entry, &pmb_map)); 309 WARN_ON(!test_bit(pmbe->entry, &pmb_map));
287 310
288 do { 311 do {
289 struct pmb_entry *pmblink = pmbe; 312 struct pmb_entry *pmblink = pmbe;
290 313
291 clear_pmb_entry(pmbe); 314 if (pmbe->entry != PMB_NO_ENTRY)
315 clear_pmb_entry(pmbe);
316
292 pmbe = pmblink->link; 317 pmbe = pmblink->link;
293 318
294 pmb_free(pmblink); 319 pmb_free(pmblink);