aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGeoff Levand <geoffrey.levand@am.sony.com>2007-06-15 18:03:54 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-28 05:16:41 -0400
commit66c63b84b23d39ce191a18833b5a769370114ec9 (patch)
tree8903417c0f89aba779e8f81bb51b9e9c6a68fd07 /drivers
parent7626e78d29651d3075e88f233c0632867ea6a35c (diff)
[POWERPC] PS3: System manager re-work
PS3 sys-manager updates to reflect the new PS3 unifed device support. Fixups to the PS3 sys-manager driver to properly support sys_reboot(). - Add varable request_tag to struct ps3_sys_manager_header. - Move ctrl_alt_del from PS3_SM_EVENT_POWER_RELEASED to PS3_SM_EVENT_POWER_PRESSED. - Make the PS3 sys-manager driver a loadable module. - Add new file sys-manager-core.c. - Add new struct ps3_sys_manager_ops for dynamic binding. - Put data sent to device on stack. - Add support for PS3_SM_SERVICE_ID_REQUEST_ERROR. Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/sys-manager-core.c68
-rw-r--r--drivers/ps3/sys-manager.c290
3 files changed, 260 insertions, 99 deletions
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index e251d1c1171c..a6d8db79b20c 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_PS3_VUART) += vuart.o 1obj-$(CONFIG_PS3_VUART) += vuart.o
2obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o 2obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o
3obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
3obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o 4obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o
diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c
new file mode 100644
index 000000000000..31648f7d9ae1
--- /dev/null
+++ b/drivers/ps3/sys-manager-core.c
@@ -0,0 +1,68 @@
1/*
2 * PS3 System Manager core.
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 <asm/ps3.h>
23
24/**
25 * Staticly linked routines that allow late binding of a loaded sys-manager
26 * module.
27 */
28
29static struct ps3_sys_manager_ops ps3_sys_manager_ops;
30
31/**
32 * ps3_register_sys_manager_ops - Bind ps3_sys_manager_ops to a module.
33 * @ops: struct ps3_sys_manager_ops.
34 *
35 * To be called from ps3_sys_manager_probe() and ps3_sys_manager_remove() to
36 * register call back ops for power control. Copies data to the static
37 * variable ps3_sys_manager_ops.
38 */
39
40void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops)
41{
42 BUG_ON(!ops);
43 BUG_ON(!ops->dev);
44 ps3_sys_manager_ops = ops ? *ops : ps3_sys_manager_ops;
45}
46EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops);
47
48void ps3_sys_manager_power_off(void)
49{
50 if (ps3_sys_manager_ops.power_off)
51 ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev);
52
53 printk(KERN_EMERG "System Halted, OK to turn off power\n");
54 local_irq_disable();
55 while (1)
56 (void)0;
57}
58
59void ps3_sys_manager_restart(void)
60{
61 if (ps3_sys_manager_ops.restart)
62 ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev);
63
64 printk(KERN_EMERG "System Halted, OK to turn off power\n");
65 local_irq_disable();
66 while (1)
67 (void)0;
68}
diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c
index 3aa2b0dcc369..8461b08ab9fb 100644
--- a/drivers/ps3/sys-manager.c
+++ b/drivers/ps3/sys-manager.c
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("PS3 System Manager");
35/** 35/**
36 * ps3_sys_manager - PS3 system manager driver. 36 * ps3_sys_manager - PS3 system manager driver.
37 * 37 *
38 * The system manager provides an asyncronous system event notification 38 * The system manager provides an asynchronous system event notification
39 * mechanism for reporting events like thermal alert and button presses to 39 * mechanism for reporting events like thermal alert and button presses to
40 * guests. It also provides support to control system shutdown and startup. 40 * guests. It also provides support to control system shutdown and startup.
41 * 41 *
@@ -52,6 +52,7 @@ MODULE_DESCRIPTION("PS3 System Manager");
52 * @size: Header size in bytes, curently 16. 52 * @size: Header size in bytes, curently 16.
53 * @payload_size: Message payload size in bytes. 53 * @payload_size: Message payload size in bytes.
54 * @service_id: Message type, one of enum ps3_sys_manager_service_id. 54 * @service_id: Message type, one of enum ps3_sys_manager_service_id.
55 * @request_tag: Unique number to identify reply.
55 */ 56 */
56 57
57struct ps3_sys_manager_header { 58struct ps3_sys_manager_header {
@@ -61,29 +62,49 @@ struct ps3_sys_manager_header {
61 u16 reserved_1; 62 u16 reserved_1;
62 u32 payload_size; 63 u32 payload_size;
63 u16 service_id; 64 u16 service_id;
64 u16 reserved_2[3]; 65 u16 reserved_2;
66 u32 request_tag;
65}; 67};
66 68
69#define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__)
70static void __maybe_unused _dump_sm_header(
71 const struct ps3_sys_manager_header *h, const char *func, int line)
72{
73 pr_debug("%s:%d: version: %xh\n", func, line, h->version);
74 pr_debug("%s:%d: size: %xh\n", func, line, h->size);
75 pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size);
76 pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id);
77 pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag);
78}
79
67/** 80/**
68 * @PS3_SM_RX_MSG_LEN - System manager received message length. 81 * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length.
82 * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length.
69 * 83 *
70 * Currently all messages received from the system manager are the same length 84 * Currently all messages received from the system manager are either
71 * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to 85 * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header
72 * simplify the logic. 86 * + 16 bytes payload = 32 bytes). This knowlege is used to simplify
87 * the logic.
73 */ 88 */
74 89
75enum { 90enum {
76 PS3_SM_RX_MSG_LEN = 32, 91 PS3_SM_RX_MSG_LEN_MIN = 24,
92 PS3_SM_RX_MSG_LEN_MAX = 32,
77}; 93};
78 94
79/** 95/**
80 * enum ps3_sys_manager_service_id - Message header service_id. 96 * enum ps3_sys_manager_service_id - Message header service_id.
81 * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. 97 * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
82 * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. 98 * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager.
83 * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. 99 * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
84 * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. 100 * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
85 * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. 101 * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
86 * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. 102 * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
103 * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
104 *
105 * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a
106 * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when
107 * a REQUEST message is sent at the wrong time.
87 */ 108 */
88 109
89enum ps3_sys_manager_service_id { 110enum ps3_sys_manager_service_id {
@@ -93,6 +114,7 @@ enum ps3_sys_manager_service_id {
93 PS3_SM_SERVICE_ID_COMMAND = 3, 114 PS3_SM_SERVICE_ID_COMMAND = 3,
94 PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, 115 PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
95 PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, 116 PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
117 PS3_SM_SERVICE_ID_REQUEST_ERROR = 6,
96 PS3_SM_SERVICE_ID_SET_ATTR = 8, 118 PS3_SM_SERVICE_ID_SET_ATTR = 8,
97}; 119};
98 120
@@ -185,11 +207,21 @@ enum ps3_sys_manager_cmd {
185}; 207};
186 208
187/** 209/**
210 * ps3_sm_force_power_off - Poweroff helper.
211 *
212 * A global variable used to force a poweroff when the power button has
213 * been pressed irrespective of how init handles the ctrl_alt_del signal.
214 *
215 */
216
217static unsigned int ps3_sm_force_power_off;
218
219/**
188 * ps3_sys_manager_write - Helper to write a two part message to the vuart. 220 * ps3_sys_manager_write - Helper to write a two part message to the vuart.
189 * 221 *
190 */ 222 */
191 223
192static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev, 224static int ps3_sys_manager_write(struct ps3_system_bus_device *dev,
193 const struct ps3_sys_manager_header *header, const void *payload) 225 const struct ps3_sys_manager_header *header, const void *payload)
194{ 226{
195 int result; 227 int result;
@@ -213,15 +245,10 @@ static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev,
213 * 245 *
214 */ 246 */
215 247
216static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, 248static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev,
217 enum ps3_sys_manager_attr attr) 249 enum ps3_sys_manager_attr attr)
218{ 250{
219 static const struct ps3_sys_manager_header header = { 251 struct ps3_sys_manager_header header;
220 .version = 1,
221 .size = 16,
222 .payload_size = 16,
223 .service_id = PS3_SM_SERVICE_ID_SET_ATTR,
224 };
225 struct { 252 struct {
226 u8 version; 253 u8 version;
227 u8 reserved_1[3]; 254 u8 reserved_1[3];
@@ -232,6 +259,12 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
232 259
233 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); 260 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
234 261
262 memset(&header, 0, sizeof(header));
263 header.version = 1;
264 header.size = 16;
265 header.payload_size = 16;
266 header.service_id = PS3_SM_SERVICE_ID_SET_ATTR;
267
235 memset(&payload, 0, sizeof(payload)); 268 memset(&payload, 0, sizeof(payload));
236 payload.version = 1; 269 payload.version = 1;
237 payload.attribute = attr; 270 payload.attribute = attr;
@@ -245,16 +278,11 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
245 * Tell the system manager what to do after this lpar is destroyed. 278 * Tell the system manager what to do after this lpar is destroyed.
246 */ 279 */
247 280
248static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, 281static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev,
249 enum ps3_sys_manager_next_op op, 282 enum ps3_sys_manager_next_op op,
250 enum ps3_sys_manager_wake_source wake_source) 283 enum ps3_sys_manager_wake_source wake_source)
251{ 284{
252 static const struct ps3_sys_manager_header header = { 285 struct ps3_sys_manager_header header;
253 .version = 1,
254 .size = 16,
255 .payload_size = 16,
256 .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP,
257 };
258 struct { 286 struct {
259 u8 version; 287 u8 version;
260 u8 type; 288 u8 type;
@@ -268,6 +296,12 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
268 296
269 dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); 297 dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
270 298
299 memset(&header, 0, sizeof(header));
300 header.version = 1;
301 header.size = 16;
302 header.payload_size = 16;
303 header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP;
304
271 memset(&payload, 0, sizeof(payload)); 305 memset(&payload, 0, sizeof(payload));
272 payload.version = 3; 306 payload.version = 3;
273 payload.type = op; 307 payload.type = op;
@@ -286,32 +320,35 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
286 * the command is then communicated back to the system manager with a response 320 * the command is then communicated back to the system manager with a response
287 * message. 321 * message.
288 * 322 *
289 * Currently, the only supported request it the 'shutdown self' request. 323 * Currently, the only supported request is the 'shutdown self' request.
290 */ 324 */
291 325
292static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev) 326static int ps3_sys_manager_send_request_shutdown(
327 struct ps3_system_bus_device *dev)
293{ 328{
294 static const struct ps3_sys_manager_header header = { 329 struct ps3_sys_manager_header header;
295 .version = 1,
296 .size = 16,
297 .payload_size = 16,
298 .service_id = PS3_SM_SERVICE_ID_REQUEST,
299 };
300 struct { 330 struct {
301 u8 version; 331 u8 version;
302 u8 type; 332 u8 type;
303 u8 gos_id; 333 u8 gos_id;
304 u8 reserved_1[13]; 334 u8 reserved_1[13];
305 } static const payload = { 335 } payload;
306 .version = 1,
307 .type = 1, /* shutdown */
308 .gos_id = 0, /* self */
309 };
310 336
311 BUILD_BUG_ON(sizeof(payload) != 16); 337 BUILD_BUG_ON(sizeof(payload) != 16);
312 338
313 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 339 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
314 340
341 memset(&header, 0, sizeof(header));
342 header.version = 1;
343 header.size = 16;
344 header.payload_size = 16;
345 header.service_id = PS3_SM_SERVICE_ID_REQUEST;
346
347 memset(&payload, 0, sizeof(payload));
348 payload.version = 1;
349 payload.type = 1; /* shutdown */
350 payload.gos_id = 0; /* self */
351
315 return ps3_sys_manager_write(dev, &header, &payload); 352 return ps3_sys_manager_write(dev, &header, &payload);
316} 353}
317 354
@@ -323,15 +360,10 @@ static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *d
323 * failure of a command sent by the system manager. 360 * failure of a command sent by the system manager.
324 */ 361 */
325 362
326static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, 363static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev,
327 u64 status) 364 u64 status)
328{ 365{
329 static const struct ps3_sys_manager_header header = { 366 struct ps3_sys_manager_header header;
330 .version = 1,
331 .size = 16,
332 .payload_size = 16,
333 .service_id = PS3_SM_SERVICE_ID_RESPONSE,
334 };
335 struct { 367 struct {
336 u8 version; 368 u8 version;
337 u8 reserved_1[3]; 369 u8 reserved_1[3];
@@ -344,6 +376,12 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
344 dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 376 dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
345 (status ? "nak" : "ack")); 377 (status ? "nak" : "ack"));
346 378
379 memset(&header, 0, sizeof(header));
380 header.version = 1;
381 header.size = 16;
382 header.payload_size = 16;
383 header.service_id = PS3_SM_SERVICE_ID_RESPONSE;
384
347 memset(&payload, 0, sizeof(payload)); 385 memset(&payload, 0, sizeof(payload));
348 payload.version = 1; 386 payload.version = 1;
349 payload.status = status; 387 payload.status = status;
@@ -356,7 +394,7 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
356 * 394 *
357 */ 395 */
358 396
359static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) 397static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
360{ 398{
361 int result; 399 int result;
362 struct { 400 struct {
@@ -370,7 +408,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
370 BUILD_BUG_ON(sizeof(event) != 16); 408 BUILD_BUG_ON(sizeof(event) != 16);
371 409
372 result = ps3_vuart_read(dev, &event, sizeof(event)); 410 result = ps3_vuart_read(dev, &event, sizeof(event));
373 BUG_ON(result); 411 BUG_ON(result && "need to retry here");
374 412
375 if (event.version != 1) { 413 if (event.version != 1) {
376 dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", 414 dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
@@ -382,11 +420,34 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
382 case PS3_SM_EVENT_POWER_PRESSED: 420 case PS3_SM_EVENT_POWER_PRESSED:
383 dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", 421 dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n",
384 __func__, __LINE__); 422 __func__, __LINE__);
423 ps3_sm_force_power_off = 1;
424 /*
425 * A memory barrier is use here to sync memory since
426 * ps3_sys_manager_final_restart() could be called on
427 * another cpu.
428 */
429 wmb();
430 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
385 break; 431 break;
386 case PS3_SM_EVENT_POWER_RELEASED: 432 case PS3_SM_EVENT_POWER_RELEASED:
387 dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", 433 dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
388 __func__, __LINE__, event.value); 434 __func__, __LINE__, event.value);
389 kill_cad_pid(SIGINT, 1); 435 break;
436 case PS3_SM_EVENT_RESET_PRESSED:
437 dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n",
438 __func__, __LINE__);
439 ps3_sm_force_power_off = 0;
440 /*
441 * A memory barrier is use here to sync memory since
442 * ps3_sys_manager_final_restart() could be called on
443 * another cpu.
444 */
445 wmb();
446 kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
447 break;
448 case PS3_SM_EVENT_RESET_RELEASED:
449 dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n",
450 __func__, __LINE__, event.value);
390 break; 451 break;
391 case PS3_SM_EVENT_THERMAL_ALERT: 452 case PS3_SM_EVENT_THERMAL_ALERT:
392 dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", 453 dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
@@ -411,7 +472,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
411 * The system manager sends this in reply to a 'request' message from the guest. 472 * The system manager sends this in reply to a 'request' message from the guest.
412 */ 473 */
413 474
414static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) 475static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
415{ 476{
416 int result; 477 int result;
417 struct { 478 struct {
@@ -425,6 +486,7 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
425 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 486 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
426 487
427 result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); 488 result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
489 BUG_ON(result && "need to retry here");
428 490
429 if(result) 491 if(result)
430 return result; 492 return result;
@@ -448,9 +510,10 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
448/** 510/**
449 * ps3_sys_manager_handle_msg - First stage msg handler. 511 * ps3_sys_manager_handle_msg - First stage msg handler.
450 * 512 *
513 * Can be called directly to manually poll vuart and pump message handler.
451 */ 514 */
452 515
453static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) 516static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
454{ 517{
455 int result; 518 int result;
456 struct ps3_sys_manager_header header; 519 struct ps3_sys_manager_header header;
@@ -464,12 +527,17 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
464 if (header.version != 1) { 527 if (header.version != 1) {
465 dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", 528 dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
466 __func__, __LINE__, header.version); 529 __func__, __LINE__, header.version);
530 dump_sm_header(&header);
467 goto fail_header; 531 goto fail_header;
468 } 532 }
469 533
470 BUILD_BUG_ON(sizeof(header) != 16); 534 BUILD_BUG_ON(sizeof(header) != 16);
471 BUG_ON(header.size != 16); 535
472 BUG_ON(header.payload_size != 16); 536 if (header.size != 16 || (header.payload_size != 8
537 && header.payload_size != 16)) {
538 dump_sm_header(&header);
539 BUG();
540 }
473 541
474 switch (header.service_id) { 542 switch (header.service_id) {
475 case PS3_SM_SERVICE_ID_EXTERN_EVENT: 543 case PS3_SM_SERVICE_ID_EXTERN_EVENT:
@@ -478,6 +546,11 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
478 case PS3_SM_SERVICE_ID_COMMAND: 546 case PS3_SM_SERVICE_ID_COMMAND:
479 dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); 547 dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
480 return ps3_sys_manager_handle_cmd(dev); 548 return ps3_sys_manager_handle_cmd(dev);
549 case PS3_SM_SERVICE_ID_REQUEST_ERROR:
550 dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__,
551 __LINE__);
552 dump_sm_header(&header);
553 break;
481 default: 554 default:
482 dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", 555 dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
483 __func__, __LINE__, header.service_id); 556 __func__, __LINE__, header.service_id);
@@ -494,45 +567,25 @@ fail_id:
494} 567}
495 568
496/** 569/**
497 * ps3_sys_manager_work - Asyncronous read handler. 570 * ps3_sys_manager_final_power_off - The final platform machine_power_off routine.
498 *
499 * Signaled when a complete message arrives at the vuart port.
500 */
501
502static void ps3_sys_manager_work(struct work_struct *work)
503{
504 struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work);
505
506 ps3_sys_manager_handle_msg(dev);
507 ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN);
508}
509
510struct {
511 struct ps3_vuart_port_device *dev;
512} static drv_priv;
513
514/**
515 * ps3_sys_manager_restart - The final platform machine_restart routine.
516 * 571 *
517 * This routine never returns. The routine disables asyncronous vuart reads 572 * This routine never returns. The routine disables asynchronous vuart reads
518 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 573 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
519 * the shutdown command sent from the system manager. Soon after the 574 * the shutdown command sent from the system manager. Soon after the
520 * acknowledgement is sent the lpar is destroyed by the HV. This routine 575 * acknowledgement is sent the lpar is destroyed by the HV. This routine
521 * should only be called from ps3_restart(). 576 * should only be called from ps3_power_off() through
577 * ps3_sys_manager_ops.power_off.
522 */ 578 */
523 579
524void ps3_sys_manager_restart(void) 580static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
525{ 581{
526 struct ps3_vuart_port_device *dev = drv_priv.dev; 582 BUG_ON(!dev);
527
528 BUG_ON(!drv_priv.dev);
529 583
530 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 584 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
531 585
532 ps3_vuart_cancel_async(dev); 586 ps3_vuart_cancel_async(dev);
533 587
534 ps3_sys_manager_send_attr(dev, 0); 588 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
535 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
536 PS3_SM_WAKE_DEFAULT); 589 PS3_SM_WAKE_DEFAULT);
537 ps3_sys_manager_send_request_shutdown(dev); 590 ps3_sys_manager_send_request_shutdown(dev);
538 591
@@ -543,26 +596,33 @@ void ps3_sys_manager_restart(void)
543} 596}
544 597
545/** 598/**
546 * ps3_sys_manager_power_off - The final platform machine_power_off routine. 599 * ps3_sys_manager_final_restart - The final platform machine_restart routine.
547 * 600 *
548 * This routine never returns. The routine disables asyncronous vuart reads 601 * This routine never returns. The routine disables asynchronous vuart reads
549 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge 602 * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
550 * the shutdown command sent from the system manager. Soon after the 603 * the shutdown command sent from the system manager. Soon after the
551 * acknowledgement is sent the lpar is destroyed by the HV. This routine 604 * acknowledgement is sent the lpar is destroyed by the HV. This routine
552 * should only be called from ps3_power_off(). 605 * should only be called from ps3_restart() through ps3_sys_manager_ops.restart.
553 */ 606 */
554 607
555void ps3_sys_manager_power_off(void) 608static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
556{ 609{
557 struct ps3_vuart_port_device *dev = drv_priv.dev; 610 BUG_ON(!dev);
558
559 BUG_ON(!drv_priv.dev);
560 611
561 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 612 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
562 613
614 /* Check if we got here via a power button event. */
615
616 if (ps3_sm_force_power_off) {
617 dev_dbg(&dev->core, "%s:%d: forcing poweroff\n",
618 __func__, __LINE__);
619 ps3_sys_manager_final_power_off(dev);
620 }
621
563 ps3_vuart_cancel_async(dev); 622 ps3_vuart_cancel_async(dev);
564 623
565 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, 624 ps3_sys_manager_send_attr(dev, 0);
625 ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
566 PS3_SM_WAKE_DEFAULT); 626 PS3_SM_WAKE_DEFAULT);
567 ps3_sys_manager_send_request_shutdown(dev); 627 ps3_sys_manager_send_request_shutdown(dev);
568 628
@@ -572,31 +632,60 @@ void ps3_sys_manager_power_off(void)
572 ps3_sys_manager_handle_msg(dev); 632 ps3_sys_manager_handle_msg(dev);
573} 633}
574 634
575static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev) 635/**
636 * ps3_sys_manager_work - Asynchronous read handler.
637 *
638 * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port.
639 */
640
641static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
642{
643 ps3_sys_manager_handle_msg(dev);
644 ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
645}
646
647static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
576{ 648{
577 int result; 649 int result;
650 struct ps3_sys_manager_ops ops;
578 651
579 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 652 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
580 653
581 BUG_ON(drv_priv.dev); 654 ops.power_off = ps3_sys_manager_final_power_off;
582 drv_priv.dev = dev; 655 ops.restart = ps3_sys_manager_final_restart;
656 ops.dev = dev;
657
658 /* ps3_sys_manager_register_ops copies ops. */
659
660 ps3_sys_manager_register_ops(&ops);
583 661
584 result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); 662 result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
585 BUG_ON(result); 663 BUG_ON(result);
586 664
587 result = ps3_vuart_read_async(dev, ps3_sys_manager_work, 665 result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
588 PS3_SM_RX_MSG_LEN);
589 BUG_ON(result); 666 BUG_ON(result);
590 667
591 return result; 668 return result;
592} 669}
593 670
671static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev)
672{
673 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
674 return 0;
675}
676
677static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev)
678{
679 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
680}
681
594static struct ps3_vuart_port_driver ps3_sys_manager = { 682static struct ps3_vuart_port_driver ps3_sys_manager = {
595 .match_id = PS3_MATCH_ID_SYSTEM_MANAGER, 683 .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
596 .core = { 684 .core.core.name = "ps3_sys_manager",
597 .name = "ps3_sys_manager",
598 },
599 .probe = ps3_sys_manager_probe, 685 .probe = ps3_sys_manager_probe,
686 .remove = ps3_sys_manager_remove,
687 .shutdown = ps3_sys_manager_shutdown,
688 .work = ps3_sys_manager_work,
600}; 689};
601 690
602static int __init ps3_sys_manager_init(void) 691static int __init ps3_sys_manager_init(void)
@@ -608,3 +697,6 @@ static int __init ps3_sys_manager_init(void)
608} 697}
609 698
610module_init(ps3_sys_manager_init); 699module_init(ps3_sys_manager_init);
700/* Module remove not supported. */
701
702MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);