aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/mm/init.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-29 20:58:26 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-29 20:58:26 -0400
commit13edad7a5cef1c952459742482482a6b05e1a8a1 (patch)
tree4d1ddcbbb7fe5cda5e75c83e3d8511ed1642e201 /arch/sparc64/mm/init.c
parented3ffaf7b5e0262cb860f106a6632933671cc88f (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.c302
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
42extern void device_scan(void); 43extern void device_scan(void);
43 44
44struct sparc_phys_banks { 45#define MAX_BANKS 32
45 unsigned long base_addr; 46
46 unsigned long num_bytes; 47static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;
47}; 48static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
49static int pavail_ents __initdata;
50static int pavail_rescan_ents __initdata;
51
52static 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
63static 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
51static 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
53unsigned long *sparc64_valid_addr_bitmap __read_mostly; 112unsigned 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
1391extern struct linux_mlist_p1275 *prom_ptot_ptr; 1453static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
1454static int pall_ents __initdata;
1455
1392extern unsigned int kvmap_linear_patch[1]; 1456extern unsigned int kvmap_linear_patch[1];
1393 1457
1394static void __init kernel_physical_mapping_init(void) 1458static 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
1435unsigned long __init find_ecache_flush_span(unsigned long size) 1498unsigned 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
1449static 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 */
1597static 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
1624void __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
1677static void __init taint_real_pages(void) 1604static 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 }