aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/mm/init.c147
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;
324unsigned long prom_pmd_phys __read_mostly; 324unsigned long prom_pmd_phys __read_mostly;
325unsigned int swapper_pgd_zero __read_mostly; 325unsigned int swapper_pgd_zero __read_mostly;
326 326
327void __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 */
330static 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
343static 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
354static 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
365static 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
372static 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
334static 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 */
340unsigned long prom_virt_to_phys(unsigned long promva, int *error) 385unsigned 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
365static 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
459static 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
411static void build_obp_pgtable(int prom_trans_ents) 466static 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