sys-manager.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. * PS3 System Manager.
  3. *
  4. * Copyright (C) 2007 Sony Computer Entertainment Inc.
  5. * Copyright 2007 Sony Corp.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; version 2 of the License.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/workqueue.h>
  23. #include <linux/reboot.h>
  24. #include <asm/firmware.h>
  25. #include <asm/ps3.h>
  26. #include "vuart.h"
  27. MODULE_AUTHOR("Sony Corporation");
  28. MODULE_LICENSE("GPL v2");
  29. MODULE_DESCRIPTION("PS3 System Manager");
  30. /**
  31. * ps3_sys_manager - PS3 system manager driver.
  32. *
  33. * The system manager provides an asynchronous system event notification
  34. * mechanism for reporting events like thermal alert and button presses to
  35. * guests. It also provides support to control system shutdown and startup.
  36. *
  37. * The actual system manager is implemented as an application running in the
  38. * system policy module in lpar_1. Guests communicate with the system manager
  39. * through port 2 of the vuart using a simple packet message protocol.
  40. * Messages are comprised of a fixed field header followed by a message
  41. * specific payload.
  42. */
  43. /**
  44. * struct ps3_sys_manager_header - System manager message header.
  45. * @version: Header version, currently 1.
  46. * @size: Header size in bytes, curently 16.
  47. * @payload_size: Message payload size in bytes.
  48. * @service_id: Message type, one of enum ps3_sys_manager_service_id.
  49. * @request_tag: Unique number to identify reply.
  50. */
  51. struct ps3_sys_manager_header {
  52. /* version 1 */
  53. u8 version;
  54. u8 size;
  55. u16 reserved_1;
  56. u32 payload_size;
  57. u16 service_id;
  58. u16 reserved_2;
  59. u32 request_tag;
  60. };
  61. #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__)
  62. static void __maybe_unused _dump_sm_header(
  63. const struct ps3_sys_manager_header *h, const char *func, int line)
  64. {
  65. pr_debug("%s:%d: version: %xh\n", func, line, h->version);
  66. pr_debug("%s:%d: size: %xh\n", func, line, h->size);
  67. pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size);
  68. pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id);
  69. pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag);
  70. }
  71. /**
  72. * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length.
  73. * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length.
  74. *
  75. * Currently all messages received from the system manager are either
  76. * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header
  77. * + 16 bytes payload = 32 bytes). This knowlege is used to simplify
  78. * the logic.
  79. */
  80. enum {
  81. PS3_SM_RX_MSG_LEN_MIN = 24,
  82. PS3_SM_RX_MSG_LEN_MAX = 32,
  83. };
  84. /**
  85. * enum ps3_sys_manager_service_id - Message header service_id.
  86. * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
  87. * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager.
  88. * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
  89. * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
  90. * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
  91. * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
  92. * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
  93. *
  94. * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a
  95. * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when
  96. * a REQUEST message is sent at the wrong time.
  97. */
  98. enum ps3_sys_manager_service_id {
  99. /* version 1 */
  100. PS3_SM_SERVICE_ID_REQUEST = 1,
  101. PS3_SM_SERVICE_ID_RESPONSE = 2,
  102. PS3_SM_SERVICE_ID_COMMAND = 3,
  103. PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
  104. PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
  105. PS3_SM_SERVICE_ID_REQUEST_ERROR = 6,
  106. PS3_SM_SERVICE_ID_SET_ATTR = 8,
  107. };
  108. /**
  109. * enum ps3_sys_manager_attr - Notification attribute (bit position mask).
  110. * @PS3_SM_ATTR_POWER: Power button.
  111. * @PS3_SM_ATTR_RESET: Reset button, not available on retail console.
  112. * @PS3_SM_ATTR_THERMAL: Sytem thermal alert.
  113. * @PS3_SM_ATTR_CONTROLLER: Remote controller event.
  114. * @PS3_SM_ATTR_ALL: Logical OR of all.
  115. *
  116. * The guest tells the system manager which events it is interested in receiving
  117. * notice of by sending the system manager a logical OR of notification
  118. * attributes via the ps3_sys_manager_send_attr() routine.
  119. */
  120. enum ps3_sys_manager_attr {
  121. /* version 1 */
  122. PS3_SM_ATTR_POWER = 1,
  123. PS3_SM_ATTR_RESET = 2,
  124. PS3_SM_ATTR_THERMAL = 4,
  125. PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */
  126. PS3_SM_ATTR_ALL = 0x0f,
  127. };
  128. /**
  129. * enum ps3_sys_manager_event - External event type, reported by system manager.
  130. * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used.
  131. * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec.
  132. * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used.
  133. * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec.
  134. * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id.
  135. * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id.
  136. */
  137. enum ps3_sys_manager_event {
  138. /* version 1 */
  139. PS3_SM_EVENT_POWER_PRESSED = 3,
  140. PS3_SM_EVENT_POWER_RELEASED = 4,
  141. PS3_SM_EVENT_RESET_PRESSED = 5,
  142. PS3_SM_EVENT_RESET_RELEASED = 6,
  143. PS3_SM_EVENT_THERMAL_ALERT = 7,
  144. PS3_SM_EVENT_THERMAL_CLEARED = 8,
  145. /* no info on controller events */
  146. };
  147. /**
  148. * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed.
  149. */
  150. enum ps3_sys_manager_next_op {
  151. /* version 3 */
  152. PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1,
  153. PS3_SM_NEXT_OP_SYS_REBOOT = 2,
  154. PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82,
  155. };
  156. /**
  157. * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask).
  158. * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR
  159. * controller, and bluetooth controller.
  160. * @PS3_SM_WAKE_RTC:
  161. * @PS3_SM_WAKE_RTC_ERROR:
  162. * @PS3_SM_WAKE_P_O_R: Power on reset.
  163. *
  164. * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN.
  165. * System will always wake from the PS3_SM_WAKE_DEFAULT sources.
  166. */
  167. enum ps3_sys_manager_wake_source {
  168. /* version 3 */
  169. PS3_SM_WAKE_DEFAULT = 0,
  170. PS3_SM_WAKE_RTC = 0x00000040,
  171. PS3_SM_WAKE_RTC_ERROR = 0x00000080,
  172. PS3_SM_WAKE_P_O_R = 0x10000000,
  173. };
  174. /**
  175. * enum ps3_sys_manager_cmd - Command from system manager to guest.
  176. *
  177. * The guest completes the actions needed, then acks or naks the command via
  178. * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN,
  179. * the guest must be fully prepared for a system poweroff prior to acking the
  180. * command.
  181. */
  182. enum ps3_sys_manager_cmd {
  183. /* version 1 */
  184. PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */
  185. };
  186. /**
  187. * ps3_sm_force_power_off - Poweroff helper.
  188. *
  189. * A global variable used to force a poweroff when the power button has
  190. * been pressed irrespective of how init handles the ctrl_alt_del signal.
  191. *
  192. */
  193. static unsigned int ps3_sm_force_power_off;
  194. /**
  195. * ps3_sys_manager_write - Helper to write a two part message to the vuart.
  196. *
  197. */
  198. static int ps3_sys_manager_write(struct ps3_system_bus_device *dev,
  199. const struct ps3_sys_manager_header *header, const void *payload)
  200. {
  201. int result;
  202. BUG_ON(header->version != 1);
  203. BUG_ON(header->size != 16);
  204. BUG_ON(header->payload_size != 8 && header->payload_size != 16);
  205. BUG_ON(header->service_id > 8);
  206. result = ps3_vuart_write(dev, header,
  207. sizeof(struct ps3_sys_manager_header));
  208. if (!result)
  209. result = ps3_vuart_write(dev, payload, header->payload_size);
  210. return result;
  211. }
  212. /**
  213. * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager.
  214. *
  215. */
  216. static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev,
  217. enum ps3_sys_manager_attr attr)
  218. {
  219. struct ps3_sys_manager_header header;
  220. struct {
  221. u8 version;
  222. u8 reserved_1[3];
  223. u32 attribute;
  224. } payload;
  225. BUILD_BUG_ON(sizeof(payload) != 8);
  226. dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
  227. memset(&header, 0, sizeof(header));
  228. header.version = 1;
  229. header.size = 16;
  230. header.payload_size = 16;
  231. header.service_id = PS3_SM_SERVICE_ID_SET_ATTR;
  232. memset(&payload, 0, sizeof(payload));
  233. payload.version = 1;
  234. payload.attribute = attr;
  235. return ps3_sys_manager_write(dev, &header, &payload);
  236. }
  237. /**
  238. * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager.
  239. *
  240. * Tell the system manager what to do after this lpar is destroyed.
  241. */
  242. static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev,
  243. enum ps3_sys_manager_next_op op,
  244. enum ps3_sys_manager_wake_source wake_source)
  245. {
  246. struct ps3_sys_manager_header header;
  247. struct {
  248. u8 version;
  249. u8 type;
  250. u8 gos_id;
  251. u8 reserved_1;
  252. u32 wake_source;
  253. u8 reserved_2[8];
  254. } payload;
  255. BUILD_BUG_ON(sizeof(payload) != 16);
  256. dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
  257. memset(&header, 0, sizeof(header));
  258. header.version = 1;
  259. header.size = 16;
  260. header.payload_size = 16;
  261. header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP;
  262. memset(&payload, 0, sizeof(payload));
  263. payload.version = 3;
  264. payload.type = op;
  265. payload.gos_id = 3; /* other os */
  266. payload.wake_source = wake_source;
  267. return ps3_sys_manager_write(dev, &header, &payload);
  268. }
  269. /**
  270. * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager.
  271. *
  272. * The guest sends this message to request an operation or action of the system
  273. * manager. The reply is a command message from the system manager. In the
  274. * command handler the guest performs the requested operation. The result of
  275. * the command is then communicated back to the system manager with a response
  276. * message.
  277. *
  278. * Currently, the only supported request is the 'shutdown self' request.
  279. */
  280. static int ps3_sys_manager_send_request_shutdown(
  281. struct ps3_system_bus_device *dev)
  282. {
  283. struct ps3_sys_manager_header header;
  284. struct {
  285. u8 version;
  286. u8 type;
  287. u8 gos_id;
  288. u8 reserved_1[13];
  289. } payload;
  290. BUILD_BUG_ON(sizeof(payload) != 16);
  291. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  292. memset(&header, 0, sizeof(header));
  293. header.version = 1;
  294. header.size = 16;
  295. header.payload_size = 16;
  296. header.service_id = PS3_SM_SERVICE_ID_REQUEST;
  297. memset(&payload, 0, sizeof(payload));
  298. payload.version = 1;
  299. payload.type = 1; /* shutdown */
  300. payload.gos_id = 0; /* self */
  301. return ps3_sys_manager_write(dev, &header, &payload);
  302. }
  303. /**
  304. * ps3_sys_manager_send_response - Send a 'response' to the system manager.
  305. * @status: zero = success, others fail.
  306. *
  307. * The guest sends this message to the system manager to acnowledge success or
  308. * failure of a command sent by the system manager.
  309. */
  310. static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev,
  311. u64 status)
  312. {
  313. struct ps3_sys_manager_header header;
  314. struct {
  315. u8 version;
  316. u8 reserved_1[3];
  317. u8 status;
  318. u8 reserved_2[11];
  319. } payload;
  320. BUILD_BUG_ON(sizeof(payload) != 16);
  321. dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
  322. (status ? "nak" : "ack"));
  323. memset(&header, 0, sizeof(header));
  324. header.version = 1;
  325. header.size = 16;
  326. header.payload_size = 16;
  327. header.service_id = PS3_SM_SERVICE_ID_RESPONSE;
  328. memset(&payload, 0, sizeof(payload));
  329. payload.version = 1;
  330. payload.status = status;
  331. return ps3_sys_manager_write(dev, &header, &payload);
  332. }
  333. /**
  334. * ps3_sys_manager_handle_event - Second stage event msg handler.
  335. *
  336. */
  337. static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
  338. {
  339. int result;
  340. struct {
  341. u8 version;
  342. u8 type;
  343. u8 reserved_1[2];
  344. u32 value;
  345. u8 reserved_2[8];
  346. } event;
  347. BUILD_BUG_ON(sizeof(event) != 16);
  348. result = ps3_vuart_read(dev, &event, sizeof(event));
  349. BUG_ON(result && "need to retry here");
  350. if (event.version != 1) {
  351. dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
  352. __func__, __LINE__, event.version);
  353. return -EIO;
  354. }
  355. switch (event.type) {
  356. case PS3_SM_EVENT_POWER_PRESSED:
  357. dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n",
  358. __func__, __LINE__);
  359. ps3_sm_force_power_off = 1;
  360. /*
  361. * A memory barrier is use here to sync memory since
  362. * ps3_sys_manager_final_restart() could be called on
  363. * another cpu.
  364. */
  365. wmb();
  366. kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
  367. break;
  368. case PS3_SM_EVENT_POWER_RELEASED:
  369. dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
  370. __func__, __LINE__, event.value);
  371. break;
  372. case PS3_SM_EVENT_RESET_PRESSED:
  373. dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n",
  374. __func__, __LINE__);
  375. ps3_sm_force_power_off = 0;
  376. /*
  377. * A memory barrier is use here to sync memory since
  378. * ps3_sys_manager_final_restart() could be called on
  379. * another cpu.
  380. */
  381. wmb();
  382. kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
  383. break;
  384. case PS3_SM_EVENT_RESET_RELEASED:
  385. dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n",
  386. __func__, __LINE__, event.value);
  387. break;
  388. case PS3_SM_EVENT_THERMAL_ALERT:
  389. dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
  390. __func__, __LINE__, event.value);
  391. printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value);
  392. break;
  393. case PS3_SM_EVENT_THERMAL_CLEARED:
  394. dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
  395. __func__, __LINE__, event.value);
  396. break;
  397. default:
  398. dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n",
  399. __func__, __LINE__, event.type);
  400. return -EIO;
  401. }
  402. return 0;
  403. }
  404. /**
  405. * ps3_sys_manager_handle_cmd - Second stage command msg handler.
  406. *
  407. * The system manager sends this in reply to a 'request' message from the guest.
  408. */
  409. static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
  410. {
  411. int result;
  412. struct {
  413. u8 version;
  414. u8 type;
  415. u8 reserved_1[14];
  416. } cmd;
  417. BUILD_BUG_ON(sizeof(cmd) != 16);
  418. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  419. result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
  420. BUG_ON(result && "need to retry here");
  421. if(result)
  422. return result;
  423. if (cmd.version != 1) {
  424. dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n",
  425. __func__, __LINE__, cmd.version);
  426. return -EIO;
  427. }
  428. if (cmd.type != PS3_SM_CMD_SHUTDOWN) {
  429. dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n",
  430. __func__, __LINE__, cmd.type);
  431. return -EIO;
  432. }
  433. ps3_sys_manager_send_response(dev, 0);
  434. return 0;
  435. }
  436. /**
  437. * ps3_sys_manager_handle_msg - First stage msg handler.
  438. *
  439. * Can be called directly to manually poll vuart and pump message handler.
  440. */
  441. static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
  442. {
  443. int result;
  444. struct ps3_sys_manager_header header;
  445. result = ps3_vuart_read(dev, &header,
  446. sizeof(struct ps3_sys_manager_header));
  447. if(result)
  448. return result;
  449. if (header.version != 1) {
  450. dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
  451. __func__, __LINE__, header.version);
  452. dump_sm_header(&header);
  453. goto fail_header;
  454. }
  455. BUILD_BUG_ON(sizeof(header) != 16);
  456. if (header.size != 16 || (header.payload_size != 8
  457. && header.payload_size != 16)) {
  458. dump_sm_header(&header);
  459. BUG();
  460. }
  461. switch (header.service_id) {
  462. case PS3_SM_SERVICE_ID_EXTERN_EVENT:
  463. dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__);
  464. return ps3_sys_manager_handle_event(dev);
  465. case PS3_SM_SERVICE_ID_COMMAND:
  466. dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
  467. return ps3_sys_manager_handle_cmd(dev);
  468. case PS3_SM_SERVICE_ID_REQUEST_ERROR:
  469. dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__,
  470. __LINE__);
  471. dump_sm_header(&header);
  472. break;
  473. default:
  474. dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
  475. __func__, __LINE__, header.service_id);
  476. break;
  477. }
  478. goto fail_id;
  479. fail_header:
  480. ps3_vuart_clear_rx_bytes(dev, 0);
  481. return -EIO;
  482. fail_id:
  483. ps3_vuart_clear_rx_bytes(dev, header.payload_size);
  484. return -EIO;
  485. }
  486. /**
  487. * ps3_sys_manager_final_power_off - The final platform machine_power_off routine.
  488. *
  489. * This routine never returns. The routine disables asynchronous vuart reads
  490. * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
  491. * the shutdown command sent from the system manager. Soon after the
  492. * acknowledgement is sent the lpar is destroyed by the HV. This routine
  493. * should only be called from ps3_power_off() through
  494. * ps3_sys_manager_ops.power_off.
  495. */
  496. static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
  497. {
  498. BUG_ON(!dev);
  499. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  500. ps3_vuart_cancel_async(dev);
  501. ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
  502. PS3_SM_WAKE_DEFAULT);
  503. ps3_sys_manager_send_request_shutdown(dev);
  504. printk(KERN_EMERG "System Halted, OK to turn off power\n");
  505. while(1)
  506. ps3_sys_manager_handle_msg(dev);
  507. }
  508. /**
  509. * ps3_sys_manager_final_restart - The final platform machine_restart routine.
  510. *
  511. * This routine never returns. The routine disables asynchronous vuart reads
  512. * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
  513. * the shutdown command sent from the system manager. Soon after the
  514. * acknowledgement is sent the lpar is destroyed by the HV. This routine
  515. * should only be called from ps3_restart() through ps3_sys_manager_ops.restart.
  516. */
  517. static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
  518. {
  519. BUG_ON(!dev);
  520. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  521. /* Check if we got here via a power button event. */
  522. if (ps3_sm_force_power_off) {
  523. dev_dbg(&dev->core, "%s:%d: forcing poweroff\n",
  524. __func__, __LINE__);
  525. ps3_sys_manager_final_power_off(dev);
  526. }
  527. ps3_vuart_cancel_async(dev);
  528. ps3_sys_manager_send_attr(dev, 0);
  529. ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
  530. PS3_SM_WAKE_DEFAULT);
  531. ps3_sys_manager_send_request_shutdown(dev);
  532. printk(KERN_EMERG "System Halted, OK to turn off power\n");
  533. while(1)
  534. ps3_sys_manager_handle_msg(dev);
  535. }
  536. /**
  537. * ps3_sys_manager_work - Asynchronous read handler.
  538. *
  539. * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port.
  540. */
  541. static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
  542. {
  543. ps3_sys_manager_handle_msg(dev);
  544. ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
  545. }
  546. static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
  547. {
  548. int result;
  549. struct ps3_sys_manager_ops ops;
  550. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  551. ops.power_off = ps3_sys_manager_final_power_off;
  552. ops.restart = ps3_sys_manager_final_restart;
  553. ops.dev = dev;
  554. /* ps3_sys_manager_register_ops copies ops. */
  555. ps3_sys_manager_register_ops(&ops);
  556. result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
  557. BUG_ON(result);
  558. result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
  559. BUG_ON(result);
  560. return result;
  561. }
  562. static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev)
  563. {
  564. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  565. return 0;
  566. }
  567. static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev)
  568. {
  569. dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  570. }
  571. static struct ps3_vuart_port_driver ps3_sys_manager = {
  572. .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
  573. .core.core.name = "ps3_sys_manager",
  574. .probe = ps3_sys_manager_probe,
  575. .remove = ps3_sys_manager_remove,
  576. .shutdown = ps3_sys_manager_shutdown,
  577. .work = ps3_sys_manager_work,
  578. };
  579. static int __init ps3_sys_manager_init(void)
  580. {
  581. if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
  582. return -ENODEV;
  583. return ps3_vuart_port_driver_register(&ps3_sys_manager);
  584. }
  585. module_init(ps3_sys_manager_init);
  586. /* Module remove not supported. */
  587. MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);