diff options
Diffstat (limited to 'arch/ppc64/kernel/prom_init.c')
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index dbbe6c79d8da..122283a1d39a 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -892,7 +892,10 @@ static void __init prom_init_mem(void) | |||
892 | if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) | 892 | if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) |
893 | RELOC(alloc_top) = RELOC(rmo_top); | 893 | RELOC(alloc_top) = RELOC(rmo_top); |
894 | else | 894 | else |
895 | RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top)); | 895 | /* Some RS64 machines have buggy firmware where claims up at 1GB |
896 | * fails. Cap at 768MB as a workaround. Still plenty of room. | ||
897 | */ | ||
898 | RELOC(alloc_top) = RELOC(rmo_top) = min(0x30000000ul, RELOC(ram_top)); | ||
896 | 899 | ||
897 | prom_printf("memory layout at init:\n"); | 900 | prom_printf("memory layout at init:\n"); |
898 | prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit)); | 901 | prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit)); |
@@ -1534,7 +1537,8 @@ static unsigned long __init dt_find_string(char *str) | |||
1534 | */ | 1537 | */ |
1535 | #define MAX_PROPERTY_NAME 64 | 1538 | #define MAX_PROPERTY_NAME 64 |
1536 | 1539 | ||
1537 | static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | 1540 | static void __init scan_dt_build_strings(phandle node, |
1541 | unsigned long *mem_start, | ||
1538 | unsigned long *mem_end) | 1542 | unsigned long *mem_end) |
1539 | { | 1543 | { |
1540 | unsigned long offset = reloc_offset(); | 1544 | unsigned long offset = reloc_offset(); |
@@ -1547,16 +1551,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1547 | /* get and store all property names */ | 1551 | /* get and store all property names */ |
1548 | prev_name = RELOC(""); | 1552 | prev_name = RELOC(""); |
1549 | for (;;) { | 1553 | for (;;) { |
1550 | int rc; | ||
1551 | |||
1552 | /* 64 is max len of name including nul. */ | 1554 | /* 64 is max len of name including nul. */ |
1553 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); | 1555 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); |
1554 | rc = call_prom("nextprop", 3, 1, node, prev_name, namep); | 1556 | if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { |
1555 | if (rc != 1) { | ||
1556 | /* No more nodes: unwind alloc */ | 1557 | /* No more nodes: unwind alloc */ |
1557 | *mem_start = (unsigned long)namep; | 1558 | *mem_start = (unsigned long)namep; |
1558 | break; | 1559 | break; |
1559 | } | 1560 | } |
1561 | |||
1562 | /* skip "name" */ | ||
1563 | if (strcmp(namep, RELOC("name")) == 0) { | ||
1564 | *mem_start = (unsigned long)namep; | ||
1565 | prev_name = RELOC("name"); | ||
1566 | continue; | ||
1567 | } | ||
1568 | /* get/create string entry */ | ||
1560 | soff = dt_find_string(namep); | 1569 | soff = dt_find_string(namep); |
1561 | if (soff != 0) { | 1570 | if (soff != 0) { |
1562 | *mem_start = (unsigned long)namep; | 1571 | *mem_start = (unsigned long)namep; |
@@ -1571,7 +1580,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1571 | 1580 | ||
1572 | /* do all our children */ | 1581 | /* do all our children */ |
1573 | child = call_prom("child", 1, 1, node); | 1582 | child = call_prom("child", 1, 1, node); |
1574 | while (child != (phandle)0) { | 1583 | while (child != 0) { |
1575 | scan_dt_build_strings(child, mem_start, mem_end); | 1584 | scan_dt_build_strings(child, mem_start, mem_end); |
1576 | child = call_prom("peer", 1, 1, child); | 1585 | child = call_prom("peer", 1, 1, child); |
1577 | } | 1586 | } |
@@ -1580,16 +1589,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1580 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | 1589 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, |
1581 | unsigned long *mem_end) | 1590 | unsigned long *mem_end) |
1582 | { | 1591 | { |
1583 | int l, align; | ||
1584 | phandle child; | 1592 | phandle child; |
1585 | char *namep, *prev_name, *sstart, *p, *ep; | 1593 | char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; |
1586 | unsigned long soff; | 1594 | unsigned long soff; |
1587 | unsigned char *valp; | 1595 | unsigned char *valp; |
1588 | unsigned long offset = reloc_offset(); | 1596 | unsigned long offset = reloc_offset(); |
1589 | char pname[MAX_PROPERTY_NAME]; | 1597 | static char pname[MAX_PROPERTY_NAME]; |
1590 | char *path; | 1598 | int l; |
1591 | |||
1592 | path = RELOC(prom_scratch); | ||
1593 | 1599 | ||
1594 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); | 1600 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); |
1595 | 1601 | ||
@@ -1599,23 +1605,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1599 | namep, *mem_end - *mem_start); | 1605 | namep, *mem_end - *mem_start); |
1600 | if (l >= 0) { | 1606 | if (l >= 0) { |
1601 | /* Didn't fit? Get more room. */ | 1607 | /* Didn't fit? Get more room. */ |
1602 | if (l+1 > *mem_end - *mem_start) { | 1608 | if ((l+1) > (*mem_end - *mem_start)) { |
1603 | namep = make_room(mem_start, mem_end, l+1, 1); | 1609 | namep = make_room(mem_start, mem_end, l+1, 1); |
1604 | call_prom("package-to-path", 3, 1, node, namep, l); | 1610 | call_prom("package-to-path", 3, 1, node, namep, l); |
1605 | } | 1611 | } |
1606 | namep[l] = '\0'; | 1612 | namep[l] = '\0'; |
1613 | |||
1607 | /* Fixup an Apple bug where they have bogus \0 chars in the | 1614 | /* Fixup an Apple bug where they have bogus \0 chars in the |
1608 | * middle of the path in some properties | 1615 | * middle of the path in some properties |
1609 | */ | 1616 | */ |
1610 | for (p = namep, ep = namep + l; p < ep; p++) | 1617 | for (p = namep, ep = namep + l; p < ep; p++) |
1611 | if (*p == '\0') { | 1618 | if (*p == '\0') { |
1612 | memmove(p, p+1, ep - p); | 1619 | memmove(p, p+1, ep - p); |
1613 | ep--; l--; | 1620 | ep--; l--; p--; |
1614 | } | 1621 | } |
1615 | *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); | 1622 | |
1623 | /* now try to extract the unit name in that mess */ | ||
1624 | for (p = namep, lp = NULL; *p; p++) | ||
1625 | if (*p == '/') | ||
1626 | lp = p + 1; | ||
1627 | if (lp != NULL) | ||
1628 | memmove(namep, lp, strlen(lp) + 1); | ||
1629 | *mem_start = _ALIGN(((unsigned long) namep) + | ||
1630 | strlen(namep) + 1, 4); | ||
1616 | } | 1631 | } |
1617 | 1632 | ||
1618 | /* get it again for debugging */ | 1633 | /* get it again for debugging */ |
1634 | path = RELOC(prom_scratch); | ||
1619 | memset(path, 0, PROM_SCRATCH_SIZE); | 1635 | memset(path, 0, PROM_SCRATCH_SIZE); |
1620 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); | 1636 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); |
1621 | 1637 | ||
@@ -1623,23 +1639,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1623 | prev_name = RELOC(""); | 1639 | prev_name = RELOC(""); |
1624 | sstart = (char *)RELOC(dt_string_start); | 1640 | sstart = (char *)RELOC(dt_string_start); |
1625 | for (;;) { | 1641 | for (;;) { |
1626 | int rc; | 1642 | if (call_prom("nextprop", 3, 1, node, prev_name, |
1627 | 1643 | RELOC(pname)) != 1) | |
1628 | rc = call_prom("nextprop", 3, 1, node, prev_name, pname); | ||
1629 | if (rc != 1) | ||
1630 | break; | 1644 | break; |
1631 | 1645 | ||
1646 | /* skip "name" */ | ||
1647 | if (strcmp(RELOC(pname), RELOC("name")) == 0) { | ||
1648 | prev_name = RELOC("name"); | ||
1649 | continue; | ||
1650 | } | ||
1651 | |||
1632 | /* find string offset */ | 1652 | /* find string offset */ |
1633 | soff = dt_find_string(pname); | 1653 | soff = dt_find_string(RELOC(pname)); |
1634 | if (soff == 0) { | 1654 | if (soff == 0) { |
1635 | prom_printf("WARNING: Can't find string index for <%s>, node %s\n", | 1655 | prom_printf("WARNING: Can't find string index for" |
1636 | pname, path); | 1656 | " <%s>, node %s\n", RELOC(pname), path); |
1637 | break; | 1657 | break; |
1638 | } | 1658 | } |
1639 | prev_name = sstart + soff; | 1659 | prev_name = sstart + soff; |
1640 | 1660 | ||
1641 | /* get length */ | 1661 | /* get length */ |
1642 | l = call_prom("getproplen", 2, 1, node, pname); | 1662 | l = call_prom("getproplen", 2, 1, node, RELOC(pname)); |
1643 | 1663 | ||
1644 | /* sanity checks */ | 1664 | /* sanity checks */ |
1645 | if (l == PROM_ERROR) | 1665 | if (l == PROM_ERROR) |
@@ -1648,7 +1668,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1648 | prom_printf("WARNING: ignoring large property "); | 1668 | prom_printf("WARNING: ignoring large property "); |
1649 | /* It seems OF doesn't null-terminate the path :-( */ | 1669 | /* It seems OF doesn't null-terminate the path :-( */ |
1650 | prom_printf("[%s] ", path); | 1670 | prom_printf("[%s] ", path); |
1651 | prom_printf("%s length 0x%x\n", pname, l); | 1671 | prom_printf("%s length 0x%x\n", RELOC(pname), l); |
1652 | continue; | 1672 | continue; |
1653 | } | 1673 | } |
1654 | 1674 | ||
@@ -1658,17 +1678,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1658 | dt_push_token(soff, mem_start, mem_end); | 1678 | dt_push_token(soff, mem_start, mem_end); |
1659 | 1679 | ||
1660 | /* push property content */ | 1680 | /* push property content */ |
1661 | align = (l >= 8) ? 8 : 4; | 1681 | valp = make_room(mem_start, mem_end, l, 4); |
1662 | valp = make_room(mem_start, mem_end, l, align); | 1682 | call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); |
1663 | call_prom("getprop", 4, 1, node, pname, valp, l); | ||
1664 | *mem_start = _ALIGN(*mem_start, 4); | 1683 | *mem_start = _ALIGN(*mem_start, 4); |
1665 | } | 1684 | } |
1666 | 1685 | ||
1667 | /* Add a "linux,phandle" property. */ | 1686 | /* Add a "linux,phandle" property. */ |
1668 | soff = dt_find_string(RELOC("linux,phandle")); | 1687 | soff = dt_find_string(RELOC("linux,phandle")); |
1669 | if (soff == 0) | 1688 | if (soff == 0) |
1670 | prom_printf("WARNING: Can't find string index for <linux-phandle>" | 1689 | prom_printf("WARNING: Can't find string index for" |
1671 | " node %s\n", path); | 1690 | " <linux-phandle> node %s\n", path); |
1672 | else { | 1691 | else { |
1673 | dt_push_token(OF_DT_PROP, mem_start, mem_end); | 1692 | dt_push_token(OF_DT_PROP, mem_start, mem_end); |
1674 | dt_push_token(4, mem_start, mem_end); | 1693 | dt_push_token(4, mem_start, mem_end); |
@@ -1679,7 +1698,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1679 | 1698 | ||
1680 | /* do all our children */ | 1699 | /* do all our children */ |
1681 | child = call_prom("child", 1, 1, node); | 1700 | child = call_prom("child", 1, 1, node); |
1682 | while (child != (phandle)0) { | 1701 | while (child != 0) { |
1683 | scan_dt_build_struct(child, mem_start, mem_end); | 1702 | scan_dt_build_struct(child, mem_start, mem_end); |
1684 | child = call_prom("peer", 1, 1, child); | 1703 | child = call_prom("peer", 1, 1, child); |
1685 | } | 1704 | } |
@@ -1718,7 +1737,8 @@ static void __init flatten_device_tree(void) | |||
1718 | 1737 | ||
1719 | /* Build header and make room for mem rsv map */ | 1738 | /* Build header and make room for mem rsv map */ |
1720 | mem_start = _ALIGN(mem_start, 4); | 1739 | mem_start = _ALIGN(mem_start, 4); |
1721 | hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); | 1740 | hdr = make_room(&mem_start, &mem_end, |
1741 | sizeof(struct boot_param_header), 4); | ||
1722 | RELOC(dt_header_start) = (unsigned long)hdr; | 1742 | RELOC(dt_header_start) = (unsigned long)hdr; |
1723 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); | 1743 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); |
1724 | 1744 | ||
@@ -1731,11 +1751,11 @@ static void __init flatten_device_tree(void) | |||
1731 | namep = make_room(&mem_start, &mem_end, 16, 1); | 1751 | namep = make_room(&mem_start, &mem_end, 16, 1); |
1732 | strcpy(namep, RELOC("linux,phandle")); | 1752 | strcpy(namep, RELOC("linux,phandle")); |
1733 | mem_start = (unsigned long)namep + strlen(namep) + 1; | 1753 | mem_start = (unsigned long)namep + strlen(namep) + 1; |
1734 | RELOC(dt_string_end) = mem_start; | ||
1735 | 1754 | ||
1736 | /* Build string array */ | 1755 | /* Build string array */ |
1737 | prom_printf("Building dt strings...\n"); | 1756 | prom_printf("Building dt strings...\n"); |
1738 | scan_dt_build_strings(root, &mem_start, &mem_end); | 1757 | scan_dt_build_strings(root, &mem_start, &mem_end); |
1758 | RELOC(dt_string_end) = mem_start; | ||
1739 | 1759 | ||
1740 | /* Build structure */ | 1760 | /* Build structure */ |
1741 | mem_start = PAGE_ALIGN(mem_start); | 1761 | mem_start = PAGE_ALIGN(mem_start); |
@@ -1750,9 +1770,11 @@ static void __init flatten_device_tree(void) | |||
1750 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); | 1770 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); |
1751 | hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); | 1771 | hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); |
1752 | hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); | 1772 | hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); |
1773 | hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); | ||
1753 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); | 1774 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); |
1754 | hdr->version = OF_DT_VERSION; | 1775 | hdr->version = OF_DT_VERSION; |
1755 | hdr->last_comp_version = 1; | 1776 | /* Version 16 is not backward compatible */ |
1777 | hdr->last_comp_version = 0x10; | ||
1756 | 1778 | ||
1757 | /* Reserve the whole thing and copy the reserve map in, we | 1779 | /* Reserve the whole thing and copy the reserve map in, we |
1758 | * also bump mem_reserve_cnt to cause further reservations to | 1780 | * also bump mem_reserve_cnt to cause further reservations to |
@@ -1808,6 +1830,9 @@ static void __init fixup_device_tree(void) | |||
1808 | /* does it need fixup ? */ | 1830 | /* does it need fixup ? */ |
1809 | if (prom_getproplen(i2c, "interrupts") > 0) | 1831 | if (prom_getproplen(i2c, "interrupts") > 0) |
1810 | return; | 1832 | return; |
1833 | |||
1834 | prom_printf("fixing up bogus interrupts for u3 i2c...\n"); | ||
1835 | |||
1811 | /* interrupt on this revision of u3 is number 0 and level */ | 1836 | /* interrupt on this revision of u3 is number 0 and level */ |
1812 | interrupts[0] = 0; | 1837 | interrupts[0] = 0; |
1813 | interrupts[1] = 1; | 1838 | interrupts[1] = 1; |