~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/tty/serial/sunhv.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* sunhv.c: Serial driver for SUN4V hypervisor console.
 
2
 *
 
3
 * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
 
4
 */
 
5
 
 
6
#include <linux/module.h>
 
7
#include <linux/kernel.h>
 
8
#include <linux/errno.h>
 
9
#include <linux/tty.h>
 
10
#include <linux/tty_flip.h>
 
11
#include <linux/major.h>
 
12
#include <linux/circ_buf.h>
 
13
#include <linux/serial.h>
 
14
#include <linux/sysrq.h>
 
15
#include <linux/console.h>
 
16
#include <linux/spinlock.h>
 
17
#include <linux/slab.h>
 
18
#include <linux/delay.h>
 
19
#include <linux/init.h>
 
20
#include <linux/of_device.h>
 
21
 
 
22
#include <asm/hypervisor.h>
 
23
#include <asm/spitfire.h>
 
24
#include <asm/prom.h>
 
25
#include <asm/irq.h>
 
26
 
 
27
#if defined(CONFIG_MAGIC_SYSRQ)
 
28
#define SUPPORT_SYSRQ
 
29
#endif
 
30
 
 
31
#include <linux/serial_core.h>
 
32
 
 
33
#include "suncore.h"
 
34
 
 
35
#define CON_BREAK       ((long)-1)
 
36
#define CON_HUP         ((long)-2)
 
37
 
 
38
#define IGNORE_BREAK    0x1
 
39
#define IGNORE_ALL      0x2
 
40
 
 
41
static char *con_write_page;
 
42
static char *con_read_page;
 
43
 
 
44
static int hung_up = 0;
 
45
 
 
46
static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
 
47
{
 
48
        while (!uart_circ_empty(xmit)) {
 
49
                long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
 
50
 
 
51
                if (status != HV_EOK)
 
52
                        break;
 
53
 
 
54
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 
55
                port->icount.tx++;
 
56
        }
 
57
}
 
58
 
 
59
static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
 
60
{
 
61
        while (!uart_circ_empty(xmit)) {
 
62
                unsigned long ra = __pa(xmit->buf + xmit->tail);
 
63
                unsigned long len, status, sent;
 
64
 
 
65
                len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
 
66
                                      UART_XMIT_SIZE);
 
67
                status = sun4v_con_write(ra, len, &sent);
 
68
                if (status != HV_EOK)
 
69
                        break;
 
70
                xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
 
71
                port->icount.tx += sent;
 
72
        }
 
73
}
 
74
 
 
75
static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
 
76
{
 
77
        int saw_console_brk = 0;
 
78
        int limit = 10000;
 
79
 
 
80
        while (limit-- > 0) {
 
81
                long status;
 
82
                long c = sun4v_con_getchar(&status);
 
83
 
 
84
                if (status == HV_EWOULDBLOCK)
 
85
                        break;
 
86
 
 
87
                if (c == CON_BREAK) {
 
88
                        if (uart_handle_break(port))
 
89
                                continue;
 
90
                        saw_console_brk = 1;
 
91
                        c = 0;
 
92
                }
 
93
 
 
94
                if (c == CON_HUP) {
 
95
                        hung_up = 1;
 
96
                        uart_handle_dcd_change(port, 0);
 
97
                } else if (hung_up) {
 
98
                        hung_up = 0;
 
99
                        uart_handle_dcd_change(port, 1);
 
100
                }
 
101
 
 
102
                if (tty == NULL) {
 
103
                        uart_handle_sysrq_char(port, c);
 
104
                        continue;
 
105
                }
 
106
 
 
107
                port->icount.rx++;
 
108
 
 
109
                if (uart_handle_sysrq_char(port, c))
 
110
                        continue;
 
111
 
 
112
                tty_insert_flip_char(tty, c, TTY_NORMAL);
 
113
        }
 
114
 
 
115
        return saw_console_brk;
 
116
}
 
117
 
 
118
static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
 
119
{
 
120
        int saw_console_brk = 0;
 
121
        int limit = 10000;
 
122
 
 
123
        while (limit-- > 0) {
 
124
                unsigned long ra = __pa(con_read_page);
 
125
                unsigned long bytes_read, i;
 
126
                long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
 
127
 
 
128
                if (stat != HV_EOK) {
 
129
                        bytes_read = 0;
 
130
 
 
131
                        if (stat == CON_BREAK) {
 
132
                                if (uart_handle_break(port))
 
133
                                        continue;
 
134
                                saw_console_brk = 1;
 
135
                                *con_read_page = 0;
 
136
                                bytes_read = 1;
 
137
                        } else if (stat == CON_HUP) {
 
138
                                hung_up = 1;
 
139
                                uart_handle_dcd_change(port, 0);
 
140
                                continue;
 
141
                        } else {
 
142
                                /* HV_EWOULDBLOCK, etc.  */
 
143
                                break;
 
144
                        }
 
145
                }
 
146
 
 
147
                if (hung_up) {
 
148
                        hung_up = 0;
 
149
                        uart_handle_dcd_change(port, 1);
 
150
                }
 
151
 
 
152
                for (i = 0; i < bytes_read; i++)
 
153
                        uart_handle_sysrq_char(port, con_read_page[i]);
 
154
 
 
155
                if (tty == NULL)
 
156
                        continue;
 
157
 
 
158
                port->icount.rx += bytes_read;
 
159
 
 
160
                tty_insert_flip_string(tty, con_read_page, bytes_read);
 
161
        }
 
162
 
 
163
        return saw_console_brk;
 
164
}
 
165
 
 
166
struct sunhv_ops {
 
167
        void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
 
168
        int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
 
169
};
 
170
 
 
171
static struct sunhv_ops bychar_ops = {
 
172
        .transmit_chars = transmit_chars_putchar,
 
173
        .receive_chars = receive_chars_getchar,
 
174
};
 
175
 
 
176
static struct sunhv_ops bywrite_ops = {
 
177
        .transmit_chars = transmit_chars_write,
 
178
        .receive_chars = receive_chars_read,
 
179
};
 
180
 
 
181
static struct sunhv_ops *sunhv_ops = &bychar_ops;
 
182
 
 
183
static struct tty_struct *receive_chars(struct uart_port *port)
 
184
{
 
185
        struct tty_struct *tty = NULL;
 
186
 
 
187
        if (port->state != NULL)                /* Unopened serial console */
 
188
                tty = port->state->port.tty;
 
189
 
 
190
        if (sunhv_ops->receive_chars(port, tty))
 
191
                sun_do_break();
 
192
 
 
193
        return tty;
 
194
}
 
195
 
 
196
static void transmit_chars(struct uart_port *port)
 
197
{
 
198
        struct circ_buf *xmit;
 
199
 
 
200
        if (!port->state)
 
201
                return;
 
202
 
 
203
        xmit = &port->state->xmit;
 
204
        if (uart_circ_empty(xmit) || uart_tx_stopped(port))
 
205
                return;
 
206
 
 
207
        sunhv_ops->transmit_chars(port, xmit);
 
208
 
 
209
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 
210
                uart_write_wakeup(port);
 
211
}
 
212
 
 
213
static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
 
214
{
 
215
        struct uart_port *port = dev_id;
 
216
        struct tty_struct *tty;
 
217
        unsigned long flags;
 
218
 
 
219
        spin_lock_irqsave(&port->lock, flags);
 
220
        tty = receive_chars(port);
 
221
        transmit_chars(port);
 
222
        spin_unlock_irqrestore(&port->lock, flags);
 
223
 
 
224
        if (tty)
 
225
                tty_flip_buffer_push(tty);
 
226
 
 
227
        return IRQ_HANDLED;
 
228
}
 
229
 
 
230
/* port->lock is not held.  */
 
231
static unsigned int sunhv_tx_empty(struct uart_port *port)
 
232
{
 
233
        /* Transmitter is always empty for us.  If the circ buffer
 
234
         * is non-empty or there is an x_char pending, our caller
 
235
         * will do the right thing and ignore what we return here.
 
236
         */
 
237
        return TIOCSER_TEMT;
 
238
}
 
239
 
 
240
/* port->lock held by caller.  */
 
241
static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
242
{
 
243
        return;
 
244
}
 
245
 
 
246
/* port->lock is held by caller and interrupts are disabled.  */
 
247
static unsigned int sunhv_get_mctrl(struct uart_port *port)
 
248
{
 
249
        return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
 
250
}
 
251
 
 
252
/* port->lock held by caller.  */
 
253
static void sunhv_stop_tx(struct uart_port *port)
 
254
{
 
255
        return;
 
256
}
 
257
 
 
258
/* port->lock held by caller.  */
 
259
static void sunhv_start_tx(struct uart_port *port)
 
260
{
 
261
        transmit_chars(port);
 
262
}
 
263
 
 
264
/* port->lock is not held.  */
 
265
static void sunhv_send_xchar(struct uart_port *port, char ch)
 
266
{
 
267
        unsigned long flags;
 
268
        int limit = 10000;
 
269
 
 
270
        spin_lock_irqsave(&port->lock, flags);
 
271
 
 
272
        while (limit-- > 0) {
 
273
                long status = sun4v_con_putchar(ch);
 
274
                if (status == HV_EOK)
 
275
                        break;
 
276
                udelay(1);
 
277
        }
 
278
 
 
279
        spin_unlock_irqrestore(&port->lock, flags);
 
280
}
 
281
 
 
282
/* port->lock held by caller.  */
 
283
static void sunhv_stop_rx(struct uart_port *port)
 
284
{
 
285
}
 
286
 
 
287
/* port->lock held by caller.  */
 
288
static void sunhv_enable_ms(struct uart_port *port)
 
289
{
 
290
}
 
291
 
 
292
/* port->lock is not held.  */
 
293
static void sunhv_break_ctl(struct uart_port *port, int break_state)
 
294
{
 
295
        if (break_state) {
 
296
                unsigned long flags;
 
297
                int limit = 10000;
 
298
 
 
299
                spin_lock_irqsave(&port->lock, flags);
 
300
 
 
301
                while (limit-- > 0) {
 
302
                        long status = sun4v_con_putchar(CON_BREAK);
 
303
                        if (status == HV_EOK)
 
304
                                break;
 
305
                        udelay(1);
 
306
                }
 
307
 
 
308
                spin_unlock_irqrestore(&port->lock, flags);
 
309
        }
 
310
}
 
311
 
 
312
/* port->lock is not held.  */
 
313
static int sunhv_startup(struct uart_port *port)
 
314
{
 
315
        return 0;
 
316
}
 
317
 
 
318
/* port->lock is not held.  */
 
319
static void sunhv_shutdown(struct uart_port *port)
 
320
{
 
321
}
 
322
 
 
323
/* port->lock is not held.  */
 
324
static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
 
325
                              struct ktermios *old)
 
326
{
 
327
        unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
 
328
        unsigned int quot = uart_get_divisor(port, baud);
 
329
        unsigned int iflag, cflag;
 
330
        unsigned long flags;
 
331
 
 
332
        spin_lock_irqsave(&port->lock, flags);
 
333
 
 
334
        iflag = termios->c_iflag;
 
335
        cflag = termios->c_cflag;
 
336
 
 
337
        port->ignore_status_mask = 0;
 
338
        if (iflag & IGNBRK)
 
339
                port->ignore_status_mask |= IGNORE_BREAK;
 
340
        if ((cflag & CREAD) == 0)
 
341
                port->ignore_status_mask |= IGNORE_ALL;
 
342
 
 
343
        /* XXX */
 
344
        uart_update_timeout(port, cflag,
 
345
                            (port->uartclk / (16 * quot)));
 
346
 
 
347
        spin_unlock_irqrestore(&port->lock, flags);
 
348
}
 
349
 
 
350
static const char *sunhv_type(struct uart_port *port)
 
351
{
 
352
        return "SUN4V HCONS";
 
353
}
 
354
 
 
355
static void sunhv_release_port(struct uart_port *port)
 
356
{
 
357
}
 
358
 
 
359
static int sunhv_request_port(struct uart_port *port)
 
360
{
 
361
        return 0;
 
362
}
 
363
 
 
364
static void sunhv_config_port(struct uart_port *port, int flags)
 
365
{
 
366
}
 
367
 
 
368
static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
 
369
{
 
370
        return -EINVAL;
 
371
}
 
372
 
 
373
static struct uart_ops sunhv_pops = {
 
374
        .tx_empty       = sunhv_tx_empty,
 
375
        .set_mctrl      = sunhv_set_mctrl,
 
376
        .get_mctrl      = sunhv_get_mctrl,
 
377
        .stop_tx        = sunhv_stop_tx,
 
378
        .start_tx       = sunhv_start_tx,
 
379
        .send_xchar     = sunhv_send_xchar,
 
380
        .stop_rx        = sunhv_stop_rx,
 
381
        .enable_ms      = sunhv_enable_ms,
 
382
        .break_ctl      = sunhv_break_ctl,
 
383
        .startup        = sunhv_startup,
 
384
        .shutdown       = sunhv_shutdown,
 
385
        .set_termios    = sunhv_set_termios,
 
386
        .type           = sunhv_type,
 
387
        .release_port   = sunhv_release_port,
 
388
        .request_port   = sunhv_request_port,
 
389
        .config_port    = sunhv_config_port,
 
390
        .verify_port    = sunhv_verify_port,
 
391
};
 
392
 
 
393
static struct uart_driver sunhv_reg = {
 
394
        .owner                  = THIS_MODULE,
 
395
        .driver_name            = "sunhv",
 
396
        .dev_name               = "ttyS",
 
397
        .major                  = TTY_MAJOR,
 
398
};
 
399
 
 
400
static struct uart_port *sunhv_port;
 
401
 
 
402
/* Copy 's' into the con_write_page, decoding "\n" into
 
403
 * "\r\n" along the way.  We have to return two lengths
 
404
 * because the caller needs to know how much to advance
 
405
 * 's' and also how many bytes to output via con_write_page.
 
406
 */
 
407
static int fill_con_write_page(const char *s, unsigned int n,
 
408
                               unsigned long *page_bytes)
 
409
{
 
410
        const char *orig_s = s;
 
411
        char *p = con_write_page;
 
412
        int left = PAGE_SIZE;
 
413
 
 
414
        while (n--) {
 
415
                if (*s == '\n') {
 
416
                        if (left < 2)
 
417
                                break;
 
418
                        *p++ = '\r';
 
419
                        left--;
 
420
                } else if (left < 1)
 
421
                        break;
 
422
                *p++ = *s++;
 
423
                left--;
 
424
        }
 
425
        *page_bytes = p - con_write_page;
 
426
        return s - orig_s;
 
427
}
 
428
 
 
429
static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
 
430
{
 
431
        struct uart_port *port = sunhv_port;
 
432
        unsigned long flags;
 
433
        int locked = 1;
 
434
 
 
435
        local_irq_save(flags);
 
436
        if (port->sysrq) {
 
437
                locked = 0;
 
438
        } else if (oops_in_progress) {
 
439
                locked = spin_trylock(&port->lock);
 
440
        } else
 
441
                spin_lock(&port->lock);
 
442
 
 
443
        while (n > 0) {
 
444
                unsigned long ra = __pa(con_write_page);
 
445
                unsigned long page_bytes;
 
446
                unsigned int cpy = fill_con_write_page(s, n,
 
447
                                                       &page_bytes);
 
448
 
 
449
                n -= cpy;
 
450
                s += cpy;
 
451
                while (page_bytes > 0) {
 
452
                        unsigned long written;
 
453
                        int limit = 1000000;
 
454
 
 
455
                        while (limit--) {
 
456
                                unsigned long stat;
 
457
 
 
458
                                stat = sun4v_con_write(ra, page_bytes,
 
459
                                                       &written);
 
460
                                if (stat == HV_EOK)
 
461
                                        break;
 
462
                                udelay(1);
 
463
                        }
 
464
                        if (limit < 0)
 
465
                                break;
 
466
                        page_bytes -= written;
 
467
                        ra += written;
 
468
                }
 
469
        }
 
470
 
 
471
        if (locked)
 
472
                spin_unlock(&port->lock);
 
473
        local_irq_restore(flags);
 
474
}
 
475
 
 
476
static inline void sunhv_console_putchar(struct uart_port *port, char c)
 
477
{
 
478
        int limit = 1000000;
 
479
 
 
480
        while (limit-- > 0) {
 
481
                long status = sun4v_con_putchar(c);
 
482
                if (status == HV_EOK)
 
483
                        break;
 
484
                udelay(1);
 
485
        }
 
486
}
 
487
 
 
488
static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
 
489
{
 
490
        struct uart_port *port = sunhv_port;
 
491
        unsigned long flags;
 
492
        int i, locked = 1;
 
493
 
 
494
        local_irq_save(flags);
 
495
        if (port->sysrq) {
 
496
                locked = 0;
 
497
        } else if (oops_in_progress) {
 
498
                locked = spin_trylock(&port->lock);
 
499
        } else
 
500
                spin_lock(&port->lock);
 
501
 
 
502
        for (i = 0; i < n; i++) {
 
503
                if (*s == '\n')
 
504
                        sunhv_console_putchar(port, '\r');
 
505
                sunhv_console_putchar(port, *s++);
 
506
        }
 
507
 
 
508
        if (locked)
 
509
                spin_unlock(&port->lock);
 
510
        local_irq_restore(flags);
 
511
}
 
512
 
 
513
static struct console sunhv_console = {
 
514
        .name   =       "ttyHV",
 
515
        .write  =       sunhv_console_write_bychar,
 
516
        .device =       uart_console_device,
 
517
        .flags  =       CON_PRINTBUFFER,
 
518
        .index  =       -1,
 
519
        .data   =       &sunhv_reg,
 
520
};
 
521
 
 
522
static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
 
523
{
 
524
        struct uart_port *port;
 
525
        unsigned long minor;
 
526
        int err;
 
527
 
 
528
        if (op->archdata.irqs[0] == 0xffffffff)
 
529
                return -ENODEV;
 
530
 
 
531
        port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
 
532
        if (unlikely(!port))
 
533
                return -ENOMEM;
 
534
 
 
535
        minor = 1;
 
536
        if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
 
537
            minor >= 1) {
 
538
                err = -ENOMEM;
 
539
                con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
 
540
                if (!con_write_page)
 
541
                        goto out_free_port;
 
542
 
 
543
                con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
 
544
                if (!con_read_page)
 
545
                        goto out_free_con_write_page;
 
546
 
 
547
                sunhv_console.write = sunhv_console_write_paged;
 
548
                sunhv_ops = &bywrite_ops;
 
549
        }
 
550
 
 
551
        sunhv_port = port;
 
552
 
 
553
        port->line = 0;
 
554
        port->ops = &sunhv_pops;
 
555
        port->type = PORT_SUNHV;
 
556
        port->uartclk = ( 29491200 / 16 ); /* arbitrary */
 
557
 
 
558
        port->membase = (unsigned char __iomem *) __pa(port);
 
559
 
 
560
        port->irq = op->archdata.irqs[0];
 
561
 
 
562
        port->dev = &op->dev;
 
563
 
 
564
        err = sunserial_register_minors(&sunhv_reg, 1);
 
565
        if (err)
 
566
                goto out_free_con_read_page;
 
567
 
 
568
        sunserial_console_match(&sunhv_console, op->dev.of_node,
 
569
                                &sunhv_reg, port->line, false);
 
570
 
 
571
        err = uart_add_one_port(&sunhv_reg, port);
 
572
        if (err)
 
573
                goto out_unregister_driver;
 
574
 
 
575
        err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
 
576
        if (err)
 
577
                goto out_remove_port;
 
578
 
 
579
        dev_set_drvdata(&op->dev, port);
 
580
 
 
581
        return 0;
 
582
 
 
583
out_remove_port:
 
584
        uart_remove_one_port(&sunhv_reg, port);
 
585
 
 
586
out_unregister_driver:
 
587
        sunserial_unregister_minors(&sunhv_reg, 1);
 
588
 
 
589
out_free_con_read_page:
 
590
        kfree(con_read_page);
 
591
 
 
592
out_free_con_write_page:
 
593
        kfree(con_write_page);
 
594
 
 
595
out_free_port:
 
596
        kfree(port);
 
597
        sunhv_port = NULL;
 
598
        return err;
 
599
}
 
600
 
 
601
static int __devexit hv_remove(struct platform_device *dev)
 
602
{
 
603
        struct uart_port *port = dev_get_drvdata(&dev->dev);
 
604
 
 
605
        free_irq(port->irq, port);
 
606
 
 
607
        uart_remove_one_port(&sunhv_reg, port);
 
608
 
 
609
        sunserial_unregister_minors(&sunhv_reg, 1);
 
610
 
 
611
        kfree(port);
 
612
        sunhv_port = NULL;
 
613
 
 
614
        dev_set_drvdata(&dev->dev, NULL);
 
615
 
 
616
        return 0;
 
617
}
 
618
 
 
619
static const struct of_device_id hv_match[] = {
 
620
        {
 
621
                .name = "console",
 
622
                .compatible = "qcn",
 
623
        },
 
624
        {
 
625
                .name = "console",
 
626
                .compatible = "SUNW,sun4v-console",
 
627
        },
 
628
        {},
 
629
};
 
630
MODULE_DEVICE_TABLE(of, hv_match);
 
631
 
 
632
static struct of_platform_driver hv_driver = {
 
633
        .driver = {
 
634
                .name = "hv",
 
635
                .owner = THIS_MODULE,
 
636
                .of_match_table = hv_match,
 
637
        },
 
638
        .probe          = hv_probe,
 
639
        .remove         = __devexit_p(hv_remove),
 
640
};
 
641
 
 
642
static int __init sunhv_init(void)
 
643
{
 
644
        if (tlb_type != hypervisor)
 
645
                return -ENODEV;
 
646
 
 
647
        return of_register_platform_driver(&hv_driver);
 
648
}
 
649
 
 
650
static void __exit sunhv_exit(void)
 
651
{
 
652
        of_unregister_platform_driver(&hv_driver);
 
653
}
 
654
 
 
655
module_init(sunhv_init);
 
656
module_exit(sunhv_exit);
 
657
 
 
658
MODULE_AUTHOR("David S. Miller");
 
659
MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
 
660
MODULE_VERSION("2.0");
 
661
MODULE_LICENSE("GPL");