aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGeoff Levand <geoffrey.levand@am.sony.com>2006-12-08 21:27:47 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-10 21:49:53 -0500
commit74e95d5de9d8eb243cda68b546bdb29f6ef0f01c (patch)
treec1f3a14628510af3ca134da5db409dcc8d428e99 /drivers
parent0204568a088fecd5478153504f9476ee2c46d5bf (diff)
[POWERPC] ps3: Add vuart support
Adds support for the PS3 virtual UART (vuart). The vuart provides a bi-directional byte stream data link between logical partitions. This is needed for the ps3 graphics driver and the ps3 power control support to be able to communicate with the lv1 policy module. Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/vuart.c965
-rw-r--r--drivers/ps3/vuart.h94
3 files changed, 1060 insertions, 0 deletions
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index b52d547b7a78..8433eb7562cb 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1 +1,2 @@
1obj-y += system-bus.o 1obj-y += system-bus.o
2obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
new file mode 100644
index 000000000000..6974f65bcda5
--- /dev/null
+++ b/drivers/ps3/vuart.c
@@ -0,0 +1,965 @@
1/*
2 * PS3 virtual uart
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 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/interrupt.h>
24#include <asm/ps3.h>
25
26#include <asm/lv1call.h>
27#include <asm/bitops.h>
28
29#include "vuart.h"
30
31MODULE_AUTHOR("Sony Corporation");
32MODULE_LICENSE("GPL v2");
33MODULE_DESCRIPTION("ps3 vuart");
34
35/**
36 * vuart - An inter-partition data link service.
37 * port 0: PS3 AV Settings.
38 * port 2: PS3 System Manager.
39 *
40 * The vuart provides a bi-directional byte stream data link between logical
41 * partitions. Its primary role is as a communications link between the guest
42 * OS and the system policy module. The current HV does not support any
43 * connections other than those listed.
44 */
45
46enum {PORT_COUNT = 3,};
47
48enum vuart_param {
49 PARAM_TX_TRIGGER = 0,
50 PARAM_RX_TRIGGER = 1,
51 PARAM_INTERRUPT_MASK = 2,
52 PARAM_RX_BUF_SIZE = 3, /* read only */
53 PARAM_RX_BYTES = 4, /* read only */
54 PARAM_TX_BUF_SIZE = 5, /* read only */
55 PARAM_TX_BYTES = 6, /* read only */
56 PARAM_INTERRUPT_STATUS = 7, /* read only */
57};
58
59enum vuart_interrupt_bit {
60 INTERRUPT_BIT_TX = 0,
61 INTERRUPT_BIT_RX = 1,
62 INTERRUPT_BIT_DISCONNECT = 2,
63};
64
65enum vuart_interrupt_mask {
66 INTERRUPT_MASK_TX = 1,
67 INTERRUPT_MASK_RX = 2,
68 INTERRUPT_MASK_DISCONNECT = 4,
69};
70
71/**
72 * struct ports_bmp - bitmap indicating ports needing service.
73 *
74 * A 256 bit read only bitmap indicating ports needing service. Do not write
75 * to these bits. Must not cross a page boundary.
76 */
77
78struct ports_bmp {
79 u64 status;
80 u64 unused[3];
81} __attribute__ ((aligned (32)));
82
83/* redefine dev_dbg to do a syntax check */
84
85#if !defined(DEBUG)
86#undef dev_dbg
87static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
88 const struct device *_dev, const char *fmt, ...) {return 0;}
89#endif
90
91#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
92static void __attribute__ ((unused)) _dump_ports_bmp(
93 const struct ports_bmp* bmp, const char* func, int line)
94{
95 pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
96}
97
98static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
99 unsigned int *port_number)
100{
101 switch(match_id) {
102 case PS3_MATCH_ID_AV_SETTINGS:
103 *port_number = 0;
104 return 0;
105 case PS3_MATCH_ID_SYSTEM_MANAGER:
106 *port_number = 2;
107 return 0;
108 default:
109 WARN_ON(1);
110 *port_number = UINT_MAX;
111 return -EINVAL;
112 };
113}
114
115#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
116static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
117 const char* func, int line)
118{
119#if defined(DEBUG)
120 static const char *strings[] = {
121 "tx_trigger ",
122 "rx_trigger ",
123 "interrupt_mask ",
124 "rx_buf_size ",
125 "rx_bytes ",
126 "tx_buf_size ",
127 "tx_bytes ",
128 "interrupt_status",
129 };
130 int result;
131 unsigned int i;
132 u64 value;
133
134 for (i = 0; i < ARRAY_SIZE(strings); i++) {
135 result = lv1_get_virtual_uart_param(port_number, i, &value);
136
137 if (result) {
138 pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
139 port_number, strings[i], ps3_result(result));
140 continue;
141 }
142 pr_debug("%s:%d: port_%u: %s = %lxh\n",
143 func, line, port_number, strings[i], value);
144 }
145#endif
146}
147
148struct vuart_triggers {
149 unsigned long rx;
150 unsigned long tx;
151};
152
153int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
154 struct vuart_triggers *trig)
155{
156 int result;
157 unsigned long size;
158 unsigned long val;
159
160 result = lv1_get_virtual_uart_param(dev->port_number,
161 PARAM_TX_TRIGGER, &trig->tx);
162
163 if (result) {
164 dev_dbg(&dev->core, "%s:%d: tx_trigger 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_BUF_SIZE, &size);
171
172 if (result) {
173 dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
174 __func__, __LINE__, ps3_result(result));
175 return result;
176 }
177
178 result = lv1_get_virtual_uart_param(dev->port_number,
179 PARAM_RX_TRIGGER, &val);
180
181 if (result) {
182 dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
183 __func__, __LINE__, ps3_result(result));
184 return result;
185 }
186
187 trig->rx = size - val;
188
189 dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
190 trig->tx, trig->rx);
191
192 return result;
193}
194
195int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
196 unsigned int rx)
197{
198 int result;
199 unsigned long size;
200
201 result = lv1_set_virtual_uart_param(dev->port_number,
202 PARAM_TX_TRIGGER, tx);
203
204 if (result) {
205 dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
206 __func__, __LINE__, ps3_result(result));
207 return result;
208 }
209
210 result = lv1_get_virtual_uart_param(dev->port_number,
211 PARAM_RX_BUF_SIZE, &size);
212
213 if (result) {
214 dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
215 __func__, __LINE__, ps3_result(result));
216 return result;
217 }
218
219 result = lv1_set_virtual_uart_param(dev->port_number,
220 PARAM_RX_TRIGGER, size - rx);
221
222 if (result) {
223 dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
224 __func__, __LINE__, ps3_result(result));
225 return result;
226 }
227
228 dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
229 tx, rx);
230
231 return result;
232}
233
234static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
235 unsigned long *bytes_waiting)
236{
237 int result = lv1_get_virtual_uart_param(dev->port_number,
238 PARAM_RX_BYTES, bytes_waiting);
239
240 if (result)
241 dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
242 __func__, __LINE__, ps3_result(result));
243
244 dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
245 *bytes_waiting);
246 return result;
247}
248
249static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
250 unsigned long mask)
251{
252 int result;
253
254 dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
255
256 dev->interrupt_mask = mask;
257
258 result = lv1_set_virtual_uart_param(dev->port_number,
259 PARAM_INTERRUPT_MASK, dev->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
268static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
269 unsigned long *status)
270{
271 int result = lv1_get_virtual_uart_param(dev->port_number,
272 PARAM_INTERRUPT_STATUS, status);
273
274 if (result)
275 dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
276 __func__, __LINE__, ps3_result(result));
277
278 dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
279 __func__, __LINE__, dev->interrupt_mask, *status,
280 dev->interrupt_mask & *status);
281
282 return result;
283}
284
285int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
286{
287 return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
288 : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
289 | INTERRUPT_MASK_TX);
290}
291
292int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
293{
294 return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
295 : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
296 | INTERRUPT_MASK_RX);
297}
298
299int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
300{
301 return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
302 : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
303 | INTERRUPT_MASK_DISCONNECT);
304}
305
306int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
307{
308 return (dev->interrupt_mask & INTERRUPT_MASK_TX)
309 ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
310 & ~INTERRUPT_MASK_TX) : 0;
311}
312
313int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
314{
315 return (dev->interrupt_mask & INTERRUPT_MASK_RX)
316 ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
317 & ~INTERRUPT_MASK_RX) : 0;
318}
319
320int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
321{
322 return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
323 ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
324 & ~INTERRUPT_MASK_DISCONNECT) : 0;
325}
326
327/**
328 * ps3_vuart_raw_write - Low level write helper.
329 *
330 * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
331 */
332
333static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
334 const void* buf, unsigned int bytes, unsigned long *bytes_written)
335{
336 int result;
337
338 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
339
340 result = lv1_write_virtual_uart(dev->port_number,
341 ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
342
343 if (result) {
344 dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
345 "%s\n", __func__, __LINE__, ps3_result(result));
346 return result;
347 }
348
349 dev->stats.bytes_written += *bytes_written;
350
351 dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
352 __LINE__, *bytes_written, bytes, dev->stats.bytes_written);
353
354 return result;
355}
356
357/**
358 * ps3_vuart_raw_read - Low level read helper.
359 *
360 * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
361 */
362
363static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
364 unsigned int bytes, unsigned long *bytes_read)
365{
366 int result;
367
368 dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
369
370 result = lv1_read_virtual_uart(dev->port_number,
371 ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
372
373 if (result) {
374 dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
375 __func__, __LINE__, ps3_result(result));
376 return result;
377 }
378
379 dev->stats.bytes_read += *bytes_read;
380
381 dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
382 *bytes_read, bytes, dev->stats.bytes_read);
383
384 return result;
385}
386
387/**
388 * struct list_buffer - An element for a port device fifo buffer list.
389 */
390
391struct list_buffer {
392 struct list_head link;
393 const unsigned char *head;
394 const unsigned char *tail;
395 unsigned long dbg_number;
396 unsigned char data[];
397};
398
399/**
400 * ps3_vuart_write - the entry point for writing data to a port
401 *
402 * If the port is idle on entry as much of the incoming data is written to
403 * the port as the port will accept. Otherwise a list buffer is created
404 * and any remaning incoming data is copied to that buffer. The buffer is
405 * then enqueued for transmision via the transmit interrupt.
406 */
407
408int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
409 unsigned int bytes)
410{
411 static unsigned long dbg_number;
412 int result;
413 unsigned long flags;
414 struct list_buffer *lb;
415
416 dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
417 bytes, bytes);
418
419 spin_lock_irqsave(&dev->tx_list.lock, flags);
420
421 if (list_empty(&dev->tx_list.head)) {
422 unsigned long bytes_written;
423
424 result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
425
426 spin_unlock_irqrestore(&dev->tx_list.lock, flags);
427
428 if (result) {
429 dev_dbg(&dev->core,
430 "%s:%d: ps3_vuart_raw_write failed\n",
431 __func__, __LINE__);
432 return result;
433 }
434
435 if (bytes_written == bytes) {
436 dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
437 __func__, __LINE__, bytes);
438 return 0;
439 }
440
441 bytes -= bytes_written;
442 buf += bytes_written;
443 } else
444 spin_unlock_irqrestore(&dev->tx_list.lock, flags);
445
446 lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
447
448 if (!lb) {
449 return -ENOMEM;
450 }
451
452 memcpy(lb->data, buf, bytes);
453 lb->head = lb->data;
454 lb->tail = lb->data + bytes;
455 lb->dbg_number = ++dbg_number;
456
457 spin_lock_irqsave(&dev->tx_list.lock, flags);
458 list_add_tail(&lb->link, &dev->tx_list.head);
459 ps3_vuart_enable_interrupt_tx(dev);
460 spin_unlock_irqrestore(&dev->tx_list.lock, flags);
461
462 dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
463 __func__, __LINE__, lb->dbg_number, bytes);
464
465 return 0;
466}
467
468/**
469 * ps3_vuart_read - the entry point for reading data from a port
470 *
471 * If enough bytes to satisfy the request are held in the buffer list those
472 * bytes are dequeued and copied to the caller's buffer. Emptied list buffers
473 * are retiered. If the request cannot be statified by bytes held in the list
474 * buffers -EAGAIN is returned.
475 */
476
477int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
478 unsigned int bytes)
479{
480 unsigned long flags;
481 struct list_buffer *lb, *n;
482 unsigned long bytes_read;
483
484 dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
485 bytes, bytes);
486
487 spin_lock_irqsave(&dev->rx_list.lock, flags);
488
489 if (dev->rx_list.bytes_held < bytes) {
490 spin_unlock_irqrestore(&dev->rx_list.lock, flags);
491 dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
492 __func__, __LINE__, bytes - dev->rx_list.bytes_held);
493 return -EAGAIN;
494 }
495
496 list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
497 bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
498
499 memcpy(buf, lb->head, bytes_read);
500 buf += bytes_read;
501 bytes -= bytes_read;
502 dev->rx_list.bytes_held -= bytes_read;
503
504 if (bytes_read < lb->tail - lb->head) {
505 lb->head += bytes_read;
506 spin_unlock_irqrestore(&dev->rx_list.lock, flags);
507
508 dev_dbg(&dev->core,
509 "%s:%d: dequeued buf_%lu, %lxh bytes\n",
510 __func__, __LINE__, lb->dbg_number, bytes_read);
511 return 0;
512 }
513
514 dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
515 lb->dbg_number);
516
517 list_del(&lb->link);
518 kfree(lb);
519 }
520 spin_unlock_irqrestore(&dev->rx_list.lock, flags);
521
522 dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
523 __func__, __LINE__, lb->dbg_number, bytes);
524
525 return 0;
526}
527
528/**
529 * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
530 *
531 * Services the transmit interrupt for the port. Writes as much data from the
532 * buffer list as the port will accept. Retires any emptied list buffers and
533 * adjusts the final list buffer state for a partial write.
534 */
535
536static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
537{
538 int result = 0;
539 unsigned long flags;
540 struct list_buffer *lb, *n;
541 unsigned long bytes_total = 0;
542
543 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
544
545 spin_lock_irqsave(&dev->tx_list.lock, flags);
546
547 list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
548
549 unsigned long bytes_written;
550
551 result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
552 &bytes_written);
553
554 if (result) {
555 dev_dbg(&dev->core,
556 "%s:%d: ps3_vuart_raw_write failed\n",
557 __func__, __LINE__);
558 break;
559 }
560
561 bytes_total += bytes_written;
562
563 if (bytes_written < lb->tail - lb->head) {
564 lb->head += bytes_written;
565 dev_dbg(&dev->core,
566 "%s:%d cleared buf_%lu, %lxh bytes\n",
567 __func__, __LINE__, lb->dbg_number,
568 bytes_written);
569 goto port_full;
570 }
571
572 dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
573 lb->dbg_number);
574
575 list_del(&lb->link);
576 kfree(lb);
577 }
578
579 ps3_vuart_disable_interrupt_tx(dev);
580port_full:
581 spin_unlock_irqrestore(&dev->tx_list.lock, flags);
582 dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
583 __func__, __LINE__, bytes_total);
584 return result;
585}
586
587/**
588 * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
589 *
590 * Services the receive interrupt for the port. Creates a list buffer and
591 * copies all waiting port data to that buffer and enqueues the buffer in the
592 * buffer list. Buffer list data is dequeued via ps3_vuart_read.
593 */
594
595static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
596{
597 static unsigned long dbg_number;
598 int result = 0;
599 unsigned long flags;
600 struct list_buffer *lb;
601 unsigned long bytes;
602
603 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
604
605 result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
606
607 if (result)
608 return -EIO;
609
610 BUG_ON(!bytes);
611
612 /* add some extra space for recently arrived data */
613
614 bytes += 128;
615
616 lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
617
618 if (!lb)
619 return -ENOMEM;
620
621 ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
622
623 lb->head = lb->data;
624 lb->tail = lb->data + bytes;
625 lb->dbg_number = ++dbg_number;
626
627 spin_lock_irqsave(&dev->rx_list.lock, flags);
628 list_add_tail(&lb->link, &dev->rx_list.head);
629 dev->rx_list.bytes_held += bytes;
630 spin_unlock_irqrestore(&dev->rx_list.lock, flags);
631
632 dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
633 __func__, __LINE__, lb->dbg_number, bytes);
634
635 return 0;
636}
637
638static int ps3_vuart_handle_interrupt_disconnect(
639 struct ps3_vuart_port_device *dev)
640{
641 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
642 BUG_ON("no support");
643 return -1;
644}
645
646/**
647 * ps3_vuart_handle_port_interrupt - second stage interrupt handler
648 *
649 * Services any pending interrupt types for the port. Passes control to the
650 * third stage type specific interrupt handler. Returns control to the first
651 * stage handler after one iteration.
652 */
653
654static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
655{
656 int result;
657 unsigned long status;
658
659 result = ps3_vuart_get_interrupt_mask(dev, &status);
660
661 if (result)
662 return result;
663
664 dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
665 status);
666
667 if (status & INTERRUPT_MASK_DISCONNECT) {
668 dev->stats.disconnect_interrupts++;
669 result = ps3_vuart_handle_interrupt_disconnect(dev);
670 if (result)
671 ps3_vuart_disable_interrupt_disconnect(dev);
672 }
673
674 if (status & INTERRUPT_MASK_TX) {
675 dev->stats.tx_interrupts++;
676 result = ps3_vuart_handle_interrupt_tx(dev);
677 if (result)
678 ps3_vuart_disable_interrupt_tx(dev);
679 }
680
681 if (status & INTERRUPT_MASK_RX) {
682 dev->stats.rx_interrupts++;
683 result = ps3_vuart_handle_interrupt_rx(dev);
684 if (result)
685 ps3_vuart_disable_interrupt_rx(dev);
686 }
687
688 return 0;
689}
690
691struct vuart_private {
692 unsigned int in_use;
693 unsigned int virq;
694 struct ps3_vuart_port_device *devices[PORT_COUNT];
695 const struct ports_bmp bmp;
696};
697
698/**
699 * ps3_vuart_irq_handler - first stage interrupt handler
700 *
701 * Loops finding any interrupting port and its associated instance data.
702 * Passes control to the second stage port specific interrupt handler. Loops
703 * until all outstanding interrupts are serviced.
704 */
705
706static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
707{
708 struct vuart_private *private;
709
710 BUG_ON(!_private);
711 private = (struct vuart_private *)_private;
712
713 while (1) {
714 unsigned int port;
715
716 dump_ports_bmp(&private->bmp);
717
718 port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
719
720 if (port == BITS_PER_LONG)
721 break;
722
723 BUG_ON(port >= PORT_COUNT);
724 BUG_ON(!private->devices[port]);
725
726 ps3_vuart_handle_port_interrupt(private->devices[port]);
727 }
728
729 return IRQ_HANDLED;
730}
731
732static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
733{
734 int result;
735 struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
736 struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
737
738 result = dev->match_id == drv->match_id;
739
740 dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
741 __LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
742 drv->core.name, (result ? "match" : "miss"));
743
744 return result;
745}
746
747static struct vuart_private vuart_private;
748
749static int ps3_vuart_probe(struct device *_dev)
750{
751 int result;
752 unsigned long tmp;
753 struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
754 struct ps3_vuart_port_driver *drv =
755 to_ps3_vuart_port_driver(_dev->driver);
756
757 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
758
759 BUG_ON(!drv);
760
761 result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
762
763 if (result) {
764 dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
765 __func__, __LINE__, dev->match_id);
766 result = -EINVAL;
767 goto fail_match;
768 }
769
770 if (vuart_private.devices[dev->port_number]) {
771 dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
772 __LINE__, dev->port_number);
773 result = -EBUSY;
774 goto fail_match;
775 }
776
777 vuart_private.devices[dev->port_number] = dev;
778
779 INIT_LIST_HEAD(&dev->tx_list.head);
780 spin_lock_init(&dev->tx_list.lock);
781 INIT_LIST_HEAD(&dev->rx_list.head);
782 spin_lock_init(&dev->rx_list.lock);
783
784 vuart_private.in_use++;
785 if (vuart_private.in_use == 1) {
786 result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
787 &vuart_private.virq);
788
789 if (result) {
790 dev_dbg(&dev->core,
791 "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
792 __func__, __LINE__, result);
793 result = -EPERM;
794 goto fail_alloc_irq;
795 }
796
797 result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
798 IRQF_DISABLED, "vuart", &vuart_private);
799
800 if (result) {
801 dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
802 __func__, __LINE__, result);
803 goto fail_request_irq;
804 }
805 }
806
807 ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
808
809 /* clear stale pending interrupts */
810 ps3_vuart_get_interrupt_mask(dev, &tmp);
811
812 ps3_vuart_set_triggers(dev, 1, 1);
813
814 if (drv->probe)
815 result = drv->probe(dev);
816 else {
817 result = 0;
818 dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
819 __LINE__);
820 }
821
822 if (result) {
823 dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
824 __func__, __LINE__);
825 goto fail_probe;
826 }
827
828 return result;
829
830fail_probe:
831fail_request_irq:
832 vuart_private.in_use--;
833 if (!vuart_private.in_use) {
834 ps3_free_vuart_irq(vuart_private.virq);
835 vuart_private.virq = NO_IRQ;
836 }
837fail_alloc_irq:
838fail_match:
839 dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
840 return result;
841}
842
843static int ps3_vuart_remove(struct device *_dev)
844{
845 struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
846 struct ps3_vuart_port_driver *drv =
847 to_ps3_vuart_port_driver(_dev->driver);
848
849 dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
850 dev->core.bus_id);
851
852 BUG_ON(vuart_private.in_use < 1);
853
854 if (drv->remove)
855 drv->remove(dev);
856 else
857 dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
858 __LINE__, dev->core.bus_id);
859
860 vuart_private.in_use--;
861
862 if (!vuart_private.in_use) {
863 free_irq(vuart_private.virq, &vuart_private);
864 ps3_free_vuart_irq(vuart_private.virq);
865 vuart_private.virq = NO_IRQ;
866 }
867 return 0;
868}
869
870/**
871 * ps3_vuart - The vuart instance.
872 *
873 * The vuart is managed as a bus that port devices connect to.
874 */
875
876struct bus_type ps3_vuart = {
877 .name = "ps3_vuart",
878 .match = ps3_vuart_match,
879 .probe = ps3_vuart_probe,
880 .remove = ps3_vuart_remove,
881};
882
883int __init ps3_vuart_init(void)
884{
885 int result;
886
887 pr_debug("%s:%d:\n", __func__, __LINE__);
888 result = bus_register(&ps3_vuart);
889 BUG_ON(result);
890 return result;
891}
892
893void __exit ps3_vuart_exit(void)
894{
895 pr_debug("%s:%d:\n", __func__, __LINE__);
896 bus_unregister(&ps3_vuart);
897}
898
899core_initcall(ps3_vuart_init);
900module_exit(ps3_vuart_exit);
901
902/**
903 * ps3_vuart_port_release_device - Remove a vuart port device.
904 */
905
906static void ps3_vuart_port_release_device(struct device *_dev)
907{
908 struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
909#if defined(DEBUG)
910 memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
911#endif
912 kfree(dev);
913}
914
915/**
916 * ps3_vuart_port_device_register - Add a vuart port device.
917 */
918
919int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
920{
921 int result;
922 static unsigned int dev_count = 1;
923
924 dev->core.parent = NULL;
925 dev->core.bus = &ps3_vuart;
926 dev->core.release = ps3_vuart_port_release_device;
927
928 snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
929 dev_count++);
930
931 dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
932
933 result = device_register(&dev->core);
934
935 return result;
936}
937
938EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
939
940/**
941 * ps3_vuart_port_driver_register - Add a vuart port device driver.
942 */
943
944int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
945{
946 int result;
947
948 pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
949 drv->core.bus = &ps3_vuart;
950 result = driver_register(&drv->core);
951 return result;
952}
953
954EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
955
956/**
957 * ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
958 */
959
960void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
961{
962 driver_unregister(&drv->core);
963}
964
965EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
new file mode 100644
index 000000000000..28fd89f0c8aa
--- /dev/null
+++ b/drivers/ps3/vuart.h
@@ -0,0 +1,94 @@
1/*
2 * PS3 virtual uart
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 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#if !defined(_PS3_VUART_H)
22#define _PS3_VUART_H
23
24struct ps3_vuart_stats {
25 unsigned long bytes_written;
26 unsigned long bytes_read;
27 unsigned long tx_interrupts;
28 unsigned long rx_interrupts;
29 unsigned long disconnect_interrupts;
30};
31
32/**
33 * struct ps3_vuart_port_device - a device on a vuart port
34 */
35
36struct ps3_vuart_port_device {
37 enum ps3_match_id match_id;
38 struct device core;
39
40 /* private driver variables */
41 unsigned int port_number;
42 unsigned long interrupt_mask;
43 struct {
44 spinlock_t lock;
45 struct list_head head;
46 } tx_list;
47 struct {
48 unsigned long bytes_held;
49 spinlock_t lock;
50 struct list_head head;
51 } rx_list;
52 struct ps3_vuart_stats stats;
53};
54
55/**
56 * struct ps3_vuart_port_driver - a driver for a device on a vuart port
57 */
58
59struct ps3_vuart_port_driver {
60 enum ps3_match_id match_id;
61 struct device_driver core;
62 int (*probe)(struct ps3_vuart_port_device *);
63 int (*remove)(struct ps3_vuart_port_device *);
64 int (*tx_event)(struct ps3_vuart_port_device *dev);
65 int (*rx_event)(struct ps3_vuart_port_device *dev);
66 int (*disconnect_event)(struct ps3_vuart_port_device *dev);
67 /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
68 /* int (*resume)(struct ps3_vuart_port_device *); */
69};
70
71int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
72int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
73void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
74int ps3_vuart_write(struct ps3_vuart_port_device *dev,
75 const void* buf, unsigned int bytes);
76int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
77 unsigned int bytes);
78static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
79 struct device_driver *_drv)
80{
81 return container_of(_drv, struct ps3_vuart_port_driver, core);
82}
83static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
84 struct device *_dev)
85{
86 return container_of(_dev, struct ps3_vuart_port_device, core);
87}
88
89int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
90 unsigned int bytes);
91int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
92 unsigned int bytes);
93
94#endif