ps3-sys-manager.c (20324B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * PS3 System Manager. 4 * 5 * Copyright (C) 2007 Sony Computer Entertainment Inc. 6 * Copyright 2007 Sony Corp. 7 */ 8 9#include <linux/kernel.h> 10#include <linux/module.h> 11#include <linux/workqueue.h> 12#include <linux/reboot.h> 13#include <linux/sched/signal.h> 14 15#include <asm/firmware.h> 16#include <asm/lv1call.h> 17#include <asm/ps3.h> 18 19#include "vuart.h" 20 21/** 22 * ps3_sys_manager - PS3 system manager driver. 23 * 24 * The system manager provides an asynchronous system event notification 25 * mechanism for reporting events like thermal alert and button presses to 26 * guests. It also provides support to control system shutdown and startup. 27 * 28 * The actual system manager is implemented as an application running in the 29 * system policy module in lpar_1. Guests communicate with the system manager 30 * through port 2 of the vuart using a simple packet message protocol. 31 * Messages are comprised of a fixed field header followed by a message 32 * specific payload. 33 */ 34 35/** 36 * struct ps3_sys_manager_header - System manager message header. 37 * @version: Header version, currently 1. 38 * @size: Header size in bytes, currently 16. 39 * @payload_size: Message payload size in bytes. 40 * @service_id: Message type, one of enum ps3_sys_manager_service_id. 41 * @request_tag: Unique number to identify reply. 42 */ 43 44struct ps3_sys_manager_header { 45 /* version 1 */ 46 u8 version; 47 u8 size; 48 u16 reserved_1; 49 u32 payload_size; 50 u16 service_id; 51 u16 reserved_2; 52 u32 request_tag; 53}; 54 55#define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) 56static void __maybe_unused _dump_sm_header( 57 const struct ps3_sys_manager_header *h, const char *func, int line) 58{ 59 pr_debug("%s:%d: version: %xh\n", func, line, h->version); 60 pr_debug("%s:%d: size: %xh\n", func, line, h->size); 61 pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); 62 pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); 63 pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); 64} 65 66/** 67 * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. 68 * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. 69 * 70 * Currently all messages received from the system manager are either 71 * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header 72 * + 16 bytes payload = 32 bytes). This knowledge is used to simplify 73 * the logic. 74 */ 75 76enum { 77 PS3_SM_RX_MSG_LEN_MIN = 24, 78 PS3_SM_RX_MSG_LEN_MAX = 32, 79}; 80 81/** 82 * enum ps3_sys_manager_service_id - Message header service_id. 83 * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 84 * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. 85 * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 86 * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 87 * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 88 * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 89 * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 90 * 91 * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a 92 * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when 93 * a REQUEST message is sent at the wrong time. 94 */ 95 96enum ps3_sys_manager_service_id { 97 /* version 1 */ 98 PS3_SM_SERVICE_ID_REQUEST = 1, 99 PS3_SM_SERVICE_ID_RESPONSE = 2, 100 PS3_SM_SERVICE_ID_COMMAND = 3, 101 PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 102 PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 103 PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, 104 PS3_SM_SERVICE_ID_SET_ATTR = 8, 105}; 106 107/** 108 * enum ps3_sys_manager_attr - Notification attribute (bit position mask). 109 * @PS3_SM_ATTR_POWER: Power button. 110 * @PS3_SM_ATTR_RESET: Reset button, not available on retail console. 111 * @PS3_SM_ATTR_THERMAL: System thermal alert. 112 * @PS3_SM_ATTR_CONTROLLER: Remote controller event. 113 * @PS3_SM_ATTR_ALL: Logical OR of all. 114 * 115 * The guest tells the system manager which events it is interested in receiving 116 * notice of by sending the system manager a logical OR of notification 117 * attributes via the ps3_sys_manager_send_attr() routine. 118 */ 119 120enum 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/** 130 * enum ps3_sys_manager_event - External event type, reported by system manager. 131 * @PS3_SM_EVENT_POWER_PRESSED: payload.value = 132 * enum ps3_sys_manager_button_event. 133 * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. 134 * @PS3_SM_EVENT_RESET_PRESSED: payload.value = 135 * enum ps3_sys_manager_button_event. 136 * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. 137 * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. 138 * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. 139 */ 140 141enum ps3_sys_manager_event { 142 /* version 1 */ 143 PS3_SM_EVENT_POWER_PRESSED = 3, 144 PS3_SM_EVENT_POWER_RELEASED = 4, 145 PS3_SM_EVENT_RESET_PRESSED = 5, 146 PS3_SM_EVENT_RESET_RELEASED = 6, 147 PS3_SM_EVENT_THERMAL_ALERT = 7, 148 PS3_SM_EVENT_THERMAL_CLEARED = 8, 149 /* no info on controller events */ 150}; 151 152/** 153 * enum ps3_sys_manager_button_event - Button event payload values. 154 * @PS3_SM_BUTTON_EVENT_HARD: Hardware generated event. 155 * @PS3_SM_BUTTON_EVENT_SOFT: Software generated event. 156 */ 157 158enum ps3_sys_manager_button_event { 159 PS3_SM_BUTTON_EVENT_HARD = 0, 160 PS3_SM_BUTTON_EVENT_SOFT = 1, 161}; 162 163/** 164 * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. 165 */ 166 167enum ps3_sys_manager_next_op { 168 /* version 3 */ 169 PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1, 170 PS3_SM_NEXT_OP_SYS_REBOOT = 2, 171 PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82, 172}; 173 174/** 175 * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask). 176 * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button. 177 * @PS3_SM_WAKE_W_O_L: Ether or wireless LAN. 178 * @PS3_SM_WAKE_P_O_R: Power on reset. 179 * 180 * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. 181 * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. 182 * Sources listed here are the only ones available to guests in the 183 * other-os lpar. 184 */ 185 186enum ps3_sys_manager_wake_source { 187 /* version 3 */ 188 PS3_SM_WAKE_DEFAULT = 0, 189 PS3_SM_WAKE_W_O_L = 0x00000400, 190 PS3_SM_WAKE_P_O_R = 0x80000000, 191}; 192 193/** 194 * user_wake_sources - User specified wakeup sources. 195 * 196 * Logical OR of enum ps3_sys_manager_wake_source types. 197 */ 198 199static u32 user_wake_sources = PS3_SM_WAKE_DEFAULT; 200 201/** 202 * enum ps3_sys_manager_cmd - Command from system manager to guest. 203 * 204 * The guest completes the actions needed, then acks or naks the command via 205 * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN, 206 * the guest must be fully prepared for a system poweroff prior to acking the 207 * command. 208 */ 209 210enum ps3_sys_manager_cmd { 211 /* version 1 */ 212 PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */ 213}; 214 215/** 216 * ps3_sm_force_power_off - Poweroff helper. 217 * 218 * A global variable used to force a poweroff when the power button has 219 * been pressed irrespective of how init handles the ctrl_alt_del signal. 220 * 221 */ 222 223static unsigned int ps3_sm_force_power_off; 224 225/** 226 * ps3_sys_manager_write - Helper to write a two part message to the vuart. 227 * 228 */ 229 230static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, 231 const struct ps3_sys_manager_header *header, const void *payload) 232{ 233 int result; 234 235 BUG_ON(header->version != 1); 236 BUG_ON(header->size != 16); 237 BUG_ON(header->payload_size != 8 && header->payload_size != 16); 238 BUG_ON(header->service_id > 8); 239 240 result = ps3_vuart_write(dev, header, 241 sizeof(struct ps3_sys_manager_header)); 242 243 if (!result) 244 result = ps3_vuart_write(dev, payload, header->payload_size); 245 246 return result; 247} 248 249/** 250 * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager. 251 * 252 */ 253 254static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, 255 enum ps3_sys_manager_attr attr) 256{ 257 struct ps3_sys_manager_header header; 258 struct { 259 u8 version; 260 u8 reserved_1[3]; 261 u32 attribute; 262 } payload; 263 264 BUILD_BUG_ON(sizeof(payload) != 8); 265 266 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 267 268 memset(&header, 0, sizeof(header)); 269 header.version = 1; 270 header.size = 16; 271 header.payload_size = 16; 272 header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; 273 274 memset(&payload, 0, sizeof(payload)); 275 payload.version = 1; 276 payload.attribute = attr; 277 278 return ps3_sys_manager_write(dev, &header, &payload); 279} 280 281/** 282 * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager. 283 * 284 * Tell the system manager what to do after this lpar is destroyed. 285 */ 286 287static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, 288 enum ps3_sys_manager_next_op op, 289 enum ps3_sys_manager_wake_source wake_source) 290{ 291 struct ps3_sys_manager_header header; 292 struct { 293 u8 version; 294 u8 type; 295 u8 gos_id; 296 u8 reserved_1; 297 u32 wake_source; 298 u8 reserved_2[8]; 299 } payload; 300 301 BUILD_BUG_ON(sizeof(payload) != 16); 302 303 dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 304 305 memset(&header, 0, sizeof(header)); 306 header.version = 1; 307 header.size = 16; 308 header.payload_size = 16; 309 header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; 310 311 memset(&payload, 0, sizeof(payload)); 312 payload.version = 3; 313 payload.type = op; 314 payload.gos_id = 3; /* other os */ 315 payload.wake_source = wake_source; 316 317 return ps3_sys_manager_write(dev, &header, &payload); 318} 319 320/** 321 * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager. 322 * 323 * The guest sends this message to request an operation or action of the system 324 * manager. The reply is a command message from the system manager. In the 325 * command handler the guest performs the requested operation. The result of 326 * the command is then communicated back to the system manager with a response 327 * message. 328 * 329 * Currently, the only supported request is the 'shutdown self' request. 330 */ 331 332static int ps3_sys_manager_send_request_shutdown( 333 struct ps3_system_bus_device *dev) 334{ 335 struct ps3_sys_manager_header header; 336 struct { 337 u8 version; 338 u8 type; 339 u8 gos_id; 340 u8 reserved_1[13]; 341 } payload; 342 343 BUILD_BUG_ON(sizeof(payload) != 16); 344 345 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 346 347 memset(&header, 0, sizeof(header)); 348 header.version = 1; 349 header.size = 16; 350 header.payload_size = 16; 351 header.service_id = PS3_SM_SERVICE_ID_REQUEST; 352 353 memset(&payload, 0, sizeof(payload)); 354 payload.version = 1; 355 payload.type = 1; /* shutdown */ 356 payload.gos_id = 0; /* self */ 357 358 return ps3_sys_manager_write(dev, &header, &payload); 359} 360 361/** 362 * ps3_sys_manager_send_response - Send a 'response' to the system manager. 363 * @status: zero = success, others fail. 364 * 365 * The guest sends this message to the system manager to acnowledge success or 366 * failure of a command sent by the system manager. 367 */ 368 369static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, 370 u64 status) 371{ 372 struct ps3_sys_manager_header header; 373 struct { 374 u8 version; 375 u8 reserved_1[3]; 376 u8 status; 377 u8 reserved_2[11]; 378 } payload; 379 380 BUILD_BUG_ON(sizeof(payload) != 16); 381 382 dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 383 (status ? "nak" : "ack")); 384 385 memset(&header, 0, sizeof(header)); 386 header.version = 1; 387 header.size = 16; 388 header.payload_size = 16; 389 header.service_id = PS3_SM_SERVICE_ID_RESPONSE; 390 391 memset(&payload, 0, sizeof(payload)); 392 payload.version = 1; 393 payload.status = status; 394 395 return ps3_sys_manager_write(dev, &header, &payload); 396} 397 398/** 399 * ps3_sys_manager_handle_event - Second stage event msg handler. 400 * 401 */ 402 403static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) 404{ 405 int result; 406 struct { 407 u8 version; 408 u8 type; 409 u8 reserved_1[2]; 410 u32 value; 411 u8 reserved_2[8]; 412 } event; 413 414 BUILD_BUG_ON(sizeof(event) != 16); 415 416 result = ps3_vuart_read(dev, &event, sizeof(event)); 417 BUG_ON(result && "need to retry here"); 418 419 if (event.version != 1) { 420 dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 421 __func__, __LINE__, event.version); 422 return -EIO; 423 } 424 425 switch (event.type) { 426 case PS3_SM_EVENT_POWER_PRESSED: 427 dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n", 428 __func__, __LINE__, 429 (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 430 : "hard")); 431 ps3_sm_force_power_off = 1; 432 /* 433 * A memory barrier is use here to sync memory since 434 * ps3_sys_manager_final_restart() could be called on 435 * another cpu. 436 */ 437 wmb(); 438 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 439 break; 440 case PS3_SM_EVENT_POWER_RELEASED: 441 dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 442 __func__, __LINE__, event.value); 443 break; 444 case PS3_SM_EVENT_RESET_PRESSED: 445 dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n", 446 __func__, __LINE__, 447 (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" 448 : "hard")); 449 ps3_sm_force_power_off = 0; 450 /* 451 * A memory barrier is use here to sync memory since 452 * ps3_sys_manager_final_restart() could be called on 453 * another cpu. 454 */ 455 wmb(); 456 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ 457 break; 458 case PS3_SM_EVENT_RESET_RELEASED: 459 dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", 460 __func__, __LINE__, event.value); 461 break; 462 case PS3_SM_EVENT_THERMAL_ALERT: 463 dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 464 __func__, __LINE__, event.value); 465 pr_info("PS3 Thermal Alert Zone %u\n", event.value); 466 break; 467 case PS3_SM_EVENT_THERMAL_CLEARED: 468 dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n", 469 __func__, __LINE__, event.value); 470 break; 471 default: 472 dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n", 473 __func__, __LINE__, event.type); 474 return -EIO; 475 } 476 477 return 0; 478} 479/** 480 * ps3_sys_manager_handle_cmd - Second stage command msg handler. 481 * 482 * The system manager sends this in reply to a 'request' message from the guest. 483 */ 484 485static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) 486{ 487 int result; 488 struct { 489 u8 version; 490 u8 type; 491 u8 reserved_1[14]; 492 } cmd; 493 494 BUILD_BUG_ON(sizeof(cmd) != 16); 495 496 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 497 498 result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 499 BUG_ON(result && "need to retry here"); 500 501 if (result) 502 return result; 503 504 if (cmd.version != 1) { 505 dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n", 506 __func__, __LINE__, cmd.version); 507 return -EIO; 508 } 509 510 if (cmd.type != PS3_SM_CMD_SHUTDOWN) { 511 dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n", 512 __func__, __LINE__, cmd.type); 513 return -EIO; 514 } 515 516 ps3_sys_manager_send_response(dev, 0); 517 return 0; 518} 519 520/** 521 * ps3_sys_manager_handle_msg - First stage msg handler. 522 * 523 * Can be called directly to manually poll vuart and pump message handler. 524 */ 525 526static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) 527{ 528 int result; 529 struct ps3_sys_manager_header header; 530 531 result = ps3_vuart_read(dev, &header, 532 sizeof(struct ps3_sys_manager_header)); 533 534 if (result) 535 return result; 536 537 if (header.version != 1) { 538 dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 539 __func__, __LINE__, header.version); 540 dump_sm_header(&header); 541 goto fail_header; 542 } 543 544 BUILD_BUG_ON(sizeof(header) != 16); 545 546 if (header.size != 16 || (header.payload_size != 8 547 && header.payload_size != 16)) { 548 dump_sm_header(&header); 549 BUG(); 550 } 551 552 switch (header.service_id) { 553 case PS3_SM_SERVICE_ID_EXTERN_EVENT: 554 dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__); 555 return ps3_sys_manager_handle_event(dev); 556 case PS3_SM_SERVICE_ID_COMMAND: 557 dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 558 return ps3_sys_manager_handle_cmd(dev); 559 case PS3_SM_SERVICE_ID_REQUEST_ERROR: 560 dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, 561 __LINE__); 562 dump_sm_header(&header); 563 break; 564 default: 565 dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 566 __func__, __LINE__, header.service_id); 567 break; 568 } 569 goto fail_id; 570 571fail_header: 572 ps3_vuart_clear_rx_bytes(dev, 0); 573 return -EIO; 574fail_id: 575 ps3_vuart_clear_rx_bytes(dev, header.payload_size); 576 return -EIO; 577} 578 579static void ps3_sys_manager_fin(struct ps3_system_bus_device *dev) 580{ 581 ps3_sys_manager_send_request_shutdown(dev); 582 583 pr_emerg("System Halted, OK to turn off power\n"); 584 585 while (ps3_sys_manager_handle_msg(dev)) { 586 /* pause until next DEC interrupt */ 587 lv1_pause(0); 588 } 589 590 while (1) { 591 /* pause, ignoring DEC interrupt */ 592 lv1_pause(1); 593 } 594} 595 596/** 597 * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. 598 * 599 * This routine never returns. The routine disables asynchronous vuart reads 600 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 601 * the shutdown command sent from the system manager. Soon after the 602 * acknowledgement is sent the lpar is destroyed by the HV. This routine 603 * should only be called from ps3_power_off() through 604 * ps3_sys_manager_ops.power_off. 605 */ 606 607static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) 608{ 609 BUG_ON(!dev); 610 611 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 612 613 ps3_vuart_cancel_async(dev); 614 615 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 616 user_wake_sources); 617 618 ps3_sys_manager_fin(dev); 619} 620 621/** 622 * ps3_sys_manager_final_restart - The final platform machine_restart routine. 623 * 624 * This routine never returns. The routine disables asynchronous vuart reads 625 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 626 * the shutdown command sent from the system manager. Soon after the 627 * acknowledgement is sent the lpar is destroyed by the HV. This routine 628 * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. 629 */ 630 631static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) 632{ 633 BUG_ON(!dev); 634 635 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 636 637 /* Check if we got here via a power button event. */ 638 639 if (ps3_sm_force_power_off) { 640 dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", 641 __func__, __LINE__); 642 ps3_sys_manager_final_power_off(dev); 643 } 644 645 ps3_vuart_cancel_async(dev); 646 647 ps3_sys_manager_send_attr(dev, 0); 648 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT, 649 user_wake_sources); 650 651 ps3_sys_manager_fin(dev); 652} 653 654/** 655 * ps3_sys_manager_get_wol - Get wake-on-lan setting. 656 */ 657 658int ps3_sys_manager_get_wol(void) 659{ 660 pr_debug("%s:%d\n", __func__, __LINE__); 661 662 return (user_wake_sources & PS3_SM_WAKE_W_O_L) != 0; 663} 664EXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol); 665 666/** 667 * ps3_sys_manager_set_wol - Set wake-on-lan setting. 668 */ 669 670void ps3_sys_manager_set_wol(int state) 671{ 672 static DEFINE_MUTEX(mutex); 673 674 mutex_lock(&mutex); 675 676 pr_debug("%s:%d: %d\n", __func__, __LINE__, state); 677 678 if (state) 679 user_wake_sources |= PS3_SM_WAKE_W_O_L; 680 else 681 user_wake_sources &= ~PS3_SM_WAKE_W_O_L; 682 mutex_unlock(&mutex); 683} 684EXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol); 685 686/** 687 * ps3_sys_manager_work - Asynchronous read handler. 688 * 689 * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. 690 */ 691 692static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) 693{ 694 ps3_sys_manager_handle_msg(dev); 695 ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 696} 697 698static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) 699{ 700 int result; 701 struct ps3_sys_manager_ops ops; 702 703 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 704 705 ops.power_off = ps3_sys_manager_final_power_off; 706 ops.restart = ps3_sys_manager_final_restart; 707 ops.dev = dev; 708 709 /* ps3_sys_manager_register_ops copies ops. */ 710 711 ps3_sys_manager_register_ops(&ops); 712 713 result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 714 BUG_ON(result); 715 716 result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); 717 BUG_ON(result); 718 719 return result; 720} 721 722static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) 723{ 724 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 725 return 0; 726} 727 728static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) 729{ 730 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 731} 732 733static struct ps3_vuart_port_driver ps3_sys_manager = { 734 .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 735 .core.core.name = "ps3_sys_manager", 736 .probe = ps3_sys_manager_probe, 737 .remove = ps3_sys_manager_remove, 738 .shutdown = ps3_sys_manager_shutdown, 739 .work = ps3_sys_manager_work, 740}; 741 742static int __init ps3_sys_manager_init(void) 743{ 744 if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 745 return -ENODEV; 746 747 return ps3_vuart_port_driver_register(&ps3_sys_manager); 748} 749 750module_init(ps3_sys_manager_init); 751/* Module remove not supported. */ 752 753MODULE_AUTHOR("Sony Corporation"); 754MODULE_LICENSE("GPL v2"); 755MODULE_DESCRIPTION("PS3 System Manager"); 756MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);