diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/mm/init.c | 147 |
1 files changed, 100 insertions, 47 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 11d2187990d4..598bfb3b0053 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -324,14 +324,59 @@ unsigned long kern_locked_tte_data; | |||
324 | unsigned long prom_pmd_phys __read_mostly; | 324 | unsigned long prom_pmd_phys __read_mostly; |
325 | unsigned int swapper_pgd_zero __read_mostly; | 325 | unsigned int swapper_pgd_zero __read_mostly; |
326 | 326 | ||
327 | void __init early_pgtable_allocfail(char *type) | 327 | /* Allocate power-of-2 aligned chunks from the end of the |
328 | * kernel image. Return physical address. | ||
329 | */ | ||
330 | static inline unsigned long early_alloc_phys(unsigned long size) | ||
328 | { | 331 | { |
329 | prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type); | 332 | unsigned long base; |
330 | prom_halt(); | 333 | |
334 | BUILD_BUG_ON(size & (size - 1)); | ||
335 | |||
336 | kern_size = (kern_size + (size - 1)) & ~(size - 1); | ||
337 | base = kern_base + kern_size; | ||
338 | kern_size += size; | ||
339 | |||
340 | return base; | ||
341 | } | ||
342 | |||
343 | static inline unsigned long load_phys32(unsigned long pa) | ||
344 | { | ||
345 | unsigned long val; | ||
346 | |||
347 | __asm__ __volatile__("lduwa [%1] %2, %0" | ||
348 | : "=&r" (val) | ||
349 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
350 | |||
351 | return val; | ||
352 | } | ||
353 | |||
354 | static inline unsigned long load_phys64(unsigned long pa) | ||
355 | { | ||
356 | unsigned long val; | ||
357 | |||
358 | __asm__ __volatile__("ldxa [%1] %2, %0" | ||
359 | : "=&r" (val) | ||
360 | : "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
361 | |||
362 | return val; | ||
363 | } | ||
364 | |||
365 | static inline void store_phys32(unsigned long pa, unsigned long val) | ||
366 | { | ||
367 | __asm__ __volatile__("stwa %0, [%1] %2" | ||
368 | : /* no outputs */ | ||
369 | : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
370 | } | ||
371 | |||
372 | static inline void store_phys64(unsigned long pa, unsigned long val) | ||
373 | { | ||
374 | __asm__ __volatile__("stxa %0, [%1] %2" | ||
375 | : /* no outputs */ | ||
376 | : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC)); | ||
331 | } | 377 | } |
332 | 378 | ||
333 | #define BASE_PAGE_SIZE 8192 | 379 | #define BASE_PAGE_SIZE 8192 |
334 | static pmd_t *prompmd; | ||
335 | 380 | ||
336 | /* | 381 | /* |
337 | * Translate PROM's mapping we capture at boot time into physical address. | 382 | * Translate PROM's mapping we capture at boot time into physical address. |
@@ -339,33 +384,34 @@ static pmd_t *prompmd; | |||
339 | */ | 384 | */ |
340 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | 385 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) |
341 | { | 386 | { |
342 | pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); | 387 | unsigned long pmd_phys = (prom_pmd_phys + |
343 | pte_t *ptep; | 388 | ((promva >> 23) & 0x7ff) * sizeof(pmd_t)); |
389 | unsigned long pte_phys; | ||
390 | pmd_t pmd_ent; | ||
391 | pte_t pte_ent; | ||
344 | unsigned long base; | 392 | unsigned long base; |
345 | 393 | ||
346 | if (pmd_none(*pmdp)) { | 394 | pmd_val(pmd_ent) = load_phys32(pmd_phys); |
395 | if (pmd_none(pmd_ent)) { | ||
347 | if (error) | 396 | if (error) |
348 | *error = 1; | 397 | *error = 1; |
349 | return(0); | 398 | return 0; |
350 | } | 399 | } |
351 | ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff); | 400 | |
352 | if (!pte_present(*ptep)) { | 401 | pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; |
402 | pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t); | ||
403 | pte_val(pte_ent) = load_phys64(pte_phys); | ||
404 | if (!pte_present(pte_ent)) { | ||
353 | if (error) | 405 | if (error) |
354 | *error = 1; | 406 | *error = 1; |
355 | return(0); | 407 | return 0; |
356 | } | 408 | } |
357 | if (error) { | 409 | if (error) { |
358 | *error = 0; | 410 | *error = 0; |
359 | return(pte_val(*ptep)); | 411 | return pte_val(pte_ent); |
360 | } | 412 | } |
361 | base = pte_val(*ptep) & _PAGE_PADDR; | 413 | base = pte_val(pte_ent) & _PAGE_PADDR; |
362 | return(base + (promva & (BASE_PAGE_SIZE - 1))); | 414 | return (base + (promva & (BASE_PAGE_SIZE - 1))); |
363 | } | ||
364 | |||
365 | static inline int in_obp_range(unsigned long vaddr) | ||
366 | { | ||
367 | return (vaddr >= LOW_OBP_ADDRESS && | ||
368 | vaddr < HI_OBP_ADDRESS); | ||
369 | } | 415 | } |
370 | 416 | ||
371 | /* The obp translations are saved based on 8k pagesize, since obp can | 417 | /* The obp translations are saved based on 8k pagesize, since obp can |
@@ -378,22 +424,25 @@ static void build_obp_range(unsigned long start, unsigned long end, unsigned lon | |||
378 | unsigned long vaddr; | 424 | unsigned long vaddr; |
379 | 425 | ||
380 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { | 426 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { |
381 | unsigned long val; | 427 | unsigned long val, pte_phys, pmd_phys; |
382 | pmd_t *pmdp; | 428 | pmd_t pmd_ent; |
383 | pte_t *ptep; | 429 | int i; |
384 | 430 | ||
385 | pmdp = prompmd + ((vaddr >> 23) & 0x7ff); | 431 | pmd_phys = (prom_pmd_phys + |
386 | if (pmd_none(*pmdp)) { | 432 | (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t))); |
387 | ptep = __alloc_bootmem(BASE_PAGE_SIZE, | 433 | pmd_val(pmd_ent) = load_phys32(pmd_phys); |
388 | BASE_PAGE_SIZE, | 434 | if (pmd_none(pmd_ent)) { |
389 | bootmap_base); | 435 | pte_phys = early_alloc_phys(BASE_PAGE_SIZE); |
390 | if (ptep == NULL) | 436 | |
391 | early_pgtable_allocfail("pte"); | 437 | for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++) |
392 | memset(ptep, 0, BASE_PAGE_SIZE); | 438 | store_phys64(pte_phys+i*sizeof(pte_t),0); |
393 | pmd_set(pmdp, ptep); | 439 | |
440 | pmd_val(pmd_ent) = pte_phys >> 11UL; | ||
441 | store_phys32(pmd_phys, pmd_val(pmd_ent)); | ||
394 | } | 442 | } |
395 | ptep = (pte_t *)__pmd_page(*pmdp) + | 443 | |
396 | ((vaddr >> 13) & 0x3ff); | 444 | pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; |
445 | pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t)); | ||
397 | 446 | ||
398 | val = data; | 447 | val = data; |
399 | 448 | ||
@@ -401,22 +450,27 @@ static void build_obp_range(unsigned long start, unsigned long end, unsigned lon | |||
401 | if (tlb_type == spitfire) | 450 | if (tlb_type == spitfire) |
402 | val &= ~0x0003fe0000000000UL; | 451 | val &= ~0x0003fe0000000000UL; |
403 | 452 | ||
404 | set_pte_at(&init_mm, vaddr, | 453 | store_phys64(pte_phys, val | _PAGE_MODIFIED); |
405 | ptep, __pte(val | _PAGE_MODIFIED)); | 454 | |
406 | data += BASE_PAGE_SIZE; | 455 | data += BASE_PAGE_SIZE; |
407 | } | 456 | } |
408 | } | 457 | } |
409 | 458 | ||
459 | static inline int in_obp_range(unsigned long vaddr) | ||
460 | { | ||
461 | return (vaddr >= LOW_OBP_ADDRESS && | ||
462 | vaddr < HI_OBP_ADDRESS); | ||
463 | } | ||
464 | |||
410 | #define OBP_PMD_SIZE 2048 | 465 | #define OBP_PMD_SIZE 2048 |
411 | static void build_obp_pgtable(int prom_trans_ents) | 466 | static void build_obp_pgtable(int prom_trans_ents) |
412 | { | 467 | { |
413 | int i; | 468 | unsigned long i; |
469 | |||
470 | prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE); | ||
471 | for (i = 0; i < OBP_PMD_SIZE; i += 4) | ||
472 | store_phys32(prom_pmd_phys + i, 0); | ||
414 | 473 | ||
415 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, | ||
416 | bootmap_base); | ||
417 | if (prompmd == NULL) | ||
418 | early_pgtable_allocfail("pmd"); | ||
419 | memset(prompmd, 0, OBP_PMD_SIZE); | ||
420 | for (i = 0; i < prom_trans_ents; i++) { | 474 | for (i = 0; i < prom_trans_ents; i++) { |
421 | unsigned long start, end; | 475 | unsigned long start, end; |
422 | 476 | ||
@@ -430,7 +484,6 @@ static void build_obp_pgtable(int prom_trans_ents) | |||
430 | 484 | ||
431 | build_obp_range(start, end, prom_trans[i].data); | 485 | build_obp_range(start, end, prom_trans[i].data); |
432 | } | 486 | } |
433 | prom_pmd_phys = __pa(prompmd); | ||
434 | } | 487 | } |
435 | 488 | ||
436 | /* Read OBP translations property into 'prom_trans[]'. | 489 | /* Read OBP translations property into 'prom_trans[]'. |
@@ -1517,13 +1570,13 @@ void __init paging_init(void) | |||
1517 | 1570 | ||
1518 | swapper_pgd_zero = pgd_val(init_mm.pgd[0]); | 1571 | swapper_pgd_zero = pgd_val(init_mm.pgd[0]); |
1519 | 1572 | ||
1573 | /* Inherit non-locked OBP mappings. */ | ||
1574 | inherit_prom_mappings(); | ||
1575 | |||
1520 | /* Setup bootmem... */ | 1576 | /* Setup bootmem... */ |
1521 | pages_avail = 0; | 1577 | pages_avail = 0; |
1522 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); | 1578 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); |
1523 | 1579 | ||
1524 | /* Inherit non-locked OBP mappings. */ | ||
1525 | inherit_prom_mappings(); | ||
1526 | |||
1527 | /* Ok, we can use our TLB miss and window trap handlers safely. | 1580 | /* Ok, we can use our TLB miss and window trap handlers safely. |
1528 | * We need to do a quick peek here to see if we are on StarFire | 1581 | * We need to do a quick peek here to see if we are on StarFire |
1529 | * or not, so setup_tba can setup the IRQ globals correctly (it | 1582 | * or not, so setup_tba can setup the IRQ globals correctly (it |