diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-29 20:58:26 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-29 20:58:26 -0400 |
commit | 13edad7a5cef1c952459742482482a6b05e1a8a1 (patch) | |
tree | 4d1ddcbbb7fe5cda5e75c83e3d8511ed1642e201 /arch/sparc64/mm/init.c | |
parent | ed3ffaf7b5e0262cb860f106a6632933671cc88f (diff) |
[SPARC64]: Rewrite convoluted physical memory probing.
Delete all of the code working with sp_banks[] and replace
with clean acquisition and sorting of physical memory
parameters from the firmware.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r-- | arch/sparc64/mm/init.c | 302 |
1 files changed, 111 insertions, 191 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 48851a2e4fe1..5db50524f20d 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/kprobes.h> | 22 | #include <linux/kprobes.h> |
23 | #include <linux/cache.h> | 23 | #include <linux/cache.h> |
24 | #include <linux/sort.h> | ||
24 | 25 | ||
25 | #include <asm/head.h> | 26 | #include <asm/head.h> |
26 | #include <asm/system.h> | 27 | #include <asm/system.h> |
@@ -41,14 +42,72 @@ | |||
41 | 42 | ||
42 | extern void device_scan(void); | 43 | extern void device_scan(void); |
43 | 44 | ||
44 | struct sparc_phys_banks { | 45 | #define MAX_BANKS 32 |
45 | unsigned long base_addr; | 46 | |
46 | unsigned long num_bytes; | 47 | static struct linux_prom64_registers pavail[MAX_BANKS] __initdata; |
47 | }; | 48 | static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata; |
49 | static int pavail_ents __initdata; | ||
50 | static int pavail_rescan_ents __initdata; | ||
51 | |||
52 | static int cmp_p64(const void *a, const void *b) | ||
53 | { | ||
54 | const struct linux_prom64_registers *x = a, *y = b; | ||
55 | |||
56 | if (x->phys_addr > y->phys_addr) | ||
57 | return 1; | ||
58 | if (x->phys_addr < y->phys_addr) | ||
59 | return -1; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static void __init read_obp_memory(const char *property, | ||
64 | struct linux_prom64_registers *regs, | ||
65 | int *num_ents) | ||
66 | { | ||
67 | int node = prom_finddevice("/memory"); | ||
68 | int prop_size = prom_getproplen(node, property); | ||
69 | int ents, ret, i; | ||
70 | |||
71 | ents = prop_size / sizeof(struct linux_prom64_registers); | ||
72 | if (ents > MAX_BANKS) { | ||
73 | prom_printf("The machine has more %s property entries than " | ||
74 | "this kernel can support (%d).\n", | ||
75 | property, MAX_BANKS); | ||
76 | prom_halt(); | ||
77 | } | ||
78 | |||
79 | ret = prom_getproperty(node, property, (char *) regs, prop_size); | ||
80 | if (ret == -1) { | ||
81 | prom_printf("Couldn't get %s property from /memory.\n"); | ||
82 | prom_halt(); | ||
83 | } | ||
84 | |||
85 | *num_ents = ents; | ||
48 | 86 | ||
49 | #define SPARC_PHYS_BANKS 32 | 87 | /* Sanitize what we got from the firmware, by page aligning |
88 | * everything. | ||
89 | */ | ||
90 | for (i = 0; i < ents; i++) { | ||
91 | unsigned long base, size; | ||
92 | |||
93 | base = regs[i].phys_addr; | ||
94 | size = regs[i].reg_size; | ||
50 | 95 | ||
51 | static struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; | 96 | size &= PAGE_MASK; |
97 | if (base & ~PAGE_MASK) { | ||
98 | unsigned long new_base = PAGE_ALIGN(base); | ||
99 | |||
100 | size -= new_base - base; | ||
101 | if ((long) size < 0L) | ||
102 | size = 0UL; | ||
103 | base = new_base; | ||
104 | } | ||
105 | regs[i].phys_addr = base; | ||
106 | regs[i].reg_size = size; | ||
107 | } | ||
108 | sort(regs, ents, sizeof(struct linux_prom64_registers), | ||
109 | cmp_p64, NULL); | ||
110 | } | ||
52 | 111 | ||
53 | unsigned long *sparc64_valid_addr_bitmap __read_mostly; | 112 | unsigned long *sparc64_valid_addr_bitmap __read_mostly; |
54 | 113 | ||
@@ -1213,14 +1272,14 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
1213 | int i; | 1272 | int i; |
1214 | 1273 | ||
1215 | #ifdef CONFIG_DEBUG_BOOTMEM | 1274 | #ifdef CONFIG_DEBUG_BOOTMEM |
1216 | prom_printf("bootmem_init: Scan sp_banks, "); | 1275 | prom_printf("bootmem_init: Scan pavail, "); |
1217 | #endif | 1276 | #endif |
1218 | 1277 | ||
1219 | bytes_avail = 0UL; | 1278 | bytes_avail = 0UL; |
1220 | for (i = 0; sp_banks[i].num_bytes != 0; i++) { | 1279 | for (i = 0; i < pavail_ents; i++) { |
1221 | end_of_phys_memory = sp_banks[i].base_addr + | 1280 | end_of_phys_memory = pavail[i].phys_addr + |
1222 | sp_banks[i].num_bytes; | 1281 | pavail[i].reg_size; |
1223 | bytes_avail += sp_banks[i].num_bytes; | 1282 | bytes_avail += pavail[i].reg_size; |
1224 | if (cmdline_memory_size) { | 1283 | if (cmdline_memory_size) { |
1225 | if (bytes_avail > cmdline_memory_size) { | 1284 | if (bytes_avail > cmdline_memory_size) { |
1226 | unsigned long slack = bytes_avail - cmdline_memory_size; | 1285 | unsigned long slack = bytes_avail - cmdline_memory_size; |
@@ -1228,12 +1287,15 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
1228 | bytes_avail -= slack; | 1287 | bytes_avail -= slack; |
1229 | end_of_phys_memory -= slack; | 1288 | end_of_phys_memory -= slack; |
1230 | 1289 | ||
1231 | sp_banks[i].num_bytes -= slack; | 1290 | pavail[i].reg_size -= slack; |
1232 | if (sp_banks[i].num_bytes == 0) { | 1291 | if ((long)pavail[i].reg_size <= 0L) { |
1233 | sp_banks[i].base_addr = 0xdeadbeef; | 1292 | pavail[i].phys_addr = 0xdeadbeefUL; |
1293 | pavail[i].reg_size = 0UL; | ||
1294 | pavail_ents = i; | ||
1234 | } else { | 1295 | } else { |
1235 | sp_banks[i+1].num_bytes = 0; | 1296 | pavail[i+1].reg_size = 0Ul; |
1236 | sp_banks[i+1].base_addr = 0xdeadbeef; | 1297 | pavail[i+1].phys_addr = 0xdeadbeefUL; |
1298 | pavail_ents = i + 1; | ||
1237 | } | 1299 | } |
1238 | break; | 1300 | break; |
1239 | } | 1301 | } |
@@ -1287,12 +1349,12 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
1287 | /* Now register the available physical memory with the | 1349 | /* Now register the available physical memory with the |
1288 | * allocator. | 1350 | * allocator. |
1289 | */ | 1351 | */ |
1290 | for (i = 0; sp_banks[i].num_bytes != 0; i++) { | 1352 | for (i = 0; i < pavail_ents; i++) { |
1291 | #ifdef CONFIG_DEBUG_BOOTMEM | 1353 | #ifdef CONFIG_DEBUG_BOOTMEM |
1292 | prom_printf("free_bootmem(sp_banks:%d): base[%lx] size[%lx]\n", | 1354 | prom_printf("free_bootmem(pavail:%d): base[%lx] size[%lx]\n", |
1293 | i, sp_banks[i].base_addr, sp_banks[i].num_bytes); | 1355 | i, pavail[i].phys_addr, pavail[i].reg_size); |
1294 | #endif | 1356 | #endif |
1295 | free_bootmem(sp_banks[i].base_addr, sp_banks[i].num_bytes); | 1357 | free_bootmem(pavail[i].phys_addr, pavail[i].reg_size); |
1296 | } | 1358 | } |
1297 | 1359 | ||
1298 | #ifdef CONFIG_BLK_DEV_INITRD | 1360 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -1341,7 +1403,7 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, | |||
1341 | unsigned long alloc_bytes = 0UL; | 1403 | unsigned long alloc_bytes = 0UL; |
1342 | 1404 | ||
1343 | if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) { | 1405 | if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) { |
1344 | prom_printf("kernel_map: Unaligned sp_banks[%lx:%lx]\n", | 1406 | prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n", |
1345 | vstart, vend); | 1407 | vstart, vend); |
1346 | prom_halt(); | 1408 | prom_halt(); |
1347 | } | 1409 | } |
@@ -1388,23 +1450,24 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, | |||
1388 | return alloc_bytes; | 1450 | return alloc_bytes; |
1389 | } | 1451 | } |
1390 | 1452 | ||
1391 | extern struct linux_mlist_p1275 *prom_ptot_ptr; | 1453 | static struct linux_prom64_registers pall[MAX_BANKS] __initdata; |
1454 | static int pall_ents __initdata; | ||
1455 | |||
1392 | extern unsigned int kvmap_linear_patch[1]; | 1456 | extern unsigned int kvmap_linear_patch[1]; |
1393 | 1457 | ||
1394 | static void __init kernel_physical_mapping_init(void) | 1458 | static void __init kernel_physical_mapping_init(void) |
1395 | { | 1459 | { |
1396 | struct linux_mlist_p1275 *p = prom_ptot_ptr; | 1460 | unsigned long i, mem_alloced = 0UL; |
1397 | unsigned long mem_alloced = 0UL; | ||
1398 | 1461 | ||
1399 | while (p) { | 1462 | read_obp_memory("reg", &pall[0], &pall_ents); |
1463 | |||
1464 | for (i = 0; i < pall_ents; i++) { | ||
1400 | unsigned long phys_start, phys_end; | 1465 | unsigned long phys_start, phys_end; |
1401 | 1466 | ||
1402 | phys_start = p->start_adr; | 1467 | phys_start = pall[i].phys_addr; |
1403 | phys_end = phys_start + p->num_bytes; | 1468 | phys_end = phys_start + pall[i].reg_size; |
1404 | mem_alloced += kernel_map_range(phys_start, phys_end, | 1469 | mem_alloced += kernel_map_range(phys_start, phys_end, |
1405 | PAGE_KERNEL); | 1470 | PAGE_KERNEL); |
1406 | |||
1407 | p = p->theres_more; | ||
1408 | } | 1471 | } |
1409 | 1472 | ||
1410 | printk("Allocated %ld bytes for kernel page tables.\n", | 1473 | printk("Allocated %ld bytes for kernel page tables.\n", |
@@ -1434,60 +1497,14 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
1434 | 1497 | ||
1435 | unsigned long __init find_ecache_flush_span(unsigned long size) | 1498 | unsigned long __init find_ecache_flush_span(unsigned long size) |
1436 | { | 1499 | { |
1437 | unsigned long i; | ||
1438 | |||
1439 | for (i = 0; ; i++) { | ||
1440 | if (sp_banks[i].num_bytes == 0) | ||
1441 | break; | ||
1442 | if (sp_banks[i].num_bytes >= size) | ||
1443 | return sp_banks[i].base_addr; | ||
1444 | } | ||
1445 | |||
1446 | return ~0UL; | ||
1447 | } | ||
1448 | |||
1449 | static void __init prom_probe_memory(void) | ||
1450 | { | ||
1451 | struct linux_mlist_p1275 *mlist; | ||
1452 | unsigned long bytes, base_paddr, tally; | ||
1453 | int i; | 1500 | int i; |
1454 | 1501 | ||
1455 | i = 0; | 1502 | for (i = 0; i < pavail_ents; i++) { |
1456 | mlist = *prom_meminfo()->p1275_available; | 1503 | if (pavail[i].reg_size >= size) |
1457 | bytes = tally = mlist->num_bytes; | 1504 | return pavail[i].phys_addr; |
1458 | base_paddr = mlist->start_adr; | ||
1459 | |||
1460 | sp_banks[0].base_addr = base_paddr; | ||
1461 | sp_banks[0].num_bytes = bytes; | ||
1462 | |||
1463 | while (mlist->theres_more != (void *) 0) { | ||
1464 | i++; | ||
1465 | mlist = mlist->theres_more; | ||
1466 | bytes = mlist->num_bytes; | ||
1467 | tally += bytes; | ||
1468 | if (i >= SPARC_PHYS_BANKS-1) { | ||
1469 | printk ("The machine has more banks than " | ||
1470 | "this kernel can support\n" | ||
1471 | "Increase the SPARC_PHYS_BANKS " | ||
1472 | "setting (currently %d)\n", | ||
1473 | SPARC_PHYS_BANKS); | ||
1474 | i = SPARC_PHYS_BANKS-1; | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | sp_banks[i].base_addr = mlist->start_adr; | ||
1479 | sp_banks[i].num_bytes = mlist->num_bytes; | ||
1480 | } | 1505 | } |
1481 | 1506 | ||
1482 | i++; | 1507 | return ~0UL; |
1483 | sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL; | ||
1484 | sp_banks[i].num_bytes = 0; | ||
1485 | |||
1486 | /* Now mask all bank sizes on a page boundary, it is all we can | ||
1487 | * use anyways. | ||
1488 | */ | ||
1489 | for (i = 0; sp_banks[i].num_bytes != 0; i++) | ||
1490 | sp_banks[i].num_bytes &= PAGE_MASK; | ||
1491 | } | 1508 | } |
1492 | 1509 | ||
1493 | /* paging_init() sets up the page tables */ | 1510 | /* paging_init() sets up the page tables */ |
@@ -1502,17 +1519,13 @@ void __init paging_init(void) | |||
1502 | unsigned long end_pfn, pages_avail, shift; | 1519 | unsigned long end_pfn, pages_avail, shift; |
1503 | unsigned long real_end, i; | 1520 | unsigned long real_end, i; |
1504 | 1521 | ||
1505 | prom_probe_memory(); | 1522 | /* Find available physical memory... */ |
1523 | read_obp_memory("available", &pavail[0], &pavail_ents); | ||
1506 | 1524 | ||
1507 | phys_base = 0xffffffffffffffffUL; | 1525 | phys_base = 0xffffffffffffffffUL; |
1508 | for (i = 0; sp_banks[i].num_bytes != 0; i++) { | 1526 | for (i = 0; i < pavail_ents; i++) |
1509 | unsigned long top; | 1527 | phys_base = min(phys_base, pavail[i].phys_addr); |
1510 | 1528 | ||
1511 | if (sp_banks[i].base_addr < phys_base) | ||
1512 | phys_base = sp_banks[i].base_addr; | ||
1513 | top = sp_banks[i].base_addr + | ||
1514 | sp_banks[i].num_bytes; | ||
1515 | } | ||
1516 | pfn_base = phys_base >> PAGE_SHIFT; | 1529 | pfn_base = phys_base >> PAGE_SHIFT; |
1517 | 1530 | ||
1518 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; | 1531 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; |
@@ -1588,128 +1601,35 @@ void __init paging_init(void) | |||
1588 | device_scan(); | 1601 | device_scan(); |
1589 | } | 1602 | } |
1590 | 1603 | ||
1591 | /* Ok, it seems that the prom can allocate some more memory chunks | ||
1592 | * as a side effect of some prom calls we perform during the | ||
1593 | * boot sequence. My most likely theory is that it is from the | ||
1594 | * prom_set_traptable() call, and OBP is allocating a scratchpad | ||
1595 | * for saving client program register state etc. | ||
1596 | */ | ||
1597 | static void __init sort_memlist(struct linux_mlist_p1275 *thislist) | ||
1598 | { | ||
1599 | int swapi = 0; | ||
1600 | int i, mitr; | ||
1601 | unsigned long tmpaddr, tmpsize; | ||
1602 | unsigned long lowest; | ||
1603 | |||
1604 | for (i = 0; thislist[i].theres_more != 0; i++) { | ||
1605 | lowest = thislist[i].start_adr; | ||
1606 | for (mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++) | ||
1607 | if (thislist[mitr].start_adr < lowest) { | ||
1608 | lowest = thislist[mitr].start_adr; | ||
1609 | swapi = mitr; | ||
1610 | } | ||
1611 | if (lowest == thislist[i].start_adr) | ||
1612 | continue; | ||
1613 | tmpaddr = thislist[swapi].start_adr; | ||
1614 | tmpsize = thislist[swapi].num_bytes; | ||
1615 | for (mitr = swapi; mitr > i; mitr--) { | ||
1616 | thislist[mitr].start_adr = thislist[mitr-1].start_adr; | ||
1617 | thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; | ||
1618 | } | ||
1619 | thislist[i].start_adr = tmpaddr; | ||
1620 | thislist[i].num_bytes = tmpsize; | ||
1621 | } | ||
1622 | } | ||
1623 | |||
1624 | void __init rescan_sp_banks(void) | ||
1625 | { | ||
1626 | struct linux_prom64_registers memlist[64]; | ||
1627 | struct linux_mlist_p1275 avail[64], *mlist; | ||
1628 | unsigned long bytes, base_paddr; | ||
1629 | int num_regs, node = prom_finddevice("/memory"); | ||
1630 | int i; | ||
1631 | |||
1632 | num_regs = prom_getproperty(node, "available", | ||
1633 | (char *) memlist, sizeof(memlist)); | ||
1634 | num_regs = (num_regs / sizeof(struct linux_prom64_registers)); | ||
1635 | for (i = 0; i < num_regs; i++) { | ||
1636 | avail[i].start_adr = memlist[i].phys_addr; | ||
1637 | avail[i].num_bytes = memlist[i].reg_size; | ||
1638 | avail[i].theres_more = &avail[i + 1]; | ||
1639 | } | ||
1640 | avail[i - 1].theres_more = NULL; | ||
1641 | sort_memlist(avail); | ||
1642 | |||
1643 | mlist = &avail[0]; | ||
1644 | i = 0; | ||
1645 | bytes = mlist->num_bytes; | ||
1646 | base_paddr = mlist->start_adr; | ||
1647 | |||
1648 | sp_banks[0].base_addr = base_paddr; | ||
1649 | sp_banks[0].num_bytes = bytes; | ||
1650 | |||
1651 | while (mlist->theres_more != NULL){ | ||
1652 | i++; | ||
1653 | mlist = mlist->theres_more; | ||
1654 | bytes = mlist->num_bytes; | ||
1655 | if (i >= SPARC_PHYS_BANKS-1) { | ||
1656 | printk ("The machine has more banks than " | ||
1657 | "this kernel can support\n" | ||
1658 | "Increase the SPARC_PHYS_BANKS " | ||
1659 | "setting (currently %d)\n", | ||
1660 | SPARC_PHYS_BANKS); | ||
1661 | i = SPARC_PHYS_BANKS-1; | ||
1662 | break; | ||
1663 | } | ||
1664 | |||
1665 | sp_banks[i].base_addr = mlist->start_adr; | ||
1666 | sp_banks[i].num_bytes = mlist->num_bytes; | ||
1667 | } | ||
1668 | |||
1669 | i++; | ||
1670 | sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL; | ||
1671 | sp_banks[i].num_bytes = 0; | ||
1672 | |||
1673 | for (i = 0; sp_banks[i].num_bytes != 0; i++) | ||
1674 | sp_banks[i].num_bytes &= PAGE_MASK; | ||
1675 | } | ||
1676 | |||
1677 | static void __init taint_real_pages(void) | 1604 | static void __init taint_real_pages(void) |
1678 | { | 1605 | { |
1679 | struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS]; | ||
1680 | int i; | 1606 | int i; |
1681 | 1607 | ||
1682 | for (i = 0; i < SPARC_PHYS_BANKS; i++) { | 1608 | read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents); |
1683 | saved_sp_banks[i].base_addr = | ||
1684 | sp_banks[i].base_addr; | ||
1685 | saved_sp_banks[i].num_bytes = | ||
1686 | sp_banks[i].num_bytes; | ||
1687 | } | ||
1688 | |||
1689 | rescan_sp_banks(); | ||
1690 | 1609 | ||
1691 | /* Find changes discovered in the sp_bank rescan and | 1610 | /* Find changes discovered in the physmem available rescan and |
1692 | * reserve the lost portions in the bootmem maps. | 1611 | * reserve the lost portions in the bootmem maps. |
1693 | */ | 1612 | */ |
1694 | for (i = 0; saved_sp_banks[i].num_bytes; i++) { | 1613 | for (i = 0; i < pavail_ents; i++) { |
1695 | unsigned long old_start, old_end; | 1614 | unsigned long old_start, old_end; |
1696 | 1615 | ||
1697 | old_start = saved_sp_banks[i].base_addr; | 1616 | old_start = pavail[i].phys_addr; |
1698 | old_end = old_start + | 1617 | old_end = old_start + |
1699 | saved_sp_banks[i].num_bytes; | 1618 | pavail[i].reg_size; |
1700 | while (old_start < old_end) { | 1619 | while (old_start < old_end) { |
1701 | int n; | 1620 | int n; |
1702 | 1621 | ||
1703 | for (n = 0; sp_banks[n].num_bytes; n++) { | 1622 | for (n = 0; pavail_rescan_ents; n++) { |
1704 | unsigned long new_start, new_end; | 1623 | unsigned long new_start, new_end; |
1705 | 1624 | ||
1706 | new_start = sp_banks[n].base_addr; | 1625 | new_start = pavail_rescan[n].phys_addr; |
1707 | new_end = new_start + sp_banks[n].num_bytes; | 1626 | new_end = new_start + |
1627 | pavail_rescan[n].reg_size; | ||
1708 | 1628 | ||
1709 | if (new_start <= old_start && | 1629 | if (new_start <= old_start && |
1710 | new_end >= (old_start + PAGE_SIZE)) { | 1630 | new_end >= (old_start + PAGE_SIZE)) { |
1711 | set_bit (old_start >> 22, | 1631 | set_bit(old_start >> 22, |
1712 | sparc64_valid_addr_bitmap); | 1632 | sparc64_valid_addr_bitmap); |
1713 | goto do_next_page; | 1633 | goto do_next_page; |
1714 | } | 1634 | } |
1715 | } | 1635 | } |