diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-08-09 04:36:34 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-08-28 20:53:31 -0400 |
commit | 34153fa3af45d84f3221d9b67ba2ab7e8a220d28 (patch) | |
tree | 74f69cd35bef255583acaac181324558a286e40c /arch/ppc64/kernel/prom_init.c | |
parent | e28f7faf05159f1cfd564596f5e6178edba6bd49 (diff) |
[PATCH] flattened device tree changes
This patch updates the format of the flattened device-tree passed
between the boot trampoline and the kernel to support a more compact
representation, for use by embedded systems mostly.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc64/kernel/prom_init.c')
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 88 |
1 files changed, 55 insertions, 33 deletions
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index dbbe6c79d8da..adcf972711fc 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1534,7 +1534,8 @@ static unsigned long __init dt_find_string(char *str) | |||
1534 | */ | 1534 | */ |
1535 | #define MAX_PROPERTY_NAME 64 | 1535 | #define MAX_PROPERTY_NAME 64 |
1536 | 1536 | ||
1537 | static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | 1537 | static void __init scan_dt_build_strings(phandle node, |
1538 | unsigned long *mem_start, | ||
1538 | unsigned long *mem_end) | 1539 | unsigned long *mem_end) |
1539 | { | 1540 | { |
1540 | unsigned long offset = reloc_offset(); | 1541 | unsigned long offset = reloc_offset(); |
@@ -1547,16 +1548,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1547 | /* get and store all property names */ | 1548 | /* get and store all property names */ |
1548 | prev_name = RELOC(""); | 1549 | prev_name = RELOC(""); |
1549 | for (;;) { | 1550 | for (;;) { |
1550 | int rc; | ||
1551 | |||
1552 | /* 64 is max len of name including nul. */ | 1551 | /* 64 is max len of name including nul. */ |
1553 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); | 1552 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); |
1554 | rc = call_prom("nextprop", 3, 1, node, prev_name, namep); | 1553 | if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { |
1555 | if (rc != 1) { | ||
1556 | /* No more nodes: unwind alloc */ | 1554 | /* No more nodes: unwind alloc */ |
1557 | *mem_start = (unsigned long)namep; | 1555 | *mem_start = (unsigned long)namep; |
1558 | break; | 1556 | break; |
1559 | } | 1557 | } |
1558 | |||
1559 | /* skip "name" */ | ||
1560 | if (strcmp(namep, RELOC("name")) == 0) { | ||
1561 | *mem_start = (unsigned long)namep; | ||
1562 | prev_name = RELOC("name"); | ||
1563 | continue; | ||
1564 | } | ||
1565 | /* get/create string entry */ | ||
1560 | soff = dt_find_string(namep); | 1566 | soff = dt_find_string(namep); |
1561 | if (soff != 0) { | 1567 | if (soff != 0) { |
1562 | *mem_start = (unsigned long)namep; | 1568 | *mem_start = (unsigned long)namep; |
@@ -1571,7 +1577,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1571 | 1577 | ||
1572 | /* do all our children */ | 1578 | /* do all our children */ |
1573 | child = call_prom("child", 1, 1, node); | 1579 | child = call_prom("child", 1, 1, node); |
1574 | while (child != (phandle)0) { | 1580 | while (child != 0) { |
1575 | scan_dt_build_strings(child, mem_start, mem_end); | 1581 | scan_dt_build_strings(child, mem_start, mem_end); |
1576 | child = call_prom("peer", 1, 1, child); | 1582 | child = call_prom("peer", 1, 1, child); |
1577 | } | 1583 | } |
@@ -1580,16 +1586,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, | 1586 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, |
1581 | unsigned long *mem_end) | 1587 | unsigned long *mem_end) |
1582 | { | 1588 | { |
1583 | int l, align; | ||
1584 | phandle child; | 1589 | phandle child; |
1585 | char *namep, *prev_name, *sstart, *p, *ep; | 1590 | char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; |
1586 | unsigned long soff; | 1591 | unsigned long soff; |
1587 | unsigned char *valp; | 1592 | unsigned char *valp; |
1588 | unsigned long offset = reloc_offset(); | 1593 | unsigned long offset = reloc_offset(); |
1589 | char pname[MAX_PROPERTY_NAME]; | 1594 | static char pname[MAX_PROPERTY_NAME]; |
1590 | char *path; | 1595 | int l; |
1591 | |||
1592 | path = RELOC(prom_scratch); | ||
1593 | 1596 | ||
1594 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); | 1597 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); |
1595 | 1598 | ||
@@ -1599,23 +1602,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1599 | namep, *mem_end - *mem_start); | 1602 | namep, *mem_end - *mem_start); |
1600 | if (l >= 0) { | 1603 | if (l >= 0) { |
1601 | /* Didn't fit? Get more room. */ | 1604 | /* Didn't fit? Get more room. */ |
1602 | if (l+1 > *mem_end - *mem_start) { | 1605 | if ((l+1) > (*mem_end - *mem_start)) { |
1603 | namep = make_room(mem_start, mem_end, l+1, 1); | 1606 | namep = make_room(mem_start, mem_end, l+1, 1); |
1604 | call_prom("package-to-path", 3, 1, node, namep, l); | 1607 | call_prom("package-to-path", 3, 1, node, namep, l); |
1605 | } | 1608 | } |
1606 | namep[l] = '\0'; | 1609 | namep[l] = '\0'; |
1610 | |||
1607 | /* Fixup an Apple bug where they have bogus \0 chars in the | 1611 | /* Fixup an Apple bug where they have bogus \0 chars in the |
1608 | * middle of the path in some properties | 1612 | * middle of the path in some properties |
1609 | */ | 1613 | */ |
1610 | for (p = namep, ep = namep + l; p < ep; p++) | 1614 | for (p = namep, ep = namep + l; p < ep; p++) |
1611 | if (*p == '\0') { | 1615 | if (*p == '\0') { |
1612 | memmove(p, p+1, ep - p); | 1616 | memmove(p, p+1, ep - p); |
1613 | ep--; l--; | 1617 | ep--; l--; p--; |
1614 | } | 1618 | } |
1615 | *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); | 1619 | |
1620 | /* now try to extract the unit name in that mess */ | ||
1621 | for (p = namep, lp = NULL; *p; p++) | ||
1622 | if (*p == '/') | ||
1623 | lp = p + 1; | ||
1624 | if (lp != NULL) | ||
1625 | memmove(namep, lp, strlen(lp) + 1); | ||
1626 | *mem_start = _ALIGN(((unsigned long) namep) + | ||
1627 | strlen(namep) + 1, 4); | ||
1616 | } | 1628 | } |
1617 | 1629 | ||
1618 | /* get it again for debugging */ | 1630 | /* get it again for debugging */ |
1631 | path = RELOC(prom_scratch); | ||
1619 | memset(path, 0, PROM_SCRATCH_SIZE); | 1632 | memset(path, 0, PROM_SCRATCH_SIZE); |
1620 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); | 1633 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); |
1621 | 1634 | ||
@@ -1623,23 +1636,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1623 | prev_name = RELOC(""); | 1636 | prev_name = RELOC(""); |
1624 | sstart = (char *)RELOC(dt_string_start); | 1637 | sstart = (char *)RELOC(dt_string_start); |
1625 | for (;;) { | 1638 | for (;;) { |
1626 | int rc; | 1639 | if (call_prom("nextprop", 3, 1, node, prev_name, |
1627 | 1640 | RELOC(pname)) != 1) | |
1628 | rc = call_prom("nextprop", 3, 1, node, prev_name, pname); | ||
1629 | if (rc != 1) | ||
1630 | break; | 1641 | break; |
1631 | 1642 | ||
1643 | /* skip "name" */ | ||
1644 | if (strcmp(RELOC(pname), RELOC("name")) == 0) { | ||
1645 | prev_name = RELOC("name"); | ||
1646 | continue; | ||
1647 | } | ||
1648 | |||
1632 | /* find string offset */ | 1649 | /* find string offset */ |
1633 | soff = dt_find_string(pname); | 1650 | soff = dt_find_string(RELOC(pname)); |
1634 | if (soff == 0) { | 1651 | if (soff == 0) { |
1635 | prom_printf("WARNING: Can't find string index for <%s>, node %s\n", | 1652 | prom_printf("WARNING: Can't find string index for" |
1636 | pname, path); | 1653 | " <%s>, node %s\n", RELOC(pname), path); |
1637 | break; | 1654 | break; |
1638 | } | 1655 | } |
1639 | prev_name = sstart + soff; | 1656 | prev_name = sstart + soff; |
1640 | 1657 | ||
1641 | /* get length */ | 1658 | /* get length */ |
1642 | l = call_prom("getproplen", 2, 1, node, pname); | 1659 | l = call_prom("getproplen", 2, 1, node, RELOC(pname)); |
1643 | 1660 | ||
1644 | /* sanity checks */ | 1661 | /* sanity checks */ |
1645 | if (l == PROM_ERROR) | 1662 | if (l == PROM_ERROR) |
@@ -1648,7 +1665,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1648 | prom_printf("WARNING: ignoring large property "); | 1665 | prom_printf("WARNING: ignoring large property "); |
1649 | /* It seems OF doesn't null-terminate the path :-( */ | 1666 | /* It seems OF doesn't null-terminate the path :-( */ |
1650 | prom_printf("[%s] ", path); | 1667 | prom_printf("[%s] ", path); |
1651 | prom_printf("%s length 0x%x\n", pname, l); | 1668 | prom_printf("%s length 0x%x\n", RELOC(pname), l); |
1652 | continue; | 1669 | continue; |
1653 | } | 1670 | } |
1654 | 1671 | ||
@@ -1658,17 +1675,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1658 | dt_push_token(soff, mem_start, mem_end); | 1675 | dt_push_token(soff, mem_start, mem_end); |
1659 | 1676 | ||
1660 | /* push property content */ | 1677 | /* push property content */ |
1661 | align = (l >= 8) ? 8 : 4; | 1678 | valp = make_room(mem_start, mem_end, l, 4); |
1662 | valp = make_room(mem_start, mem_end, l, align); | 1679 | 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); | 1680 | *mem_start = _ALIGN(*mem_start, 4); |
1665 | } | 1681 | } |
1666 | 1682 | ||
1667 | /* Add a "linux,phandle" property. */ | 1683 | /* Add a "linux,phandle" property. */ |
1668 | soff = dt_find_string(RELOC("linux,phandle")); | 1684 | soff = dt_find_string(RELOC("linux,phandle")); |
1669 | if (soff == 0) | 1685 | if (soff == 0) |
1670 | prom_printf("WARNING: Can't find string index for <linux-phandle>" | 1686 | prom_printf("WARNING: Can't find string index for" |
1671 | " node %s\n", path); | 1687 | " <linux-phandle> node %s\n", path); |
1672 | else { | 1688 | else { |
1673 | dt_push_token(OF_DT_PROP, mem_start, mem_end); | 1689 | dt_push_token(OF_DT_PROP, mem_start, mem_end); |
1674 | dt_push_token(4, mem_start, mem_end); | 1690 | dt_push_token(4, mem_start, mem_end); |
@@ -1679,7 +1695,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1679 | 1695 | ||
1680 | /* do all our children */ | 1696 | /* do all our children */ |
1681 | child = call_prom("child", 1, 1, node); | 1697 | child = call_prom("child", 1, 1, node); |
1682 | while (child != (phandle)0) { | 1698 | while (child != 0) { |
1683 | scan_dt_build_struct(child, mem_start, mem_end); | 1699 | scan_dt_build_struct(child, mem_start, mem_end); |
1684 | child = call_prom("peer", 1, 1, child); | 1700 | child = call_prom("peer", 1, 1, child); |
1685 | } | 1701 | } |
@@ -1718,7 +1734,8 @@ static void __init flatten_device_tree(void) | |||
1718 | 1734 | ||
1719 | /* Build header and make room for mem rsv map */ | 1735 | /* Build header and make room for mem rsv map */ |
1720 | mem_start = _ALIGN(mem_start, 4); | 1736 | mem_start = _ALIGN(mem_start, 4); |
1721 | hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); | 1737 | hdr = make_room(&mem_start, &mem_end, |
1738 | sizeof(struct boot_param_header), 4); | ||
1722 | RELOC(dt_header_start) = (unsigned long)hdr; | 1739 | RELOC(dt_header_start) = (unsigned long)hdr; |
1723 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); | 1740 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); |
1724 | 1741 | ||
@@ -1731,11 +1748,11 @@ static void __init flatten_device_tree(void) | |||
1731 | namep = make_room(&mem_start, &mem_end, 16, 1); | 1748 | namep = make_room(&mem_start, &mem_end, 16, 1); |
1732 | strcpy(namep, RELOC("linux,phandle")); | 1749 | strcpy(namep, RELOC("linux,phandle")); |
1733 | mem_start = (unsigned long)namep + strlen(namep) + 1; | 1750 | mem_start = (unsigned long)namep + strlen(namep) + 1; |
1734 | RELOC(dt_string_end) = mem_start; | ||
1735 | 1751 | ||
1736 | /* Build string array */ | 1752 | /* Build string array */ |
1737 | prom_printf("Building dt strings...\n"); | 1753 | prom_printf("Building dt strings...\n"); |
1738 | scan_dt_build_strings(root, &mem_start, &mem_end); | 1754 | scan_dt_build_strings(root, &mem_start, &mem_end); |
1755 | RELOC(dt_string_end) = mem_start; | ||
1739 | 1756 | ||
1740 | /* Build structure */ | 1757 | /* Build structure */ |
1741 | mem_start = PAGE_ALIGN(mem_start); | 1758 | mem_start = PAGE_ALIGN(mem_start); |
@@ -1750,9 +1767,11 @@ static void __init flatten_device_tree(void) | |||
1750 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); | 1767 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); |
1751 | hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); | 1768 | 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); | 1769 | hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); |
1770 | hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); | ||
1753 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); | 1771 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); |
1754 | hdr->version = OF_DT_VERSION; | 1772 | hdr->version = OF_DT_VERSION; |
1755 | hdr->last_comp_version = 1; | 1773 | /* Version 16 is not backward compatible */ |
1774 | hdr->last_comp_version = 0x10; | ||
1756 | 1775 | ||
1757 | /* Reserve the whole thing and copy the reserve map in, we | 1776 | /* Reserve the whole thing and copy the reserve map in, we |
1758 | * also bump mem_reserve_cnt to cause further reservations to | 1777 | * also bump mem_reserve_cnt to cause further reservations to |
@@ -1808,6 +1827,9 @@ static void __init fixup_device_tree(void) | |||
1808 | /* does it need fixup ? */ | 1827 | /* does it need fixup ? */ |
1809 | if (prom_getproplen(i2c, "interrupts") > 0) | 1828 | if (prom_getproplen(i2c, "interrupts") > 0) |
1810 | return; | 1829 | return; |
1830 | |||
1831 | prom_printf("fixing up bogus interrupts for u3 i2c...\n"); | ||
1832 | |||
1811 | /* interrupt on this revision of u3 is number 0 and level */ | 1833 | /* interrupt on this revision of u3 is number 0 and level */ |
1812 | interrupts[0] = 0; | 1834 | interrupts[0] = 0; |
1813 | interrupts[1] = 1; | 1835 | interrupts[1] = 1; |