mdesc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /* mdesc.c: Sun4V machine description handling.
  2. *
  3. * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/types.h>
  7. #include <linux/bootmem.h>
  8. #include <linux/log2.h>
  9. #include <asm/hypervisor.h>
  10. #include <asm/mdesc.h>
  11. #include <asm/prom.h>
  12. #include <asm/oplib.h>
  13. #include <asm/smp.h>
  14. /* Unlike the OBP device tree, the machine description is a full-on
  15. * DAG. An arbitrary number of ARCs are possible from one
  16. * node to other nodes and thus we can't use the OBP device_node
  17. * data structure to represent these nodes inside of the kernel.
  18. *
  19. * Actually, it isn't even a DAG, because there are back pointers
  20. * which create cycles in the graph.
  21. *
  22. * mdesc_hdr and mdesc_elem describe the layout of the data structure
  23. * we get from the Hypervisor.
  24. */
  25. struct mdesc_hdr {
  26. u32 version; /* Transport version */
  27. u32 node_sz; /* node block size */
  28. u32 name_sz; /* name block size */
  29. u32 data_sz; /* data block size */
  30. };
  31. struct mdesc_elem {
  32. u8 tag;
  33. #define MD_LIST_END 0x00
  34. #define MD_NODE 0x4e
  35. #define MD_NODE_END 0x45
  36. #define MD_NOOP 0x20
  37. #define MD_PROP_ARC 0x61
  38. #define MD_PROP_VAL 0x76
  39. #define MD_PROP_STR 0x73
  40. #define MD_PROP_DATA 0x64
  41. u8 name_len;
  42. u16 resv;
  43. u32 name_offset;
  44. union {
  45. struct {
  46. u32 data_len;
  47. u32 data_offset;
  48. } data;
  49. u64 val;
  50. } d;
  51. };
  52. static struct mdesc_hdr *main_mdesc;
  53. static struct mdesc_node *allnodes;
  54. static struct mdesc_node *allnodes_tail;
  55. static unsigned int unique_id;
  56. static struct mdesc_node **mdesc_hash;
  57. static unsigned int mdesc_hash_size;
  58. static inline unsigned int node_hashfn(u64 node)
  59. {
  60. return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16)))
  61. & (mdesc_hash_size - 1);
  62. }
  63. static inline void hash_node(struct mdesc_node *mp)
  64. {
  65. struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)];
  66. mp->hash_next = *head;
  67. *head = mp;
  68. if (allnodes_tail) {
  69. allnodes_tail->allnodes_next = mp;
  70. allnodes_tail = mp;
  71. } else {
  72. allnodes = allnodes_tail = mp;
  73. }
  74. }
  75. static struct mdesc_node *find_node(u64 node)
  76. {
  77. struct mdesc_node *mp = mdesc_hash[node_hashfn(node)];
  78. while (mp) {
  79. if (mp->node == node)
  80. return mp;
  81. mp = mp->hash_next;
  82. }
  83. return NULL;
  84. }
  85. struct property *md_find_property(const struct mdesc_node *mp,
  86. const char *name,
  87. int *lenp)
  88. {
  89. struct property *pp;
  90. for (pp = mp->properties; pp != 0; pp = pp->next) {
  91. if (strcasecmp(pp->name, name) == 0) {
  92. if (lenp)
  93. *lenp = pp->length;
  94. break;
  95. }
  96. }
  97. return pp;
  98. }
  99. EXPORT_SYMBOL(md_find_property);
  100. /*
  101. * Find a property with a given name for a given node
  102. * and return the value.
  103. */
  104. const void *md_get_property(const struct mdesc_node *mp, const char *name,
  105. int *lenp)
  106. {
  107. struct property *pp = md_find_property(mp, name, lenp);
  108. return pp ? pp->value : NULL;
  109. }
  110. EXPORT_SYMBOL(md_get_property);
  111. struct mdesc_node *md_find_node_by_name(struct mdesc_node *from,
  112. const char *name)
  113. {
  114. struct mdesc_node *mp;
  115. mp = from ? from->allnodes_next : allnodes;
  116. for (; mp != NULL; mp = mp->allnodes_next) {
  117. if (strcmp(mp->name, name) == 0)
  118. break;
  119. }
  120. return mp;
  121. }
  122. EXPORT_SYMBOL(md_find_node_by_name);
  123. static unsigned int mdesc_early_allocated;
  124. static void * __init mdesc_early_alloc(unsigned long size)
  125. {
  126. void *ret;
  127. ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
  128. if (ret == NULL) {
  129. prom_printf("MDESC: alloc of %lu bytes failed.\n", size);
  130. prom_halt();
  131. }
  132. memset(ret, 0, size);
  133. mdesc_early_allocated += size;
  134. return ret;
  135. }
  136. static unsigned int __init count_arcs(struct mdesc_elem *ep)
  137. {
  138. unsigned int ret = 0;
  139. ep++;
  140. while (ep->tag != MD_NODE_END) {
  141. if (ep->tag == MD_PROP_ARC)
  142. ret++;
  143. ep++;
  144. }
  145. return ret;
  146. }
  147. static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names)
  148. {
  149. unsigned int num_arcs = count_arcs(ep);
  150. struct mdesc_node *mp;
  151. mp = mdesc_early_alloc(sizeof(*mp) +
  152. (num_arcs * sizeof(struct mdesc_arc)));
  153. mp->name = names + ep->name_offset;
  154. mp->node = node;
  155. mp->unique_id = unique_id++;
  156. mp->num_arcs = num_arcs;
  157. hash_node(mp);
  158. }
  159. static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
  160. {
  161. return (struct mdesc_elem *) (mdesc + 1);
  162. }
  163. static inline void *name_block(struct mdesc_hdr *mdesc)
  164. {
  165. return ((void *) node_block(mdesc)) + mdesc->node_sz;
  166. }
  167. static inline void *data_block(struct mdesc_hdr *mdesc)
  168. {
  169. return ((void *) name_block(mdesc)) + mdesc->name_sz;
  170. }
  171. /* In order to avoid recursion (the graph can be very deep) we use a
  172. * two pass algorithm. First we allocate all the nodes and hash them.
  173. * Then we iterate over each node, filling in the arcs and properties.
  174. */
  175. static void __init build_all_nodes(struct mdesc_hdr *mdesc)
  176. {
  177. struct mdesc_elem *start, *ep;
  178. struct mdesc_node *mp;
  179. const char *names;
  180. void *data;
  181. u64 last_node;
  182. start = ep = node_block(mdesc);
  183. last_node = mdesc->node_sz / 16;
  184. names = name_block(mdesc);
  185. while (1) {
  186. u64 node = ep - start;
  187. if (ep->tag == MD_LIST_END)
  188. break;
  189. if (ep->tag != MD_NODE) {
  190. prom_printf("MDESC: Inconsistent element list.\n");
  191. prom_halt();
  192. }
  193. mdesc_node_alloc(node, ep, names);
  194. if (ep->d.val >= last_node) {
  195. printk("MDESC: Warning, early break out of node scan.\n");
  196. printk("MDESC: Next node [%lu] last_node [%lu].\n",
  197. node, last_node);
  198. break;
  199. }
  200. ep = start + ep->d.val;
  201. }
  202. data = data_block(mdesc);
  203. for (mp = allnodes; mp; mp = mp->allnodes_next) {
  204. struct mdesc_elem *ep = start + mp->node;
  205. struct property **link = &mp->properties;
  206. unsigned int this_arc = 0;
  207. ep++;
  208. while (ep->tag != MD_NODE_END) {
  209. switch (ep->tag) {
  210. case MD_PROP_ARC: {
  211. struct mdesc_node *target;
  212. if (this_arc >= mp->num_arcs) {
  213. prom_printf("MDESC: ARC overrun [%u:%u]\n",
  214. this_arc, mp->num_arcs);
  215. prom_halt();
  216. }
  217. target = find_node(ep->d.val);
  218. if (!target) {
  219. printk("MDESC: Warning, arc points to "
  220. "missing node, ignoring.\n");
  221. break;
  222. }
  223. mp->arcs[this_arc].name =
  224. (names + ep->name_offset);
  225. mp->arcs[this_arc].arc = target;
  226. this_arc++;
  227. break;
  228. }
  229. case MD_PROP_VAL:
  230. case MD_PROP_STR:
  231. case MD_PROP_DATA: {
  232. struct property *p = mdesc_early_alloc(sizeof(*p));
  233. p->unique_id = unique_id++;
  234. p->name = (char *) names + ep->name_offset;
  235. if (ep->tag == MD_PROP_VAL) {
  236. p->value = &ep->d.val;
  237. p->length = 8;
  238. } else {
  239. p->value = data + ep->d.data.data_offset;
  240. p->length = ep->d.data.data_len;
  241. }
  242. *link = p;
  243. link = &p->next;
  244. break;
  245. }
  246. case MD_NOOP:
  247. break;
  248. default:
  249. printk("MDESC: Warning, ignoring unknown tag type %02x\n",
  250. ep->tag);
  251. }
  252. ep++;
  253. }
  254. }
  255. }
  256. static unsigned int __init count_nodes(struct mdesc_hdr *mdesc)
  257. {
  258. struct mdesc_elem *ep = node_block(mdesc);
  259. struct mdesc_elem *end;
  260. unsigned int cnt = 0;
  261. end = ((void *)ep) + mdesc->node_sz;
  262. while (ep < end) {
  263. if (ep->tag == MD_NODE)
  264. cnt++;
  265. ep++;
  266. }
  267. return cnt;
  268. }
  269. static void __init report_platform_properties(void)
  270. {
  271. struct mdesc_node *pn = md_find_node_by_name(NULL, "platform");
  272. const char *s;
  273. const u64 *v;
  274. if (!pn) {
  275. prom_printf("No platform node in machine-description.\n");
  276. prom_halt();
  277. }
  278. s = md_get_property(pn, "banner-name", NULL);
  279. printk("PLATFORM: banner-name [%s]\n", s);
  280. s = md_get_property(pn, "name", NULL);
  281. printk("PLATFORM: name [%s]\n", s);
  282. v = md_get_property(pn, "hostid", NULL);
  283. if (v)
  284. printk("PLATFORM: hostid [%08lx]\n", *v);
  285. v = md_get_property(pn, "serial#", NULL);
  286. if (v)
  287. printk("PLATFORM: serial# [%08lx]\n", *v);
  288. v = md_get_property(pn, "stick-frequency", NULL);
  289. printk("PLATFORM: stick-frequency [%08lx]\n", *v);
  290. v = md_get_property(pn, "mac-address", NULL);
  291. if (v)
  292. printk("PLATFORM: mac-address [%lx]\n", *v);
  293. v = md_get_property(pn, "watchdog-resolution", NULL);
  294. if (v)
  295. printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v);
  296. v = md_get_property(pn, "watchdog-max-timeout", NULL);
  297. if (v)
  298. printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v);
  299. v = md_get_property(pn, "max-cpus", NULL);
  300. if (v)
  301. printk("PLATFORM: max-cpus [%lu]\n", *v);
  302. }
  303. static int inline find_in_proplist(const char *list, const char *match, int len)
  304. {
  305. while (len > 0) {
  306. int l;
  307. if (!strcmp(list, match))
  308. return 1;
  309. l = strlen(list) + 1;
  310. list += l;
  311. len -= l;
  312. }
  313. return 0;
  314. }
  315. static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp)
  316. {
  317. const u64 *level = md_get_property(mp, "level", NULL);
  318. const u64 *size = md_get_property(mp, "size", NULL);
  319. const u64 *line_size = md_get_property(mp, "line-size", NULL);
  320. const char *type;
  321. int type_len;
  322. type = md_get_property(mp, "type", &type_len);
  323. switch (*level) {
  324. case 1:
  325. if (find_in_proplist(type, "instn", type_len)) {
  326. c->icache_size = *size;
  327. c->icache_line_size = *line_size;
  328. } else if (find_in_proplist(type, "data", type_len)) {
  329. c->dcache_size = *size;
  330. c->dcache_line_size = *line_size;
  331. }
  332. break;
  333. case 2:
  334. c->ecache_size = *size;
  335. c->ecache_line_size = *line_size;
  336. break;
  337. default:
  338. break;
  339. }
  340. if (*level == 1) {
  341. unsigned int i;
  342. for (i = 0; i < mp->num_arcs; i++) {
  343. struct mdesc_node *t = mp->arcs[i].arc;
  344. if (strcmp(mp->arcs[i].name, "fwd"))
  345. continue;
  346. if (!strcmp(t->name, "cache"))
  347. fill_in_one_cache(c, t);
  348. }
  349. }
  350. }
  351. static void __init mark_core_ids(struct mdesc_node *mp, int core_id)
  352. {
  353. unsigned int i;
  354. for (i = 0; i < mp->num_arcs; i++) {
  355. struct mdesc_node *t = mp->arcs[i].arc;
  356. const u64 *id;
  357. if (strcmp(mp->arcs[i].name, "back"))
  358. continue;
  359. if (!strcmp(t->name, "cpu")) {
  360. id = md_get_property(t, "id", NULL);
  361. if (*id < NR_CPUS)
  362. cpu_data(*id).core_id = core_id;
  363. } else {
  364. unsigned int j;
  365. for (j = 0; j < t->num_arcs; j++) {
  366. struct mdesc_node *n = t->arcs[j].arc;
  367. if (strcmp(t->arcs[j].name, "back"))
  368. continue;
  369. if (strcmp(n->name, "cpu"))
  370. continue;
  371. id = md_get_property(n, "id", NULL);
  372. if (*id < NR_CPUS)
  373. cpu_data(*id).core_id = core_id;
  374. }
  375. }
  376. }
  377. }
  378. static void __init set_core_ids(void)
  379. {
  380. struct mdesc_node *mp;
  381. int idx;
  382. idx = 1;
  383. md_for_each_node_by_name(mp, "cache") {
  384. const u64 *level = md_get_property(mp, "level", NULL);
  385. const char *type;
  386. int len;
  387. if (*level != 1)
  388. continue;
  389. type = md_get_property(mp, "type", &len);
  390. if (!find_in_proplist(type, "instn", len))
  391. continue;
  392. mark_core_ids(mp, idx);
  393. idx++;
  394. }
  395. }
  396. static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id)
  397. {
  398. int i;
  399. for (i = 0; i < mp->num_arcs; i++) {
  400. struct mdesc_node *t = mp->arcs[i].arc;
  401. const u64 *id;
  402. if (strcmp(mp->arcs[i].name, "back"))
  403. continue;
  404. if (strcmp(t->name, "cpu"))
  405. continue;
  406. id = md_get_property(t, "id", NULL);
  407. if (*id < NR_CPUS)
  408. cpu_data(*id).proc_id = proc_id;
  409. }
  410. }
  411. static void __init __set_proc_ids(const char *exec_unit_name)
  412. {
  413. struct mdesc_node *mp;
  414. int idx;
  415. idx = 0;
  416. md_for_each_node_by_name(mp, exec_unit_name) {
  417. const char *type;
  418. int len;
  419. type = md_get_property(mp, "type", &len);
  420. if (!find_in_proplist(type, "int", len) &&
  421. !find_in_proplist(type, "integer", len))
  422. continue;
  423. mark_proc_ids(mp, idx);
  424. idx++;
  425. }
  426. }
  427. static void __init set_proc_ids(void)
  428. {
  429. __set_proc_ids("exec_unit");
  430. __set_proc_ids("exec-unit");
  431. }
  432. static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def)
  433. {
  434. u64 val;
  435. if (!p)
  436. goto use_default;
  437. val = *p;
  438. if (!val || val >= 64)
  439. goto use_default;
  440. *mask = ((1U << val) * 64U) - 1U;
  441. return;
  442. use_default:
  443. *mask = ((1U << def) * 64U) - 1U;
  444. }
  445. static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb)
  446. {
  447. const u64 *val;
  448. val = md_get_property(mp, "q-cpu-mondo-#bits", NULL);
  449. get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
  450. val = md_get_property(mp, "q-dev-mondo-#bits", NULL);
  451. get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
  452. val = md_get_property(mp, "q-resumable-#bits", NULL);
  453. get_one_mondo_bits(val, &tb->resum_qmask, 6);
  454. val = md_get_property(mp, "q-nonresumable-#bits", NULL);
  455. get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
  456. }
  457. static void __init mdesc_fill_in_cpu_data(void)
  458. {
  459. struct mdesc_node *mp;
  460. ncpus_probed = 0;
  461. md_for_each_node_by_name(mp, "cpu") {
  462. const u64 *id = md_get_property(mp, "id", NULL);
  463. const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL);
  464. struct trap_per_cpu *tb;
  465. cpuinfo_sparc *c;
  466. unsigned int i;
  467. int cpuid;
  468. ncpus_probed++;
  469. cpuid = *id;
  470. #ifdef CONFIG_SMP
  471. if (cpuid >= NR_CPUS)
  472. continue;
  473. #else
  474. /* On uniprocessor we only want the values for the
  475. * real physical cpu the kernel booted onto, however
  476. * cpu_data() only has one entry at index 0.
  477. */
  478. if (cpuid != real_hard_smp_processor_id())
  479. continue;
  480. cpuid = 0;
  481. #endif
  482. c = &cpu_data(cpuid);
  483. c->clock_tick = *cfreq;
  484. tb = &trap_block[cpuid];
  485. get_mondo_data(mp, tb);
  486. for (i = 0; i < mp->num_arcs; i++) {
  487. struct mdesc_node *t = mp->arcs[i].arc;
  488. unsigned int j;
  489. if (strcmp(mp->arcs[i].name, "fwd"))
  490. continue;
  491. if (!strcmp(t->name, "cache")) {
  492. fill_in_one_cache(c, t);
  493. continue;
  494. }
  495. for (j = 0; j < t->num_arcs; j++) {
  496. struct mdesc_node *n;
  497. n = t->arcs[j].arc;
  498. if (strcmp(t->arcs[j].name, "fwd"))
  499. continue;
  500. if (!strcmp(n->name, "cache"))
  501. fill_in_one_cache(c, n);
  502. }
  503. }
  504. #ifdef CONFIG_SMP
  505. cpu_set(cpuid, cpu_present_map);
  506. cpu_set(cpuid, phys_cpu_present_map);
  507. #endif
  508. c->core_id = 0;
  509. c->proc_id = -1;
  510. }
  511. #ifdef CONFIG_SMP
  512. sparc64_multi_core = 1;
  513. #endif
  514. set_core_ids();
  515. set_proc_ids();
  516. smp_fill_in_sib_core_maps();
  517. }
  518. void __init sun4v_mdesc_init(void)
  519. {
  520. unsigned long len, real_len, status;
  521. (void) sun4v_mach_desc(0UL, 0UL, &len);
  522. printk("MDESC: Size is %lu bytes.\n", len);
  523. main_mdesc = mdesc_early_alloc(len);
  524. status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len);
  525. if (status != HV_EOK || real_len > len) {
  526. prom_printf("sun4v_mach_desc fails, err(%lu), "
  527. "len(%lu), real_len(%lu)\n",
  528. status, len, real_len);
  529. prom_halt();
  530. }
  531. len = count_nodes(main_mdesc);
  532. printk("MDESC: %lu nodes.\n", len);
  533. len = roundup_pow_of_two(len);
  534. mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *));
  535. mdesc_hash_size = len;
  536. printk("MDESC: Hash size %lu entries.\n", len);
  537. build_all_nodes(main_mdesc);
  538. printk("MDESC: Built graph with %u bytes of memory.\n",
  539. mdesc_early_allocated);
  540. report_platform_properties();
  541. mdesc_fill_in_cpu_data();
  542. }