Commit fde5efd0e50e026f3f69629fc5790a4f0533dcaa

Authored by Geoff Levand
Committed by Paul Mackerras
1 parent ea1547d311

[POWERPC] PS3: System manager support

Add PS3 system manager support and the ppc_md routines restart() and
power_off().

The system manager provides an event notification mechanism for reporting
events like thermal alert and button presses.  It also provides support to
control system shutdown and startup.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

Showing 5 changed files with 643 additions and 4 deletions Side-by-side Diff

arch/powerpc/platforms/ps3/Kconfig
... ... @@ -62,5 +62,15 @@
62 62 This support is required for graphics and sound. In
63 63 general, all users will say Y or M.
64 64  
  65 +config PS3_SYS_MANAGER
  66 + bool "PS3 System Manager driver"
  67 + select PS3_VUART
  68 + default y
  69 + help
  70 + Include support for the PS3 System Manager.
  71 +
  72 + This support is required for system control. In
  73 + general, all users will say Y.
  74 +
65 75 endmenu
arch/powerpc/platforms/ps3/setup.c
... ... @@ -42,6 +42,10 @@
42 42 #define DBG(fmt...) do{if(0)printk(fmt);}while(0)
43 43 #endif
44 44  
  45 +#if !defined(CONFIG_SMP)
  46 +static void smp_send_stop(void) {}
  47 +#endif
  48 +
45 49 int ps3_get_firmware_version(union ps3_firmware_version *v)
46 50 {
47 51 int result = lv1_get_version_info(&v->raw);
48 52  
49 53  
50 54  
51 55  
... ... @@ -66,22 +70,35 @@
66 70 lv1_pause(0);
67 71 }
68 72  
  73 +static void ps3_restart(char *cmd)
  74 +{
  75 + DBG("%s:%d cmd '%s'\n", __func__, __LINE__, cmd);
  76 +
  77 + smp_send_stop();
  78 + ps3_sys_manager_restart(); /* never returns */
  79 +}
  80 +
  81 +static void ps3_power_off(void)
  82 +{
  83 + DBG("%s:%d\n", __func__, __LINE__);
  84 +
  85 + smp_send_stop();
  86 + ps3_sys_manager_power_off(); /* never returns */
  87 +}
  88 +
69 89 static void ps3_panic(char *str)
70 90 {
71 91 DBG("%s:%d %s\n", __func__, __LINE__, str);
72 92  
73   -#ifdef CONFIG_SMP
74 93 smp_send_stop();
75   -#endif
76 94 printk("\n");
77 95 printk(" System does not reboot automatically.\n");
78 96 printk(" Please press POWER button.\n");
79 97 printk("\n");
80 98  
81   - for (;;) ;
  99 + while(1);
82 100 }
83 101  
84   -
85 102 static void prealloc(struct ps3_prealloc *p)
86 103 {
87 104 if (!p->size)
... ... @@ -219,6 +236,8 @@
219 236 .get_rtc_time = ps3_get_rtc_time,
220 237 .calibrate_decr = ps3_calibrate_decr,
221 238 .progress = ps3_progress,
  239 + .restart = ps3_restart,
  240 + .power_off = ps3_power_off,
222 241 #if defined(CONFIG_KEXEC)
223 242 .kexec_cpu_down = ps3_kexec_cpu_down,
224 243 .machine_kexec = ps3_machine_kexec,
drivers/ps3/Makefile
1 1 obj-$(CONFIG_PS3_VUART) += vuart.o
2 2 obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o
  3 +obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o
drivers/ps3/sys-manager.c
  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 +
  21 +#include <linux/kernel.h>
  22 +#include <linux/module.h>
  23 +#include <linux/workqueue.h>
  24 +#include <linux/reboot.h>
  25 +#include <asm/ps3.h>
  26 +#include "vuart.h"
  27 +
  28 +MODULE_AUTHOR("Sony Corporation");
  29 +MODULE_LICENSE("GPL v2");
  30 +MODULE_DESCRIPTION("PS3 System Manager");
  31 +
  32 +/**
  33 + * ps3_sys_manager - PS3 system manager driver.
  34 + *
  35 + * The system manager provides an asyncronous system event notification
  36 + * mechanism for reporting events like thermal alert and button presses to
  37 + * guests. It also provides support to control system shutdown and startup.
  38 + *
  39 + * The actual system manager is implemented as an application running in the
  40 + * system policy module in lpar_1. Guests communicate with the system manager
  41 + * through port 2 of the vuart using a simple packet message protocol.
  42 + * Messages are comprised of a fixed field header followed by a message
  43 + * specific payload.
  44 + */
  45 +
  46 +/**
  47 + * struct ps3_sys_manager_header - System manager message header.
  48 + * @version: Header version, currently 1.
  49 + * @size: Header size in bytes, curently 16.
  50 + * @payload_size: Message payload size in bytes.
  51 + * @service_id: Message type, one of enum ps3_sys_manager_service_id.
  52 + */
  53 +
  54 +struct ps3_sys_manager_header {
  55 + /* version 1 */
  56 + u8 version;
  57 + u8 size;
  58 + u16 reserved_1;
  59 + u32 payload_size;
  60 + u16 service_id;
  61 + u16 reserved_2[3];
  62 +};
  63 +
  64 +/**
  65 + * @PS3_SM_RX_MSG_LEN - System manager received message length.
  66 + *
  67 + * Currently all messages received from the system manager are the same length
  68 + * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to
  69 + * simplify the logic.
  70 + */
  71 +
  72 +enum {
  73 + PS3_SM_RX_MSG_LEN = 32,
  74 +};
  75 +
  76 +/**
  77 + * enum ps3_sys_manager_service_id - Message header service_id.
  78 + * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
  79 + * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
  80 + * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
  81 + * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
  82 + * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
  83 + * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
  84 + */
  85 +
  86 +enum ps3_sys_manager_service_id {
  87 + /* version 1 */
  88 + PS3_SM_SERVICE_ID_REQUEST = 1,
  89 + PS3_SM_SERVICE_ID_RESPONSE = 2,
  90 + PS3_SM_SERVICE_ID_COMMAND = 3,
  91 + PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
  92 + PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
  93 + PS3_SM_SERVICE_ID_SET_ATTR = 8,
  94 +};
  95 +
  96 +/**
  97 + * enum ps3_sys_manager_attr - Notification attribute (bit position mask).
  98 + * @PS3_SM_ATTR_POWER: Power button.
  99 + * @PS3_SM_ATTR_RESET: Reset button, not available on retail console.
  100 + * @PS3_SM_ATTR_THERMAL: Sytem thermal alert.
  101 + * @PS3_SM_ATTR_CONTROLLER: Remote controller event.
  102 + * @PS3_SM_ATTR_ALL: Logical OR of all.
  103 + *
  104 + * The guest tells the system manager which events it is interested in receiving
  105 + * notice of by sending the system manager a logical OR of notification
  106 + * attributes via the ps3_sys_manager_send_attr() routine.
  107 + */
  108 +
  109 +enum ps3_sys_manager_attr {
  110 + /* version 1 */
  111 + PS3_SM_ATTR_POWER = 1,
  112 + PS3_SM_ATTR_RESET = 2,
  113 + PS3_SM_ATTR_THERMAL = 4,
  114 + PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */
  115 + PS3_SM_ATTR_ALL = 0x0f,
  116 +};
  117 +
  118 +/**
  119 + * enum ps3_sys_manager_event - External event type, reported by system manager.
  120 + * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used.
  121 + * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec.
  122 + * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used.
  123 + * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec.
  124 + * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id.
  125 + * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id.
  126 + */
  127 +
  128 +enum ps3_sys_manager_event {
  129 + /* version 1 */
  130 + PS3_SM_EVENT_POWER_PRESSED = 3,
  131 + PS3_SM_EVENT_POWER_RELEASED = 4,
  132 + PS3_SM_EVENT_RESET_PRESSED = 5,
  133 + PS3_SM_EVENT_RESET_RELEASED = 6,
  134 + PS3_SM_EVENT_THERMAL_ALERT = 7,
  135 + PS3_SM_EVENT_THERMAL_CLEARED = 8,
  136 + /* no info on controller events */
  137 +};
  138 +
  139 +/**
  140 + * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed.
  141 + */
  142 +
  143 +enum ps3_sys_manager_next_op {
  144 + /* version 3 */
  145 + PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1,
  146 + PS3_SM_NEXT_OP_SYS_REBOOT = 2,
  147 + PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82,
  148 +};
  149 +
  150 +/**
  151 + * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask).
  152 + * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR
  153 + * controller, and bluetooth controller.
  154 + * @PS3_SM_WAKE_RTC:
  155 + * @PS3_SM_WAKE_RTC_ERROR:
  156 + * @PS3_SM_WAKE_P_O_R: Power on reset.
  157 + *
  158 + * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN.
  159 + * System will always wake from the PS3_SM_WAKE_DEFAULT sources.
  160 + */
  161 +
  162 +enum ps3_sys_manager_wake_source {
  163 + /* version 3 */
  164 + PS3_SM_WAKE_DEFAULT = 0,
  165 + PS3_SM_WAKE_RTC = 0x00000040,
  166 + PS3_SM_WAKE_RTC_ERROR = 0x00000080,
  167 + PS3_SM_WAKE_P_O_R = 0x10000000,
  168 +};
  169 +
  170 +/**
  171 + * enum ps3_sys_manager_cmd - Command from system manager to guest.
  172 + *
  173 + * The guest completes the actions needed, then acks or naks the command via
  174 + * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN,
  175 + * the guest must be fully prepared for a system poweroff prior to acking the
  176 + * command.
  177 + */
  178 +
  179 +enum ps3_sys_manager_cmd {
  180 + /* version 1 */
  181 + PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */
  182 +};
  183 +
  184 +/**
  185 + * ps3_sys_manager_write - Helper to write a two part message to the vuart.
  186 + *
  187 + */
  188 +
  189 +static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev,
  190 + const struct ps3_sys_manager_header *header, const void *payload)
  191 +{
  192 + int result;
  193 +
  194 + BUG_ON(header->version != 1);
  195 + BUG_ON(header->size != 16);
  196 + BUG_ON(header->payload_size != 8 && header->payload_size != 16);
  197 + BUG_ON(header->service_id > 8);
  198 +
  199 + result = ps3_vuart_write(dev, header,
  200 + sizeof(struct ps3_sys_manager_header));
  201 +
  202 + if (!result)
  203 + result = ps3_vuart_write(dev, payload, header->payload_size);
  204 +
  205 + return result;
  206 +}
  207 +
  208 +/**
  209 + * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager.
  210 + *
  211 + */
  212 +
  213 +static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
  214 + enum ps3_sys_manager_attr attr)
  215 +{
  216 + static const struct ps3_sys_manager_header header = {
  217 + .version = 1,
  218 + .size = 16,
  219 + .payload_size = 16,
  220 + .service_id = PS3_SM_SERVICE_ID_SET_ATTR,
  221 + };
  222 + struct {
  223 + u8 version;
  224 + u8 reserved_1[3];
  225 + u32 attribute;
  226 + } payload;
  227 +
  228 + BUILD_BUG_ON(sizeof(payload) != 8);
  229 +
  230 + dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
  231 +
  232 + memset(&payload, 0, sizeof(payload));
  233 + payload.version = 1;
  234 + payload.attribute = attr;
  235 +
  236 + return ps3_sys_manager_write(dev, &header, &payload);
  237 +}
  238 +
  239 +/**
  240 + * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager.
  241 + *
  242 + * Tell the system manager what to do after this lpar is destroyed.
  243 + */
  244 +
  245 +static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
  246 + enum ps3_sys_manager_next_op op,
  247 + enum ps3_sys_manager_wake_source wake_source)
  248 +{
  249 + static const struct ps3_sys_manager_header header = {
  250 + .version = 1,
  251 + .size = 16,
  252 + .payload_size = 16,
  253 + .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP,
  254 + };
  255 + struct {
  256 + u8 version;
  257 + u8 type;
  258 + u8 gos_id;
  259 + u8 reserved_1;
  260 + u32 wake_source;
  261 + u8 reserved_2[8];
  262 + } payload;
  263 +
  264 + BUILD_BUG_ON(sizeof(payload) != 16);
  265 +
  266 + dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
  267 +
  268 + memset(&payload, 0, sizeof(payload));
  269 + payload.version = 3;
  270 + payload.type = op;
  271 + payload.gos_id = 3; /* other os */
  272 + payload.wake_source = wake_source;
  273 +
  274 + return ps3_sys_manager_write(dev, &header, &payload);
  275 +}
  276 +
  277 +/**
  278 + * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager.
  279 + *
  280 + * The guest sends this message to request an operation or action of the system
  281 + * manager. The reply is a command message from the system manager. In the
  282 + * command handler the guest performs the requested operation. The result of
  283 + * the command is then communicated back to the system manager with a response
  284 + * message.
  285 + *
  286 + * Currently, the only supported request it the 'shutdown self' request.
  287 + */
  288 +
  289 +static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev)
  290 +{
  291 + static const struct ps3_sys_manager_header header = {
  292 + .version = 1,
  293 + .size = 16,
  294 + .payload_size = 16,
  295 + .service_id = PS3_SM_SERVICE_ID_REQUEST,
  296 + };
  297 + struct {
  298 + u8 version;
  299 + u8 type;
  300 + u8 gos_id;
  301 + u8 reserved_1[13];
  302 + } static const payload = {
  303 + .version = 1,
  304 + .type = 1, /* shutdown */
  305 + .gos_id = 0, /* self */
  306 + };
  307 +
  308 + BUILD_BUG_ON(sizeof(payload) != 16);
  309 +
  310 + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  311 +
  312 + return ps3_sys_manager_write(dev, &header, &payload);
  313 +}
  314 +
  315 +/**
  316 + * ps3_sys_manager_send_response - Send a 'response' to the system manager.
  317 + * @status: zero = success, others fail.
  318 + *
  319 + * The guest sends this message to the system manager to acnowledge success or
  320 + * failure of a command sent by the system manager.
  321 + */
  322 +
  323 +static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
  324 + u64 status)
  325 +{
  326 + static const struct ps3_sys_manager_header header = {
  327 + .version = 1,
  328 + .size = 16,
  329 + .payload_size = 16,
  330 + .service_id = PS3_SM_SERVICE_ID_RESPONSE,
  331 + };
  332 + struct {
  333 + u8 version;
  334 + u8 reserved_1[3];
  335 + u8 status;
  336 + u8 reserved_2[11];
  337 + } payload;
  338 +
  339 + BUILD_BUG_ON(sizeof(payload) != 16);
  340 +
  341 + dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
  342 + (status ? "nak" : "ack"));
  343 +
  344 + memset(&payload, 0, sizeof(payload));
  345 + payload.version = 1;
  346 + payload.status = status;
  347 +
  348 + return ps3_sys_manager_write(dev, &header, &payload);
  349 +}
  350 +
  351 +/**
  352 + * ps3_sys_manager_handle_event - Second stage event msg handler.
  353 + *
  354 + */
  355 +
  356 +static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
  357 +{
  358 + int result;
  359 + struct {
  360 + u8 version;
  361 + u8 type;
  362 + u8 reserved_1[2];
  363 + u32 value;
  364 + u8 reserved_2[8];
  365 + } event;
  366 +
  367 + BUILD_BUG_ON(sizeof(event) != 16);
  368 +
  369 + result = ps3_vuart_read(dev, &event, sizeof(event));
  370 + BUG_ON(result);
  371 +
  372 + if (event.version != 1) {
  373 + dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
  374 + __func__, __LINE__, event.version);
  375 + return -EIO;
  376 + }
  377 +
  378 + switch (event.type) {
  379 + case PS3_SM_EVENT_POWER_PRESSED:
  380 + dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n",
  381 + __func__, __LINE__);
  382 + break;
  383 + case PS3_SM_EVENT_POWER_RELEASED:
  384 + dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
  385 + __func__, __LINE__, event.value);
  386 + kill_cad_pid(SIGINT, 1);
  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 +
  403 + return 0;
  404 +}
  405 +/**
  406 + * ps3_sys_manager_handle_cmd - Second stage command msg handler.
  407 + *
  408 + * The system manager sends this in reply to a 'request' message from the guest.
  409 + */
  410 +
  411 +static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
  412 +{
  413 + int result;
  414 + struct {
  415 + u8 version;
  416 + u8 type;
  417 + u8 reserved_1[14];
  418 + } cmd;
  419 +
  420 + BUILD_BUG_ON(sizeof(cmd) != 16);
  421 +
  422 + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  423 +
  424 + result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
  425 +
  426 + if(result)
  427 + return result;
  428 +
  429 + if (cmd.version != 1) {
  430 + dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n",
  431 + __func__, __LINE__, cmd.version);
  432 + return -EIO;
  433 + }
  434 +
  435 + if (cmd.type != PS3_SM_CMD_SHUTDOWN) {
  436 + dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n",
  437 + __func__, __LINE__, cmd.type);
  438 + return -EIO;
  439 + }
  440 +
  441 + ps3_sys_manager_send_response(dev, 0);
  442 + return 0;
  443 +}
  444 +
  445 +/**
  446 + * ps3_sys_manager_handle_msg - First stage msg handler.
  447 + *
  448 + */
  449 +
  450 +static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
  451 +{
  452 + int result;
  453 + struct ps3_sys_manager_header header;
  454 +
  455 + result = ps3_vuart_read(dev, &header,
  456 + sizeof(struct ps3_sys_manager_header));
  457 +
  458 + if(result)
  459 + return result;
  460 +
  461 + if (header.version != 1) {
  462 + dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
  463 + __func__, __LINE__, header.version);
  464 + goto fail_header;
  465 + }
  466 +
  467 + BUILD_BUG_ON(sizeof(header) != 16);
  468 + BUG_ON(header.size != 16);
  469 + BUG_ON(header.payload_size != 16);
  470 +
  471 + switch (header.service_id) {
  472 + case PS3_SM_SERVICE_ID_EXTERN_EVENT:
  473 + dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__);
  474 + return ps3_sys_manager_handle_event(dev);
  475 + case PS3_SM_SERVICE_ID_COMMAND:
  476 + dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
  477 + return ps3_sys_manager_handle_cmd(dev);
  478 + default:
  479 + dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
  480 + __func__, __LINE__, header.service_id);
  481 + break;
  482 + }
  483 + goto fail_id;
  484 +
  485 +fail_header:
  486 + ps3_vuart_clear_rx_bytes(dev, 0);
  487 + return -EIO;
  488 +fail_id:
  489 + ps3_vuart_clear_rx_bytes(dev, header.payload_size);
  490 + return -EIO;
  491 +}
  492 +
  493 +/**
  494 + * ps3_sys_manager_work - Asyncronous read handler.
  495 + *
  496 + * Signaled when a complete message arrives at the vuart port.
  497 + */
  498 +
  499 +static void ps3_sys_manager_work(struct work_struct *work)
  500 +{
  501 + struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work);
  502 +
  503 + ps3_sys_manager_handle_msg(dev);
  504 + ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN);
  505 +}
  506 +
  507 +struct {
  508 + struct ps3_vuart_port_device *dev;
  509 +} static drv_priv;
  510 +
  511 +/**
  512 + * ps3_sys_manager_restart - The final platform machine_restart routine.
  513 + *
  514 + * This routine never returns. The routine disables asyncronous vuart reads
  515 + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
  516 + * the shutdown command sent from the system manager. Soon after the
  517 + * acknowledgement is sent the lpar is destroyed by the HV. This routine
  518 + * should only be called from ps3_restart().
  519 + */
  520 +
  521 +void ps3_sys_manager_restart(void)
  522 +{
  523 + struct ps3_vuart_port_device *dev = drv_priv.dev;
  524 +
  525 + BUG_ON(!drv_priv.dev);
  526 +
  527 + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  528 +
  529 + ps3_vuart_cancel_async(dev);
  530 +
  531 + ps3_sys_manager_send_attr(dev, 0);
  532 + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
  533 + PS3_SM_WAKE_DEFAULT);
  534 + ps3_sys_manager_send_request_shutdown(dev);
  535 +
  536 + printk(KERN_EMERG "System Halted, OK to turn off power\n");
  537 +
  538 + while(1)
  539 + ps3_sys_manager_handle_msg(dev);
  540 +}
  541 +
  542 +/**
  543 + * ps3_sys_manager_power_off - The final platform machine_power_off routine.
  544 + *
  545 + * This routine never returns. The routine disables asyncronous vuart reads
  546 + * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
  547 + * the shutdown command sent from the system manager. Soon after the
  548 + * acknowledgement is sent the lpar is destroyed by the HV. This routine
  549 + * should only be called from ps3_power_off().
  550 + */
  551 +
  552 +void ps3_sys_manager_power_off(void)
  553 +{
  554 + struct ps3_vuart_port_device *dev = drv_priv.dev;
  555 +
  556 + BUG_ON(!drv_priv.dev);
  557 +
  558 + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  559 +
  560 + ps3_vuart_cancel_async(dev);
  561 +
  562 + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
  563 + PS3_SM_WAKE_DEFAULT);
  564 + ps3_sys_manager_send_request_shutdown(dev);
  565 +
  566 + printk(KERN_EMERG "System Halted, OK to turn off power\n");
  567 +
  568 + while(1)
  569 + ps3_sys_manager_handle_msg(dev);
  570 +}
  571 +
  572 +static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev)
  573 +{
  574 + int result;
  575 +
  576 + dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
  577 +
  578 + BUG_ON(drv_priv.dev);
  579 + drv_priv.dev = dev;
  580 +
  581 + result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
  582 + BUG_ON(result);
  583 +
  584 + result = ps3_vuart_read_async(dev, ps3_sys_manager_work,
  585 + PS3_SM_RX_MSG_LEN);
  586 + BUG_ON(result);
  587 +
  588 + return result;
  589 +}
  590 +
  591 +static struct ps3_vuart_port_driver ps3_sys_manager = {
  592 + .match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
  593 + .core = {
  594 + .name = "ps3_sys_manager",
  595 + },
  596 + .probe = ps3_sys_manager_probe,
  597 +};
  598 +
  599 +static int __init ps3_sys_manager_init(void)
  600 +{
  601 + return ps3_vuart_port_driver_register(&ps3_sys_manager);
  602 +}
  603 +
  604 +module_init(ps3_sys_manager_init);
include/asm-powerpc/ps3.h
... ... @@ -370,6 +370,11 @@
370 370  
371 371 int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
372 372  
  373 +/* system manager */
  374 +
  375 +void ps3_sys_manager_restart(void);
  376 +void ps3_sys_manager_power_off(void);
  377 +
373 378 struct ps3_prealloc {
374 379 const char *name;
375 380 void *address;