dlpar.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * Support for dynamic reconfiguration for PCI, Memory, and CPU
  3. * Hotplug and Dynamic Logical Partitioning on RPA platforms.
  4. *
  5. * Copyright (C) 2009 Nathan Fontenot
  6. * Copyright (C) 2009 IBM Corporation
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License version
  10. * 2 as published by the Free Software Foundation.
  11. */
  12. #define pr_fmt(fmt) "dlpar: " fmt
  13. #include <linux/kernel.h>
  14. #include <linux/notifier.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/cpu.h>
  17. #include <linux/slab.h>
  18. #include <linux/of.h>
  19. #include "of_helpers.h"
  20. #include "offline_states.h"
  21. #include "pseries.h"
  22. #include <asm/prom.h>
  23. #include <asm/machdep.h>
  24. #include <asm/uaccess.h>
  25. #include <asm/rtas.h>
  26. struct cc_workarea {
  27. __be32 drc_index;
  28. __be32 zero;
  29. __be32 name_offset;
  30. __be32 prop_length;
  31. __be32 prop_offset;
  32. };
  33. void dlpar_free_cc_property(struct property *prop)
  34. {
  35. kfree(prop->name);
  36. kfree(prop->value);
  37. kfree(prop);
  38. }
  39. static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
  40. {
  41. struct property *prop;
  42. char *name;
  43. char *value;
  44. prop = kzalloc(sizeof(*prop), GFP_KERNEL);
  45. if (!prop)
  46. return NULL;
  47. name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
  48. prop->name = kstrdup(name, GFP_KERNEL);
  49. prop->length = be32_to_cpu(ccwa->prop_length);
  50. value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
  51. prop->value = kmemdup(value, prop->length, GFP_KERNEL);
  52. if (!prop->value) {
  53. dlpar_free_cc_property(prop);
  54. return NULL;
  55. }
  56. return prop;
  57. }
  58. static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
  59. const char *path)
  60. {
  61. struct device_node *dn;
  62. char *name;
  63. /* If parent node path is "/" advance path to NULL terminator to
  64. * prevent double leading slashs in full_name.
  65. */
  66. if (!path[1])
  67. path++;
  68. dn = kzalloc(sizeof(*dn), GFP_KERNEL);
  69. if (!dn)
  70. return NULL;
  71. name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
  72. dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name);
  73. if (!dn->full_name) {
  74. kfree(dn);
  75. return NULL;
  76. }
  77. of_node_set_flag(dn, OF_DYNAMIC);
  78. of_node_init(dn);
  79. return dn;
  80. }
  81. static void dlpar_free_one_cc_node(struct device_node *dn)
  82. {
  83. struct property *prop;
  84. while (dn->properties) {
  85. prop = dn->properties;
  86. dn->properties = prop->next;
  87. dlpar_free_cc_property(prop);
  88. }
  89. kfree(dn->full_name);
  90. kfree(dn);
  91. }
  92. void dlpar_free_cc_nodes(struct device_node *dn)
  93. {
  94. if (dn->child)
  95. dlpar_free_cc_nodes(dn->child);
  96. if (dn->sibling)
  97. dlpar_free_cc_nodes(dn->sibling);
  98. dlpar_free_one_cc_node(dn);
  99. }
  100. #define COMPLETE 0
  101. #define NEXT_SIBLING 1
  102. #define NEXT_CHILD 2
  103. #define NEXT_PROPERTY 3
  104. #define PREV_PARENT 4
  105. #define MORE_MEMORY 5
  106. #define CALL_AGAIN -2
  107. #define ERR_CFG_USE -9003
  108. struct device_node *dlpar_configure_connector(__be32 drc_index,
  109. struct device_node *parent)
  110. {
  111. struct device_node *dn;
  112. struct device_node *first_dn = NULL;
  113. struct device_node *last_dn = NULL;
  114. struct property *property;
  115. struct property *last_property = NULL;
  116. struct cc_workarea *ccwa;
  117. char *data_buf;
  118. const char *parent_path = parent->full_name;
  119. int cc_token;
  120. int rc = -1;
  121. cc_token = rtas_token("ibm,configure-connector");
  122. if (cc_token == RTAS_UNKNOWN_SERVICE)
  123. return NULL;
  124. data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
  125. if (!data_buf)
  126. return NULL;
  127. ccwa = (struct cc_workarea *)&data_buf[0];
  128. ccwa->drc_index = drc_index;
  129. ccwa->zero = 0;
  130. do {
  131. /* Since we release the rtas_data_buf lock between configure
  132. * connector calls we want to re-populate the rtas_data_buffer
  133. * with the contents of the previous call.
  134. */
  135. spin_lock(&rtas_data_buf_lock);
  136. memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
  137. rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
  138. memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
  139. spin_unlock(&rtas_data_buf_lock);
  140. switch (rc) {
  141. case COMPLETE:
  142. break;
  143. case NEXT_SIBLING:
  144. dn = dlpar_parse_cc_node(ccwa, parent_path);
  145. if (!dn)
  146. goto cc_error;
  147. dn->parent = last_dn->parent;
  148. last_dn->sibling = dn;
  149. last_dn = dn;
  150. break;
  151. case NEXT_CHILD:
  152. if (first_dn)
  153. parent_path = last_dn->full_name;
  154. dn = dlpar_parse_cc_node(ccwa, parent_path);
  155. if (!dn)
  156. goto cc_error;
  157. if (!first_dn) {
  158. dn->parent = parent;
  159. first_dn = dn;
  160. } else {
  161. dn->parent = last_dn;
  162. if (last_dn)
  163. last_dn->child = dn;
  164. }
  165. last_dn = dn;
  166. break;
  167. case NEXT_PROPERTY:
  168. property = dlpar_parse_cc_property(ccwa);
  169. if (!property)
  170. goto cc_error;
  171. if (!last_dn->properties)
  172. last_dn->properties = property;
  173. else
  174. last_property->next = property;
  175. last_property = property;
  176. break;
  177. case PREV_PARENT:
  178. last_dn = last_dn->parent;
  179. parent_path = last_dn->parent->full_name;
  180. break;
  181. case CALL_AGAIN:
  182. break;
  183. case MORE_MEMORY:
  184. case ERR_CFG_USE:
  185. default:
  186. printk(KERN_ERR "Unexpected Error (%d) "
  187. "returned from configure-connector\n", rc);
  188. goto cc_error;
  189. }
  190. } while (rc);
  191. cc_error:
  192. kfree(data_buf);
  193. if (rc) {
  194. if (first_dn)
  195. dlpar_free_cc_nodes(first_dn);
  196. return NULL;
  197. }
  198. return first_dn;
  199. }
  200. int dlpar_attach_node(struct device_node *dn)
  201. {
  202. int rc;
  203. dn->parent = pseries_of_derive_parent(dn->full_name);
  204. if (IS_ERR(dn->parent))
  205. return PTR_ERR(dn->parent);
  206. rc = of_attach_node(dn);
  207. if (rc) {
  208. printk(KERN_ERR "Failed to add device node %s\n",
  209. dn->full_name);
  210. return rc;
  211. }
  212. of_node_put(dn->parent);
  213. return 0;
  214. }
  215. int dlpar_detach_node(struct device_node *dn)
  216. {
  217. struct device_node *child;
  218. int rc;
  219. child = of_get_next_child(dn, NULL);
  220. while (child) {
  221. dlpar_detach_node(child);
  222. child = of_get_next_child(dn, child);
  223. }
  224. rc = of_detach_node(dn);
  225. if (rc)
  226. return rc;
  227. of_node_put(dn);
  228. return 0;
  229. }
  230. #define DR_ENTITY_SENSE 9003
  231. #define DR_ENTITY_PRESENT 1
  232. #define DR_ENTITY_UNUSABLE 2
  233. #define ALLOCATION_STATE 9003
  234. #define ALLOC_UNUSABLE 0
  235. #define ALLOC_USABLE 1
  236. #define ISOLATION_STATE 9001
  237. #define ISOLATE 0
  238. #define UNISOLATE 1
  239. int dlpar_acquire_drc(u32 drc_index)
  240. {
  241. int dr_status, rc;
  242. rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
  243. DR_ENTITY_SENSE, drc_index);
  244. if (rc || dr_status != DR_ENTITY_UNUSABLE)
  245. return -1;
  246. rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
  247. if (rc)
  248. return rc;
  249. rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
  250. if (rc) {
  251. rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
  252. return rc;
  253. }
  254. return 0;
  255. }
  256. int dlpar_release_drc(u32 drc_index)
  257. {
  258. int dr_status, rc;
  259. rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
  260. DR_ENTITY_SENSE, drc_index);
  261. if (rc || dr_status != DR_ENTITY_PRESENT)
  262. return -1;
  263. rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
  264. if (rc)
  265. return rc;
  266. rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
  267. if (rc) {
  268. rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
  269. return rc;
  270. }
  271. return 0;
  272. }
  273. #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
  274. static int dlpar_online_cpu(struct device_node *dn)
  275. {
  276. int rc = 0;
  277. unsigned int cpu;
  278. int len, nthreads, i;
  279. const __be32 *intserv;
  280. u32 thread;
  281. intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
  282. if (!intserv)
  283. return -EINVAL;
  284. nthreads = len / sizeof(u32);
  285. cpu_maps_update_begin();
  286. for (i = 0; i < nthreads; i++) {
  287. thread = be32_to_cpu(intserv[i]);
  288. for_each_present_cpu(cpu) {
  289. if (get_hard_smp_processor_id(cpu) != thread)
  290. continue;
  291. BUG_ON(get_cpu_current_state(cpu)
  292. != CPU_STATE_OFFLINE);
  293. cpu_maps_update_done();
  294. rc = device_online(get_cpu_device(cpu));
  295. if (rc)
  296. goto out;
  297. cpu_maps_update_begin();
  298. break;
  299. }
  300. if (cpu == num_possible_cpus())
  301. printk(KERN_WARNING "Could not find cpu to online "
  302. "with physical id 0x%x\n", thread);
  303. }
  304. cpu_maps_update_done();
  305. out:
  306. return rc;
  307. }
  308. static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
  309. {
  310. struct device_node *dn, *parent;
  311. u32 drc_index;
  312. int rc;
  313. rc = kstrtou32(buf, 0, &drc_index);
  314. if (rc)
  315. return -EINVAL;
  316. rc = dlpar_acquire_drc(drc_index);
  317. if (rc)
  318. return -EINVAL;
  319. parent = of_find_node_by_path("/cpus");
  320. if (!parent)
  321. return -ENODEV;
  322. dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
  323. of_node_put(parent);
  324. if (!dn) {
  325. dlpar_release_drc(drc_index);
  326. return -EINVAL;
  327. }
  328. rc = dlpar_attach_node(dn);
  329. if (rc) {
  330. dlpar_release_drc(drc_index);
  331. dlpar_free_cc_nodes(dn);
  332. return rc;
  333. }
  334. rc = dlpar_online_cpu(dn);
  335. if (rc)
  336. return rc;
  337. return count;
  338. }
  339. static int dlpar_offline_cpu(struct device_node *dn)
  340. {
  341. int rc = 0;
  342. unsigned int cpu;
  343. int len, nthreads, i;
  344. const __be32 *intserv;
  345. u32 thread;
  346. intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
  347. if (!intserv)
  348. return -EINVAL;
  349. nthreads = len / sizeof(u32);
  350. cpu_maps_update_begin();
  351. for (i = 0; i < nthreads; i++) {
  352. thread = be32_to_cpu(intserv[i]);
  353. for_each_present_cpu(cpu) {
  354. if (get_hard_smp_processor_id(cpu) != thread)
  355. continue;
  356. if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
  357. break;
  358. if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
  359. set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
  360. cpu_maps_update_done();
  361. rc = device_offline(get_cpu_device(cpu));
  362. if (rc)
  363. goto out;
  364. cpu_maps_update_begin();
  365. break;
  366. }
  367. /*
  368. * The cpu is in CPU_STATE_INACTIVE.
  369. * Upgrade it's state to CPU_STATE_OFFLINE.
  370. */
  371. set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
  372. BUG_ON(plpar_hcall_norets(H_PROD, thread)
  373. != H_SUCCESS);
  374. __cpu_die(cpu);
  375. break;
  376. }
  377. if (cpu == num_possible_cpus())
  378. printk(KERN_WARNING "Could not find cpu to offline "
  379. "with physical id 0x%x\n", thread);
  380. }
  381. cpu_maps_update_done();
  382. out:
  383. return rc;
  384. }
  385. static ssize_t dlpar_cpu_release(const char *buf, size_t count)
  386. {
  387. struct device_node *dn;
  388. u32 drc_index;
  389. int rc;
  390. dn = of_find_node_by_path(buf);
  391. if (!dn)
  392. return -EINVAL;
  393. rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
  394. if (rc) {
  395. of_node_put(dn);
  396. return -EINVAL;
  397. }
  398. rc = dlpar_offline_cpu(dn);
  399. if (rc) {
  400. of_node_put(dn);
  401. return -EINVAL;
  402. }
  403. rc = dlpar_release_drc(drc_index);
  404. if (rc) {
  405. of_node_put(dn);
  406. return rc;
  407. }
  408. rc = dlpar_detach_node(dn);
  409. if (rc) {
  410. dlpar_acquire_drc(drc_index);
  411. return rc;
  412. }
  413. of_node_put(dn);
  414. return count;
  415. }
  416. #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
  417. static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
  418. {
  419. int rc;
  420. /* pseries error logs are in BE format, convert to cpu type */
  421. switch (hp_elog->id_type) {
  422. case PSERIES_HP_ELOG_ID_DRC_COUNT:
  423. hp_elog->_drc_u.drc_count =
  424. be32_to_cpu(hp_elog->_drc_u.drc_count);
  425. break;
  426. case PSERIES_HP_ELOG_ID_DRC_INDEX:
  427. hp_elog->_drc_u.drc_index =
  428. be32_to_cpu(hp_elog->_drc_u.drc_index);
  429. }
  430. switch (hp_elog->resource) {
  431. case PSERIES_HP_ELOG_RESOURCE_MEM:
  432. rc = dlpar_memory(hp_elog);
  433. break;
  434. default:
  435. pr_warn_ratelimited("Invalid resource (%d) specified\n",
  436. hp_elog->resource);
  437. rc = -EINVAL;
  438. }
  439. return rc;
  440. }
  441. static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
  442. const char *buf, size_t count)
  443. {
  444. struct pseries_hp_errorlog *hp_elog;
  445. const char *arg;
  446. int rc;
  447. hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL);
  448. if (!hp_elog) {
  449. rc = -ENOMEM;
  450. goto dlpar_store_out;
  451. }
  452. /* Parse out the request from the user, this will be in the form
  453. * <resource> <action> <id_type> <id>
  454. */
  455. arg = buf;
  456. if (!strncmp(arg, "memory", 6)) {
  457. hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
  458. arg += strlen("memory ");
  459. } else {
  460. pr_err("Invalid resource specified: \"%s\"\n", buf);
  461. rc = -EINVAL;
  462. goto dlpar_store_out;
  463. }
  464. if (!strncmp(arg, "add", 3)) {
  465. hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
  466. arg += strlen("add ");
  467. } else if (!strncmp(arg, "remove", 6)) {
  468. hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
  469. arg += strlen("remove ");
  470. } else {
  471. pr_err("Invalid action specified: \"%s\"\n", buf);
  472. rc = -EINVAL;
  473. goto dlpar_store_out;
  474. }
  475. if (!strncmp(arg, "index", 5)) {
  476. u32 index;
  477. hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
  478. arg += strlen("index ");
  479. if (kstrtou32(arg, 0, &index)) {
  480. rc = -EINVAL;
  481. pr_err("Invalid drc_index specified: \"%s\"\n", buf);
  482. goto dlpar_store_out;
  483. }
  484. hp_elog->_drc_u.drc_index = cpu_to_be32(index);
  485. } else if (!strncmp(arg, "count", 5)) {
  486. u32 count;
  487. hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
  488. arg += strlen("count ");
  489. if (kstrtou32(arg, 0, &count)) {
  490. rc = -EINVAL;
  491. pr_err("Invalid count specified: \"%s\"\n", buf);
  492. goto dlpar_store_out;
  493. }
  494. hp_elog->_drc_u.drc_count = cpu_to_be32(count);
  495. } else {
  496. pr_err("Invalid id_type specified: \"%s\"\n", buf);
  497. rc = -EINVAL;
  498. goto dlpar_store_out;
  499. }
  500. rc = handle_dlpar_errorlog(hp_elog);
  501. dlpar_store_out:
  502. kfree(hp_elog);
  503. return rc ? rc : count;
  504. }
  505. static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
  506. static int __init pseries_dlpar_init(void)
  507. {
  508. int rc;
  509. #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
  510. ppc_md.cpu_probe = dlpar_cpu_probe;
  511. ppc_md.cpu_release = dlpar_cpu_release;
  512. #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
  513. rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
  514. return rc;
  515. }
  516. machine_device_initcall(pseries, pseries_dlpar_init);