source: mainline/boot/genarch/ofw_tree.c@ 715a847f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 715a847f was 0b414b5, checked in by Jakub Jermar <jakub@…>, 19 years ago

Extend the OFW device tree node with a void pointer. The boot loader is
supposed to reset all pointers in all nodes. The kernel uses the pointer
to recognize that a particular device has already been visited and initialized.

Read interrupt mapping from the OFW device tree for FHC devices (z8530) and
EBUS devices (ns16550). In case of FHC devices, remove hardwired values from
the code and use only values read from the tree. FHC initialization is started
when a FHC device wants to map its interrupt. In case of EBUS devices, map
the interrupt to INO. Interrupt enabling in the interrupt controller for that
specific interrupt is not implemented yet.

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/*
2 * Copyright (C) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <ofw_tree.h>
30#include <ofw.h>
31#include <types.h>
32#include <string.h>
33#include <balloc.h>
34#include <asm.h>
35
36#define MAX_PATH_LEN 256
37
38static ofw_tree_node_t *ofw_tree_node_alloc(void)
39{
40 return balloc(sizeof(ofw_tree_node_t), sizeof(ofw_tree_node_t));
41}
42
43static ofw_tree_property_t *ofw_tree_properties_alloc(unsigned count)
44{
45 return balloc(count * sizeof(ofw_tree_property_t), sizeof(ofw_tree_property_t));
46}
47
48static void * ofw_tree_space_alloc(size_t size)
49{
50 char *addr;
51
52 /*
53 * What we do here is a nasty hack :-)
54 * Problem: string property values that are allocated via this
55 * function typically do not contain the trailing '\0'. This
56 * is very uncomfortable for kernel, which is supposed to deal
57 * with the properties.
58 * Solution: when allocating space via this function, we always
59 * allocate space for the extra '\0' character that we store
60 * behind the requested memory.
61 */
62 addr = balloc(size + 1, size);
63 if (addr)
64 addr[size] = '\0';
65 return addr;
66}
67
68/** Transfer information from one OpenFirmware node into its memory representation.
69 *
70 * Transfer entire information from the OpenFirmware device tree 'current' node to
71 * its memory representation in 'current_node'. This function recursively processes
72 * all node's peers and children.
73 *
74 * @param current_node Pointer to uninitialized ofw_tree_node structure that will
75 * become the memory represenation of 'current'.
76 * @param parent_node Parent ofw_tree_node structure or NULL in case of root node.
77 * @param current OpenFirmware phandle to the current device tree node.
78 */
79static void ofw_tree_node_process(ofw_tree_node_t *current_node,
80 ofw_tree_node_t *parent_node, phandle current)
81{
82 static char path[MAX_PATH_LEN+1];
83 static char name[OFW_TREE_PROPERTY_MAX_NAMELEN];
84 phandle peer;
85 phandle child;
86 unsigned properties = 0;
87 size_t len;
88 int i;
89
90 /*
91 * Initialize node.
92 */
93 current_node->parent = parent_node;
94 current_node->peer = NULL;
95 current_node->child = NULL;
96 current_node->node_handle = current;
97 current_node->properties = 0;
98 current_node->property = NULL;
99 current_node->device = NULL;
100
101 /*
102 * Get the disambigued name.
103 */
104 len = ofw_package_to_path(current, path, MAX_PATH_LEN);
105 if (len == -1)
106 return;
107
108 path[len] = '\0';
109 for (i = len - 1; i >= 0 && path[i] != '/'; i--)
110 ;
111 i++; /* do not include '/' */
112
113 len -= i;
114 current_node->da_name = ofw_tree_space_alloc(len + 1); /* add space for trailing '\0' */
115 if (!current_node->da_name)
116 return;
117
118 memcpy(current_node->da_name, &path[i], len);
119 current_node->da_name[len] = '\0';
120
121 /*
122 * Recursively process the potential peer node.
123 */
124 peer = ofw_get_peer_node(current);
125 if (peer != 0 && peer != -1) {
126 ofw_tree_node_t *peer_node;
127
128 peer_node = ofw_tree_node_alloc();
129 if (peer_node) {
130 ofw_tree_node_process(peer_node, parent_node, peer);
131 current_node->peer = peer_node;
132 }
133 }
134
135 /*
136 * Recursively process the potential child node.
137 */
138 child = ofw_get_child_node(current);
139 if (child != 0 && child != -1) {
140 ofw_tree_node_t *child_node;
141
142 child_node = ofw_tree_node_alloc();
143 if (child_node) {
144 ofw_tree_node_process(child_node, current_node, child);
145 current_node->child = child_node;
146 }
147 }
148
149 /*
150 * Count properties.
151 */
152 name[0] = '\0';
153 while (ofw_next_property(current, name, name) == 1)
154 current_node->properties++;
155
156 if (!current_node->properties)
157 return;
158
159 /*
160 * Copy properties.
161 */
162 current_node->property = ofw_tree_properties_alloc(current_node->properties);
163 if (!current_node->property)
164 return;
165
166 name[0] = '\0';
167 for (i = 0; ofw_next_property(current, name, name) == 1; i++) {
168 size_t size;
169
170 if (i == current_node->properties)
171 break;
172
173 memcpy(current_node->property[i].name, name, OFW_TREE_PROPERTY_MAX_NAMELEN);
174 current_node->property[i].name[OFW_TREE_PROPERTY_MAX_NAMELEN] = '\0';
175
176 size = ofw_get_proplen(current, name);
177 current_node->property[i].size = size;
178 if (size) {
179 void *buf;
180
181 buf = ofw_tree_space_alloc(size);
182 if (current_node->property[i].value = buf) {
183 /*
184 * Copy property value to memory node.
185 */
186 (void) ofw_get_property(current, name, buf, size);
187 }
188 } else {
189 current_node->property[i].value = NULL;
190 }
191 }
192
193 current_node->properties = i; /* Just in case we ran out of memory. */
194}
195
196/** Construct memory representation of OpenFirmware device tree.
197 *
198 * @return NULL on failure or pointer to the root node.
199 */
200ofw_tree_node_t *ofw_tree_build(void)
201{
202 ofw_tree_node_t *root;
203
204 root = ofw_tree_node_alloc();
205 if (root)
206 ofw_tree_node_process(root, NULL, ofw_root);
207
208 return root;
209}
Note: See TracBrowser for help on using the repository browser.