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