1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * PS3 virtual uart |
4 | * |
5 | * Copyright (C) 2006 Sony Computer Entertainment Inc. |
6 | * Copyright 2006 Sony Corp. |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/module.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/workqueue.h> |
14 | #include <linux/bitops.h> |
15 | #include <asm/ps3.h> |
16 | |
17 | #include <asm/firmware.h> |
18 | #include <asm/lv1call.h> |
19 | |
20 | #include "vuart.h" |
21 | |
22 | MODULE_AUTHOR("Sony Corporation" ); |
23 | MODULE_LICENSE("GPL v2" ); |
24 | MODULE_DESCRIPTION("PS3 vuart" ); |
25 | |
26 | /** |
27 | * vuart - An inter-partition data link service. |
28 | * port 0: PS3 AV Settings. |
29 | * port 2: PS3 System Manager. |
30 | * |
31 | * The vuart provides a bi-directional byte stream data link between logical |
32 | * partitions. Its primary role is as a communications link between the guest |
33 | * OS and the system policy module. The current HV does not support any |
34 | * connections other than those listed. |
35 | */ |
36 | |
37 | enum {PORT_COUNT = 3,}; |
38 | |
39 | enum vuart_param { |
40 | PARAM_TX_TRIGGER = 0, |
41 | PARAM_RX_TRIGGER = 1, |
42 | PARAM_INTERRUPT_MASK = 2, |
43 | PARAM_RX_BUF_SIZE = 3, /* read only */ |
44 | PARAM_RX_BYTES = 4, /* read only */ |
45 | PARAM_TX_BUF_SIZE = 5, /* read only */ |
46 | PARAM_TX_BYTES = 6, /* read only */ |
47 | PARAM_INTERRUPT_STATUS = 7, /* read only */ |
48 | }; |
49 | |
50 | enum vuart_interrupt_bit { |
51 | INTERRUPT_BIT_TX = 0, |
52 | INTERRUPT_BIT_RX = 1, |
53 | INTERRUPT_BIT_DISCONNECT = 2, |
54 | }; |
55 | |
56 | enum vuart_interrupt_mask { |
57 | INTERRUPT_MASK_TX = 1, |
58 | INTERRUPT_MASK_RX = 2, |
59 | INTERRUPT_MASK_DISCONNECT = 4, |
60 | }; |
61 | |
62 | /** |
63 | * struct ps3_vuart_port_priv - private vuart device data. |
64 | */ |
65 | |
66 | struct ps3_vuart_port_priv { |
67 | u64 interrupt_mask; |
68 | |
69 | struct { |
70 | spinlock_t lock; |
71 | struct list_head head; |
72 | } tx_list; |
73 | struct { |
74 | struct ps3_vuart_work work; |
75 | unsigned long bytes_held; |
76 | spinlock_t lock; |
77 | struct list_head head; |
78 | } rx_list; |
79 | struct ps3_vuart_stats stats; |
80 | }; |
81 | |
82 | static struct ps3_vuart_port_priv *to_port_priv( |
83 | struct ps3_system_bus_device *dev) |
84 | { |
85 | BUG_ON(!dev); |
86 | BUG_ON(!dev->driver_priv); |
87 | return (struct ps3_vuart_port_priv *)dev->driver_priv; |
88 | } |
89 | |
90 | /** |
91 | * struct ports_bmp - bitmap indicating ports needing service. |
92 | * |
93 | * A 256 bit read only bitmap indicating ports needing service. Do not write |
94 | * to these bits. Must not cross a page boundary. |
95 | */ |
96 | |
97 | struct ports_bmp { |
98 | u64 status; |
99 | u64 unused[3]; |
100 | } __attribute__((aligned(32))); |
101 | |
102 | #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) |
103 | static void __maybe_unused _dump_ports_bmp( |
104 | const struct ports_bmp *bmp, const char *func, int line) |
105 | { |
106 | pr_debug("%s:%d: ports_bmp: %016llxh\n" , func, line, bmp->status); |
107 | } |
108 | |
109 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) |
110 | static void __maybe_unused _dump_port_params(unsigned int port_number, |
111 | const char *func, int line) |
112 | { |
113 | #if defined(DEBUG) |
114 | static const char *strings[] = { |
115 | "tx_trigger " , |
116 | "rx_trigger " , |
117 | "interrupt_mask " , |
118 | "rx_buf_size " , |
119 | "rx_bytes " , |
120 | "tx_buf_size " , |
121 | "tx_bytes " , |
122 | "interrupt_status" , |
123 | }; |
124 | int result; |
125 | unsigned int i; |
126 | u64 value; |
127 | |
128 | for (i = 0; i < ARRAY_SIZE(strings); i++) { |
129 | result = lv1_get_virtual_uart_param(port_number, i, &value); |
130 | |
131 | if (result) { |
132 | pr_debug("%s:%d: port_%u: %s failed: %s\n" , func, line, |
133 | port_number, strings[i], ps3_result(result)); |
134 | continue; |
135 | } |
136 | pr_debug("%s:%d: port_%u: %s = %lxh\n" , |
137 | func, line, port_number, strings[i], value); |
138 | } |
139 | #endif |
140 | } |
141 | |
142 | int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, |
143 | struct vuart_triggers *trig) |
144 | { |
145 | int result; |
146 | u64 size; |
147 | u64 val; |
148 | u64 tx; |
149 | |
150 | result = lv1_get_virtual_uart_param(dev->port_number, |
151 | PARAM_TX_TRIGGER, &tx); |
152 | trig->tx = tx; |
153 | |
154 | if (result) { |
155 | dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n" , |
156 | __func__, __LINE__, ps3_result(result)); |
157 | return result; |
158 | } |
159 | |
160 | result = lv1_get_virtual_uart_param(dev->port_number, |
161 | PARAM_RX_BUF_SIZE, &size); |
162 | |
163 | if (result) { |
164 | dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n" , |
165 | __func__, __LINE__, ps3_result(result)); |
166 | return result; |
167 | } |
168 | |
169 | result = lv1_get_virtual_uart_param(dev->port_number, |
170 | PARAM_RX_TRIGGER, &val); |
171 | |
172 | if (result) { |
173 | dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n" , |
174 | __func__, __LINE__, ps3_result(result)); |
175 | return result; |
176 | } |
177 | |
178 | trig->rx = size - val; |
179 | |
180 | dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n" , __func__, __LINE__, |
181 | trig->tx, trig->rx); |
182 | |
183 | return result; |
184 | } |
185 | |
186 | int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx, |
187 | unsigned int rx) |
188 | { |
189 | int result; |
190 | u64 size; |
191 | |
192 | result = lv1_set_virtual_uart_param(dev->port_number, |
193 | PARAM_TX_TRIGGER, tx); |
194 | |
195 | if (result) { |
196 | dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n" , |
197 | __func__, __LINE__, ps3_result(result)); |
198 | return result; |
199 | } |
200 | |
201 | result = lv1_get_virtual_uart_param(dev->port_number, |
202 | PARAM_RX_BUF_SIZE, &size); |
203 | |
204 | if (result) { |
205 | dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n" , |
206 | __func__, __LINE__, ps3_result(result)); |
207 | return result; |
208 | } |
209 | |
210 | result = lv1_set_virtual_uart_param(dev->port_number, |
211 | PARAM_RX_TRIGGER, size - rx); |
212 | |
213 | if (result) { |
214 | dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n" , |
215 | __func__, __LINE__, ps3_result(result)); |
216 | return result; |
217 | } |
218 | |
219 | dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n" , __func__, __LINE__, |
220 | tx, rx); |
221 | |
222 | return result; |
223 | } |
224 | |
225 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev, |
226 | u64 *bytes_waiting) |
227 | { |
228 | int result; |
229 | |
230 | result = lv1_get_virtual_uart_param(dev->port_number, |
231 | PARAM_RX_BYTES, bytes_waiting); |
232 | |
233 | if (result) |
234 | dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n" , |
235 | __func__, __LINE__, ps3_result(result)); |
236 | |
237 | dev_dbg(&dev->core, "%s:%d: %llxh\n" , __func__, __LINE__, |
238 | *bytes_waiting); |
239 | return result; |
240 | } |
241 | |
242 | /** |
243 | * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources. |
244 | * @dev: The struct ps3_system_bus_device instance. |
245 | * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables. |
246 | */ |
247 | |
248 | static int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev, |
249 | unsigned long mask) |
250 | { |
251 | int result; |
252 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
253 | |
254 | dev_dbg(&dev->core, "%s:%d: %lxh\n" , __func__, __LINE__, mask); |
255 | |
256 | priv->interrupt_mask = mask; |
257 | |
258 | result = lv1_set_virtual_uart_param(dev->port_number, |
259 | PARAM_INTERRUPT_MASK, priv->interrupt_mask); |
260 | |
261 | if (result) |
262 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n" , |
263 | __func__, __LINE__, ps3_result(result)); |
264 | |
265 | return result; |
266 | } |
267 | |
268 | static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev, |
269 | unsigned long *status) |
270 | { |
271 | int result; |
272 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
273 | u64 tmp; |
274 | |
275 | result = lv1_get_virtual_uart_param(dev->port_number, |
276 | PARAM_INTERRUPT_STATUS, &tmp); |
277 | |
278 | if (result) |
279 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n" , |
280 | __func__, __LINE__, ps3_result(result)); |
281 | |
282 | *status = tmp & priv->interrupt_mask; |
283 | |
284 | dev_dbg(&dev->core, "%s:%d: m %llxh, s %llxh, m&s %lxh\n" , |
285 | __func__, __LINE__, priv->interrupt_mask, tmp, *status); |
286 | |
287 | return result; |
288 | } |
289 | |
290 | int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev) |
291 | { |
292 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
293 | |
294 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 |
295 | : ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
296 | | INTERRUPT_MASK_TX); |
297 | } |
298 | |
299 | int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev) |
300 | { |
301 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
302 | |
303 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 |
304 | : ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
305 | | INTERRUPT_MASK_RX); |
306 | } |
307 | |
308 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
309 | { |
310 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
311 | |
312 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 |
313 | : ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
314 | | INTERRUPT_MASK_DISCONNECT); |
315 | } |
316 | |
317 | int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev) |
318 | { |
319 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
320 | |
321 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) |
322 | ? ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
323 | & ~INTERRUPT_MASK_TX) : 0; |
324 | } |
325 | |
326 | int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev) |
327 | { |
328 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
329 | |
330 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) |
331 | ? ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
332 | & ~INTERRUPT_MASK_RX) : 0; |
333 | } |
334 | |
335 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
336 | { |
337 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
338 | |
339 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) |
340 | ? ps3_vuart_set_interrupt_mask(dev, mask: priv->interrupt_mask |
341 | & ~INTERRUPT_MASK_DISCONNECT) : 0; |
342 | } |
343 | |
344 | /** |
345 | * ps3_vuart_raw_write - Low level write helper. |
346 | * @dev: The struct ps3_system_bus_device instance. |
347 | * |
348 | * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. |
349 | */ |
350 | |
351 | static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev, |
352 | const void *buf, unsigned int bytes, u64 *bytes_written) |
353 | { |
354 | int result; |
355 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
356 | |
357 | result = lv1_write_virtual_uart(dev->port_number, |
358 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); |
359 | |
360 | if (result) { |
361 | dev_warn(&dev->core, "%s:%d: lv1_write_virtual_uart failed: " |
362 | "%s\n" , __func__, __LINE__, ps3_result(result)); |
363 | return result; |
364 | } |
365 | |
366 | priv->stats.bytes_written += *bytes_written; |
367 | |
368 | dev_dbg(&dev->core, "%s:%d: wrote %llxh/%xh=>%lxh\n" , __func__, __LINE__, |
369 | *bytes_written, bytes, priv->stats.bytes_written); |
370 | |
371 | return result; |
372 | } |
373 | |
374 | /** |
375 | * ps3_vuart_raw_read - Low level read helper. |
376 | * @dev: The struct ps3_system_bus_device instance. |
377 | * |
378 | * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. |
379 | */ |
380 | |
381 | static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf, |
382 | unsigned int bytes, u64 *bytes_read) |
383 | { |
384 | int result; |
385 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
386 | |
387 | dev_dbg(&dev->core, "%s:%d: %xh\n" , __func__, __LINE__, bytes); |
388 | |
389 | result = lv1_read_virtual_uart(dev->port_number, |
390 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); |
391 | |
392 | if (result) { |
393 | dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n" , |
394 | __func__, __LINE__, ps3_result(result)); |
395 | return result; |
396 | } |
397 | |
398 | priv->stats.bytes_read += *bytes_read; |
399 | |
400 | dev_dbg(&dev->core, "%s:%d: read %llxh/%xh=>%lxh\n" , __func__, __LINE__, |
401 | *bytes_read, bytes, priv->stats.bytes_read); |
402 | |
403 | return result; |
404 | } |
405 | |
406 | /** |
407 | * ps3_vuart_clear_rx_bytes - Discard bytes received. |
408 | * @dev: The struct ps3_system_bus_device instance. |
409 | * @bytes: Max byte count to discard, zero = all pending. |
410 | * |
411 | * Used to clear pending rx interrupt source. Will not block. |
412 | */ |
413 | |
414 | void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, |
415 | unsigned int bytes) |
416 | { |
417 | int result; |
418 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
419 | u64 bytes_waiting; |
420 | void *tmp; |
421 | |
422 | result = ps3_vuart_get_rx_bytes_waiting(dev, bytes_waiting: &bytes_waiting); |
423 | |
424 | BUG_ON(result); |
425 | |
426 | bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting; |
427 | |
428 | dev_dbg(&dev->core, "%s:%d: %u\n" , __func__, __LINE__, bytes); |
429 | |
430 | if (!bytes) |
431 | return; |
432 | |
433 | /* Add some extra space for recently arrived data. */ |
434 | |
435 | bytes += 128; |
436 | |
437 | tmp = kmalloc(size: bytes, GFP_KERNEL); |
438 | |
439 | if (!tmp) |
440 | return; |
441 | |
442 | ps3_vuart_raw_read(dev, buf: tmp, bytes, bytes_read: &bytes_waiting); |
443 | |
444 | kfree(objp: tmp); |
445 | |
446 | /* Don't include these bytes in the stats. */ |
447 | |
448 | priv->stats.bytes_read -= bytes_waiting; |
449 | } |
450 | EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes); |
451 | |
452 | /** |
453 | * struct list_buffer - An element for a port device fifo buffer list. |
454 | */ |
455 | |
456 | struct list_buffer { |
457 | struct list_head link; |
458 | const unsigned char *head; |
459 | const unsigned char *tail; |
460 | unsigned long dbg_number; |
461 | unsigned char data[]; |
462 | }; |
463 | |
464 | /** |
465 | * ps3_vuart_write - the entry point for writing data to a port |
466 | * @dev: The struct ps3_system_bus_device instance. |
467 | * |
468 | * If the port is idle on entry as much of the incoming data is written to |
469 | * the port as the port will accept. Otherwise a list buffer is created |
470 | * and any remaning incoming data is copied to that buffer. The buffer is |
471 | * then enqueued for transmision via the transmit interrupt. |
472 | */ |
473 | |
474 | int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, |
475 | unsigned int bytes) |
476 | { |
477 | static unsigned long dbg_number; |
478 | int result; |
479 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
480 | unsigned long flags; |
481 | struct list_buffer *lb; |
482 | |
483 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n" , __func__, __LINE__, |
484 | bytes, bytes); |
485 | |
486 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
487 | |
488 | if (list_empty(head: &priv->tx_list.head)) { |
489 | u64 bytes_written; |
490 | |
491 | result = ps3_vuart_raw_write(dev, buf, bytes, bytes_written: &bytes_written); |
492 | |
493 | spin_unlock_irqrestore(lock: &priv->tx_list.lock, flags); |
494 | |
495 | if (result) { |
496 | dev_dbg(&dev->core, |
497 | "%s:%d: ps3_vuart_raw_write failed\n" , |
498 | __func__, __LINE__); |
499 | return result; |
500 | } |
501 | |
502 | if (bytes_written == bytes) { |
503 | dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n" , |
504 | __func__, __LINE__, bytes); |
505 | return 0; |
506 | } |
507 | |
508 | bytes -= bytes_written; |
509 | buf += bytes_written; |
510 | } else |
511 | spin_unlock_irqrestore(lock: &priv->tx_list.lock, flags); |
512 | |
513 | lb = kmalloc(size: sizeof(struct list_buffer) + bytes, GFP_KERNEL); |
514 | |
515 | if (!lb) |
516 | return -ENOMEM; |
517 | |
518 | memcpy(lb->data, buf, bytes); |
519 | lb->head = lb->data; |
520 | lb->tail = lb->data + bytes; |
521 | lb->dbg_number = ++dbg_number; |
522 | |
523 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
524 | list_add_tail(new: &lb->link, head: &priv->tx_list.head); |
525 | ps3_vuart_enable_interrupt_tx(dev); |
526 | spin_unlock_irqrestore(lock: &priv->tx_list.lock, flags); |
527 | |
528 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n" , |
529 | __func__, __LINE__, lb->dbg_number, bytes); |
530 | |
531 | return 0; |
532 | } |
533 | EXPORT_SYMBOL_GPL(ps3_vuart_write); |
534 | |
535 | /** |
536 | * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list. |
537 | * @dev: The struct ps3_system_bus_device instance. |
538 | * @bytes_queued: Number of bytes queued to the buffer list. |
539 | * |
540 | * Must be called with priv->rx_list.lock held. |
541 | */ |
542 | |
543 | static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev, |
544 | u64 *bytes_queued) |
545 | { |
546 | static unsigned long dbg_number; |
547 | int result; |
548 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
549 | struct list_buffer *lb; |
550 | u64 bytes; |
551 | |
552 | *bytes_queued = 0; |
553 | |
554 | result = ps3_vuart_get_rx_bytes_waiting(dev, bytes_waiting: &bytes); |
555 | BUG_ON(result); |
556 | |
557 | if (result) |
558 | return -EIO; |
559 | |
560 | if (!bytes) |
561 | return 0; |
562 | |
563 | /* Add some extra space for recently arrived data. */ |
564 | |
565 | bytes += 128; |
566 | |
567 | lb = kmalloc(size: sizeof(struct list_buffer) + bytes, GFP_ATOMIC); |
568 | |
569 | if (!lb) |
570 | return -ENOMEM; |
571 | |
572 | ps3_vuart_raw_read(dev, buf: lb->data, bytes, bytes_read: &bytes); |
573 | |
574 | lb->head = lb->data; |
575 | lb->tail = lb->data + bytes; |
576 | lb->dbg_number = ++dbg_number; |
577 | |
578 | list_add_tail(new: &lb->link, head: &priv->rx_list.head); |
579 | priv->rx_list.bytes_held += bytes; |
580 | |
581 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %llxh bytes\n" , |
582 | __func__, __LINE__, lb->dbg_number, bytes); |
583 | |
584 | *bytes_queued = bytes; |
585 | |
586 | return 0; |
587 | } |
588 | |
589 | /** |
590 | * ps3_vuart_read - The entry point for reading data from a port. |
591 | * |
592 | * Queue data waiting at the port, and if enough bytes to satisfy the request |
593 | * are held in the buffer list those bytes are dequeued and copied to the |
594 | * caller's buffer. Emptied list buffers are retiered. If the request cannot |
595 | * be statified by bytes held in the list buffers -EAGAIN is returned. |
596 | */ |
597 | |
598 | int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, |
599 | unsigned int bytes) |
600 | { |
601 | int result; |
602 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
603 | unsigned long flags; |
604 | struct list_buffer *lb, *n; |
605 | unsigned long bytes_read; |
606 | |
607 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n" , __func__, __LINE__, |
608 | bytes, bytes); |
609 | |
610 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
611 | |
612 | /* Queue rx bytes here for polled reads. */ |
613 | |
614 | while (priv->rx_list.bytes_held < bytes) { |
615 | u64 tmp; |
616 | |
617 | result = ps3_vuart_queue_rx_bytes(dev, bytes_queued: &tmp); |
618 | if (result || !tmp) { |
619 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n" , |
620 | __func__, __LINE__, |
621 | bytes - priv->rx_list.bytes_held); |
622 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
623 | return -EAGAIN; |
624 | } |
625 | } |
626 | |
627 | list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) { |
628 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); |
629 | |
630 | memcpy(buf, lb->head, bytes_read); |
631 | buf += bytes_read; |
632 | bytes -= bytes_read; |
633 | priv->rx_list.bytes_held -= bytes_read; |
634 | |
635 | if (bytes_read < lb->tail - lb->head) { |
636 | lb->head += bytes_read; |
637 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " |
638 | "bytes\n" , __func__, __LINE__, lb->dbg_number, |
639 | bytes_read); |
640 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
641 | return 0; |
642 | } |
643 | |
644 | dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh " |
645 | "bytes\n" , __func__, __LINE__, lb->dbg_number, |
646 | bytes_read); |
647 | |
648 | list_del(entry: &lb->link); |
649 | kfree(objp: lb); |
650 | } |
651 | |
652 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
653 | return 0; |
654 | } |
655 | EXPORT_SYMBOL_GPL(ps3_vuart_read); |
656 | |
657 | /** |
658 | * ps3_vuart_work - Asynchronous read handler. |
659 | */ |
660 | |
661 | static void ps3_vuart_work(struct work_struct *work) |
662 | { |
663 | struct ps3_system_bus_device *dev = |
664 | ps3_vuart_work_to_system_bus_dev(work: work); |
665 | struct ps3_vuart_port_driver *drv = |
666 | ps3_system_bus_dev_to_vuart_drv(dev: dev); |
667 | |
668 | BUG_ON(!drv); |
669 | drv->work(dev); |
670 | } |
671 | |
672 | int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes) |
673 | { |
674 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
675 | unsigned long flags; |
676 | |
677 | if (priv->rx_list.work.trigger) { |
678 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n" , |
679 | __func__, __LINE__); |
680 | return -EAGAIN; |
681 | } |
682 | |
683 | BUG_ON(!bytes); |
684 | |
685 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
686 | if (priv->rx_list.bytes_held >= bytes) { |
687 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n" , |
688 | __func__, __LINE__, bytes); |
689 | schedule_work(work: &priv->rx_list.work.work); |
690 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
691 | return 0; |
692 | } |
693 | |
694 | priv->rx_list.work.trigger = bytes; |
695 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
696 | |
697 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n" , __func__, |
698 | __LINE__, bytes, bytes); |
699 | |
700 | return 0; |
701 | } |
702 | EXPORT_SYMBOL_GPL(ps3_vuart_read_async); |
703 | |
704 | void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev) |
705 | { |
706 | to_port_priv(dev)->rx_list.work.trigger = 0; |
707 | } |
708 | EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async); |
709 | |
710 | /** |
711 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler |
712 | * |
713 | * Services the transmit interrupt for the port. Writes as much data from the |
714 | * buffer list as the port will accept. Retires any emptied list buffers and |
715 | * adjusts the final list buffer state for a partial write. |
716 | */ |
717 | |
718 | static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev) |
719 | { |
720 | int result = 0; |
721 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
722 | unsigned long flags; |
723 | struct list_buffer *lb, *n; |
724 | unsigned long bytes_total = 0; |
725 | |
726 | dev_dbg(&dev->core, "%s:%d\n" , __func__, __LINE__); |
727 | |
728 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
729 | |
730 | list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) { |
731 | |
732 | u64 bytes_written; |
733 | |
734 | result = ps3_vuart_raw_write(dev, buf: lb->head, bytes: lb->tail - lb->head, |
735 | bytes_written: &bytes_written); |
736 | |
737 | if (result) { |
738 | dev_dbg(&dev->core, |
739 | "%s:%d: ps3_vuart_raw_write failed\n" , |
740 | __func__, __LINE__); |
741 | break; |
742 | } |
743 | |
744 | bytes_total += bytes_written; |
745 | |
746 | if (bytes_written < lb->tail - lb->head) { |
747 | lb->head += bytes_written; |
748 | dev_dbg(&dev->core, |
749 | "%s:%d cleared buf_%lu, %llxh bytes\n" , |
750 | __func__, __LINE__, lb->dbg_number, |
751 | bytes_written); |
752 | goto port_full; |
753 | } |
754 | |
755 | dev_dbg(&dev->core, "%s:%d free buf_%lu\n" , __func__, __LINE__, |
756 | lb->dbg_number); |
757 | |
758 | list_del(entry: &lb->link); |
759 | kfree(objp: lb); |
760 | } |
761 | |
762 | ps3_vuart_disable_interrupt_tx(dev); |
763 | port_full: |
764 | spin_unlock_irqrestore(lock: &priv->tx_list.lock, flags); |
765 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n" , |
766 | __func__, __LINE__, bytes_total); |
767 | return result; |
768 | } |
769 | |
770 | /** |
771 | * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler |
772 | * |
773 | * Services the receive interrupt for the port. Creates a list buffer and |
774 | * copies all waiting port data to that buffer and enqueues the buffer in the |
775 | * buffer list. Buffer list data is dequeued via ps3_vuart_read. |
776 | */ |
777 | |
778 | static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev) |
779 | { |
780 | int result; |
781 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
782 | unsigned long flags; |
783 | u64 bytes; |
784 | |
785 | dev_dbg(&dev->core, "%s:%d\n" , __func__, __LINE__); |
786 | |
787 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
788 | result = ps3_vuart_queue_rx_bytes(dev, bytes_queued: &bytes); |
789 | |
790 | if (result) { |
791 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
792 | return result; |
793 | } |
794 | |
795 | if (priv->rx_list.work.trigger && priv->rx_list.bytes_held |
796 | >= priv->rx_list.work.trigger) { |
797 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n" , |
798 | __func__, __LINE__, priv->rx_list.work.trigger); |
799 | priv->rx_list.work.trigger = 0; |
800 | schedule_work(work: &priv->rx_list.work.work); |
801 | } |
802 | |
803 | spin_unlock_irqrestore(lock: &priv->rx_list.lock, flags); |
804 | return result; |
805 | } |
806 | |
807 | static int ps3_vuart_handle_interrupt_disconnect( |
808 | struct ps3_system_bus_device *dev) |
809 | { |
810 | dev_dbg(&dev->core, "%s:%d\n" , __func__, __LINE__); |
811 | BUG_ON("no support" ); |
812 | return -1; |
813 | } |
814 | |
815 | /** |
816 | * ps3_vuart_handle_port_interrupt - second stage interrupt handler |
817 | * |
818 | * Services any pending interrupt types for the port. Passes control to the |
819 | * third stage type specific interrupt handler. Returns control to the first |
820 | * stage handler after one iteration. |
821 | */ |
822 | |
823 | static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev) |
824 | { |
825 | int result; |
826 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
827 | unsigned long status; |
828 | |
829 | result = ps3_vuart_get_interrupt_status(dev, status: &status); |
830 | |
831 | if (result) |
832 | return result; |
833 | |
834 | dev_dbg(&dev->core, "%s:%d: status: %lxh\n" , __func__, __LINE__, |
835 | status); |
836 | |
837 | if (status & INTERRUPT_MASK_DISCONNECT) { |
838 | priv->stats.disconnect_interrupts++; |
839 | result = ps3_vuart_handle_interrupt_disconnect(dev); |
840 | if (result) |
841 | ps3_vuart_disable_interrupt_disconnect(dev); |
842 | } |
843 | |
844 | if (status & INTERRUPT_MASK_TX) { |
845 | priv->stats.tx_interrupts++; |
846 | result = ps3_vuart_handle_interrupt_tx(dev); |
847 | if (result) |
848 | ps3_vuart_disable_interrupt_tx(dev); |
849 | } |
850 | |
851 | if (status & INTERRUPT_MASK_RX) { |
852 | priv->stats.rx_interrupts++; |
853 | result = ps3_vuart_handle_interrupt_rx(dev); |
854 | if (result) |
855 | ps3_vuart_disable_interrupt_rx(dev); |
856 | } |
857 | |
858 | return 0; |
859 | } |
860 | |
861 | static struct vuart_bus_priv { |
862 | struct ports_bmp *bmp; |
863 | unsigned int virq; |
864 | struct mutex probe_mutex; |
865 | int use_count; |
866 | struct ps3_system_bus_device *devices[PORT_COUNT]; |
867 | } vuart_bus_priv; |
868 | |
869 | /** |
870 | * ps3_vuart_irq_handler - first stage interrupt handler |
871 | * |
872 | * Loops finding any interrupting port and its associated instance data. |
873 | * Passes control to the second stage port specific interrupt handler. Loops |
874 | * until all outstanding interrupts are serviced. |
875 | */ |
876 | |
877 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) |
878 | { |
879 | struct vuart_bus_priv *bus_priv = _private; |
880 | |
881 | BUG_ON(!bus_priv); |
882 | |
883 | while (1) { |
884 | unsigned int port; |
885 | |
886 | dump_ports_bmp(bus_priv->bmp); |
887 | |
888 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status); |
889 | |
890 | if (port == BITS_PER_LONG) |
891 | break; |
892 | |
893 | BUG_ON(port >= PORT_COUNT); |
894 | BUG_ON(!bus_priv->devices[port]); |
895 | |
896 | ps3_vuart_handle_port_interrupt(dev: bus_priv->devices[port]); |
897 | } |
898 | |
899 | return IRQ_HANDLED; |
900 | } |
901 | |
902 | static int ps3_vuart_bus_interrupt_get(void) |
903 | { |
904 | int result; |
905 | |
906 | pr_debug(" -> %s:%d\n" , __func__, __LINE__); |
907 | |
908 | vuart_bus_priv.use_count++; |
909 | |
910 | BUG_ON(vuart_bus_priv.use_count > 2); |
911 | |
912 | if (vuart_bus_priv.use_count != 1) |
913 | return 0; |
914 | |
915 | BUG_ON(vuart_bus_priv.bmp); |
916 | |
917 | vuart_bus_priv.bmp = kzalloc(size: sizeof(struct ports_bmp), GFP_KERNEL); |
918 | |
919 | if (!vuart_bus_priv.bmp) { |
920 | result = -ENOMEM; |
921 | goto fail_bmp_malloc; |
922 | } |
923 | |
924 | result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp, |
925 | &vuart_bus_priv.virq); |
926 | |
927 | if (result) { |
928 | pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n" , |
929 | __func__, __LINE__, result); |
930 | result = -EPERM; |
931 | goto fail_alloc_irq; |
932 | } |
933 | |
934 | result = request_irq(irq: vuart_bus_priv.virq, handler: ps3_vuart_irq_handler, |
935 | flags: 0, name: "vuart" , dev: &vuart_bus_priv); |
936 | |
937 | if (result) { |
938 | pr_debug("%s:%d: request_irq failed (%d)\n" , |
939 | __func__, __LINE__, result); |
940 | goto fail_request_irq; |
941 | } |
942 | |
943 | pr_debug(" <- %s:%d: ok\n" , __func__, __LINE__); |
944 | return result; |
945 | |
946 | fail_request_irq: |
947 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); |
948 | vuart_bus_priv.virq = 0; |
949 | fail_alloc_irq: |
950 | kfree(objp: vuart_bus_priv.bmp); |
951 | vuart_bus_priv.bmp = NULL; |
952 | fail_bmp_malloc: |
953 | vuart_bus_priv.use_count--; |
954 | pr_debug(" <- %s:%d: failed\n" , __func__, __LINE__); |
955 | return result; |
956 | } |
957 | |
958 | static int ps3_vuart_bus_interrupt_put(void) |
959 | { |
960 | pr_debug(" -> %s:%d\n" , __func__, __LINE__); |
961 | |
962 | vuart_bus_priv.use_count--; |
963 | |
964 | BUG_ON(vuart_bus_priv.use_count < 0); |
965 | |
966 | if (vuart_bus_priv.use_count != 0) |
967 | return 0; |
968 | |
969 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); |
970 | |
971 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); |
972 | vuart_bus_priv.virq = 0; |
973 | |
974 | kfree(objp: vuart_bus_priv.bmp); |
975 | vuart_bus_priv.bmp = NULL; |
976 | |
977 | pr_debug(" <- %s:%d\n" , __func__, __LINE__); |
978 | return 0; |
979 | } |
980 | |
981 | static int ps3_vuart_probe(struct ps3_system_bus_device *dev) |
982 | { |
983 | int result; |
984 | struct ps3_vuart_port_driver *drv; |
985 | struct ps3_vuart_port_priv *priv = NULL; |
986 | |
987 | dev_dbg(&dev->core, "%s:%d\n" , __func__, __LINE__); |
988 | |
989 | drv = ps3_system_bus_dev_to_vuart_drv(dev: dev); |
990 | BUG_ON(!drv); |
991 | |
992 | dev_dbg(&dev->core, "%s:%d: (%s)\n" , __func__, __LINE__, |
993 | drv->core.core.name); |
994 | |
995 | if (dev->port_number >= PORT_COUNT) { |
996 | BUG(); |
997 | return -EINVAL; |
998 | } |
999 | |
1000 | mutex_lock(&vuart_bus_priv.probe_mutex); |
1001 | |
1002 | result = ps3_vuart_bus_interrupt_get(); |
1003 | |
1004 | if (result) |
1005 | goto fail_setup_interrupt; |
1006 | |
1007 | if (vuart_bus_priv.devices[dev->port_number]) { |
1008 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n" , __func__, |
1009 | __LINE__, dev->port_number); |
1010 | result = -EBUSY; |
1011 | goto fail_busy; |
1012 | } |
1013 | |
1014 | vuart_bus_priv.devices[dev->port_number] = dev; |
1015 | |
1016 | /* Setup dev->driver_priv. */ |
1017 | |
1018 | dev->driver_priv = kzalloc(size: sizeof(struct ps3_vuart_port_priv), |
1019 | GFP_KERNEL); |
1020 | |
1021 | if (!dev->driver_priv) { |
1022 | result = -ENOMEM; |
1023 | goto fail_dev_malloc; |
1024 | } |
1025 | |
1026 | priv = to_port_priv(dev); |
1027 | |
1028 | INIT_LIST_HEAD(list: &priv->tx_list.head); |
1029 | spin_lock_init(&priv->tx_list.lock); |
1030 | |
1031 | INIT_LIST_HEAD(list: &priv->rx_list.head); |
1032 | spin_lock_init(&priv->rx_list.lock); |
1033 | |
1034 | INIT_WORK(&priv->rx_list.work.work, ps3_vuart_work); |
1035 | priv->rx_list.work.trigger = 0; |
1036 | priv->rx_list.work.dev = dev; |
1037 | |
1038 | /* clear stale pending interrupts */ |
1039 | |
1040 | ps3_vuart_clear_rx_bytes(dev, 0); |
1041 | |
1042 | ps3_vuart_set_interrupt_mask(dev, mask: INTERRUPT_MASK_RX); |
1043 | |
1044 | ps3_vuart_set_triggers(dev, tx: 1, rx: 1); |
1045 | |
1046 | if (drv->probe) |
1047 | result = drv->probe(dev); |
1048 | else { |
1049 | result = 0; |
1050 | dev_info(&dev->core, "%s:%d: no probe method\n" , __func__, |
1051 | __LINE__); |
1052 | } |
1053 | |
1054 | if (result) { |
1055 | dev_dbg(&dev->core, "%s:%d: drv->probe failed\n" , |
1056 | __func__, __LINE__); |
1057 | goto fail_probe; |
1058 | } |
1059 | |
1060 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1061 | |
1062 | return result; |
1063 | |
1064 | fail_probe: |
1065 | ps3_vuart_set_interrupt_mask(dev, mask: 0); |
1066 | kfree(objp: dev->driver_priv); |
1067 | dev->driver_priv = NULL; |
1068 | fail_dev_malloc: |
1069 | vuart_bus_priv.devices[dev->port_number] = NULL; |
1070 | fail_busy: |
1071 | ps3_vuart_bus_interrupt_put(); |
1072 | fail_setup_interrupt: |
1073 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1074 | dev_dbg(&dev->core, "%s:%d: failed\n" , __func__, __LINE__); |
1075 | return result; |
1076 | } |
1077 | |
1078 | /** |
1079 | * ps3_vuart_cleanup - common cleanup helper. |
1080 | * @dev: The struct ps3_system_bus_device instance. |
1081 | * |
1082 | * Cleans interrupts and HV resources. Must be called with |
1083 | * vuart_bus_priv.probe_mutex held. Used by ps3_vuart_remove and |
1084 | * ps3_vuart_shutdown. After this call, polled reading will still work. |
1085 | */ |
1086 | |
1087 | static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev) |
1088 | { |
1089 | dev_dbg(&dev->core, "%s:%d\n" , __func__, __LINE__); |
1090 | |
1091 | ps3_vuart_cancel_async(dev); |
1092 | ps3_vuart_set_interrupt_mask(dev, mask: 0); |
1093 | ps3_vuart_bus_interrupt_put(); |
1094 | return 0; |
1095 | } |
1096 | |
1097 | /** |
1098 | * ps3_vuart_remove - Completely clean the device instance. |
1099 | * @dev: The struct ps3_system_bus_device instance. |
1100 | * |
1101 | * Cleans all memory, interrupts and HV resources. After this call the |
1102 | * device can no longer be used. |
1103 | */ |
1104 | |
1105 | static void ps3_vuart_remove(struct ps3_system_bus_device *dev) |
1106 | { |
1107 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
1108 | struct ps3_vuart_port_driver *drv; |
1109 | |
1110 | BUG_ON(!dev); |
1111 | |
1112 | mutex_lock(&vuart_bus_priv.probe_mutex); |
1113 | |
1114 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n" , __func__, __LINE__, |
1115 | dev->match_id); |
1116 | |
1117 | if (!dev->core.driver) { |
1118 | dev_dbg(&dev->core, "%s:%d: no driver bound\n" , __func__, |
1119 | __LINE__); |
1120 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1121 | return; |
1122 | } |
1123 | |
1124 | drv = ps3_system_bus_dev_to_vuart_drv(dev: dev); |
1125 | |
1126 | BUG_ON(!drv); |
1127 | |
1128 | if (drv->remove) { |
1129 | drv->remove(dev); |
1130 | } else { |
1131 | dev_dbg(&dev->core, "%s:%d: no remove method\n" , __func__, |
1132 | __LINE__); |
1133 | BUG(); |
1134 | } |
1135 | |
1136 | ps3_vuart_cleanup(dev); |
1137 | |
1138 | vuart_bus_priv.devices[dev->port_number] = NULL; |
1139 | kfree(objp: priv); |
1140 | priv = NULL; |
1141 | |
1142 | dev_dbg(&dev->core, " <- %s:%d\n" , __func__, __LINE__); |
1143 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1144 | } |
1145 | |
1146 | /** |
1147 | * ps3_vuart_shutdown - Cleans interrupts and HV resources. |
1148 | * @dev: The struct ps3_system_bus_device instance. |
1149 | * |
1150 | * Cleans interrupts and HV resources. After this call the |
1151 | * device can still be used in polling mode. This behavior required |
1152 | * by sys-manager to be able to complete the device power operation |
1153 | * sequence. |
1154 | */ |
1155 | |
1156 | static void ps3_vuart_shutdown(struct ps3_system_bus_device *dev) |
1157 | { |
1158 | struct ps3_vuart_port_driver *drv; |
1159 | |
1160 | BUG_ON(!dev); |
1161 | |
1162 | mutex_lock(&vuart_bus_priv.probe_mutex); |
1163 | |
1164 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n" , __func__, __LINE__, |
1165 | dev->match_id); |
1166 | |
1167 | if (!dev->core.driver) { |
1168 | dev_dbg(&dev->core, "%s:%d: no driver bound\n" , __func__, |
1169 | __LINE__); |
1170 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1171 | return; |
1172 | } |
1173 | |
1174 | drv = ps3_system_bus_dev_to_vuart_drv(dev: dev); |
1175 | |
1176 | BUG_ON(!drv); |
1177 | |
1178 | if (drv->shutdown) |
1179 | drv->shutdown(dev); |
1180 | else if (drv->remove) { |
1181 | dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n" , |
1182 | __func__, __LINE__); |
1183 | drv->remove(dev); |
1184 | } else { |
1185 | dev_dbg(&dev->core, "%s:%d: no shutdown method\n" , __func__, |
1186 | __LINE__); |
1187 | BUG(); |
1188 | } |
1189 | |
1190 | ps3_vuart_cleanup(dev); |
1191 | |
1192 | dev_dbg(&dev->core, " <- %s:%d\n" , __func__, __LINE__); |
1193 | |
1194 | mutex_unlock(lock: &vuart_bus_priv.probe_mutex); |
1195 | } |
1196 | |
1197 | static int __init ps3_vuart_bus_init(void) |
1198 | { |
1199 | pr_debug("%s:%d:\n" , __func__, __LINE__); |
1200 | |
1201 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
1202 | return -ENODEV; |
1203 | |
1204 | mutex_init(&vuart_bus_priv.probe_mutex); |
1205 | |
1206 | return 0; |
1207 | } |
1208 | |
1209 | static void __exit ps3_vuart_bus_exit(void) |
1210 | { |
1211 | pr_debug("%s:%d:\n" , __func__, __LINE__); |
1212 | } |
1213 | |
1214 | core_initcall(ps3_vuart_bus_init); |
1215 | module_exit(ps3_vuart_bus_exit); |
1216 | |
1217 | /** |
1218 | * ps3_vuart_port_driver_register - Add a vuart port device driver. |
1219 | */ |
1220 | |
1221 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) |
1222 | { |
1223 | int result; |
1224 | |
1225 | pr_debug("%s:%d: (%s)\n" , __func__, __LINE__, drv->core.core.name); |
1226 | |
1227 | BUG_ON(!drv->core.match_id); |
1228 | BUG_ON(!drv->core.core.name); |
1229 | |
1230 | drv->core.probe = ps3_vuart_probe; |
1231 | drv->core.remove = ps3_vuart_remove; |
1232 | drv->core.shutdown = ps3_vuart_shutdown; |
1233 | |
1234 | result = ps3_system_bus_driver_register(&drv->core); |
1235 | return result; |
1236 | } |
1237 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); |
1238 | |
1239 | /** |
1240 | * ps3_vuart_port_driver_unregister - Remove a vuart port device driver. |
1241 | */ |
1242 | |
1243 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) |
1244 | { |
1245 | pr_debug("%s:%d: (%s)\n" , __func__, __LINE__, drv->core.core.name); |
1246 | ps3_system_bus_driver_unregister(&drv->core); |
1247 | } |
1248 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); |
1249 | |