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