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#include <linux/serial_core.h>
  29#include <linux/sunserialcore.h>
  30
  31#define CON_BREAK       ((long)-1)
  32#define CON_HUP         ((long)-2)
  33
  34#define IGNORE_BREAK    0x1
  35#define IGNORE_ALL      0x2
  36
  37static char *con_write_page;
  38static char *con_read_page;
  39
  40static int hung_up = 0;
  41
  42static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
  43{
  44        while (!uart_circ_empty(xmit)) {
  45                long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
  46
  47                if (status != HV_EOK)
  48                        break;
  49
  50                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
  51                port->icount.tx++;
  52        }
  53}
  54
  55static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
  56{
  57        while (!uart_circ_empty(xmit)) {
  58                unsigned long ra = __pa(xmit->buf + xmit->tail);
  59                unsigned long len, status, sent;
  60
  61                len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
  62                                      UART_XMIT_SIZE);
  63                status = sun4v_con_write(ra, len, &sent);
  64                if (status != HV_EOK)
  65                        break;
  66                xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
  67                port->icount.tx += sent;
  68        }
  69}
  70
  71static int receive_chars_getchar(struct uart_port *port)
  72{
  73        int saw_console_brk = 0;
  74        int limit = 10000;
  75
  76        while (limit-- > 0) {
  77                long status;
  78                long c = sun4v_con_getchar(&status);
  79
  80                if (status == HV_EWOULDBLOCK)
  81                        break;
  82
  83                if (c == CON_BREAK) {
  84                        if (uart_handle_break(port))
  85                                continue;
  86                        saw_console_brk = 1;
  87                        c = 0;
  88                }
  89
  90                if (c == CON_HUP) {
  91                        hung_up = 1;
  92                        uart_handle_dcd_change(port, 0);
  93                } else if (hung_up) {
  94                        hung_up = 0;
  95                        uart_handle_dcd_change(port, 1);
  96                }
  97
  98                if (port->state == NULL) {
  99                        uart_handle_sysrq_char(port, c);
 100                        continue;
 101                }
 102
 103                port->icount.rx++;
 104
 105                if (uart_handle_sysrq_char(port, c))
 106                        continue;
 107
 108                tty_insert_flip_char(&port->state->port, c, TTY_NORMAL);
 109        }
 110
 111        return saw_console_brk;
 112}
 113
 114static int receive_chars_read(struct uart_port *port)
 115{
 116        static int saw_console_brk;
 117        int limit = 10000;
 118
 119        while (limit-- > 0) {
 120                unsigned long ra = __pa(con_read_page);
 121                unsigned long bytes_read, i;
 122                long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
 123
 124                if (stat != HV_EOK) {
 125                        bytes_read = 0;
 126
 127                        if (stat == CON_BREAK) {
 128                                if (saw_console_brk)
 129                                        sun_do_break();
 130
 131                                if (uart_handle_break(port))
 132                                        continue;
 133                                saw_console_brk = 1;
 134                                *con_read_page = 0;
 135                                bytes_read = 1;
 136                        } else if (stat == CON_HUP) {
 137                                hung_up = 1;
 138                                uart_handle_dcd_change(port, 0);
 139                                continue;
 140                        } else {
 141                                /* HV_EWOULDBLOCK, etc.  */
 142                                break;
 143                        }
 144                }
 145
 146                if (hung_up) {
 147                        hung_up = 0;
 148                        uart_handle_dcd_change(port, 1);
 149                }
 150
 151                if (port->sysrq != 0 &&  *con_read_page) {
 152                        for (i = 0; i < bytes_read; i++)
 153                                uart_handle_sysrq_char(port, con_read_page[i]);
 154                        saw_console_brk = 0;
 155                }
 156
 157                if (port->state == NULL)
 158                        continue;
 159
 160                port->icount.rx += bytes_read;
 161
 162                tty_insert_flip_string(&port->state->port, con_read_page,
 163                                bytes_read);
 164        }
 165
 166        return saw_console_brk;
 167}
 168
 169struct sunhv_ops {
 170        void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
 171        int (*receive_chars)(struct uart_port *port);
 172};
 173
 174static const struct sunhv_ops bychar_ops = {
 175        .transmit_chars = transmit_chars_putchar,
 176        .receive_chars = receive_chars_getchar,
 177};
 178
 179static const struct sunhv_ops bywrite_ops = {
 180        .transmit_chars = transmit_chars_write,
 181        .receive_chars = receive_chars_read,
 182};
 183
 184static const struct sunhv_ops *sunhv_ops = &bychar_ops;
 185
 186static struct tty_port *receive_chars(struct uart_port *port)
 187{
 188        struct tty_port *tport = NULL;
 189
 190        if (port->state != NULL)                /* Unopened serial console */
 191                tport = &port->state->port;
 192
 193        if (sunhv_ops->receive_chars(port))
 194                sun_do_break();
 195
 196        return tport;
 197}
 198
 199static void transmit_chars(struct uart_port *port)
 200{
 201        struct circ_buf *xmit;
 202
 203        if (!port->state)
 204                return;
 205
 206        xmit = &port->state->xmit;
 207        if (uart_circ_empty(xmit) || uart_tx_stopped(port))
 208                return;
 209
 210        sunhv_ops->transmit_chars(port, xmit);
 211
 212        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 213                uart_write_wakeup(port);
 214}
 215
 216static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
 217{
 218        struct uart_port *port = dev_id;
 219        struct tty_port *tport;
 220        unsigned long flags;
 221
 222        spin_lock_irqsave(&port->lock, flags);
 223        tport = receive_chars(port);
 224        transmit_chars(port);
 225        spin_unlock_irqrestore(&port->lock, flags);
 226
 227        if (tport)
 228                tty_flip_buffer_push(tport);
 229
 230        return IRQ_HANDLED;
 231}
 232
 233/* port->lock is not held.  */
 234static unsigned int sunhv_tx_empty(struct uart_port *port)
 235{
 236        /* Transmitter is always empty for us.  If the circ buffer
 237         * is non-empty or there is an x_char pending, our caller
 238         * will do the right thing and ignore what we return here.
 239         */
 240        return TIOCSER_TEMT;
 241}
 242
 243/* port->lock held by caller.  */
 244static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
 245{
 246        return;
 247}
 248
 249/* port->lock is held by caller and interrupts are disabled.  */
 250static unsigned int sunhv_get_mctrl(struct uart_port *port)
 251{
 252        return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
 253}
 254
 255/* port->lock held by caller.  */
 256static void sunhv_stop_tx(struct uart_port *port)
 257{
 258        return;
 259}
 260
 261/* port->lock held by caller.  */
 262static void sunhv_start_tx(struct uart_port *port)
 263{
 264        transmit_chars(port);
 265}
 266
 267/* port->lock is not held.  */
 268static void sunhv_send_xchar(struct uart_port *port, char ch)
 269{
 270        unsigned long flags;
 271        int limit = 10000;
 272
 273        if (ch == __DISABLED_CHAR)
 274                return;
 275
 276        spin_lock_irqsave(&port->lock, flags);
 277
 278        while (limit-- > 0) {
 279                long status = sun4v_con_putchar(ch);
 280                if (status == HV_EOK)
 281                        break;
 282                udelay(1);
 283        }
 284
 285        spin_unlock_irqrestore(&port->lock, flags);
 286}
 287
 288/* port->lock held by caller.  */
 289static void sunhv_stop_rx(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 const 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        .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
 393static struct uart_driver sunhv_reg = {
 394        .owner                  = THIS_MODULE,
 395        .driver_name            = "sunhv",
 396        .dev_name               = "ttyHV",
 397        .major                  = TTY_MAJOR,
 398};
 399
 400static struct uart_port *sunhv_port;
 401
 402void sunhv_migrate_hvcons_irq(int cpu)
 403{
 404        /* Migrate hvcons irq to param cpu */
 405        irq_force_affinity(sunhv_port->irq, cpumask_of(cpu));
 406}
 407
 408/* Copy 's' into the con_write_page, decoding "\n" into
 409 * "\r\n" along the way.  We have to return two lengths
 410 * because the caller needs to know how much to advance
 411 * 's' and also how many bytes to output via con_write_page.
 412 */
 413static int fill_con_write_page(const char *s, unsigned int n,
 414                               unsigned long *page_bytes)
 415{
 416        const char *orig_s = s;
 417        char *p = con_write_page;
 418        int left = PAGE_SIZE;
 419
 420        while (n--) {
 421                if (*s == '\n') {
 422                        if (left < 2)
 423                                break;
 424                        *p++ = '\r';
 425                        left--;
 426                } else if (left < 1)
 427                        break;
 428                *p++ = *s++;
 429                left--;
 430        }
 431        *page_bytes = p - con_write_page;
 432        return s - orig_s;
 433}
 434
 435static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
 436{
 437        struct uart_port *port = sunhv_port;
 438        unsigned long flags;
 439        int locked = 1;
 440
 441        if (port->sysrq || oops_in_progress)
 442                locked = spin_trylock_irqsave(&port->lock, flags);
 443        else
 444                spin_lock_irqsave(&port->lock, flags);
 445
 446        while (n > 0) {
 447                unsigned long ra = __pa(con_write_page);
 448                unsigned long page_bytes;
 449                unsigned int cpy = fill_con_write_page(s, n,
 450                                                       &page_bytes);
 451
 452                n -= cpy;
 453                s += cpy;
 454                while (page_bytes > 0) {
 455                        unsigned long written;
 456                        int limit = 1000000;
 457
 458                        while (limit--) {
 459                                unsigned long stat;
 460
 461                                stat = sun4v_con_write(ra, page_bytes,
 462                                                       &written);
 463                                if (stat == HV_EOK)
 464                                        break;
 465                                udelay(1);
 466                        }
 467                        if (limit < 0)
 468                                break;
 469                        page_bytes -= written;
 470                        ra += written;
 471                }
 472        }
 473
 474        if (locked)
 475                spin_unlock_irqrestore(&port->lock, flags);
 476}
 477
 478static inline void sunhv_console_putchar(struct uart_port *port, char c)
 479{
 480        int limit = 1000000;
 481
 482        while (limit-- > 0) {
 483                long status = sun4v_con_putchar(c);
 484                if (status == HV_EOK)
 485                        break;
 486                udelay(1);
 487        }
 488}
 489
 490static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
 491{
 492        struct uart_port *port = sunhv_port;
 493        unsigned long flags;
 494        int i, locked = 1;
 495
 496        if (port->sysrq || oops_in_progress)
 497                locked = spin_trylock_irqsave(&port->lock, flags);
 498        else
 499                spin_lock_irqsave(&port->lock, flags);
 500
 501        for (i = 0; i < n; i++) {
 502                if (*s == '\n')
 503                        sunhv_console_putchar(port, '\r');
 504                sunhv_console_putchar(port, *s++);
 505        }
 506
 507        if (locked)
 508                spin_unlock_irqrestore(&port->lock, flags);
 509}
 510
 511static struct console sunhv_console = {
 512        .name   =       "ttyHV",
 513        .write  =       sunhv_console_write_bychar,
 514        .device =       uart_console_device,
 515        .flags  =       CON_PRINTBUFFER,
 516        .index  =       -1,
 517        .data   =       &sunhv_reg,
 518};
 519
 520static int hv_probe(struct platform_device *op)
 521{
 522        struct uart_port *port;
 523        unsigned long minor;
 524        int err;
 525
 526        if (op->archdata.irqs[0] == 0xffffffff)
 527                return -ENODEV;
 528
 529        port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
 530        if (unlikely(!port))
 531                return -ENOMEM;
 532
 533        minor = 1;
 534        if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
 535            minor >= 1) {
 536                err = -ENOMEM;
 537                con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
 538                if (!con_write_page)
 539                        goto out_free_port;
 540
 541                con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
 542                if (!con_read_page)
 543                        goto out_free_con_write_page;
 544
 545                sunhv_console.write = sunhv_console_write_paged;
 546                sunhv_ops = &bywrite_ops;
 547        }
 548
 549        sunhv_port = port;
 550
 551        port->has_sysrq = 1;
 552        port->line = 0;
 553        port->ops = &sunhv_pops;
 554        port->type = PORT_SUNHV;
 555        port->uartclk = ( 29491200 / 16 ); /* arbitrary */
 556
 557        port->membase = (unsigned char __iomem *) __pa(port);
 558
 559        port->irq = op->archdata.irqs[0];
 560
 561        port->dev = &op->dev;
 562
 563        err = sunserial_register_minors(&sunhv_reg, 1);
 564        if (err)
 565                goto out_free_con_read_page;
 566
 567        sunserial_console_match(&sunhv_console, op->dev.of_node,
 568                                &sunhv_reg, port->line, false);
 569
 570        err = uart_add_one_port(&sunhv_reg, port);
 571        if (err)
 572                goto out_unregister_driver;
 573
 574        err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
 575        if (err)
 576                goto out_remove_port;
 577
 578        platform_set_drvdata(op, port);
 579
 580        return 0;
 581
 582out_remove_port:
 583        uart_remove_one_port(&sunhv_reg, port);
 584
 585out_unregister_driver:
 586        sunserial_unregister_minors(&sunhv_reg, 1);
 587
 588out_free_con_read_page:
 589        kfree(con_read_page);
 590
 591out_free_con_write_page:
 592        kfree(con_write_page);
 593
 594out_free_port:
 595        kfree(port);
 596        sunhv_port = NULL;
 597        return err;
 598}
 599
 600static int hv_remove(struct platform_device *dev)
 601{
 602        struct uart_port *port = platform_get_drvdata(dev);
 603
 604        free_irq(port->irq, port);
 605
 606        uart_remove_one_port(&sunhv_reg, port);
 607
 608        sunserial_unregister_minors(&sunhv_reg, 1);
 609        kfree(con_read_page);
 610        kfree(con_write_page);
 611        kfree(port);
 612        sunhv_port = NULL;
 613
 614        return 0;
 615}
 616
 617static const struct of_device_id hv_match[] = {
 618        {
 619                .name = "console",
 620                .compatible = "qcn",
 621        },
 622        {
 623                .name = "console",
 624                .compatible = "SUNW,sun4v-console",
 625        },
 626        {},
 627};
 628
 629static struct platform_driver hv_driver = {
 630        .driver = {
 631                .name = "hv",
 632                .of_match_table = hv_match,
 633        },
 634        .probe          = hv_probe,
 635        .remove         = hv_remove,
 636};
 637
 638static int __init sunhv_init(void)
 639{
 640        if (tlb_type != hypervisor)
 641                return -ENODEV;
 642
 643        return platform_driver_register(&hv_driver);
 644}
 645device_initcall(sunhv_init);
 646
 647#if 0 /* ...def MODULE ; never supported as such */
 648MODULE_AUTHOR("David S. Miller");
 649MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
 650MODULE_VERSION("2.0");
 651MODULE_LICENSE("GPL");
 652#endif
 653