Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Geoff Levand and committed by
Paul Mackerras
fde5efd0 ea1547d3

+643 -4
+10
arch/powerpc/platforms/ps3/Kconfig
··· 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
+23 -4
arch/powerpc/platforms/ps3/setup.c
··· 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); ··· 70 66 lv1_pause(0); 71 67 } 72 68 69 + static void ps3_restart(char *cmd) 70 + { 71 + DBG("%s:%d cmd '%s'\n", __func__, __LINE__, cmd); 72 + 73 + smp_send_stop(); 74 + ps3_sys_manager_restart(); /* never returns */ 75 + } 76 + 77 + static void ps3_power_off(void) 78 + { 79 + DBG("%s:%d\n", __func__, __LINE__); 80 + 81 + smp_send_stop(); 82 + ps3_sys_manager_power_off(); /* never returns */ 83 + } 84 + 73 85 static void ps3_panic(char *str) 74 86 { 75 87 DBG("%s:%d %s\n", __func__, __LINE__, str); 76 88 77 - #ifdef CONFIG_SMP 78 89 smp_send_stop(); 79 - #endif 80 90 printk("\n"); 81 91 printk(" System does not reboot automatically.\n"); 82 92 printk(" Please press POWER button.\n"); 83 93 printk("\n"); 84 94 85 - for (;;) ; 95 + while(1); 86 96 } 87 - 88 97 89 98 static void prealloc(struct ps3_prealloc *p) 90 99 { ··· 236 219 .get_rtc_time = ps3_get_rtc_time, 237 220 .calibrate_decr = ps3_calibrate_decr, 238 221 .progress = ps3_progress, 222 + .restart = ps3_restart, 223 + .power_off = ps3_power_off, 239 224 #if defined(CONFIG_KEXEC) 240 225 .kexec_cpu_down = ps3_kexec_cpu_down, 241 226 .machine_kexec = ps3_machine_kexec,
+1
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
+604
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);
+5
include/asm-powerpc/ps3.h
··· 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;