diff options
Diffstat (limited to 'arch/sparc64/kernel/mdesc.c')
-rw-r--r-- | arch/sparc64/kernel/mdesc.c | 666 |
1 files changed, 370 insertions, 296 deletions
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index f0e16045fb16..9e5088d563cc 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <linux/types.h> | 6 | #include <linux/types.h> |
7 | #include <linux/bootmem.h> | 7 | #include <linux/bootmem.h> |
8 | #include <linux/log2.h> | 8 | #include <linux/log2.h> |
9 | #include <linux/list.h> | ||
10 | #include <linux/slab.h> | ||
9 | 11 | ||
10 | #include <asm/hypervisor.h> | 12 | #include <asm/hypervisor.h> |
11 | #include <asm/mdesc.h> | 13 | #include <asm/mdesc.h> |
@@ -29,7 +31,7 @@ struct mdesc_hdr { | |||
29 | u32 node_sz; /* node block size */ | 31 | u32 node_sz; /* node block size */ |
30 | u32 name_sz; /* name block size */ | 32 | u32 name_sz; /* name block size */ |
31 | u32 data_sz; /* data block size */ | 33 | u32 data_sz; /* data block size */ |
32 | }; | 34 | } __attribute__((aligned(16))); |
33 | 35 | ||
34 | struct mdesc_elem { | 36 | struct mdesc_elem { |
35 | u8 tag; | 37 | u8 tag; |
@@ -53,306 +55,386 @@ struct mdesc_elem { | |||
53 | } d; | 55 | } d; |
54 | }; | 56 | }; |
55 | 57 | ||
56 | static struct mdesc_hdr *main_mdesc; | 58 | struct mdesc_mem_ops { |
57 | static struct mdesc_node *allnodes; | 59 | struct mdesc_handle *(*alloc)(unsigned int mdesc_size); |
58 | 60 | void (*free)(struct mdesc_handle *handle); | |
59 | static struct mdesc_node *allnodes_tail; | 61 | }; |
60 | static unsigned int unique_id; | ||
61 | 62 | ||
62 | static struct mdesc_node **mdesc_hash; | 63 | struct mdesc_handle { |
63 | static unsigned int mdesc_hash_size; | 64 | struct list_head list; |
65 | struct mdesc_mem_ops *mops; | ||
66 | void *self_base; | ||
67 | atomic_t refcnt; | ||
68 | unsigned int handle_size; | ||
69 | struct mdesc_hdr mdesc; | ||
70 | }; | ||
64 | 71 | ||
65 | static inline unsigned int node_hashfn(u64 node) | 72 | static void mdesc_handle_init(struct mdesc_handle *hp, |
73 | unsigned int handle_size, | ||
74 | void *base) | ||
66 | { | 75 | { |
67 | return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16))) | 76 | BUG_ON(((unsigned long)&hp->mdesc) & (16UL - 1)); |
68 | & (mdesc_hash_size - 1); | 77 | |
78 | memset(hp, 0, handle_size); | ||
79 | INIT_LIST_HEAD(&hp->list); | ||
80 | hp->self_base = base; | ||
81 | atomic_set(&hp->refcnt, 1); | ||
82 | hp->handle_size = handle_size; | ||
69 | } | 83 | } |
70 | 84 | ||
71 | static inline void hash_node(struct mdesc_node *mp) | 85 | static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size) |
72 | { | 86 | { |
73 | struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)]; | 87 | struct mdesc_handle *hp; |
88 | unsigned int handle_size, alloc_size; | ||
74 | 89 | ||
75 | mp->hash_next = *head; | 90 | handle_size = (sizeof(struct mdesc_handle) - |
76 | *head = mp; | 91 | sizeof(struct mdesc_hdr) + |
92 | mdesc_size); | ||
93 | alloc_size = PAGE_ALIGN(handle_size); | ||
77 | 94 | ||
78 | if (allnodes_tail) { | 95 | hp = __alloc_bootmem(alloc_size, PAGE_SIZE, 0UL); |
79 | allnodes_tail->allnodes_next = mp; | 96 | if (hp) |
80 | allnodes_tail = mp; | 97 | mdesc_handle_init(hp, handle_size, hp); |
81 | } else { | 98 | |
82 | allnodes = allnodes_tail = mp; | 99 | return hp; |
83 | } | ||
84 | } | 100 | } |
85 | 101 | ||
86 | static struct mdesc_node *find_node(u64 node) | 102 | static void mdesc_bootmem_free(struct mdesc_handle *hp) |
87 | { | 103 | { |
88 | struct mdesc_node *mp = mdesc_hash[node_hashfn(node)]; | 104 | unsigned int alloc_size, handle_size = hp->handle_size; |
105 | unsigned long start, end; | ||
89 | 106 | ||
90 | while (mp) { | 107 | BUG_ON(atomic_read(&hp->refcnt) != 0); |
91 | if (mp->node == node) | 108 | BUG_ON(!list_empty(&hp->list)); |
92 | return mp; | ||
93 | 109 | ||
94 | mp = mp->hash_next; | 110 | alloc_size = PAGE_ALIGN(handle_size); |
111 | |||
112 | start = (unsigned long) hp; | ||
113 | end = start + alloc_size; | ||
114 | |||
115 | while (start < end) { | ||
116 | struct page *p; | ||
117 | |||
118 | p = virt_to_page(start); | ||
119 | ClearPageReserved(p); | ||
120 | __free_page(p); | ||
121 | start += PAGE_SIZE; | ||
95 | } | 122 | } |
96 | return NULL; | ||
97 | } | 123 | } |
98 | 124 | ||
99 | struct property *md_find_property(const struct mdesc_node *mp, | 125 | static struct mdesc_mem_ops bootmem_mdesc_memops = { |
100 | const char *name, | 126 | .alloc = mdesc_bootmem_alloc, |
101 | int *lenp) | 127 | .free = mdesc_bootmem_free, |
128 | }; | ||
129 | |||
130 | static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size) | ||
102 | { | 131 | { |
103 | struct property *pp; | 132 | unsigned int handle_size; |
133 | void *base; | ||
104 | 134 | ||
105 | for (pp = mp->properties; pp != 0; pp = pp->next) { | 135 | handle_size = (sizeof(struct mdesc_handle) - |
106 | if (strcasecmp(pp->name, name) == 0) { | 136 | sizeof(struct mdesc_hdr) + |
107 | if (lenp) | 137 | mdesc_size); |
108 | *lenp = pp->length; | 138 | |
109 | break; | 139 | base = kmalloc(handle_size + 15, GFP_KERNEL); |
110 | } | 140 | if (base) { |
141 | struct mdesc_handle *hp; | ||
142 | unsigned long addr; | ||
143 | |||
144 | addr = (unsigned long)base; | ||
145 | addr = (addr + 15UL) & ~15UL; | ||
146 | hp = (struct mdesc_handle *) addr; | ||
147 | |||
148 | mdesc_handle_init(hp, handle_size, base); | ||
149 | return hp; | ||
111 | } | 150 | } |
112 | return pp; | 151 | |
152 | return NULL; | ||
113 | } | 153 | } |
114 | EXPORT_SYMBOL(md_find_property); | ||
115 | 154 | ||
116 | /* | 155 | static void mdesc_kfree(struct mdesc_handle *hp) |
117 | * Find a property with a given name for a given node | ||
118 | * and return the value. | ||
119 | */ | ||
120 | const void *md_get_property(const struct mdesc_node *mp, const char *name, | ||
121 | int *lenp) | ||
122 | { | 156 | { |
123 | struct property *pp = md_find_property(mp, name, lenp); | 157 | BUG_ON(atomic_read(&hp->refcnt) != 0); |
124 | return pp ? pp->value : NULL; | 158 | BUG_ON(!list_empty(&hp->list)); |
159 | |||
160 | kfree(hp->self_base); | ||
125 | } | 161 | } |
126 | EXPORT_SYMBOL(md_get_property); | ||
127 | 162 | ||
128 | struct mdesc_node *md_find_node_by_name(struct mdesc_node *from, | 163 | static struct mdesc_mem_ops kmalloc_mdesc_memops = { |
129 | const char *name) | 164 | .alloc = mdesc_kmalloc, |
165 | .free = mdesc_kfree, | ||
166 | }; | ||
167 | |||
168 | static struct mdesc_handle *mdesc_alloc(unsigned int mdesc_size, | ||
169 | struct mdesc_mem_ops *mops) | ||
130 | { | 170 | { |
131 | struct mdesc_node *mp; | 171 | struct mdesc_handle *hp = mops->alloc(mdesc_size); |
132 | 172 | ||
133 | mp = from ? from->allnodes_next : allnodes; | 173 | if (hp) |
134 | for (; mp != NULL; mp = mp->allnodes_next) { | 174 | hp->mops = mops; |
135 | if (strcmp(mp->name, name) == 0) | ||
136 | break; | ||
137 | } | ||
138 | return mp; | ||
139 | } | ||
140 | EXPORT_SYMBOL(md_find_node_by_name); | ||
141 | 175 | ||
142 | static unsigned int mdesc_early_allocated; | 176 | return hp; |
177 | } | ||
143 | 178 | ||
144 | static void * __init mdesc_early_alloc(unsigned long size) | 179 | static void mdesc_free(struct mdesc_handle *hp) |
145 | { | 180 | { |
146 | void *ret; | 181 | hp->mops->free(hp); |
182 | } | ||
147 | 183 | ||
148 | ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); | 184 | static struct mdesc_handle *cur_mdesc; |
149 | if (ret == NULL) { | 185 | static LIST_HEAD(mdesc_zombie_list); |
150 | prom_printf("MDESC: alloc of %lu bytes failed.\n", size); | 186 | static DEFINE_SPINLOCK(mdesc_lock); |
151 | prom_halt(); | ||
152 | } | ||
153 | 187 | ||
154 | memset(ret, 0, size); | 188 | struct mdesc_handle *mdesc_grab(void) |
189 | { | ||
190 | struct mdesc_handle *hp; | ||
191 | unsigned long flags; | ||
155 | 192 | ||
156 | mdesc_early_allocated += size; | 193 | spin_lock_irqsave(&mdesc_lock, flags); |
194 | hp = cur_mdesc; | ||
195 | if (hp) | ||
196 | atomic_inc(&hp->refcnt); | ||
197 | spin_unlock_irqrestore(&mdesc_lock, flags); | ||
157 | 198 | ||
158 | return ret; | 199 | return hp; |
159 | } | 200 | } |
201 | EXPORT_SYMBOL(mdesc_grab); | ||
160 | 202 | ||
161 | static unsigned int __init count_arcs(struct mdesc_elem *ep) | 203 | void mdesc_release(struct mdesc_handle *hp) |
162 | { | 204 | { |
163 | unsigned int ret = 0; | 205 | unsigned long flags; |
164 | 206 | ||
165 | ep++; | 207 | spin_lock_irqsave(&mdesc_lock, flags); |
166 | while (ep->tag != MD_NODE_END) { | 208 | if (atomic_dec_and_test(&hp->refcnt)) { |
167 | if (ep->tag == MD_PROP_ARC) | 209 | list_del_init(&hp->list); |
168 | ret++; | 210 | hp->mops->free(hp); |
169 | ep++; | ||
170 | } | 211 | } |
171 | return ret; | 212 | spin_unlock_irqrestore(&mdesc_lock, flags); |
172 | } | 213 | } |
214 | EXPORT_SYMBOL(mdesc_release); | ||
173 | 215 | ||
174 | static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names) | 216 | static void do_mdesc_update(struct work_struct *work) |
175 | { | 217 | { |
176 | unsigned int num_arcs = count_arcs(ep); | 218 | unsigned long len, real_len, status; |
177 | struct mdesc_node *mp; | 219 | struct mdesc_handle *hp, *orig_hp; |
220 | unsigned long flags; | ||
221 | |||
222 | (void) sun4v_mach_desc(0UL, 0UL, &len); | ||
223 | |||
224 | hp = mdesc_alloc(len, &kmalloc_mdesc_memops); | ||
225 | if (!hp) { | ||
226 | printk(KERN_ERR "MD: mdesc alloc fails\n"); | ||
227 | return; | ||
228 | } | ||
229 | |||
230 | status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len); | ||
231 | if (status != HV_EOK || real_len > len) { | ||
232 | printk(KERN_ERR "MD: mdesc reread fails with %lu\n", | ||
233 | status); | ||
234 | atomic_dec(&hp->refcnt); | ||
235 | mdesc_free(hp); | ||
236 | return; | ||
237 | } | ||
178 | 238 | ||
179 | mp = mdesc_early_alloc(sizeof(*mp) + | 239 | spin_lock_irqsave(&mdesc_lock, flags); |
180 | (num_arcs * sizeof(struct mdesc_arc))); | 240 | orig_hp = cur_mdesc; |
181 | mp->name = names + ep->name_offset; | 241 | cur_mdesc = hp; |
182 | mp->node = node; | ||
183 | mp->unique_id = unique_id++; | ||
184 | mp->num_arcs = num_arcs; | ||
185 | 242 | ||
186 | hash_node(mp); | 243 | if (atomic_dec_and_test(&orig_hp->refcnt)) |
244 | mdesc_free(orig_hp); | ||
245 | else | ||
246 | list_add(&orig_hp->list, &mdesc_zombie_list); | ||
247 | spin_unlock_irqrestore(&mdesc_lock, flags); | ||
187 | } | 248 | } |
188 | 249 | ||
189 | static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) | 250 | static DECLARE_WORK(mdesc_update_work, do_mdesc_update); |
251 | |||
252 | void mdesc_update(void) | ||
253 | { | ||
254 | schedule_work(&mdesc_update_work); | ||
255 | } | ||
256 | |||
257 | static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) | ||
190 | { | 258 | { |
191 | return (struct mdesc_elem *) (mdesc + 1); | 259 | return (struct mdesc_elem *) (mdesc + 1); |
192 | } | 260 | } |
193 | 261 | ||
194 | static inline void *name_block(struct mdesc_hdr *mdesc) | 262 | static void *name_block(struct mdesc_hdr *mdesc) |
195 | { | 263 | { |
196 | return ((void *) node_block(mdesc)) + mdesc->node_sz; | 264 | return ((void *) node_block(mdesc)) + mdesc->node_sz; |
197 | } | 265 | } |
198 | 266 | ||
199 | static inline void *data_block(struct mdesc_hdr *mdesc) | 267 | static void *data_block(struct mdesc_hdr *mdesc) |
200 | { | 268 | { |
201 | return ((void *) name_block(mdesc)) + mdesc->name_sz; | 269 | return ((void *) name_block(mdesc)) + mdesc->name_sz; |
202 | } | 270 | } |
203 | 271 | ||
204 | /* In order to avoid recursion (the graph can be very deep) we use a | 272 | u64 mdesc_node_by_name(struct mdesc_handle *hp, |
205 | * two pass algorithm. First we allocate all the nodes and hash them. | 273 | u64 from_node, const char *name) |
206 | * Then we iterate over each node, filling in the arcs and properties. | ||
207 | */ | ||
208 | static void __init build_all_nodes(struct mdesc_hdr *mdesc) | ||
209 | { | 274 | { |
210 | struct mdesc_elem *start, *ep; | 275 | struct mdesc_elem *ep = node_block(&hp->mdesc); |
211 | struct mdesc_node *mp; | 276 | const char *names = name_block(&hp->mdesc); |
212 | const char *names; | 277 | u64 last_node = hp->mdesc.node_sz / 16; |
213 | void *data; | 278 | u64 ret; |
214 | u64 last_node; | 279 | |
215 | 280 | if (from_node == MDESC_NODE_NULL) | |
216 | start = ep = node_block(mdesc); | 281 | from_node = 0; |
217 | last_node = mdesc->node_sz / 16; | 282 | |
283 | if (from_node >= last_node) | ||
284 | return MDESC_NODE_NULL; | ||
285 | |||
286 | ret = ep[from_node].d.val; | ||
287 | while (ret < last_node) { | ||
288 | if (ep[ret].tag != MD_NODE) | ||
289 | return MDESC_NODE_NULL; | ||
290 | if (!strcmp(names + ep[ret].name_offset, name)) | ||
291 | break; | ||
292 | ret = ep[ret].d.val; | ||
293 | } | ||
294 | if (ret >= last_node) | ||
295 | ret = MDESC_NODE_NULL; | ||
296 | return ret; | ||
297 | } | ||
298 | EXPORT_SYMBOL(mdesc_node_by_name); | ||
218 | 299 | ||
219 | names = name_block(mdesc); | 300 | const void *mdesc_get_property(struct mdesc_handle *hp, u64 node, |
301 | const char *name, int *lenp) | ||
302 | { | ||
303 | const char *names = name_block(&hp->mdesc); | ||
304 | u64 last_node = hp->mdesc.node_sz / 16; | ||
305 | void *data = data_block(&hp->mdesc); | ||
306 | struct mdesc_elem *ep; | ||
220 | 307 | ||
221 | while (1) { | 308 | if (node == MDESC_NODE_NULL || node >= last_node) |
222 | u64 node = ep - start; | 309 | return NULL; |
223 | 310 | ||
224 | if (ep->tag == MD_LIST_END) | 311 | ep = node_block(&hp->mdesc) + node; |
312 | ep++; | ||
313 | for (; ep->tag != MD_NODE_END; ep++) { | ||
314 | void *val = NULL; | ||
315 | int len = 0; | ||
316 | |||
317 | switch (ep->tag) { | ||
318 | case MD_PROP_VAL: | ||
319 | val = &ep->d.val; | ||
320 | len = 8; | ||
225 | break; | 321 | break; |
226 | 322 | ||
227 | if (ep->tag != MD_NODE) { | 323 | case MD_PROP_STR: |
228 | prom_printf("MDESC: Inconsistent element list.\n"); | 324 | case MD_PROP_DATA: |
229 | prom_halt(); | 325 | val = data + ep->d.data.data_offset; |
230 | } | 326 | len = ep->d.data.data_len; |
231 | 327 | break; | |
232 | mdesc_node_alloc(node, ep, names); | ||
233 | 328 | ||
234 | if (ep->d.val >= last_node) { | 329 | default: |
235 | printk("MDESC: Warning, early break out of node scan.\n"); | ||
236 | printk("MDESC: Next node [%lu] last_node [%lu].\n", | ||
237 | node, last_node); | ||
238 | break; | 330 | break; |
239 | } | 331 | } |
332 | if (!val) | ||
333 | continue; | ||
240 | 334 | ||
241 | ep = start + ep->d.val; | 335 | if (!strcmp(names + ep->name_offset, name)) { |
336 | if (lenp) | ||
337 | *lenp = len; | ||
338 | return val; | ||
339 | } | ||
242 | } | 340 | } |
243 | 341 | ||
244 | data = data_block(mdesc); | 342 | return NULL; |
245 | for (mp = allnodes; mp; mp = mp->allnodes_next) { | 343 | } |
246 | struct mdesc_elem *ep = start + mp->node; | 344 | EXPORT_SYMBOL(mdesc_get_property); |
247 | struct property **link = &mp->properties; | ||
248 | unsigned int this_arc = 0; | ||
249 | |||
250 | ep++; | ||
251 | while (ep->tag != MD_NODE_END) { | ||
252 | switch (ep->tag) { | ||
253 | case MD_PROP_ARC: { | ||
254 | struct mdesc_node *target; | ||
255 | |||
256 | if (this_arc >= mp->num_arcs) { | ||
257 | prom_printf("MDESC: ARC overrun [%u:%u]\n", | ||
258 | this_arc, mp->num_arcs); | ||
259 | prom_halt(); | ||
260 | } | ||
261 | target = find_node(ep->d.val); | ||
262 | if (!target) { | ||
263 | printk("MDESC: Warning, arc points to " | ||
264 | "missing node, ignoring.\n"); | ||
265 | break; | ||
266 | } | ||
267 | mp->arcs[this_arc].name = | ||
268 | (names + ep->name_offset); | ||
269 | mp->arcs[this_arc].arc = target; | ||
270 | this_arc++; | ||
271 | break; | ||
272 | } | ||
273 | 345 | ||
274 | case MD_PROP_VAL: | 346 | u64 mdesc_next_arc(struct mdesc_handle *hp, u64 from, const char *arc_type) |
275 | case MD_PROP_STR: | 347 | { |
276 | case MD_PROP_DATA: { | 348 | struct mdesc_elem *ep, *base = node_block(&hp->mdesc); |
277 | struct property *p = mdesc_early_alloc(sizeof(*p)); | 349 | const char *names = name_block(&hp->mdesc); |
278 | 350 | u64 last_node = hp->mdesc.node_sz / 16; | |
279 | p->unique_id = unique_id++; | ||
280 | p->name = (char *) names + ep->name_offset; | ||
281 | if (ep->tag == MD_PROP_VAL) { | ||
282 | p->value = &ep->d.val; | ||
283 | p->length = 8; | ||
284 | } else { | ||
285 | p->value = data + ep->d.data.data_offset; | ||
286 | p->length = ep->d.data.data_len; | ||
287 | } | ||
288 | *link = p; | ||
289 | link = &p->next; | ||
290 | break; | ||
291 | } | ||
292 | 351 | ||
293 | case MD_NOOP: | 352 | if (from == MDESC_NODE_NULL || from >= last_node) |
294 | break; | 353 | return MDESC_NODE_NULL; |
295 | 354 | ||
296 | default: | 355 | ep = base + from; |
297 | printk("MDESC: Warning, ignoring unknown tag type %02x\n", | 356 | |
298 | ep->tag); | 357 | ep++; |
299 | } | 358 | for (; ep->tag != MD_NODE_END; ep++) { |
300 | ep++; | 359 | if (ep->tag != MD_PROP_ARC) |
301 | } | 360 | continue; |
361 | |||
362 | if (strcmp(names + ep->name_offset, arc_type)) | ||
363 | continue; | ||
364 | |||
365 | return ep - base; | ||
302 | } | 366 | } |
367 | |||
368 | return MDESC_NODE_NULL; | ||
303 | } | 369 | } |
370 | EXPORT_SYMBOL(mdesc_next_arc); | ||
304 | 371 | ||
305 | static unsigned int __init count_nodes(struct mdesc_hdr *mdesc) | 372 | u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc) |
306 | { | 373 | { |
307 | struct mdesc_elem *ep = node_block(mdesc); | 374 | struct mdesc_elem *ep, *base = node_block(&hp->mdesc); |
308 | struct mdesc_elem *end; | 375 | |
309 | unsigned int cnt = 0; | 376 | ep = base + arc; |
310 | 377 | ||
311 | end = ((void *)ep) + mdesc->node_sz; | 378 | return ep->d.val; |
312 | while (ep < end) { | ||
313 | if (ep->tag == MD_NODE) | ||
314 | cnt++; | ||
315 | ep++; | ||
316 | } | ||
317 | return cnt; | ||
318 | } | 379 | } |
380 | EXPORT_SYMBOL(mdesc_arc_target); | ||
381 | |||
382 | const char *mdesc_node_name(struct mdesc_handle *hp, u64 node) | ||
383 | { | ||
384 | struct mdesc_elem *ep, *base = node_block(&hp->mdesc); | ||
385 | const char *names = name_block(&hp->mdesc); | ||
386 | u64 last_node = hp->mdesc.node_sz / 16; | ||
387 | |||
388 | if (node == MDESC_NODE_NULL || node >= last_node) | ||
389 | return NULL; | ||
390 | |||
391 | ep = base + node; | ||
392 | if (ep->tag != MD_NODE) | ||
393 | return NULL; | ||
394 | |||
395 | return names + ep->name_offset; | ||
396 | } | ||
397 | EXPORT_SYMBOL(mdesc_node_name); | ||
319 | 398 | ||
320 | static void __init report_platform_properties(void) | 399 | static void __init report_platform_properties(void) |
321 | { | 400 | { |
322 | struct mdesc_node *pn = md_find_node_by_name(NULL, "platform"); | 401 | struct mdesc_handle *hp = mdesc_grab(); |
402 | u64 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform"); | ||
323 | const char *s; | 403 | const char *s; |
324 | const u64 *v; | 404 | const u64 *v; |
325 | 405 | ||
326 | if (!pn) { | 406 | if (pn == MDESC_NODE_NULL) { |
327 | prom_printf("No platform node in machine-description.\n"); | 407 | prom_printf("No platform node in machine-description.\n"); |
328 | prom_halt(); | 408 | prom_halt(); |
329 | } | 409 | } |
330 | 410 | ||
331 | s = md_get_property(pn, "banner-name", NULL); | 411 | s = mdesc_get_property(hp, pn, "banner-name", NULL); |
332 | printk("PLATFORM: banner-name [%s]\n", s); | 412 | printk("PLATFORM: banner-name [%s]\n", s); |
333 | s = md_get_property(pn, "name", NULL); | 413 | s = mdesc_get_property(hp, pn, "name", NULL); |
334 | printk("PLATFORM: name [%s]\n", s); | 414 | printk("PLATFORM: name [%s]\n", s); |
335 | 415 | ||
336 | v = md_get_property(pn, "hostid", NULL); | 416 | v = mdesc_get_property(hp, pn, "hostid", NULL); |
337 | if (v) | 417 | if (v) |
338 | printk("PLATFORM: hostid [%08lx]\n", *v); | 418 | printk("PLATFORM: hostid [%08lx]\n", *v); |
339 | v = md_get_property(pn, "serial#", NULL); | 419 | v = mdesc_get_property(hp, pn, "serial#", NULL); |
340 | if (v) | 420 | if (v) |
341 | printk("PLATFORM: serial# [%08lx]\n", *v); | 421 | printk("PLATFORM: serial# [%08lx]\n", *v); |
342 | v = md_get_property(pn, "stick-frequency", NULL); | 422 | v = mdesc_get_property(hp, pn, "stick-frequency", NULL); |
343 | printk("PLATFORM: stick-frequency [%08lx]\n", *v); | 423 | printk("PLATFORM: stick-frequency [%08lx]\n", *v); |
344 | v = md_get_property(pn, "mac-address", NULL); | 424 | v = mdesc_get_property(hp, pn, "mac-address", NULL); |
345 | if (v) | 425 | if (v) |
346 | printk("PLATFORM: mac-address [%lx]\n", *v); | 426 | printk("PLATFORM: mac-address [%lx]\n", *v); |
347 | v = md_get_property(pn, "watchdog-resolution", NULL); | 427 | v = mdesc_get_property(hp, pn, "watchdog-resolution", NULL); |
348 | if (v) | 428 | if (v) |
349 | printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v); | 429 | printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v); |
350 | v = md_get_property(pn, "watchdog-max-timeout", NULL); | 430 | v = mdesc_get_property(hp, pn, "watchdog-max-timeout", NULL); |
351 | if (v) | 431 | if (v) |
352 | printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v); | 432 | printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v); |
353 | v = md_get_property(pn, "max-cpus", NULL); | 433 | v = mdesc_get_property(hp, pn, "max-cpus", NULL); |
354 | if (v) | 434 | if (v) |
355 | printk("PLATFORM: max-cpus [%lu]\n", *v); | 435 | printk("PLATFORM: max-cpus [%lu]\n", *v); |
436 | |||
437 | mdesc_release(hp); | ||
356 | } | 438 | } |
357 | 439 | ||
358 | static int inline find_in_proplist(const char *list, const char *match, int len) | 440 | static int inline find_in_proplist(const char *list, const char *match, int len) |
@@ -369,15 +451,17 @@ static int inline find_in_proplist(const char *list, const char *match, int len) | |||
369 | return 0; | 451 | return 0; |
370 | } | 452 | } |
371 | 453 | ||
372 | static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp) | 454 | static void __init fill_in_one_cache(cpuinfo_sparc *c, |
455 | struct mdesc_handle *hp, | ||
456 | u64 mp) | ||
373 | { | 457 | { |
374 | const u64 *level = md_get_property(mp, "level", NULL); | 458 | const u64 *level = mdesc_get_property(hp, mp, "level", NULL); |
375 | const u64 *size = md_get_property(mp, "size", NULL); | 459 | const u64 *size = mdesc_get_property(hp, mp, "size", NULL); |
376 | const u64 *line_size = md_get_property(mp, "line-size", NULL); | 460 | const u64 *line_size = mdesc_get_property(hp, mp, "line-size", NULL); |
377 | const char *type; | 461 | const char *type; |
378 | int type_len; | 462 | int type_len; |
379 | 463 | ||
380 | type = md_get_property(mp, "type", &type_len); | 464 | type = mdesc_get_property(hp, mp, "type", &type_len); |
381 | 465 | ||
382 | switch (*level) { | 466 | switch (*level) { |
383 | case 1: | 467 | case 1: |
@@ -400,48 +484,44 @@ static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp) | |||
400 | } | 484 | } |
401 | 485 | ||
402 | if (*level == 1) { | 486 | if (*level == 1) { |
403 | unsigned int i; | 487 | u64 a; |
404 | 488 | ||
405 | for (i = 0; i < mp->num_arcs; i++) { | 489 | mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { |
406 | struct mdesc_node *t = mp->arcs[i].arc; | 490 | u64 target = mdesc_arc_target(hp, a); |
491 | const char *name = mdesc_node_name(hp, target); | ||
407 | 492 | ||
408 | if (strcmp(mp->arcs[i].name, "fwd")) | 493 | if (!strcmp(name, "cache")) |
409 | continue; | 494 | fill_in_one_cache(c, hp, target); |
410 | |||
411 | if (!strcmp(t->name, "cache")) | ||
412 | fill_in_one_cache(c, t); | ||
413 | } | 495 | } |
414 | } | 496 | } |
415 | } | 497 | } |
416 | 498 | ||
417 | static void __init mark_core_ids(struct mdesc_node *mp, int core_id) | 499 | static void __init mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id) |
418 | { | 500 | { |
419 | unsigned int i; | 501 | u64 a; |
420 | 502 | ||
421 | for (i = 0; i < mp->num_arcs; i++) { | 503 | mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) { |
422 | struct mdesc_node *t = mp->arcs[i].arc; | 504 | u64 t = mdesc_arc_target(hp, a); |
505 | const char *name; | ||
423 | const u64 *id; | 506 | const u64 *id; |
424 | 507 | ||
425 | if (strcmp(mp->arcs[i].name, "back")) | 508 | name = mdesc_node_name(hp, t); |
426 | continue; | 509 | if (!strcmp(name, "cpu")) { |
427 | 510 | id = mdesc_get_property(hp, t, "id", NULL); | |
428 | if (!strcmp(t->name, "cpu")) { | ||
429 | id = md_get_property(t, "id", NULL); | ||
430 | if (*id < NR_CPUS) | 511 | if (*id < NR_CPUS) |
431 | cpu_data(*id).core_id = core_id; | 512 | cpu_data(*id).core_id = core_id; |
432 | } else { | 513 | } else { |
433 | unsigned int j; | 514 | u64 j; |
434 | 515 | ||
435 | for (j = 0; j < t->num_arcs; j++) { | 516 | mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_BACK) { |
436 | struct mdesc_node *n = t->arcs[j].arc; | 517 | u64 n = mdesc_arc_target(hp, j); |
518 | const char *n_name; | ||
437 | 519 | ||
438 | if (strcmp(t->arcs[j].name, "back")) | 520 | n_name = mdesc_node_name(hp, n); |
521 | if (strcmp(n_name, "cpu")) | ||
439 | continue; | 522 | continue; |
440 | 523 | ||
441 | if (strcmp(n->name, "cpu")) | 524 | id = mdesc_get_property(hp, n, "id", NULL); |
442 | continue; | ||
443 | |||
444 | id = md_get_property(n, "id", NULL); | ||
445 | if (*id < NR_CPUS) | 525 | if (*id < NR_CPUS) |
446 | cpu_data(*id).core_id = core_id; | 526 | cpu_data(*id).core_id = core_id; |
447 | } | 527 | } |
@@ -449,75 +529,76 @@ static void __init mark_core_ids(struct mdesc_node *mp, int core_id) | |||
449 | } | 529 | } |
450 | } | 530 | } |
451 | 531 | ||
452 | static void __init set_core_ids(void) | 532 | static void __init set_core_ids(struct mdesc_handle *hp) |
453 | { | 533 | { |
454 | struct mdesc_node *mp; | ||
455 | int idx; | 534 | int idx; |
535 | u64 mp; | ||
456 | 536 | ||
457 | idx = 1; | 537 | idx = 1; |
458 | md_for_each_node_by_name(mp, "cache") { | 538 | mdesc_for_each_node_by_name(hp, mp, "cache") { |
459 | const u64 *level = md_get_property(mp, "level", NULL); | 539 | const u64 *level; |
460 | const char *type; | 540 | const char *type; |
461 | int len; | 541 | int len; |
462 | 542 | ||
543 | level = mdesc_get_property(hp, mp, "level", NULL); | ||
463 | if (*level != 1) | 544 | if (*level != 1) |
464 | continue; | 545 | continue; |
465 | 546 | ||
466 | type = md_get_property(mp, "type", &len); | 547 | type = mdesc_get_property(hp, mp, "type", &len); |
467 | if (!find_in_proplist(type, "instn", len)) | 548 | if (!find_in_proplist(type, "instn", len)) |
468 | continue; | 549 | continue; |
469 | 550 | ||
470 | mark_core_ids(mp, idx); | 551 | mark_core_ids(hp, mp, idx); |
471 | 552 | ||
472 | idx++; | 553 | idx++; |
473 | } | 554 | } |
474 | } | 555 | } |
475 | 556 | ||
476 | static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) | 557 | static void __init mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id) |
477 | { | 558 | { |
478 | int i; | 559 | u64 a; |
479 | 560 | ||
480 | for (i = 0; i < mp->num_arcs; i++) { | 561 | mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) { |
481 | struct mdesc_node *t = mp->arcs[i].arc; | 562 | u64 t = mdesc_arc_target(hp, a); |
563 | const char *name; | ||
482 | const u64 *id; | 564 | const u64 *id; |
483 | 565 | ||
484 | if (strcmp(mp->arcs[i].name, "back")) | 566 | name = mdesc_node_name(hp, t); |
485 | continue; | 567 | if (strcmp(name, "cpu")) |
486 | |||
487 | if (strcmp(t->name, "cpu")) | ||
488 | continue; | 568 | continue; |
489 | 569 | ||
490 | id = md_get_property(t, "id", NULL); | 570 | id = mdesc_get_property(hp, t, "id", NULL); |
491 | if (*id < NR_CPUS) | 571 | if (*id < NR_CPUS) |
492 | cpu_data(*id).proc_id = proc_id; | 572 | cpu_data(*id).proc_id = proc_id; |
493 | } | 573 | } |
494 | } | 574 | } |
495 | 575 | ||
496 | static void __init __set_proc_ids(const char *exec_unit_name) | 576 | static void __init __set_proc_ids(struct mdesc_handle *hp, |
577 | const char *exec_unit_name) | ||
497 | { | 578 | { |
498 | struct mdesc_node *mp; | ||
499 | int idx; | 579 | int idx; |
580 | u64 mp; | ||
500 | 581 | ||
501 | idx = 0; | 582 | idx = 0; |
502 | md_for_each_node_by_name(mp, exec_unit_name) { | 583 | mdesc_for_each_node_by_name(hp, mp, exec_unit_name) { |
503 | const char *type; | 584 | const char *type; |
504 | int len; | 585 | int len; |
505 | 586 | ||
506 | type = md_get_property(mp, "type", &len); | 587 | type = mdesc_get_property(hp, mp, "type", &len); |
507 | if (!find_in_proplist(type, "int", len) && | 588 | if (!find_in_proplist(type, "int", len) && |
508 | !find_in_proplist(type, "integer", len)) | 589 | !find_in_proplist(type, "integer", len)) |
509 | continue; | 590 | continue; |
510 | 591 | ||
511 | mark_proc_ids(mp, idx); | 592 | mark_proc_ids(hp, mp, idx); |
512 | 593 | ||
513 | idx++; | 594 | idx++; |
514 | } | 595 | } |
515 | } | 596 | } |
516 | 597 | ||
517 | static void __init set_proc_ids(void) | 598 | static void __init set_proc_ids(struct mdesc_handle *hp) |
518 | { | 599 | { |
519 | __set_proc_ids("exec_unit"); | 600 | __set_proc_ids(hp, "exec_unit"); |
520 | __set_proc_ids("exec-unit"); | 601 | __set_proc_ids(hp, "exec-unit"); |
521 | } | 602 | } |
522 | 603 | ||
523 | static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) | 604 | static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) |
@@ -538,35 +619,37 @@ use_default: | |||
538 | *mask = ((1U << def) * 64U) - 1U; | 619 | *mask = ((1U << def) * 64U) - 1U; |
539 | } | 620 | } |
540 | 621 | ||
541 | static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb) | 622 | static void __init get_mondo_data(struct mdesc_handle *hp, u64 mp, |
623 | struct trap_per_cpu *tb) | ||
542 | { | 624 | { |
543 | const u64 *val; | 625 | const u64 *val; |
544 | 626 | ||
545 | val = md_get_property(mp, "q-cpu-mondo-#bits", NULL); | 627 | val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL); |
546 | get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); | 628 | get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); |
547 | 629 | ||
548 | val = md_get_property(mp, "q-dev-mondo-#bits", NULL); | 630 | val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL); |
549 | get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); | 631 | get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); |
550 | 632 | ||
551 | val = md_get_property(mp, "q-resumable-#bits", NULL); | 633 | val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL); |
552 | get_one_mondo_bits(val, &tb->resum_qmask, 6); | 634 | get_one_mondo_bits(val, &tb->resum_qmask, 6); |
553 | 635 | ||
554 | val = md_get_property(mp, "q-nonresumable-#bits", NULL); | 636 | val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL); |
555 | get_one_mondo_bits(val, &tb->nonresum_qmask, 2); | 637 | get_one_mondo_bits(val, &tb->nonresum_qmask, 2); |
556 | } | 638 | } |
557 | 639 | ||
558 | static void __init mdesc_fill_in_cpu_data(void) | 640 | static void __init mdesc_fill_in_cpu_data(void) |
559 | { | 641 | { |
560 | struct mdesc_node *mp; | 642 | struct mdesc_handle *hp = mdesc_grab(); |
643 | u64 mp; | ||
561 | 644 | ||
562 | ncpus_probed = 0; | 645 | ncpus_probed = 0; |
563 | md_for_each_node_by_name(mp, "cpu") { | 646 | mdesc_for_each_node_by_name(hp, mp, "cpu") { |
564 | const u64 *id = md_get_property(mp, "id", NULL); | 647 | const u64 *id = mdesc_get_property(hp, mp, "id", NULL); |
565 | const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL); | 648 | const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); |
566 | struct trap_per_cpu *tb; | 649 | struct trap_per_cpu *tb; |
567 | cpuinfo_sparc *c; | 650 | cpuinfo_sparc *c; |
568 | unsigned int i; | ||
569 | int cpuid; | 651 | int cpuid; |
652 | u64 a; | ||
570 | 653 | ||
571 | ncpus_probed++; | 654 | ncpus_probed++; |
572 | 655 | ||
@@ -589,29 +672,25 @@ static void __init mdesc_fill_in_cpu_data(void) | |||
589 | c->clock_tick = *cfreq; | 672 | c->clock_tick = *cfreq; |
590 | 673 | ||
591 | tb = &trap_block[cpuid]; | 674 | tb = &trap_block[cpuid]; |
592 | get_mondo_data(mp, tb); | 675 | get_mondo_data(hp, mp, tb); |
593 | |||
594 | for (i = 0; i < mp->num_arcs; i++) { | ||
595 | struct mdesc_node *t = mp->arcs[i].arc; | ||
596 | unsigned int j; | ||
597 | 676 | ||
598 | if (strcmp(mp->arcs[i].name, "fwd")) | 677 | mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { |
599 | continue; | 678 | u64 j, t = mdesc_arc_target(hp, a); |
679 | const char *t_name; | ||
600 | 680 | ||
601 | if (!strcmp(t->name, "cache")) { | 681 | t_name = mdesc_node_name(hp, t); |
602 | fill_in_one_cache(c, t); | 682 | if (!strcmp(t_name, "cache")) { |
683 | fill_in_one_cache(c, hp, t); | ||
603 | continue; | 684 | continue; |
604 | } | 685 | } |
605 | 686 | ||
606 | for (j = 0; j < t->num_arcs; j++) { | 687 | mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) { |
607 | struct mdesc_node *n; | 688 | u64 n = mdesc_arc_target(hp, j); |
689 | const char *n_name; | ||
608 | 690 | ||
609 | n = t->arcs[j].arc; | 691 | n_name = mdesc_node_name(hp, n); |
610 | if (strcmp(t->arcs[j].name, "fwd")) | 692 | if (!strcmp(n_name, "cache")) |
611 | continue; | 693 | fill_in_one_cache(c, hp, n); |
612 | |||
613 | if (!strcmp(n->name, "cache")) | ||
614 | fill_in_one_cache(c, n); | ||
615 | } | 694 | } |
616 | } | 695 | } |
617 | 696 | ||
@@ -628,44 +707,39 @@ static void __init mdesc_fill_in_cpu_data(void) | |||
628 | sparc64_multi_core = 1; | 707 | sparc64_multi_core = 1; |
629 | #endif | 708 | #endif |
630 | 709 | ||
631 | set_core_ids(); | 710 | set_core_ids(hp); |
632 | set_proc_ids(); | 711 | set_proc_ids(hp); |
633 | 712 | ||
634 | smp_fill_in_sib_core_maps(); | 713 | smp_fill_in_sib_core_maps(); |
714 | |||
715 | mdesc_release(hp); | ||
635 | } | 716 | } |
636 | 717 | ||
637 | void __init sun4v_mdesc_init(void) | 718 | void __init sun4v_mdesc_init(void) |
638 | { | 719 | { |
720 | struct mdesc_handle *hp; | ||
639 | unsigned long len, real_len, status; | 721 | unsigned long len, real_len, status; |
640 | 722 | ||
641 | (void) sun4v_mach_desc(0UL, 0UL, &len); | 723 | (void) sun4v_mach_desc(0UL, 0UL, &len); |
642 | 724 | ||
643 | printk("MDESC: Size is %lu bytes.\n", len); | 725 | printk("MDESC: Size is %lu bytes.\n", len); |
644 | 726 | ||
645 | main_mdesc = mdesc_early_alloc(len); | 727 | hp = mdesc_alloc(len, &bootmem_mdesc_memops); |
728 | if (hp == NULL) { | ||
729 | prom_printf("MDESC: alloc of %lu bytes failed.\n", len); | ||
730 | prom_halt(); | ||
731 | } | ||
646 | 732 | ||
647 | status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len); | 733 | status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len); |
648 | if (status != HV_EOK || real_len > len) { | 734 | if (status != HV_EOK || real_len > len) { |
649 | prom_printf("sun4v_mach_desc fails, err(%lu), " | 735 | prom_printf("sun4v_mach_desc fails, err(%lu), " |
650 | "len(%lu), real_len(%lu)\n", | 736 | "len(%lu), real_len(%lu)\n", |
651 | status, len, real_len); | 737 | status, len, real_len); |
738 | mdesc_free(hp); | ||
652 | prom_halt(); | 739 | prom_halt(); |
653 | } | 740 | } |
654 | 741 | ||
655 | len = count_nodes(main_mdesc); | 742 | cur_mdesc = hp; |
656 | printk("MDESC: %lu nodes.\n", len); | ||
657 | |||
658 | len = roundup_pow_of_two(len); | ||
659 | |||
660 | mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *)); | ||
661 | mdesc_hash_size = len; | ||
662 | |||
663 | printk("MDESC: Hash size %lu entries.\n", len); | ||
664 | |||
665 | build_all_nodes(main_mdesc); | ||
666 | |||
667 | printk("MDESC: Built graph with %u bytes of memory.\n", | ||
668 | mdesc_early_allocated); | ||
669 | 743 | ||
670 | report_platform_properties(); | 744 | report_platform_properties(); |
671 | mdesc_fill_in_cpu_data(); | 745 | mdesc_fill_in_cpu_data(); |