0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/workqueue.h>
0012 #include <linux/reboot.h>
0013 #include <linux/sched/signal.h>
0014
0015 #include <asm/firmware.h>
0016 #include <asm/lv1call.h>
0017 #include <asm/ps3.h>
0018
0019 #include "vuart.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 struct ps3_sys_manager_header {
0045
0046 u8 version;
0047 u8 size;
0048 u16 reserved_1;
0049 u32 payload_size;
0050 u16 service_id;
0051 u16 reserved_2;
0052 u32 request_tag;
0053 };
0054
0055 #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__)
0056 static void __maybe_unused _dump_sm_header(
0057 const struct ps3_sys_manager_header *h, const char *func, int line)
0058 {
0059 pr_debug("%s:%d: version: %xh\n", func, line, h->version);
0060 pr_debug("%s:%d: size: %xh\n", func, line, h->size);
0061 pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size);
0062 pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id);
0063 pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag);
0064 }
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 enum {
0077 PS3_SM_RX_MSG_LEN_MIN = 24,
0078 PS3_SM_RX_MSG_LEN_MAX = 32,
0079 };
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 enum ps3_sys_manager_service_id {
0097
0098 PS3_SM_SERVICE_ID_REQUEST = 1,
0099 PS3_SM_SERVICE_ID_RESPONSE = 2,
0100 PS3_SM_SERVICE_ID_COMMAND = 3,
0101 PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
0102 PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
0103 PS3_SM_SERVICE_ID_REQUEST_ERROR = 6,
0104 PS3_SM_SERVICE_ID_SET_ATTR = 8,
0105 };
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120 enum ps3_sys_manager_attr {
0121
0122 PS3_SM_ATTR_POWER = 1,
0123 PS3_SM_ATTR_RESET = 2,
0124 PS3_SM_ATTR_THERMAL = 4,
0125 PS3_SM_ATTR_CONTROLLER = 8,
0126 PS3_SM_ATTR_ALL = 0x0f,
0127 };
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 enum ps3_sys_manager_event {
0142
0143 PS3_SM_EVENT_POWER_PRESSED = 3,
0144 PS3_SM_EVENT_POWER_RELEASED = 4,
0145 PS3_SM_EVENT_RESET_PRESSED = 5,
0146 PS3_SM_EVENT_RESET_RELEASED = 6,
0147 PS3_SM_EVENT_THERMAL_ALERT = 7,
0148 PS3_SM_EVENT_THERMAL_CLEARED = 8,
0149
0150 };
0151
0152
0153
0154
0155
0156
0157
0158 enum ps3_sys_manager_button_event {
0159 PS3_SM_BUTTON_EVENT_HARD = 0,
0160 PS3_SM_BUTTON_EVENT_SOFT = 1,
0161 };
0162
0163
0164
0165
0166
0167 enum ps3_sys_manager_next_op {
0168
0169 PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1,
0170 PS3_SM_NEXT_OP_SYS_REBOOT = 2,
0171 PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82,
0172 };
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 enum ps3_sys_manager_wake_source {
0187
0188 PS3_SM_WAKE_DEFAULT = 0,
0189 PS3_SM_WAKE_W_O_L = 0x00000400,
0190 PS3_SM_WAKE_P_O_R = 0x80000000,
0191 };
0192
0193
0194
0195
0196
0197
0198
0199 static u32 user_wake_sources = PS3_SM_WAKE_DEFAULT;
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 enum ps3_sys_manager_cmd {
0211
0212 PS3_SM_CMD_SHUTDOWN = 1,
0213 };
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 static unsigned int ps3_sm_force_power_off;
0224
0225
0226
0227
0228
0229
0230 static int ps3_sys_manager_write(struct ps3_system_bus_device *dev,
0231 const struct ps3_sys_manager_header *header, const void *payload)
0232 {
0233 int result;
0234
0235 BUG_ON(header->version != 1);
0236 BUG_ON(header->size != 16);
0237 BUG_ON(header->payload_size != 8 && header->payload_size != 16);
0238 BUG_ON(header->service_id > 8);
0239
0240 result = ps3_vuart_write(dev, header,
0241 sizeof(struct ps3_sys_manager_header));
0242
0243 if (!result)
0244 result = ps3_vuart_write(dev, payload, header->payload_size);
0245
0246 return result;
0247 }
0248
0249
0250
0251
0252
0253
0254 static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev,
0255 enum ps3_sys_manager_attr attr)
0256 {
0257 struct ps3_sys_manager_header header;
0258 struct {
0259 u8 version;
0260 u8 reserved_1[3];
0261 u32 attribute;
0262 } payload;
0263
0264 BUILD_BUG_ON(sizeof(payload) != 8);
0265
0266 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
0267
0268 memset(&header, 0, sizeof(header));
0269 header.version = 1;
0270 header.size = 16;
0271 header.payload_size = 16;
0272 header.service_id = PS3_SM_SERVICE_ID_SET_ATTR;
0273
0274 memset(&payload, 0, sizeof(payload));
0275 payload.version = 1;
0276 payload.attribute = attr;
0277
0278 return ps3_sys_manager_write(dev, &header, &payload);
0279 }
0280
0281
0282
0283
0284
0285
0286
0287 static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev,
0288 enum ps3_sys_manager_next_op op,
0289 enum ps3_sys_manager_wake_source wake_source)
0290 {
0291 struct ps3_sys_manager_header header;
0292 struct {
0293 u8 version;
0294 u8 type;
0295 u8 gos_id;
0296 u8 reserved_1;
0297 u32 wake_source;
0298 u8 reserved_2[8];
0299 } payload;
0300
0301 BUILD_BUG_ON(sizeof(payload) != 16);
0302
0303 dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
0304
0305 memset(&header, 0, sizeof(header));
0306 header.version = 1;
0307 header.size = 16;
0308 header.payload_size = 16;
0309 header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP;
0310
0311 memset(&payload, 0, sizeof(payload));
0312 payload.version = 3;
0313 payload.type = op;
0314 payload.gos_id = 3;
0315 payload.wake_source = wake_source;
0316
0317 return ps3_sys_manager_write(dev, &header, &payload);
0318 }
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332 static int ps3_sys_manager_send_request_shutdown(
0333 struct ps3_system_bus_device *dev)
0334 {
0335 struct ps3_sys_manager_header header;
0336 struct {
0337 u8 version;
0338 u8 type;
0339 u8 gos_id;
0340 u8 reserved_1[13];
0341 } payload;
0342
0343 BUILD_BUG_ON(sizeof(payload) != 16);
0344
0345 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0346
0347 memset(&header, 0, sizeof(header));
0348 header.version = 1;
0349 header.size = 16;
0350 header.payload_size = 16;
0351 header.service_id = PS3_SM_SERVICE_ID_REQUEST;
0352
0353 memset(&payload, 0, sizeof(payload));
0354 payload.version = 1;
0355 payload.type = 1;
0356 payload.gos_id = 0;
0357
0358 return ps3_sys_manager_write(dev, &header, &payload);
0359 }
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev,
0370 u64 status)
0371 {
0372 struct ps3_sys_manager_header header;
0373 struct {
0374 u8 version;
0375 u8 reserved_1[3];
0376 u8 status;
0377 u8 reserved_2[11];
0378 } payload;
0379
0380 BUILD_BUG_ON(sizeof(payload) != 16);
0381
0382 dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
0383 (status ? "nak" : "ack"));
0384
0385 memset(&header, 0, sizeof(header));
0386 header.version = 1;
0387 header.size = 16;
0388 header.payload_size = 16;
0389 header.service_id = PS3_SM_SERVICE_ID_RESPONSE;
0390
0391 memset(&payload, 0, sizeof(payload));
0392 payload.version = 1;
0393 payload.status = status;
0394
0395 return ps3_sys_manager_write(dev, &header, &payload);
0396 }
0397
0398
0399
0400
0401
0402
0403 static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
0404 {
0405 int result;
0406 struct {
0407 u8 version;
0408 u8 type;
0409 u8 reserved_1[2];
0410 u32 value;
0411 u8 reserved_2[8];
0412 } event;
0413
0414 BUILD_BUG_ON(sizeof(event) != 16);
0415
0416 result = ps3_vuart_read(dev, &event, sizeof(event));
0417 BUG_ON(result && "need to retry here");
0418
0419 if (event.version != 1) {
0420 dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
0421 __func__, __LINE__, event.version);
0422 return -EIO;
0423 }
0424
0425 switch (event.type) {
0426 case PS3_SM_EVENT_POWER_PRESSED:
0427 dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n",
0428 __func__, __LINE__,
0429 (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft"
0430 : "hard"));
0431 ps3_sm_force_power_off = 1;
0432
0433
0434
0435
0436
0437 wmb();
0438 kill_cad_pid(SIGINT, 1);
0439 break;
0440 case PS3_SM_EVENT_POWER_RELEASED:
0441 dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
0442 __func__, __LINE__, event.value);
0443 break;
0444 case PS3_SM_EVENT_RESET_PRESSED:
0445 dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n",
0446 __func__, __LINE__,
0447 (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft"
0448 : "hard"));
0449 ps3_sm_force_power_off = 0;
0450
0451
0452
0453
0454
0455 wmb();
0456 kill_cad_pid(SIGINT, 1);
0457 break;
0458 case PS3_SM_EVENT_RESET_RELEASED:
0459 dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n",
0460 __func__, __LINE__, event.value);
0461 break;
0462 case PS3_SM_EVENT_THERMAL_ALERT:
0463 dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
0464 __func__, __LINE__, event.value);
0465 pr_info("PS3 Thermal Alert Zone %u\n", event.value);
0466 break;
0467 case PS3_SM_EVENT_THERMAL_CLEARED:
0468 dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
0469 __func__, __LINE__, event.value);
0470 break;
0471 default:
0472 dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n",
0473 __func__, __LINE__, event.type);
0474 return -EIO;
0475 }
0476
0477 return 0;
0478 }
0479
0480
0481
0482
0483
0484
0485 static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
0486 {
0487 int result;
0488 struct {
0489 u8 version;
0490 u8 type;
0491 u8 reserved_1[14];
0492 } cmd;
0493
0494 BUILD_BUG_ON(sizeof(cmd) != 16);
0495
0496 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0497
0498 result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
0499 BUG_ON(result && "need to retry here");
0500
0501 if (result)
0502 return result;
0503
0504 if (cmd.version != 1) {
0505 dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n",
0506 __func__, __LINE__, cmd.version);
0507 return -EIO;
0508 }
0509
0510 if (cmd.type != PS3_SM_CMD_SHUTDOWN) {
0511 dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n",
0512 __func__, __LINE__, cmd.type);
0513 return -EIO;
0514 }
0515
0516 ps3_sys_manager_send_response(dev, 0);
0517 return 0;
0518 }
0519
0520
0521
0522
0523
0524
0525
0526 static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
0527 {
0528 int result;
0529 struct ps3_sys_manager_header header;
0530
0531 result = ps3_vuart_read(dev, &header,
0532 sizeof(struct ps3_sys_manager_header));
0533
0534 if (result)
0535 return result;
0536
0537 if (header.version != 1) {
0538 dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
0539 __func__, __LINE__, header.version);
0540 dump_sm_header(&header);
0541 goto fail_header;
0542 }
0543
0544 BUILD_BUG_ON(sizeof(header) != 16);
0545
0546 if (header.size != 16 || (header.payload_size != 8
0547 && header.payload_size != 16)) {
0548 dump_sm_header(&header);
0549 BUG();
0550 }
0551
0552 switch (header.service_id) {
0553 case PS3_SM_SERVICE_ID_EXTERN_EVENT:
0554 dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__);
0555 return ps3_sys_manager_handle_event(dev);
0556 case PS3_SM_SERVICE_ID_COMMAND:
0557 dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
0558 return ps3_sys_manager_handle_cmd(dev);
0559 case PS3_SM_SERVICE_ID_REQUEST_ERROR:
0560 dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__,
0561 __LINE__);
0562 dump_sm_header(&header);
0563 break;
0564 default:
0565 dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
0566 __func__, __LINE__, header.service_id);
0567 break;
0568 }
0569 goto fail_id;
0570
0571 fail_header:
0572 ps3_vuart_clear_rx_bytes(dev, 0);
0573 return -EIO;
0574 fail_id:
0575 ps3_vuart_clear_rx_bytes(dev, header.payload_size);
0576 return -EIO;
0577 }
0578
0579 static void ps3_sys_manager_fin(struct ps3_system_bus_device *dev)
0580 {
0581 ps3_sys_manager_send_request_shutdown(dev);
0582
0583 pr_emerg("System Halted, OK to turn off power\n");
0584
0585 while (ps3_sys_manager_handle_msg(dev)) {
0586
0587 lv1_pause(0);
0588 }
0589
0590 while (1) {
0591
0592 lv1_pause(1);
0593 }
0594 }
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607 static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
0608 {
0609 BUG_ON(!dev);
0610
0611 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0612
0613 ps3_vuart_cancel_async(dev);
0614
0615 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
0616 user_wake_sources);
0617
0618 ps3_sys_manager_fin(dev);
0619 }
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631 static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
0632 {
0633 BUG_ON(!dev);
0634
0635 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0636
0637
0638
0639 if (ps3_sm_force_power_off) {
0640 dev_dbg(&dev->core, "%s:%d: forcing poweroff\n",
0641 __func__, __LINE__);
0642 ps3_sys_manager_final_power_off(dev);
0643 }
0644
0645 ps3_vuart_cancel_async(dev);
0646
0647 ps3_sys_manager_send_attr(dev, 0);
0648 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT,
0649 user_wake_sources);
0650
0651 ps3_sys_manager_fin(dev);
0652 }
0653
0654
0655
0656
0657
0658 int ps3_sys_manager_get_wol(void)
0659 {
0660 pr_debug("%s:%d\n", __func__, __LINE__);
0661
0662 return (user_wake_sources & PS3_SM_WAKE_W_O_L) != 0;
0663 }
0664 EXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol);
0665
0666
0667
0668
0669
0670 void ps3_sys_manager_set_wol(int state)
0671 {
0672 static DEFINE_MUTEX(mutex);
0673
0674 mutex_lock(&mutex);
0675
0676 pr_debug("%s:%d: %d\n", __func__, __LINE__, state);
0677
0678 if (state)
0679 user_wake_sources |= PS3_SM_WAKE_W_O_L;
0680 else
0681 user_wake_sources &= ~PS3_SM_WAKE_W_O_L;
0682 mutex_unlock(&mutex);
0683 }
0684 EXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol);
0685
0686
0687
0688
0689
0690
0691
0692 static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
0693 {
0694 ps3_sys_manager_handle_msg(dev);
0695 ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
0696 }
0697
0698 static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
0699 {
0700 int result;
0701 struct ps3_sys_manager_ops ops;
0702
0703 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0704
0705 ops.power_off = ps3_sys_manager_final_power_off;
0706 ops.restart = ps3_sys_manager_final_restart;
0707 ops.dev = dev;
0708
0709
0710
0711 ps3_sys_manager_register_ops(&ops);
0712
0713 result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
0714 BUG_ON(result);
0715
0716 result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
0717 BUG_ON(result);
0718
0719 return result;
0720 }
0721
0722 static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev)
0723 {
0724 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0725 return 0;
0726 }
0727
0728 static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev)
0729 {
0730 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
0731 }
0732
0733 static struct ps3_vuart_port_driver ps3_sys_manager = {
0734 .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
0735 .core.core.name = "ps3_sys_manager",
0736 .probe = ps3_sys_manager_probe,
0737 .remove = ps3_sys_manager_remove,
0738 .shutdown = ps3_sys_manager_shutdown,
0739 .work = ps3_sys_manager_work,
0740 };
0741
0742 static int __init ps3_sys_manager_init(void)
0743 {
0744 if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
0745 return -ENODEV;
0746
0747 return ps3_vuart_port_driver_register(&ps3_sys_manager);
0748 }
0749
0750 module_init(ps3_sys_manager_init);
0751
0752
0753 MODULE_AUTHOR("Sony Corporation");
0754 MODULE_LICENSE("GPL v2");
0755 MODULE_DESCRIPTION("PS3 System Manager");
0756 MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);