aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/mdesc.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-12 16:47:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-16 07:04:28 -0400
commit43fdf27470b216ebdef47e09ff83bed2f2894b13 (patch)
tree76b9b838089e5679471026037c93325c228df84a /arch/sparc64/kernel/mdesc.c
parent133f09a169f3022be3de671b29658b7ecb375022 (diff)
[SPARC64]: Abstract out mdesc accesses for better MD update handling.
Since we have to be able to handle MD updates, having an in-tree set of data structures representing the MD objects actually makes things more painful. The MD itself is easy to parse, and we can implement the existing interfaces using direct parsing of the MD binary image. The MD is now reference counted, so accesses have to now take the form: handle = mdesc_grab(); ... operations on MD ... mdesc_release(handle); The only remaining issue are cases where code holds on to references to MD property values. mdesc_get_property() returns a direct pointer to the property value, most cases just pull in the information they need and discard the pointer, but there are few that use the pointer directly over a long lifetime. Those will be fixed up in a subsequent changeset. A preliminary handler for MD update events from domain services is there, it is rudimentry but it works and handles all of the reference counting. It does not check the generation number of the MDs, and it does not generate a "add/delete" list for notification to interesting parties about MD changes but that will be forthcoming. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/mdesc.c')
-rw-r--r--arch/sparc64/kernel/mdesc.c666
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
34struct mdesc_elem { 36struct mdesc_elem {
35 u8 tag; 37 u8 tag;
@@ -53,306 +55,386 @@ struct mdesc_elem {
53 } d; 55 } d;
54}; 56};
55 57
56static struct mdesc_hdr *main_mdesc; 58struct mdesc_mem_ops {
57static struct mdesc_node *allnodes; 59 struct mdesc_handle *(*alloc)(unsigned int mdesc_size);
58 60 void (*free)(struct mdesc_handle *handle);
59static struct mdesc_node *allnodes_tail; 61};
60static unsigned int unique_id;
61 62
62static struct mdesc_node **mdesc_hash; 63struct mdesc_handle {
63static 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
65static inline unsigned int node_hashfn(u64 node) 72static 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
71static inline void hash_node(struct mdesc_node *mp) 85static 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
86static struct mdesc_node *find_node(u64 node) 102static 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
99struct property *md_find_property(const struct mdesc_node *mp, 125static 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
130static 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}
114EXPORT_SYMBOL(md_find_property);
115 154
116/* 155static 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 */
120const 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}
126EXPORT_SYMBOL(md_get_property);
127 162
128struct mdesc_node *md_find_node_by_name(struct mdesc_node *from, 163static struct mdesc_mem_ops kmalloc_mdesc_memops = {
129 const char *name) 164 .alloc = mdesc_kmalloc,
165 .free = mdesc_kfree,
166};
167
168static 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}
140EXPORT_SYMBOL(md_find_node_by_name);
141 175
142static unsigned int mdesc_early_allocated; 176 return hp;
177}
143 178
144static void * __init mdesc_early_alloc(unsigned long size) 179static 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); 184static struct mdesc_handle *cur_mdesc;
149 if (ret == NULL) { 185static LIST_HEAD(mdesc_zombie_list);
150 prom_printf("MDESC: alloc of %lu bytes failed.\n", size); 186static DEFINE_SPINLOCK(mdesc_lock);
151 prom_halt();
152 }
153 187
154 memset(ret, 0, size); 188struct 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}
201EXPORT_SYMBOL(mdesc_grab);
160 202
161static unsigned int __init count_arcs(struct mdesc_elem *ep) 203void 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}
214EXPORT_SYMBOL(mdesc_release);
173 215
174static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names) 216static 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
189static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) 250static DECLARE_WORK(mdesc_update_work, do_mdesc_update);
251
252void mdesc_update(void)
253{
254 schedule_work(&mdesc_update_work);
255}
256
257static 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
194static inline void *name_block(struct mdesc_hdr *mdesc) 262static 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
199static inline void *data_block(struct mdesc_hdr *mdesc) 267static 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 272u64 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 */
208static 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}
298EXPORT_SYMBOL(mdesc_node_by_name);
218 299
219 names = name_block(mdesc); 300const 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; 344EXPORT_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: 346u64 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}
370EXPORT_SYMBOL(mdesc_next_arc);
304 371
305static unsigned int __init count_nodes(struct mdesc_hdr *mdesc) 372u64 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}
380EXPORT_SYMBOL(mdesc_arc_target);
381
382const 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}
397EXPORT_SYMBOL(mdesc_node_name);
319 398
320static void __init report_platform_properties(void) 399static 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
358static int inline find_in_proplist(const char *list, const char *match, int len) 440static 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
372static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp) 454static 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
417static void __init mark_core_ids(struct mdesc_node *mp, int core_id) 499static 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
452static void __init set_core_ids(void) 532static 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
476static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) 557static 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
496static void __init __set_proc_ids(const char *exec_unit_name) 576static 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
517static void __init set_proc_ids(void) 598static 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
523static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) 604static 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
541static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb) 622static 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
558static void __init mdesc_fill_in_cpu_data(void) 640static 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
637void __init sun4v_mdesc_init(void) 718void __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();