This source file includes following definitions.
- _dump_sm_header
- ps3_sys_manager_write
- ps3_sys_manager_send_attr
- ps3_sys_manager_send_next_op
- ps3_sys_manager_send_request_shutdown
- ps3_sys_manager_send_response
- ps3_sys_manager_handle_event
- ps3_sys_manager_handle_cmd
- ps3_sys_manager_handle_msg
- ps3_sys_manager_fin
- ps3_sys_manager_final_power_off
- ps3_sys_manager_final_restart
- ps3_sys_manager_get_wol
- ps3_sys_manager_set_wol
- ps3_sys_manager_work
- ps3_sys_manager_probe
- ps3_sys_manager_remove
- ps3_sys_manager_shutdown
- ps3_sys_manager_init
1
2
3
4
5
6
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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 struct ps3_sys_manager_header {
45
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__)
56 static 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
68
69
70
71
72
73
74
75
76 enum {
77 PS3_SM_RX_MSG_LEN_MIN = 24,
78 PS3_SM_RX_MSG_LEN_MAX = 32,
79 };
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 enum ps3_sys_manager_service_id {
97
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
109
110
111
112
113
114
115
116
117
118
119
120 enum ps3_sys_manager_attr {
121
122 PS3_SM_ATTR_POWER = 1,
123 PS3_SM_ATTR_RESET = 2,
124 PS3_SM_ATTR_THERMAL = 4,
125 PS3_SM_ATTR_CONTROLLER = 8,
126 PS3_SM_ATTR_ALL = 0x0f,
127 };
128
129
130
131
132
133
134
135
136
137
138
139
140
141 enum ps3_sys_manager_event {
142
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
150 };
151
152
153
154
155
156
157
158 enum ps3_sys_manager_button_event {
159 PS3_SM_BUTTON_EVENT_HARD = 0,
160 PS3_SM_BUTTON_EVENT_SOFT = 1,
161 };
162
163
164
165
166
167 enum ps3_sys_manager_next_op {
168
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
176
177
178
179
180
181
182
183
184
185
186 enum ps3_sys_manager_wake_source {
187
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
195
196
197
198
199 static u32 user_wake_sources = PS3_SM_WAKE_DEFAULT;
200
201
202
203
204
205
206
207
208
209
210 enum ps3_sys_manager_cmd {
211
212 PS3_SM_CMD_SHUTDOWN = 1,
213 };
214
215
216
217
218
219
220
221
222
223 static unsigned int ps3_sm_force_power_off;
224
225
226
227
228
229
230 static 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
251
252
253
254 static 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
283
284
285
286
287 static 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;
315 payload.wake_source = wake_source;
316
317 return ps3_sys_manager_write(dev, &header, &payload);
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332 static 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;
356 payload.gos_id = 0;
357
358 return ps3_sys_manager_write(dev, &header, &payload);
359 }
360
361
362
363
364
365
366
367
368
369 static 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
400
401
402
403 static 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
434
435
436
437 wmb();
438 kill_cad_pid(SIGINT, 1);
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
452
453
454
455 wmb();
456 kill_cad_pid(SIGINT, 1);
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
481
482
483
484
485 static 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
522
523
524
525
526 static 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
571 fail_header:
572 ps3_vuart_clear_rx_bytes(dev, 0);
573 return -EIO;
574 fail_id:
575 ps3_vuart_clear_rx_bytes(dev, header.payload_size);
576 return -EIO;
577 }
578
579 static 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
587 lv1_pause(0);
588 }
589
590 while (1) {
591
592 lv1_pause(1);
593 }
594 }
595
596
597
598
599
600
601
602
603
604
605
606
607 static 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
623
624
625
626
627
628
629
630
631 static 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
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
656
657
658 int 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 }
664 EXPORT_SYMBOL_GPL(ps3_sys_manager_get_wol);
665
666
667
668
669
670 void 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 }
684 EXPORT_SYMBOL_GPL(ps3_sys_manager_set_wol);
685
686
687
688
689
690
691
692 static 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
698 static 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
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
722 static 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
728 static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev)
729 {
730 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
731 }
732
733 static 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
742 static 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
750 module_init(ps3_sys_manager_init);
751
752
753 MODULE_AUTHOR("Sony Corporation");
754 MODULE_LICENSE("GPL v2");
755 MODULE_DESCRIPTION("PS3 System Manager");
756 MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);