Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* sunhv.c: Serial driver for SUN4V hypervisor console.
0003  *
0004  * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/errno.h>
0009 #include <linux/tty.h>
0010 #include <linux/tty_flip.h>
0011 #include <linux/major.h>
0012 #include <linux/circ_buf.h>
0013 #include <linux/serial.h>
0014 #include <linux/sysrq.h>
0015 #include <linux/console.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/slab.h>
0018 #include <linux/delay.h>
0019 #include <linux/init.h>
0020 #include <linux/of_device.h>
0021 
0022 #include <asm/hypervisor.h>
0023 #include <asm/spitfire.h>
0024 #include <asm/prom.h>
0025 #include <asm/irq.h>
0026 #include <asm/setup.h>
0027 
0028 #include <linux/serial_core.h>
0029 #include <linux/sunserialcore.h>
0030 
0031 #define CON_BREAK   ((long)-1)
0032 #define CON_HUP     ((long)-2)
0033 
0034 #define IGNORE_BREAK    0x1
0035 #define IGNORE_ALL  0x2
0036 
0037 static char *con_write_page;
0038 static char *con_read_page;
0039 
0040 static int hung_up = 0;
0041 
0042 static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
0043 {
0044     while (!uart_circ_empty(xmit)) {
0045         long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
0046 
0047         if (status != HV_EOK)
0048             break;
0049 
0050         xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
0051         port->icount.tx++;
0052     }
0053 }
0054 
0055 static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
0056 {
0057     while (!uart_circ_empty(xmit)) {
0058         unsigned long ra = __pa(xmit->buf + xmit->tail);
0059         unsigned long len, status, sent;
0060 
0061         len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
0062                       UART_XMIT_SIZE);
0063         status = sun4v_con_write(ra, len, &sent);
0064         if (status != HV_EOK)
0065             break;
0066         xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
0067         port->icount.tx += sent;
0068     }
0069 }
0070 
0071 static int receive_chars_getchar(struct uart_port *port)
0072 {
0073     int saw_console_brk = 0;
0074     int limit = 10000;
0075 
0076     while (limit-- > 0) {
0077         long status;
0078         long c = sun4v_con_getchar(&status);
0079 
0080         if (status == HV_EWOULDBLOCK)
0081             break;
0082 
0083         if (c == CON_BREAK) {
0084             if (uart_handle_break(port))
0085                 continue;
0086             saw_console_brk = 1;
0087             c = 0;
0088         }
0089 
0090         if (c == CON_HUP) {
0091             hung_up = 1;
0092             uart_handle_dcd_change(port, 0);
0093         } else if (hung_up) {
0094             hung_up = 0;
0095             uart_handle_dcd_change(port, 1);
0096         }
0097 
0098         if (port->state == NULL) {
0099             uart_handle_sysrq_char(port, c);
0100             continue;
0101         }
0102 
0103         port->icount.rx++;
0104 
0105         if (uart_handle_sysrq_char(port, c))
0106             continue;
0107 
0108         tty_insert_flip_char(&port->state->port, c, TTY_NORMAL);
0109     }
0110 
0111     return saw_console_brk;
0112 }
0113 
0114 static int receive_chars_read(struct uart_port *port)
0115 {
0116     static int saw_console_brk;
0117     int limit = 10000;
0118 
0119     while (limit-- > 0) {
0120         unsigned long ra = __pa(con_read_page);
0121         unsigned long bytes_read, i;
0122         long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
0123 
0124         if (stat != HV_EOK) {
0125             bytes_read = 0;
0126 
0127             if (stat == CON_BREAK) {
0128                 if (saw_console_brk)
0129                     sun_do_break();
0130 
0131                 if (uart_handle_break(port))
0132                     continue;
0133                 saw_console_brk = 1;
0134                 *con_read_page = 0;
0135                 bytes_read = 1;
0136             } else if (stat == CON_HUP) {
0137                 hung_up = 1;
0138                 uart_handle_dcd_change(port, 0);
0139                 continue;
0140             } else {
0141                 /* HV_EWOULDBLOCK, etc.  */
0142                 break;
0143             }
0144         }
0145 
0146         if (hung_up) {
0147             hung_up = 0;
0148             uart_handle_dcd_change(port, 1);
0149         }
0150 
0151         if (port->sysrq != 0 &&  *con_read_page) {
0152             for (i = 0; i < bytes_read; i++)
0153                 uart_handle_sysrq_char(port, con_read_page[i]);
0154             saw_console_brk = 0;
0155         }
0156 
0157         if (port->state == NULL)
0158             continue;
0159 
0160         port->icount.rx += bytes_read;
0161 
0162         tty_insert_flip_string(&port->state->port, con_read_page,
0163                 bytes_read);
0164     }
0165 
0166     return saw_console_brk;
0167 }
0168 
0169 struct sunhv_ops {
0170     void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
0171     int (*receive_chars)(struct uart_port *port);
0172 };
0173 
0174 static const struct sunhv_ops bychar_ops = {
0175     .transmit_chars = transmit_chars_putchar,
0176     .receive_chars = receive_chars_getchar,
0177 };
0178 
0179 static const struct sunhv_ops bywrite_ops = {
0180     .transmit_chars = transmit_chars_write,
0181     .receive_chars = receive_chars_read,
0182 };
0183 
0184 static const struct sunhv_ops *sunhv_ops = &bychar_ops;
0185 
0186 static struct tty_port *receive_chars(struct uart_port *port)
0187 {
0188     struct tty_port *tport = NULL;
0189 
0190     if (port->state != NULL)        /* Unopened serial console */
0191         tport = &port->state->port;
0192 
0193     if (sunhv_ops->receive_chars(port))
0194         sun_do_break();
0195 
0196     return tport;
0197 }
0198 
0199 static void transmit_chars(struct uart_port *port)
0200 {
0201     struct circ_buf *xmit;
0202 
0203     if (!port->state)
0204         return;
0205 
0206     xmit = &port->state->xmit;
0207     if (uart_circ_empty(xmit) || uart_tx_stopped(port))
0208         return;
0209 
0210     sunhv_ops->transmit_chars(port, xmit);
0211 
0212     if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
0213         uart_write_wakeup(port);
0214 }
0215 
0216 static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
0217 {
0218     struct uart_port *port = dev_id;
0219     struct tty_port *tport;
0220     unsigned long flags;
0221 
0222     spin_lock_irqsave(&port->lock, flags);
0223     tport = receive_chars(port);
0224     transmit_chars(port);
0225     spin_unlock_irqrestore(&port->lock, flags);
0226 
0227     if (tport)
0228         tty_flip_buffer_push(tport);
0229 
0230     return IRQ_HANDLED;
0231 }
0232 
0233 /* port->lock is not held.  */
0234 static unsigned int sunhv_tx_empty(struct uart_port *port)
0235 {
0236     /* Transmitter is always empty for us.  If the circ buffer
0237      * is non-empty or there is an x_char pending, our caller
0238      * will do the right thing and ignore what we return here.
0239      */
0240     return TIOCSER_TEMT;
0241 }
0242 
0243 /* port->lock held by caller.  */
0244 static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
0245 {
0246     return;
0247 }
0248 
0249 /* port->lock is held by caller and interrupts are disabled.  */
0250 static unsigned int sunhv_get_mctrl(struct uart_port *port)
0251 {
0252     return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
0253 }
0254 
0255 /* port->lock held by caller.  */
0256 static void sunhv_stop_tx(struct uart_port *port)
0257 {
0258     return;
0259 }
0260 
0261 /* port->lock held by caller.  */
0262 static void sunhv_start_tx(struct uart_port *port)
0263 {
0264     transmit_chars(port);
0265 }
0266 
0267 /* port->lock is not held.  */
0268 static void sunhv_send_xchar(struct uart_port *port, char ch)
0269 {
0270     unsigned long flags;
0271     int limit = 10000;
0272 
0273     if (ch == __DISABLED_CHAR)
0274         return;
0275 
0276     spin_lock_irqsave(&port->lock, flags);
0277 
0278     while (limit-- > 0) {
0279         long status = sun4v_con_putchar(ch);
0280         if (status == HV_EOK)
0281             break;
0282         udelay(1);
0283     }
0284 
0285     spin_unlock_irqrestore(&port->lock, flags);
0286 }
0287 
0288 /* port->lock held by caller.  */
0289 static void sunhv_stop_rx(struct uart_port *port)
0290 {
0291 }
0292 
0293 /* port->lock is not held.  */
0294 static void sunhv_break_ctl(struct uart_port *port, int break_state)
0295 {
0296     if (break_state) {
0297         unsigned long flags;
0298         int limit = 10000;
0299 
0300         spin_lock_irqsave(&port->lock, flags);
0301 
0302         while (limit-- > 0) {
0303             long status = sun4v_con_putchar(CON_BREAK);
0304             if (status == HV_EOK)
0305                 break;
0306             udelay(1);
0307         }
0308 
0309         spin_unlock_irqrestore(&port->lock, flags);
0310     }
0311 }
0312 
0313 /* port->lock is not held.  */
0314 static int sunhv_startup(struct uart_port *port)
0315 {
0316     return 0;
0317 }
0318 
0319 /* port->lock is not held.  */
0320 static void sunhv_shutdown(struct uart_port *port)
0321 {
0322 }
0323 
0324 /* port->lock is not held.  */
0325 static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
0326                   struct ktermios *old)
0327 {
0328     unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
0329     unsigned int quot = uart_get_divisor(port, baud);
0330     unsigned int iflag, cflag;
0331     unsigned long flags;
0332 
0333     spin_lock_irqsave(&port->lock, flags);
0334 
0335     iflag = termios->c_iflag;
0336     cflag = termios->c_cflag;
0337 
0338     port->ignore_status_mask = 0;
0339     if (iflag & IGNBRK)
0340         port->ignore_status_mask |= IGNORE_BREAK;
0341     if ((cflag & CREAD) == 0)
0342         port->ignore_status_mask |= IGNORE_ALL;
0343 
0344     /* XXX */
0345     uart_update_timeout(port, cflag,
0346                 (port->uartclk / (16 * quot)));
0347 
0348     spin_unlock_irqrestore(&port->lock, flags);
0349 }
0350 
0351 static const char *sunhv_type(struct uart_port *port)
0352 {
0353     return "SUN4V HCONS";
0354 }
0355 
0356 static void sunhv_release_port(struct uart_port *port)
0357 {
0358 }
0359 
0360 static int sunhv_request_port(struct uart_port *port)
0361 {
0362     return 0;
0363 }
0364 
0365 static void sunhv_config_port(struct uart_port *port, int flags)
0366 {
0367 }
0368 
0369 static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
0370 {
0371     return -EINVAL;
0372 }
0373 
0374 static const struct uart_ops sunhv_pops = {
0375     .tx_empty   = sunhv_tx_empty,
0376     .set_mctrl  = sunhv_set_mctrl,
0377     .get_mctrl  = sunhv_get_mctrl,
0378     .stop_tx    = sunhv_stop_tx,
0379     .start_tx   = sunhv_start_tx,
0380     .send_xchar = sunhv_send_xchar,
0381     .stop_rx    = sunhv_stop_rx,
0382     .break_ctl  = sunhv_break_ctl,
0383     .startup    = sunhv_startup,
0384     .shutdown   = sunhv_shutdown,
0385     .set_termios    = sunhv_set_termios,
0386     .type       = sunhv_type,
0387     .release_port   = sunhv_release_port,
0388     .request_port   = sunhv_request_port,
0389     .config_port    = sunhv_config_port,
0390     .verify_port    = sunhv_verify_port,
0391 };
0392 
0393 static struct uart_driver sunhv_reg = {
0394     .owner          = THIS_MODULE,
0395     .driver_name        = "sunhv",
0396     .dev_name       = "ttyHV",
0397     .major          = TTY_MAJOR,
0398 };
0399 
0400 static struct uart_port *sunhv_port;
0401 
0402 void sunhv_migrate_hvcons_irq(int cpu)
0403 {
0404     /* Migrate hvcons irq to param cpu */
0405     irq_force_affinity(sunhv_port->irq, cpumask_of(cpu));
0406 }
0407 
0408 /* Copy 's' into the con_write_page, decoding "\n" into
0409  * "\r\n" along the way.  We have to return two lengths
0410  * because the caller needs to know how much to advance
0411  * 's' and also how many bytes to output via con_write_page.
0412  */
0413 static int fill_con_write_page(const char *s, unsigned int n,
0414                    unsigned long *page_bytes)
0415 {
0416     const char *orig_s = s;
0417     char *p = con_write_page;
0418     int left = PAGE_SIZE;
0419 
0420     while (n--) {
0421         if (*s == '\n') {
0422             if (left < 2)
0423                 break;
0424             *p++ = '\r';
0425             left--;
0426         } else if (left < 1)
0427             break;
0428         *p++ = *s++;
0429         left--;
0430     }
0431     *page_bytes = p - con_write_page;
0432     return s - orig_s;
0433 }
0434 
0435 static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
0436 {
0437     struct uart_port *port = sunhv_port;
0438     unsigned long flags;
0439     int locked = 1;
0440 
0441     if (port->sysrq || oops_in_progress)
0442         locked = spin_trylock_irqsave(&port->lock, flags);
0443     else
0444         spin_lock_irqsave(&port->lock, flags);
0445 
0446     while (n > 0) {
0447         unsigned long ra = __pa(con_write_page);
0448         unsigned long page_bytes;
0449         unsigned int cpy = fill_con_write_page(s, n,
0450                                &page_bytes);
0451 
0452         n -= cpy;
0453         s += cpy;
0454         while (page_bytes > 0) {
0455             unsigned long written;
0456             int limit = 1000000;
0457 
0458             while (limit--) {
0459                 unsigned long stat;
0460 
0461                 stat = sun4v_con_write(ra, page_bytes,
0462                                &written);
0463                 if (stat == HV_EOK)
0464                     break;
0465                 udelay(1);
0466             }
0467             if (limit < 0)
0468                 break;
0469             page_bytes -= written;
0470             ra += written;
0471         }
0472     }
0473 
0474     if (locked)
0475         spin_unlock_irqrestore(&port->lock, flags);
0476 }
0477 
0478 static inline void sunhv_console_putchar(struct uart_port *port, char c)
0479 {
0480     int limit = 1000000;
0481 
0482     while (limit-- > 0) {
0483         long status = sun4v_con_putchar(c);
0484         if (status == HV_EOK)
0485             break;
0486         udelay(1);
0487     }
0488 }
0489 
0490 static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
0491 {
0492     struct uart_port *port = sunhv_port;
0493     unsigned long flags;
0494     int i, locked = 1;
0495 
0496     if (port->sysrq || oops_in_progress)
0497         locked = spin_trylock_irqsave(&port->lock, flags);
0498     else
0499         spin_lock_irqsave(&port->lock, flags);
0500 
0501     for (i = 0; i < n; i++) {
0502         if (*s == '\n')
0503             sunhv_console_putchar(port, '\r');
0504         sunhv_console_putchar(port, *s++);
0505     }
0506 
0507     if (locked)
0508         spin_unlock_irqrestore(&port->lock, flags);
0509 }
0510 
0511 static struct console sunhv_console = {
0512     .name   =   "ttyHV",
0513     .write  =   sunhv_console_write_bychar,
0514     .device =   uart_console_device,
0515     .flags  =   CON_PRINTBUFFER,
0516     .index  =   -1,
0517     .data   =   &sunhv_reg,
0518 };
0519 
0520 static int hv_probe(struct platform_device *op)
0521 {
0522     struct uart_port *port;
0523     unsigned long minor;
0524     int err;
0525 
0526     if (op->archdata.irqs[0] == 0xffffffff)
0527         return -ENODEV;
0528 
0529     port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
0530     if (unlikely(!port))
0531         return -ENOMEM;
0532 
0533     minor = 1;
0534     if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
0535         minor >= 1) {
0536         err = -ENOMEM;
0537         con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
0538         if (!con_write_page)
0539             goto out_free_port;
0540 
0541         con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
0542         if (!con_read_page)
0543             goto out_free_con_write_page;
0544 
0545         sunhv_console.write = sunhv_console_write_paged;
0546         sunhv_ops = &bywrite_ops;
0547     }
0548 
0549     sunhv_port = port;
0550 
0551     port->has_sysrq = 1;
0552     port->line = 0;
0553     port->ops = &sunhv_pops;
0554     port->type = PORT_SUNHV;
0555     port->uartclk = ( 29491200 / 16 ); /* arbitrary */
0556 
0557     port->membase = (unsigned char __iomem *) __pa(port);
0558 
0559     port->irq = op->archdata.irqs[0];
0560 
0561     port->dev = &op->dev;
0562 
0563     err = sunserial_register_minors(&sunhv_reg, 1);
0564     if (err)
0565         goto out_free_con_read_page;
0566 
0567     sunserial_console_match(&sunhv_console, op->dev.of_node,
0568                 &sunhv_reg, port->line, false);
0569 
0570     err = uart_add_one_port(&sunhv_reg, port);
0571     if (err)
0572         goto out_unregister_driver;
0573 
0574     err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
0575     if (err)
0576         goto out_remove_port;
0577 
0578     platform_set_drvdata(op, port);
0579 
0580     return 0;
0581 
0582 out_remove_port:
0583     uart_remove_one_port(&sunhv_reg, port);
0584 
0585 out_unregister_driver:
0586     sunserial_unregister_minors(&sunhv_reg, 1);
0587 
0588 out_free_con_read_page:
0589     kfree(con_read_page);
0590 
0591 out_free_con_write_page:
0592     kfree(con_write_page);
0593 
0594 out_free_port:
0595     kfree(port);
0596     sunhv_port = NULL;
0597     return err;
0598 }
0599 
0600 static int hv_remove(struct platform_device *dev)
0601 {
0602     struct uart_port *port = platform_get_drvdata(dev);
0603 
0604     free_irq(port->irq, port);
0605 
0606     uart_remove_one_port(&sunhv_reg, port);
0607 
0608     sunserial_unregister_minors(&sunhv_reg, 1);
0609     kfree(con_read_page);
0610     kfree(con_write_page);
0611     kfree(port);
0612     sunhv_port = NULL;
0613 
0614     return 0;
0615 }
0616 
0617 static const struct of_device_id hv_match[] = {
0618     {
0619         .name = "console",
0620         .compatible = "qcn",
0621     },
0622     {
0623         .name = "console",
0624         .compatible = "SUNW,sun4v-console",
0625     },
0626     {},
0627 };
0628 
0629 static struct platform_driver hv_driver = {
0630     .driver = {
0631         .name = "hv",
0632         .of_match_table = hv_match,
0633     },
0634     .probe      = hv_probe,
0635     .remove     = hv_remove,
0636 };
0637 
0638 static int __init sunhv_init(void)
0639 {
0640     if (tlb_type != hypervisor)
0641         return -ENODEV;
0642 
0643     return platform_driver_register(&hv_driver);
0644 }
0645 device_initcall(sunhv_init);
0646 
0647 #if 0 /* ...def MODULE ; never supported as such */
0648 MODULE_AUTHOR("David S. Miller");
0649 MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
0650 MODULE_VERSION("2.0");
0651 MODULE_LICENSE("GPL");
0652 #endif