diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:05:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-19 16:05:14 -0500 |
commit | 5c56f466835d20fc4f7119063a8c029f7170a317 (patch) | |
tree | cfa8afcea4defb59de32c501245bae16d0fdc5d0 /drivers | |
parent | dd397a6d1ae125686d97a20f983778c331093206 (diff) | |
parent | c2944612cf30aece4526f23e96e1d234a1870ed6 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (34 commits)
[POWERPC] 86xx: Cleaned up platform dts files
[POWERPC] 85xx: Renamed MPC8568 MDS board code to match other boards
[POWERPC] 85xx: Cleaning up machine probing
[POWERPC] QE: clean up ucc_slow.c and ucc_fast.c
[POWERPC] 85xx: Cleaned up platform dts files
[POWERPC] 83xx: Renamed MPC8323 MDS dts and defconfig to match other boards
[POWERPC] 83xx: Updated and renamed MPC8360PB to MPC836x MDS
[POWERPC] 83xx: Use of_platform_bus_probe to setup QE devices
[POWERPC] 83xx: use default value of loops_per_jiffy
[POWERPC] 83xx: Remove obsolete setting of ROOT_DEV.
[POWERPC] 83xx: Cleaning up machine probing and board initcalls
[POWERPC] Dispose irq mapping when done in mpc52xx_serial.c
[POWERPC] 86xx: Add missing of_node_put() in mpc86xx_hpcn_init_irq().
[POWERPC] 8[56]xx: Remove obsolete setting of ROOT_DEV for 85xx and 86xx platforms.
[POWERPC] pseries: Enabling auto poweron after power is restored.
[POWERPC] use winbond libata instead of ide driver for pseries CD drives
[POWERPC] powerpc: remove references to the obsolete linux,platform property
[POWERPC] add of_get_mac_address and update fsl_soc.c to use it
[POWERPC] 83xx: Cleaned up 83xx platform dts files
[POWERPC] Fix bug with early ioremap and 64k pages
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ps3/Makefile | 1 | ||||
-rw-r--r-- | drivers/ps3/sys-manager.c | 604 | ||||
-rw-r--r-- | drivers/ps3/vuart.c | 398 | ||||
-rw-r--r-- | drivers/ps3/vuart.h | 59 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.c | 2 | ||||
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 4 |
6 files changed, 931 insertions, 137 deletions
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index 96958c03cf61..e251d1c1171c 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-$(CONFIG_PS3_VUART) += vuart.o | 1 | obj-$(CONFIG_PS3_VUART) += vuart.o |
2 | obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o | 2 | obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o |
3 | obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o | ||
diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c new file mode 100644 index 000000000000..0fc30be8b81e --- /dev/null +++ b/drivers/ps3/sys-manager.c | |||
@@ -0,0 +1,604 @@ | |||
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); | ||
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index ef8fd4c30875..746298107d6f 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c | |||
@@ -21,8 +21,10 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/workqueue.h> | ||
24 | #include <asm/ps3.h> | 25 | #include <asm/ps3.h> |
25 | 26 | ||
27 | #include <asm/firmware.h> | ||
26 | #include <asm/lv1call.h> | 28 | #include <asm/lv1call.h> |
27 | #include <asm/bitops.h> | 29 | #include <asm/bitops.h> |
28 | 30 | ||
@@ -30,7 +32,7 @@ | |||
30 | 32 | ||
31 | MODULE_AUTHOR("Sony Corporation"); | 33 | MODULE_AUTHOR("Sony Corporation"); |
32 | MODULE_LICENSE("GPL v2"); | 34 | MODULE_LICENSE("GPL v2"); |
33 | MODULE_DESCRIPTION("ps3 vuart"); | 35 | MODULE_DESCRIPTION("PS3 vuart"); |
34 | 36 | ||
35 | /** | 37 | /** |
36 | * vuart - An inter-partition data link service. | 38 | * vuart - An inter-partition data link service. |
@@ -157,7 +159,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
157 | unsigned long size; | 159 | unsigned long size; |
158 | unsigned long val; | 160 | unsigned long val; |
159 | 161 | ||
160 | result = lv1_get_virtual_uart_param(dev->port_number, | 162 | result = lv1_get_virtual_uart_param(dev->priv->port_number, |
161 | PARAM_TX_TRIGGER, &trig->tx); | 163 | PARAM_TX_TRIGGER, &trig->tx); |
162 | 164 | ||
163 | if (result) { | 165 | if (result) { |
@@ -166,7 +168,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
166 | return result; | 168 | return result; |
167 | } | 169 | } |
168 | 170 | ||
169 | result = lv1_get_virtual_uart_param(dev->port_number, | 171 | result = lv1_get_virtual_uart_param(dev->priv->port_number, |
170 | PARAM_RX_BUF_SIZE, &size); | 172 | PARAM_RX_BUF_SIZE, &size); |
171 | 173 | ||
172 | if (result) { | 174 | if (result) { |
@@ -175,7 +177,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
175 | return result; | 177 | return result; |
176 | } | 178 | } |
177 | 179 | ||
178 | result = lv1_get_virtual_uart_param(dev->port_number, | 180 | result = lv1_get_virtual_uart_param(dev->priv->port_number, |
179 | PARAM_RX_TRIGGER, &val); | 181 | PARAM_RX_TRIGGER, &val); |
180 | 182 | ||
181 | if (result) { | 183 | if (result) { |
@@ -198,7 +200,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
198 | int result; | 200 | int result; |
199 | unsigned long size; | 201 | unsigned long size; |
200 | 202 | ||
201 | result = lv1_set_virtual_uart_param(dev->port_number, | 203 | result = lv1_set_virtual_uart_param(dev->priv->port_number, |
202 | PARAM_TX_TRIGGER, tx); | 204 | PARAM_TX_TRIGGER, tx); |
203 | 205 | ||
204 | if (result) { | 206 | if (result) { |
@@ -207,7 +209,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
207 | return result; | 209 | return result; |
208 | } | 210 | } |
209 | 211 | ||
210 | result = lv1_get_virtual_uart_param(dev->port_number, | 212 | result = lv1_get_virtual_uart_param(dev->priv->port_number, |
211 | PARAM_RX_BUF_SIZE, &size); | 213 | PARAM_RX_BUF_SIZE, &size); |
212 | 214 | ||
213 | if (result) { | 215 | if (result) { |
@@ -216,7 +218,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
216 | return result; | 218 | return result; |
217 | } | 219 | } |
218 | 220 | ||
219 | result = lv1_set_virtual_uart_param(dev->port_number, | 221 | result = lv1_set_virtual_uart_param(dev->priv->port_number, |
220 | PARAM_RX_TRIGGER, size - rx); | 222 | PARAM_RX_TRIGGER, size - rx); |
221 | 223 | ||
222 | if (result) { | 224 | if (result) { |
@@ -232,9 +234,9 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
232 | } | 234 | } |
233 | 235 | ||
234 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, | 236 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, |
235 | unsigned long *bytes_waiting) | 237 | u64 *bytes_waiting) |
236 | { | 238 | { |
237 | int result = lv1_get_virtual_uart_param(dev->port_number, | 239 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, |
238 | PARAM_RX_BYTES, bytes_waiting); | 240 | PARAM_RX_BYTES, bytes_waiting); |
239 | 241 | ||
240 | if (result) | 242 | if (result) |
@@ -253,10 +255,10 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | |||
253 | 255 | ||
254 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); | 256 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); |
255 | 257 | ||
256 | dev->interrupt_mask = mask; | 258 | dev->priv->interrupt_mask = mask; |
257 | 259 | ||
258 | result = lv1_set_virtual_uart_param(dev->port_number, | 260 | result = lv1_set_virtual_uart_param(dev->priv->port_number, |
259 | PARAM_INTERRUPT_MASK, dev->interrupt_mask); | 261 | PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask); |
260 | 262 | ||
261 | if (result) | 263 | if (result) |
262 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", | 264 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", |
@@ -265,62 +267,64 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | |||
265 | return result; | 267 | return result; |
266 | } | 268 | } |
267 | 269 | ||
268 | static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev, | 270 | static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev, |
269 | unsigned long *status) | 271 | unsigned long *status) |
270 | { | 272 | { |
271 | int result = lv1_get_virtual_uart_param(dev->port_number, | 273 | u64 tmp; |
272 | PARAM_INTERRUPT_STATUS, status); | 274 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, |
275 | PARAM_INTERRUPT_STATUS, &tmp); | ||
273 | 276 | ||
274 | if (result) | 277 | if (result) |
275 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", | 278 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", |
276 | __func__, __LINE__, ps3_result(result)); | 279 | __func__, __LINE__, ps3_result(result)); |
277 | 280 | ||
281 | *status = tmp & dev->priv->interrupt_mask; | ||
282 | |||
278 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", | 283 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", |
279 | __func__, __LINE__, dev->interrupt_mask, *status, | 284 | __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status); |
280 | dev->interrupt_mask & *status); | ||
281 | 285 | ||
282 | return result; | 286 | return result; |
283 | } | 287 | } |
284 | 288 | ||
285 | int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) | 289 | int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) |
286 | { | 290 | { |
287 | return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0 | 291 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 |
288 | : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 292 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
289 | | INTERRUPT_MASK_TX); | 293 | | INTERRUPT_MASK_TX); |
290 | } | 294 | } |
291 | 295 | ||
292 | int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) | 296 | int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) |
293 | { | 297 | { |
294 | return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0 | 298 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 |
295 | : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 299 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
296 | | INTERRUPT_MASK_RX); | 300 | | INTERRUPT_MASK_RX); |
297 | } | 301 | } |
298 | 302 | ||
299 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 303 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) |
300 | { | 304 | { |
301 | return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 | 305 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 |
302 | : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 306 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
303 | | INTERRUPT_MASK_DISCONNECT); | 307 | | INTERRUPT_MASK_DISCONNECT); |
304 | } | 308 | } |
305 | 309 | ||
306 | int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) | 310 | int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) |
307 | { | 311 | { |
308 | return (dev->interrupt_mask & INTERRUPT_MASK_TX) | 312 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) |
309 | ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 313 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
310 | & ~INTERRUPT_MASK_TX) : 0; | 314 | & ~INTERRUPT_MASK_TX) : 0; |
311 | } | 315 | } |
312 | 316 | ||
313 | int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) | 317 | int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) |
314 | { | 318 | { |
315 | return (dev->interrupt_mask & INTERRUPT_MASK_RX) | 319 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) |
316 | ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 320 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
317 | & ~INTERRUPT_MASK_RX) : 0; | 321 | & ~INTERRUPT_MASK_RX) : 0; |
318 | } | 322 | } |
319 | 323 | ||
320 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 324 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) |
321 | { | 325 | { |
322 | return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) | 326 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) |
323 | ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask | 327 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask |
324 | & ~INTERRUPT_MASK_DISCONNECT) : 0; | 328 | & ~INTERRUPT_MASK_DISCONNECT) : 0; |
325 | } | 329 | } |
326 | 330 | ||
@@ -335,9 +339,7 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | |||
335 | { | 339 | { |
336 | int result; | 340 | int result; |
337 | 341 | ||
338 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); | 342 | result = lv1_write_virtual_uart(dev->priv->port_number, |
339 | |||
340 | result = lv1_write_virtual_uart(dev->port_number, | ||
341 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); | 343 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); |
342 | 344 | ||
343 | if (result) { | 345 | if (result) { |
@@ -346,10 +348,10 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | |||
346 | return result; | 348 | return result; |
347 | } | 349 | } |
348 | 350 | ||
349 | dev->stats.bytes_written += *bytes_written; | 351 | dev->priv->stats.bytes_written += *bytes_written; |
350 | 352 | ||
351 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, | 353 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, |
352 | __LINE__, *bytes_written, bytes, dev->stats.bytes_written); | 354 | *bytes_written, bytes, dev->priv->stats.bytes_written); |
353 | 355 | ||
354 | return result; | 356 | return result; |
355 | } | 357 | } |
@@ -367,7 +369,7 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | |||
367 | 369 | ||
368 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); | 370 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); |
369 | 371 | ||
370 | result = lv1_read_virtual_uart(dev->port_number, | 372 | result = lv1_read_virtual_uart(dev->priv->port_number, |
371 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); | 373 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); |
372 | 374 | ||
373 | if (result) { | 375 | if (result) { |
@@ -376,15 +378,58 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | |||
376 | return result; | 378 | return result; |
377 | } | 379 | } |
378 | 380 | ||
379 | dev->stats.bytes_read += *bytes_read; | 381 | dev->priv->stats.bytes_read += *bytes_read; |
380 | 382 | ||
381 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, | 383 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, |
382 | *bytes_read, bytes, dev->stats.bytes_read); | 384 | *bytes_read, bytes, dev->priv->stats.bytes_read); |
383 | 385 | ||
384 | return result; | 386 | return result; |
385 | } | 387 | } |
386 | 388 | ||
387 | /** | 389 | /** |
390 | * ps3_vuart_clear_rx_bytes - Discard bytes received. | ||
391 | * @bytes: Max byte count to discard, zero = all pending. | ||
392 | * | ||
393 | * Used to clear pending rx interrupt source. Will not block. | ||
394 | */ | ||
395 | |||
396 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | ||
397 | unsigned int bytes) | ||
398 | { | ||
399 | int result; | ||
400 | u64 bytes_waiting; | ||
401 | void* tmp; | ||
402 | |||
403 | result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting); | ||
404 | |||
405 | BUG_ON(result); | ||
406 | |||
407 | bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting; | ||
408 | |||
409 | dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes); | ||
410 | |||
411 | if (!bytes) | ||
412 | return; | ||
413 | |||
414 | /* Add some extra space for recently arrived data. */ | ||
415 | |||
416 | bytes += 128; | ||
417 | |||
418 | tmp = kmalloc(bytes, GFP_KERNEL); | ||
419 | |||
420 | if (!tmp) | ||
421 | return; | ||
422 | |||
423 | ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting); | ||
424 | |||
425 | kfree(tmp); | ||
426 | |||
427 | /* Don't include these bytes in the stats. */ | ||
428 | |||
429 | dev->priv->stats.bytes_read -= bytes_waiting; | ||
430 | } | ||
431 | |||
432 | /** | ||
388 | * struct list_buffer - An element for a port device fifo buffer list. | 433 | * struct list_buffer - An element for a port device fifo buffer list. |
389 | */ | 434 | */ |
390 | 435 | ||
@@ -416,14 +461,14 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
416 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 461 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
417 | bytes, bytes); | 462 | bytes, bytes); |
418 | 463 | ||
419 | spin_lock_irqsave(&dev->tx_list.lock, flags); | 464 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); |
420 | 465 | ||
421 | if (list_empty(&dev->tx_list.head)) { | 466 | if (list_empty(&dev->priv->tx_list.head)) { |
422 | unsigned long bytes_written; | 467 | unsigned long bytes_written; |
423 | 468 | ||
424 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); | 469 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); |
425 | 470 | ||
426 | spin_unlock_irqrestore(&dev->tx_list.lock, flags); | 471 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); |
427 | 472 | ||
428 | if (result) { | 473 | if (result) { |
429 | dev_dbg(&dev->core, | 474 | dev_dbg(&dev->core, |
@@ -441,7 +486,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
441 | bytes -= bytes_written; | 486 | bytes -= bytes_written; |
442 | buf += bytes_written; | 487 | buf += bytes_written; |
443 | } else | 488 | } else |
444 | spin_unlock_irqrestore(&dev->tx_list.lock, flags); | 489 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); |
445 | 490 | ||
446 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); | 491 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); |
447 | 492 | ||
@@ -454,10 +499,10 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
454 | lb->tail = lb->data + bytes; | 499 | lb->tail = lb->data + bytes; |
455 | lb->dbg_number = ++dbg_number; | 500 | lb->dbg_number = ++dbg_number; |
456 | 501 | ||
457 | spin_lock_irqsave(&dev->tx_list.lock, flags); | 502 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); |
458 | list_add_tail(&lb->link, &dev->tx_list.head); | 503 | list_add_tail(&lb->link, &dev->priv->tx_list.head); |
459 | ps3_vuart_enable_interrupt_tx(dev); | 504 | ps3_vuart_enable_interrupt_tx(dev); |
460 | spin_unlock_irqrestore(&dev->tx_list.lock, flags); | 505 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); |
461 | 506 | ||
462 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", | 507 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", |
463 | __func__, __LINE__, lb->dbg_number, bytes); | 508 | __func__, __LINE__, lb->dbg_number, bytes); |
@@ -484,47 +529,83 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
484 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 529 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
485 | bytes, bytes); | 530 | bytes, bytes); |
486 | 531 | ||
487 | spin_lock_irqsave(&dev->rx_list.lock, flags); | 532 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); |
488 | 533 | ||
489 | if (dev->rx_list.bytes_held < bytes) { | 534 | if (dev->priv->rx_list.bytes_held < bytes) { |
490 | spin_unlock_irqrestore(&dev->rx_list.lock, flags); | 535 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); |
491 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", | 536 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", |
492 | __func__, __LINE__, bytes - dev->rx_list.bytes_held); | 537 | __func__, __LINE__, |
538 | bytes - dev->priv->rx_list.bytes_held); | ||
493 | return -EAGAIN; | 539 | return -EAGAIN; |
494 | } | 540 | } |
495 | 541 | ||
496 | list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) { | 542 | list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) { |
497 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); | 543 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); |
498 | 544 | ||
499 | memcpy(buf, lb->head, bytes_read); | 545 | memcpy(buf, lb->head, bytes_read); |
500 | buf += bytes_read; | 546 | buf += bytes_read; |
501 | bytes -= bytes_read; | 547 | bytes -= bytes_read; |
502 | dev->rx_list.bytes_held -= bytes_read; | 548 | dev->priv->rx_list.bytes_held -= bytes_read; |
503 | 549 | ||
504 | if (bytes_read < lb->tail - lb->head) { | 550 | if (bytes_read < lb->tail - lb->head) { |
505 | lb->head += bytes_read; | 551 | lb->head += bytes_read; |
506 | spin_unlock_irqrestore(&dev->rx_list.lock, flags); | 552 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " |
507 | 553 | "bytes\n", __func__, __LINE__, lb->dbg_number, | |
508 | dev_dbg(&dev->core, | 554 | bytes_read); |
509 | "%s:%d: dequeued buf_%lu, %lxh bytes\n", | 555 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); |
510 | __func__, __LINE__, lb->dbg_number, bytes_read); | ||
511 | return 0; | 556 | return 0; |
512 | } | 557 | } |
513 | 558 | ||
514 | dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__, | 559 | dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh " |
515 | lb->dbg_number); | 560 | "bytes\n", __func__, __LINE__, lb->dbg_number, |
561 | bytes_read); | ||
516 | 562 | ||
517 | list_del(&lb->link); | 563 | list_del(&lb->link); |
518 | kfree(lb); | 564 | kfree(lb); |
519 | } | 565 | } |
520 | spin_unlock_irqrestore(&dev->rx_list.lock, flags); | ||
521 | 566 | ||
522 | dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n", | 567 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); |
523 | __func__, __LINE__, lb->dbg_number, bytes); | 568 | return 0; |
569 | } | ||
570 | |||
571 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | ||
572 | unsigned int bytes) | ||
573 | { | ||
574 | unsigned long flags; | ||
575 | |||
576 | if(dev->priv->work.trigger) { | ||
577 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", | ||
578 | __func__, __LINE__); | ||
579 | return -EAGAIN; | ||
580 | } | ||
581 | |||
582 | BUG_ON(!bytes); | ||
583 | |||
584 | PREPARE_WORK(&dev->priv->work.work, func); | ||
585 | |||
586 | spin_lock_irqsave(&dev->priv->work.lock, flags); | ||
587 | if(dev->priv->rx_list.bytes_held >= bytes) { | ||
588 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", | ||
589 | __func__, __LINE__, bytes); | ||
590 | schedule_work(&dev->priv->work.work); | ||
591 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | dev->priv->work.trigger = bytes; | ||
596 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
597 | |||
598 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, | ||
599 | __LINE__, bytes, bytes); | ||
524 | 600 | ||
525 | return 0; | 601 | return 0; |
526 | } | 602 | } |
527 | 603 | ||
604 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | ||
605 | { | ||
606 | dev->priv->work.trigger = 0; | ||
607 | } | ||
608 | |||
528 | /** | 609 | /** |
529 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler | 610 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler |
530 | * | 611 | * |
@@ -542,9 +623,9 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | |||
542 | 623 | ||
543 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 624 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
544 | 625 | ||
545 | spin_lock_irqsave(&dev->tx_list.lock, flags); | 626 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); |
546 | 627 | ||
547 | list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) { | 628 | list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) { |
548 | 629 | ||
549 | unsigned long bytes_written; | 630 | unsigned long bytes_written; |
550 | 631 | ||
@@ -578,7 +659,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | |||
578 | 659 | ||
579 | ps3_vuart_disable_interrupt_tx(dev); | 660 | ps3_vuart_disable_interrupt_tx(dev); |
580 | port_full: | 661 | port_full: |
581 | spin_unlock_irqrestore(&dev->tx_list.lock, flags); | 662 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); |
582 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", | 663 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", |
583 | __func__, __LINE__, bytes_total); | 664 | __func__, __LINE__, bytes_total); |
584 | return result; | 665 | return result; |
@@ -609,7 +690,7 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) | |||
609 | 690 | ||
610 | BUG_ON(!bytes); | 691 | BUG_ON(!bytes); |
611 | 692 | ||
612 | /* add some extra space for recently arrived data */ | 693 | /* Add some extra space for recently arrived data. */ |
613 | 694 | ||
614 | bytes += 128; | 695 | bytes += 128; |
615 | 696 | ||
@@ -624,14 +705,23 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) | |||
624 | lb->tail = lb->data + bytes; | 705 | lb->tail = lb->data + bytes; |
625 | lb->dbg_number = ++dbg_number; | 706 | lb->dbg_number = ++dbg_number; |
626 | 707 | ||
627 | spin_lock_irqsave(&dev->rx_list.lock, flags); | 708 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); |
628 | list_add_tail(&lb->link, &dev->rx_list.head); | 709 | list_add_tail(&lb->link, &dev->priv->rx_list.head); |
629 | dev->rx_list.bytes_held += bytes; | 710 | dev->priv->rx_list.bytes_held += bytes; |
630 | spin_unlock_irqrestore(&dev->rx_list.lock, flags); | 711 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); |
631 | 712 | ||
632 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n", | 713 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", |
633 | __func__, __LINE__, lb->dbg_number, bytes); | 714 | __func__, __LINE__, lb->dbg_number, bytes); |
634 | 715 | ||
716 | spin_lock_irqsave(&dev->priv->work.lock, flags); | ||
717 | if(dev->priv->work.trigger | ||
718 | && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { | ||
719 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", | ||
720 | __func__, __LINE__, dev->priv->work.trigger); | ||
721 | dev->priv->work.trigger = 0; | ||
722 | schedule_work(&dev->priv->work.work); | ||
723 | } | ||
724 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
635 | return 0; | 725 | return 0; |
636 | } | 726 | } |
637 | 727 | ||
@@ -656,7 +746,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
656 | int result; | 746 | int result; |
657 | unsigned long status; | 747 | unsigned long status; |
658 | 748 | ||
659 | result = ps3_vuart_get_interrupt_mask(dev, &status); | 749 | result = ps3_vuart_get_interrupt_status(dev, &status); |
660 | 750 | ||
661 | if (result) | 751 | if (result) |
662 | return result; | 752 | return result; |
@@ -665,21 +755,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
665 | status); | 755 | status); |
666 | 756 | ||
667 | if (status & INTERRUPT_MASK_DISCONNECT) { | 757 | if (status & INTERRUPT_MASK_DISCONNECT) { |
668 | dev->stats.disconnect_interrupts++; | 758 | dev->priv->stats.disconnect_interrupts++; |
669 | result = ps3_vuart_handle_interrupt_disconnect(dev); | 759 | result = ps3_vuart_handle_interrupt_disconnect(dev); |
670 | if (result) | 760 | if (result) |
671 | ps3_vuart_disable_interrupt_disconnect(dev); | 761 | ps3_vuart_disable_interrupt_disconnect(dev); |
672 | } | 762 | } |
673 | 763 | ||
674 | if (status & INTERRUPT_MASK_TX) { | 764 | if (status & INTERRUPT_MASK_TX) { |
675 | dev->stats.tx_interrupts++; | 765 | dev->priv->stats.tx_interrupts++; |
676 | result = ps3_vuart_handle_interrupt_tx(dev); | 766 | result = ps3_vuart_handle_interrupt_tx(dev); |
677 | if (result) | 767 | if (result) |
678 | ps3_vuart_disable_interrupt_tx(dev); | 768 | ps3_vuart_disable_interrupt_tx(dev); |
679 | } | 769 | } |
680 | 770 | ||
681 | if (status & INTERRUPT_MASK_RX) { | 771 | if (status & INTERRUPT_MASK_RX) { |
682 | dev->stats.rx_interrupts++; | 772 | dev->priv->stats.rx_interrupts++; |
683 | result = ps3_vuart_handle_interrupt_rx(dev); | 773 | result = ps3_vuart_handle_interrupt_rx(dev); |
684 | if (result) | 774 | if (result) |
685 | ps3_vuart_disable_interrupt_rx(dev); | 775 | ps3_vuart_disable_interrupt_rx(dev); |
@@ -688,12 +778,13 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
688 | return 0; | 778 | return 0; |
689 | } | 779 | } |
690 | 780 | ||
691 | struct vuart_private { | 781 | struct vuart_bus_priv { |
692 | unsigned int in_use; | 782 | const struct ports_bmp bmp; |
693 | unsigned int virq; | 783 | unsigned int virq; |
784 | struct semaphore probe_mutex; | ||
785 | int use_count; | ||
694 | struct ps3_vuart_port_device *devices[PORT_COUNT]; | 786 | struct ps3_vuart_port_device *devices[PORT_COUNT]; |
695 | const struct ports_bmp bmp; | 787 | } static vuart_bus_priv; |
696 | }; | ||
697 | 788 | ||
698 | /** | 789 | /** |
699 | * ps3_vuart_irq_handler - first stage interrupt handler | 790 | * ps3_vuart_irq_handler - first stage interrupt handler |
@@ -705,25 +796,25 @@ struct vuart_private { | |||
705 | 796 | ||
706 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) | 797 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) |
707 | { | 798 | { |
708 | struct vuart_private *private; | 799 | struct vuart_bus_priv *bus_priv; |
709 | 800 | ||
710 | BUG_ON(!_private); | 801 | BUG_ON(!_private); |
711 | private = (struct vuart_private *)_private; | 802 | bus_priv = (struct vuart_bus_priv *)_private; |
712 | 803 | ||
713 | while (1) { | 804 | while (1) { |
714 | unsigned int port; | 805 | unsigned int port; |
715 | 806 | ||
716 | dump_ports_bmp(&private->bmp); | 807 | dump_ports_bmp(&bus_priv->bmp); |
717 | 808 | ||
718 | port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status); | 809 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status); |
719 | 810 | ||
720 | if (port == BITS_PER_LONG) | 811 | if (port == BITS_PER_LONG) |
721 | break; | 812 | break; |
722 | 813 | ||
723 | BUG_ON(port >= PORT_COUNT); | 814 | BUG_ON(port >= PORT_COUNT); |
724 | BUG_ON(!private->devices[port]); | 815 | BUG_ON(!bus_priv->devices[port]); |
725 | 816 | ||
726 | ps3_vuart_handle_port_interrupt(private->devices[port]); | 817 | ps3_vuart_handle_port_interrupt(bus_priv->devices[port]); |
727 | } | 818 | } |
728 | 819 | ||
729 | return IRQ_HANDLED; | 820 | return IRQ_HANDLED; |
@@ -744,12 +835,10 @@ static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv) | |||
744 | return result; | 835 | return result; |
745 | } | 836 | } |
746 | 837 | ||
747 | static struct vuart_private vuart_private; | ||
748 | |||
749 | static int ps3_vuart_probe(struct device *_dev) | 838 | static int ps3_vuart_probe(struct device *_dev) |
750 | { | 839 | { |
751 | int result; | 840 | int result; |
752 | unsigned long tmp; | 841 | unsigned int port_number; |
753 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | 842 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); |
754 | struct ps3_vuart_port_driver *drv = | 843 | struct ps3_vuart_port_driver *drv = |
755 | to_ps3_vuart_port_driver(_dev->driver); | 844 | to_ps3_vuart_port_driver(_dev->driver); |
@@ -758,7 +847,12 @@ static int ps3_vuart_probe(struct device *_dev) | |||
758 | 847 | ||
759 | BUG_ON(!drv); | 848 | BUG_ON(!drv); |
760 | 849 | ||
761 | result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number); | 850 | down(&vuart_bus_priv.probe_mutex); |
851 | |||
852 | /* Setup vuart_bus_priv.devices[]. */ | ||
853 | |||
854 | result = ps3_vuart_match_id_to_port(dev->match_id, | ||
855 | &port_number); | ||
762 | 856 | ||
763 | if (result) { | 857 | if (result) { |
764 | dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", | 858 | dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", |
@@ -767,24 +861,41 @@ static int ps3_vuart_probe(struct device *_dev) | |||
767 | goto fail_match; | 861 | goto fail_match; |
768 | } | 862 | } |
769 | 863 | ||
770 | if (vuart_private.devices[dev->port_number]) { | 864 | if (vuart_bus_priv.devices[port_number]) { |
771 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, | 865 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, |
772 | __LINE__, dev->port_number); | 866 | __LINE__, port_number); |
773 | result = -EBUSY; | 867 | result = -EBUSY; |
774 | goto fail_match; | 868 | goto fail_match; |
775 | } | 869 | } |
776 | 870 | ||
777 | vuart_private.devices[dev->port_number] = dev; | 871 | vuart_bus_priv.devices[port_number] = dev; |
872 | |||
873 | /* Setup dev->priv. */ | ||
874 | |||
875 | dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL); | ||
876 | |||
877 | if (!dev->priv) { | ||
878 | result = -ENOMEM; | ||
879 | goto fail_alloc; | ||
880 | } | ||
778 | 881 | ||
779 | INIT_LIST_HEAD(&dev->tx_list.head); | 882 | dev->priv->port_number = port_number; |
780 | spin_lock_init(&dev->tx_list.lock); | 883 | |
781 | INIT_LIST_HEAD(&dev->rx_list.head); | 884 | INIT_LIST_HEAD(&dev->priv->tx_list.head); |
782 | spin_lock_init(&dev->rx_list.lock); | 885 | spin_lock_init(&dev->priv->tx_list.lock); |
886 | |||
887 | INIT_LIST_HEAD(&dev->priv->rx_list.head); | ||
888 | spin_lock_init(&dev->priv->rx_list.lock); | ||
889 | |||
890 | INIT_WORK(&dev->priv->work.work, NULL); | ||
891 | spin_lock_init(&dev->priv->work.lock); | ||
892 | dev->priv->work.trigger = 0; | ||
893 | dev->priv->work.dev = dev; | ||
894 | |||
895 | if (++vuart_bus_priv.use_count == 1) { | ||
783 | 896 | ||
784 | vuart_private.in_use++; | ||
785 | if (vuart_private.in_use == 1) { | ||
786 | result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, | 897 | result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, |
787 | (void*)&vuart_private.bmp.status, &vuart_private.virq); | 898 | (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); |
788 | 899 | ||
789 | if (result) { | 900 | if (result) { |
790 | dev_dbg(&dev->core, | 901 | dev_dbg(&dev->core, |
@@ -794,8 +905,8 @@ static int ps3_vuart_probe(struct device *_dev) | |||
794 | goto fail_alloc_irq; | 905 | goto fail_alloc_irq; |
795 | } | 906 | } |
796 | 907 | ||
797 | result = request_irq(vuart_private.virq, ps3_vuart_irq_handler, | 908 | result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, |
798 | IRQF_DISABLED, "vuart", &vuart_private); | 909 | IRQF_DISABLED, "vuart", &vuart_bus_priv); |
799 | 910 | ||
800 | if (result) { | 911 | if (result) { |
801 | dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", | 912 | dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", |
@@ -804,10 +915,11 @@ static int ps3_vuart_probe(struct device *_dev) | |||
804 | } | 915 | } |
805 | } | 916 | } |
806 | 917 | ||
807 | ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); | ||
808 | |||
809 | /* clear stale pending interrupts */ | 918 | /* clear stale pending interrupts */ |
810 | ps3_vuart_get_interrupt_mask(dev, &tmp); | 919 | |
920 | ps3_vuart_clear_rx_bytes(dev, 0); | ||
921 | |||
922 | ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); | ||
811 | 923 | ||
812 | ps3_vuart_set_triggers(dev, 1, 1); | 924 | ps3_vuart_set_triggers(dev, 1, 1); |
813 | 925 | ||
@@ -822,20 +934,27 @@ static int ps3_vuart_probe(struct device *_dev) | |||
822 | if (result) { | 934 | if (result) { |
823 | dev_dbg(&dev->core, "%s:%d: drv->probe failed\n", | 935 | dev_dbg(&dev->core, "%s:%d: drv->probe failed\n", |
824 | __func__, __LINE__); | 936 | __func__, __LINE__); |
937 | down(&vuart_bus_priv.probe_mutex); | ||
825 | goto fail_probe; | 938 | goto fail_probe; |
826 | } | 939 | } |
827 | 940 | ||
941 | up(&vuart_bus_priv.probe_mutex); | ||
942 | |||
828 | return result; | 943 | return result; |
829 | 944 | ||
830 | fail_probe: | 945 | fail_probe: |
946 | ps3_vuart_set_interrupt_mask(dev, 0); | ||
831 | fail_request_irq: | 947 | fail_request_irq: |
832 | vuart_private.in_use--; | 948 | ps3_free_vuart_irq(vuart_bus_priv.virq); |
833 | if (!vuart_private.in_use) { | 949 | vuart_bus_priv.virq = NO_IRQ; |
834 | ps3_free_vuart_irq(vuart_private.virq); | ||
835 | vuart_private.virq = NO_IRQ; | ||
836 | } | ||
837 | fail_alloc_irq: | 950 | fail_alloc_irq: |
951 | --vuart_bus_priv.use_count; | ||
952 | kfree(dev->priv); | ||
953 | dev->priv = NULL; | ||
954 | fail_alloc: | ||
955 | vuart_bus_priv.devices[port_number] = 0; | ||
838 | fail_match: | 956 | fail_match: |
957 | up(&vuart_bus_priv.probe_mutex); | ||
839 | dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); | 958 | dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); |
840 | return result; | 959 | return result; |
841 | } | 960 | } |
@@ -846,10 +965,12 @@ static int ps3_vuart_remove(struct device *_dev) | |||
846 | struct ps3_vuart_port_driver *drv = | 965 | struct ps3_vuart_port_driver *drv = |
847 | to_ps3_vuart_port_driver(_dev->driver); | 966 | to_ps3_vuart_port_driver(_dev->driver); |
848 | 967 | ||
968 | down(&vuart_bus_priv.probe_mutex); | ||
969 | |||
849 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, | 970 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, |
850 | dev->core.bus_id); | 971 | dev->core.bus_id); |
851 | 972 | ||
852 | BUG_ON(vuart_private.in_use < 1); | 973 | BUG_ON(vuart_bus_priv.use_count < 1); |
853 | 974 | ||
854 | if (drv->remove) | 975 | if (drv->remove) |
855 | drv->remove(dev); | 976 | drv->remove(dev); |
@@ -857,13 +978,19 @@ static int ps3_vuart_remove(struct device *_dev) | |||
857 | dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, | 978 | dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, |
858 | __LINE__, dev->core.bus_id); | 979 | __LINE__, dev->core.bus_id); |
859 | 980 | ||
860 | vuart_private.in_use--; | 981 | vuart_bus_priv.devices[dev->priv->port_number] = 0; |
861 | 982 | ||
862 | if (!vuart_private.in_use) { | 983 | if (--vuart_bus_priv.use_count == 0) { |
863 | free_irq(vuart_private.virq, &vuart_private); | 984 | BUG(); |
864 | ps3_free_vuart_irq(vuart_private.virq); | 985 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); |
865 | vuart_private.virq = NO_IRQ; | 986 | ps3_free_vuart_irq(vuart_bus_priv.virq); |
987 | vuart_bus_priv.virq = NO_IRQ; | ||
866 | } | 988 | } |
989 | |||
990 | kfree(dev->priv); | ||
991 | dev->priv = NULL; | ||
992 | |||
993 | up(&vuart_bus_priv.probe_mutex); | ||
867 | return 0; | 994 | return 0; |
868 | } | 995 | } |
869 | 996 | ||
@@ -884,12 +1011,12 @@ static void ps3_vuart_shutdown(struct device *_dev) | |||
884 | } | 1011 | } |
885 | 1012 | ||
886 | /** | 1013 | /** |
887 | * ps3_vuart - The vuart instance. | 1014 | * ps3_vuart_bus - The vuart bus instance. |
888 | * | 1015 | * |
889 | * The vuart is managed as a bus that port devices connect to. | 1016 | * The vuart is managed as a bus that port devices connect to. |
890 | */ | 1017 | */ |
891 | 1018 | ||
892 | struct bus_type ps3_vuart = { | 1019 | struct bus_type ps3_vuart_bus = { |
893 | .name = "ps3_vuart", | 1020 | .name = "ps3_vuart", |
894 | .match = ps3_vuart_match, | 1021 | .match = ps3_vuart_match, |
895 | .probe = ps3_vuart_probe, | 1022 | .probe = ps3_vuart_probe, |
@@ -897,24 +1024,30 @@ struct bus_type ps3_vuart = { | |||
897 | .shutdown = ps3_vuart_shutdown, | 1024 | .shutdown = ps3_vuart_shutdown, |
898 | }; | 1025 | }; |
899 | 1026 | ||
900 | int __init ps3_vuart_init(void) | 1027 | int __init ps3_vuart_bus_init(void) |
901 | { | 1028 | { |
902 | int result; | 1029 | int result; |
903 | 1030 | ||
904 | pr_debug("%s:%d:\n", __func__, __LINE__); | 1031 | pr_debug("%s:%d:\n", __func__, __LINE__); |
905 | result = bus_register(&ps3_vuart); | 1032 | |
1033 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
1034 | return 0; | ||
1035 | |||
1036 | init_MUTEX(&vuart_bus_priv.probe_mutex); | ||
1037 | result = bus_register(&ps3_vuart_bus); | ||
906 | BUG_ON(result); | 1038 | BUG_ON(result); |
1039 | |||
907 | return result; | 1040 | return result; |
908 | } | 1041 | } |
909 | 1042 | ||
910 | void __exit ps3_vuart_exit(void) | 1043 | void __exit ps3_vuart_bus_exit(void) |
911 | { | 1044 | { |
912 | pr_debug("%s:%d:\n", __func__, __LINE__); | 1045 | pr_debug("%s:%d:\n", __func__, __LINE__); |
913 | bus_unregister(&ps3_vuart); | 1046 | bus_unregister(&ps3_vuart_bus); |
914 | } | 1047 | } |
915 | 1048 | ||
916 | core_initcall(ps3_vuart_init); | 1049 | core_initcall(ps3_vuart_bus_init); |
917 | module_exit(ps3_vuart_exit); | 1050 | module_exit(ps3_vuart_bus_exit); |
918 | 1051 | ||
919 | /** | 1052 | /** |
920 | * ps3_vuart_port_release_device - Remove a vuart port device. | 1053 | * ps3_vuart_port_release_device - Remove a vuart port device. |
@@ -922,11 +1055,14 @@ module_exit(ps3_vuart_exit); | |||
922 | 1055 | ||
923 | static void ps3_vuart_port_release_device(struct device *_dev) | 1056 | static void ps3_vuart_port_release_device(struct device *_dev) |
924 | { | 1057 | { |
925 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
926 | #if defined(DEBUG) | 1058 | #if defined(DEBUG) |
927 | memset(dev, 0xad, sizeof(struct ps3_vuart_port_device)); | 1059 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); |
1060 | |||
1061 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | ||
1062 | |||
1063 | BUG_ON(dev->priv && "forgot to free"); | ||
1064 | memset(&dev->core, 0, sizeof(dev->core)); | ||
928 | #endif | 1065 | #endif |
929 | kfree(dev); | ||
930 | } | 1066 | } |
931 | 1067 | ||
932 | /** | 1068 | /** |
@@ -935,11 +1071,12 @@ static void ps3_vuart_port_release_device(struct device *_dev) | |||
935 | 1071 | ||
936 | int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) | 1072 | int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) |
937 | { | 1073 | { |
938 | int result; | ||
939 | static unsigned int dev_count = 1; | 1074 | static unsigned int dev_count = 1; |
940 | 1075 | ||
1076 | BUG_ON(dev->priv && "forgot to free"); | ||
1077 | |||
941 | dev->core.parent = NULL; | 1078 | dev->core.parent = NULL; |
942 | dev->core.bus = &ps3_vuart; | 1079 | dev->core.bus = &ps3_vuart_bus; |
943 | dev->core.release = ps3_vuart_port_release_device; | 1080 | dev->core.release = ps3_vuart_port_release_device; |
944 | 1081 | ||
945 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", | 1082 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", |
@@ -947,9 +1084,7 @@ int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) | |||
947 | 1084 | ||
948 | dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); | 1085 | dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); |
949 | 1086 | ||
950 | result = device_register(&dev->core); | 1087 | return device_register(&dev->core); |
951 | |||
952 | return result; | ||
953 | } | 1088 | } |
954 | 1089 | ||
955 | EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); | 1090 | EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); |
@@ -963,7 +1098,7 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) | |||
963 | int result; | 1098 | int result; |
964 | 1099 | ||
965 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | 1100 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); |
966 | drv->core.bus = &ps3_vuart; | 1101 | drv->core.bus = &ps3_vuart_bus; |
967 | result = driver_register(&drv->core); | 1102 | result = driver_register(&drv->core); |
968 | return result; | 1103 | return result; |
969 | } | 1104 | } |
@@ -976,6 +1111,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); | |||
976 | 1111 | ||
977 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) | 1112 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) |
978 | { | 1113 | { |
1114 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | ||
979 | driver_unregister(&drv->core); | 1115 | driver_unregister(&drv->core); |
980 | } | 1116 | } |
981 | 1117 | ||
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 2cbf728a3a0b..1be992d568c8 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h | |||
@@ -21,6 +21,44 @@ | |||
21 | #if !defined(_PS3_VUART_H) | 21 | #if !defined(_PS3_VUART_H) |
22 | #define _PS3_VUART_H | 22 | #define _PS3_VUART_H |
23 | 23 | ||
24 | #include <asm/ps3.h> | ||
25 | |||
26 | struct ps3_vuart_stats { | ||
27 | unsigned long bytes_written; | ||
28 | unsigned long bytes_read; | ||
29 | unsigned long tx_interrupts; | ||
30 | unsigned long rx_interrupts; | ||
31 | unsigned long disconnect_interrupts; | ||
32 | }; | ||
33 | |||
34 | struct ps3_vuart_work { | ||
35 | struct work_struct work; | ||
36 | unsigned long trigger; | ||
37 | spinlock_t lock; | ||
38 | struct ps3_vuart_port_device* dev; /* to convert work to device */ | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * struct ps3_vuart_port_priv - private vuart device data. | ||
43 | */ | ||
44 | |||
45 | struct ps3_vuart_port_priv { | ||
46 | unsigned int port_number; | ||
47 | u64 interrupt_mask; | ||
48 | |||
49 | struct { | ||
50 | spinlock_t lock; | ||
51 | struct list_head head; | ||
52 | } tx_list; | ||
53 | struct { | ||
54 | unsigned long bytes_held; | ||
55 | spinlock_t lock; | ||
56 | struct list_head head; | ||
57 | } rx_list; | ||
58 | struct ps3_vuart_stats stats; | ||
59 | struct ps3_vuart_work work; | ||
60 | }; | ||
61 | |||
24 | /** | 62 | /** |
25 | * struct ps3_vuart_port_driver - a driver for a device on a vuart port | 63 | * struct ps3_vuart_port_driver - a driver for a device on a vuart port |
26 | */ | 64 | */ |
@@ -41,10 +79,6 @@ struct ps3_vuart_port_driver { | |||
41 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); | 79 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); |
42 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); | 80 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); |
43 | 81 | ||
44 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, | ||
45 | const void* buf, unsigned int bytes); | ||
46 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
47 | unsigned int bytes); | ||
48 | static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( | 82 | static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( |
49 | struct device_driver *_drv) | 83 | struct device_driver *_drv) |
50 | { | 84 | { |
@@ -55,5 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device( | |||
55 | { | 89 | { |
56 | return container_of(_dev, struct ps3_vuart_port_device, core); | 90 | return container_of(_dev, struct ps3_vuart_port_device, core); |
57 | } | 91 | } |
92 | static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( | ||
93 | struct work_struct *_work) | ||
94 | { | ||
95 | struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, | ||
96 | work); | ||
97 | return vw->dev; | ||
98 | } | ||
99 | |||
100 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | ||
101 | unsigned int bytes); | ||
102 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
103 | unsigned int bytes); | ||
104 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | ||
105 | unsigned int bytes); | ||
106 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); | ||
107 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | ||
108 | unsigned int bytes); | ||
58 | 109 | ||
59 | #endif | 110 | #endif |
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 787a8f134677..fa455996ad8f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c | |||
@@ -285,7 +285,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) | |||
285 | int __init cpm_uart_init_portdesc(void) | 285 | int __init cpm_uart_init_portdesc(void) |
286 | { | 286 | { |
287 | #if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2) | 287 | #if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2) |
288 | u32 addr; | 288 | u16 *addr; |
289 | #endif | 289 | #endif |
290 | pr_debug("CPM uart[-]:init portdesc\n"); | 290 | pr_debug("CPM uart[-]:init portdesc\n"); |
291 | 291 | ||
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 955bbd653e22..8d24cd521056 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c | |||
@@ -995,8 +995,10 @@ mpc52xx_uart_of_remove(struct of_device *op) | |||
995 | struct uart_port *port = dev_get_drvdata(&op->dev); | 995 | struct uart_port *port = dev_get_drvdata(&op->dev); |
996 | dev_set_drvdata(&op->dev, NULL); | 996 | dev_set_drvdata(&op->dev, NULL); |
997 | 997 | ||
998 | if (port) | 998 | if (port) { |
999 | uart_remove_one_port(&mpc52xx_uart_driver, port); | 999 | uart_remove_one_port(&mpc52xx_uart_driver, port); |
1000 | irq_dispose_mapping(port->irq); | ||
1001 | } | ||
1000 | 1002 | ||
1001 | return 0; | 1003 | return 0; |
1002 | } | 1004 | } |