sunhv.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /* sunhv.c: Serial driver for SUN4V hypervisor console.
  2. *
  3. * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
  4. */
  5. #include <linux/module.h>
  6. #include <linux/kernel.h>
  7. #include <linux/errno.h>
  8. #include <linux/tty.h>
  9. #include <linux/tty_flip.h>
  10. #include <linux/major.h>
  11. #include <linux/circ_buf.h>
  12. #include <linux/serial.h>
  13. #include <linux/sysrq.h>
  14. #include <linux/console.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/slab.h>
  17. #include <linux/delay.h>
  18. #include <linux/init.h>
  19. #include <asm/hypervisor.h>
  20. #include <asm/spitfire.h>
  21. #if defined(CONFIG_MAGIC_SYSRQ)
  22. #define SUPPORT_SYSRQ
  23. #endif
  24. #include <linux/serial_core.h>
  25. #include "suncore.h"
  26. #define CON_BREAK ((long)-1)
  27. #define CON_HUP ((long)-2)
  28. static inline long hypervisor_con_getchar(long *status)
  29. {
  30. register unsigned long func asm("%o5");
  31. register unsigned long arg0 asm("%o0");
  32. register unsigned long arg1 asm("%o1");
  33. func = HV_FAST_CONS_GETCHAR;
  34. arg0 = 0;
  35. arg1 = 0;
  36. __asm__ __volatile__("ta %6"
  37. : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
  38. : "0" (func), "1" (arg0), "2" (arg1),
  39. "i" (HV_FAST_TRAP));
  40. *status = arg0;
  41. return (long) arg1;
  42. }
  43. static inline long hypervisor_con_putchar(long ch)
  44. {
  45. register unsigned long func asm("%o5");
  46. register unsigned long arg0 asm("%o0");
  47. func = HV_FAST_CONS_PUTCHAR;
  48. arg0 = ch;
  49. __asm__ __volatile__("ta %4"
  50. : "=&r" (func), "=&r" (arg0)
  51. : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
  52. return (long) arg0;
  53. }
  54. #define IGNORE_BREAK 0x1
  55. #define IGNORE_ALL 0x2
  56. static int hung_up = 0;
  57. static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs)
  58. {
  59. struct tty_struct *tty = NULL;
  60. int saw_console_brk = 0;
  61. int limit = 10000;
  62. if (port->info != NULL) /* Unopened serial console */
  63. tty = port->info->tty;
  64. while (limit-- > 0) {
  65. long status;
  66. long c = hypervisor_con_getchar(&status);
  67. unsigned char flag;
  68. if (status == HV_EWOULDBLOCK)
  69. break;
  70. if (c == CON_BREAK) {
  71. saw_console_brk = 1;
  72. c = 0;
  73. }
  74. if (c == CON_HUP) {
  75. hung_up = 1;
  76. uart_handle_dcd_change(port, 0);
  77. } else if (hung_up) {
  78. hung_up = 0;
  79. uart_handle_dcd_change(port, 1);
  80. }
  81. if (tty == NULL) {
  82. uart_handle_sysrq_char(port, c, regs);
  83. continue;
  84. }
  85. flag = TTY_NORMAL;
  86. port->icount.rx++;
  87. if (c == CON_BREAK) {
  88. port->icount.brk++;
  89. if (uart_handle_break(port))
  90. continue;
  91. flag = TTY_BREAK;
  92. }
  93. if (uart_handle_sysrq_char(port, c, regs))
  94. continue;
  95. if ((port->ignore_status_mask & IGNORE_ALL) ||
  96. ((port->ignore_status_mask & IGNORE_BREAK) &&
  97. (c == CON_BREAK)))
  98. continue;
  99. tty_insert_flip_char(tty, c, flag);
  100. }
  101. if (saw_console_brk)
  102. sun_do_break();
  103. return tty;
  104. }
  105. static void transmit_chars(struct uart_port *port)
  106. {
  107. struct circ_buf *xmit = &port->info->xmit;
  108. if (uart_circ_empty(xmit) || uart_tx_stopped(port))
  109. return;
  110. while (!uart_circ_empty(xmit)) {
  111. long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
  112. if (status != HV_EOK)
  113. break;
  114. xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
  115. port->icount.tx++;
  116. }
  117. if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
  118. uart_write_wakeup(port);
  119. }
  120. static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  121. {
  122. struct uart_port *port = dev_id;
  123. struct tty_struct *tty;
  124. unsigned long flags;
  125. spin_lock_irqsave(&port->lock, flags);
  126. tty = receive_chars(port, regs);
  127. transmit_chars(port);
  128. spin_unlock_irqrestore(&port->lock, flags);
  129. if (tty)
  130. tty_flip_buffer_push(tty);
  131. return IRQ_HANDLED;
  132. }
  133. /* port->lock is not held. */
  134. static unsigned int sunhv_tx_empty(struct uart_port *port)
  135. {
  136. /* Transmitter is always empty for us. If the circ buffer
  137. * is non-empty or there is an x_char pending, our caller
  138. * will do the right thing and ignore what we return here.
  139. */
  140. return TIOCSER_TEMT;
  141. }
  142. /* port->lock held by caller. */
  143. static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl)
  144. {
  145. return;
  146. }
  147. /* port->lock is held by caller and interrupts are disabled. */
  148. static unsigned int sunhv_get_mctrl(struct uart_port *port)
  149. {
  150. return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
  151. }
  152. /* port->lock held by caller. */
  153. static void sunhv_stop_tx(struct uart_port *port)
  154. {
  155. return;
  156. }
  157. /* port->lock held by caller. */
  158. static void sunhv_start_tx(struct uart_port *port)
  159. {
  160. struct circ_buf *xmit = &port->info->xmit;
  161. unsigned long flags;
  162. spin_lock_irqsave(&port->lock, flags);
  163. while (!uart_circ_empty(xmit)) {
  164. long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
  165. if (status != HV_EOK)
  166. break;
  167. xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
  168. port->icount.tx++;
  169. }
  170. spin_unlock_irqrestore(&port->lock, flags);
  171. }
  172. /* port->lock is not held. */
  173. static void sunhv_send_xchar(struct uart_port *port, char ch)
  174. {
  175. unsigned long flags;
  176. int limit = 10000;
  177. spin_lock_irqsave(&port->lock, flags);
  178. while (limit-- > 0) {
  179. long status = hypervisor_con_putchar(ch);
  180. if (status == HV_EOK)
  181. break;
  182. }
  183. spin_unlock_irqrestore(&port->lock, flags);
  184. }
  185. /* port->lock held by caller. */
  186. static void sunhv_stop_rx(struct uart_port *port)
  187. {
  188. }
  189. /* port->lock held by caller. */
  190. static void sunhv_enable_ms(struct uart_port *port)
  191. {
  192. }
  193. /* port->lock is not held. */
  194. static void sunhv_break_ctl(struct uart_port *port, int break_state)
  195. {
  196. if (break_state) {
  197. unsigned long flags;
  198. int limit = 10000;
  199. spin_lock_irqsave(&port->lock, flags);
  200. while (limit-- > 0) {
  201. long status = hypervisor_con_putchar(CON_BREAK);
  202. if (status == HV_EOK)
  203. break;
  204. }
  205. spin_unlock_irqrestore(&port->lock, flags);
  206. }
  207. }
  208. /* port->lock is not held. */
  209. static int sunhv_startup(struct uart_port *port)
  210. {
  211. return 0;
  212. }
  213. /* port->lock is not held. */
  214. static void sunhv_shutdown(struct uart_port *port)
  215. {
  216. }
  217. /* port->lock is not held. */
  218. static void sunhv_set_termios(struct uart_port *port, struct termios *termios,
  219. struct termios *old)
  220. {
  221. unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
  222. unsigned int quot = uart_get_divisor(port, baud);
  223. unsigned int iflag, cflag;
  224. unsigned long flags;
  225. spin_lock_irqsave(&port->lock, flags);
  226. iflag = termios->c_iflag;
  227. cflag = termios->c_cflag;
  228. port->ignore_status_mask = 0;
  229. if (iflag & IGNBRK)
  230. port->ignore_status_mask |= IGNORE_BREAK;
  231. if ((cflag & CREAD) == 0)
  232. port->ignore_status_mask |= IGNORE_ALL;
  233. /* XXX */
  234. uart_update_timeout(port, cflag,
  235. (port->uartclk / (16 * quot)));
  236. spin_unlock_irqrestore(&port->lock, flags);
  237. }
  238. static const char *sunhv_type(struct uart_port *port)
  239. {
  240. return "SUN4V HCONS";
  241. }
  242. static void sunhv_release_port(struct uart_port *port)
  243. {
  244. }
  245. static int sunhv_request_port(struct uart_port *port)
  246. {
  247. return 0;
  248. }
  249. static void sunhv_config_port(struct uart_port *port, int flags)
  250. {
  251. }
  252. static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser)
  253. {
  254. return -EINVAL;
  255. }
  256. static struct uart_ops sunhv_pops = {
  257. .tx_empty = sunhv_tx_empty,
  258. .set_mctrl = sunhv_set_mctrl,
  259. .get_mctrl = sunhv_get_mctrl,
  260. .stop_tx = sunhv_stop_tx,
  261. .start_tx = sunhv_start_tx,
  262. .send_xchar = sunhv_send_xchar,
  263. .stop_rx = sunhv_stop_rx,
  264. .enable_ms = sunhv_enable_ms,
  265. .break_ctl = sunhv_break_ctl,
  266. .startup = sunhv_startup,
  267. .shutdown = sunhv_shutdown,
  268. .set_termios = sunhv_set_termios,
  269. .type = sunhv_type,
  270. .release_port = sunhv_release_port,
  271. .request_port = sunhv_request_port,
  272. .config_port = sunhv_config_port,
  273. .verify_port = sunhv_verify_port,
  274. };
  275. static struct uart_driver sunhv_reg = {
  276. .owner = THIS_MODULE,
  277. .driver_name = "serial",
  278. .devfs_name = "tts/",
  279. .dev_name = "ttyS",
  280. .major = TTY_MAJOR,
  281. };
  282. static struct uart_port *sunhv_port;
  283. static inline void sunhv_console_putchar(struct uart_port *port, char c)
  284. {
  285. unsigned long flags;
  286. int limit = 10000;
  287. spin_lock_irqsave(&port->lock, flags);
  288. while (limit-- > 0) {
  289. long status = hypervisor_con_putchar(c);
  290. if (status == HV_EOK)
  291. break;
  292. }
  293. spin_unlock_irqrestore(&port->lock, flags);
  294. }
  295. static void sunhv_console_write(struct console *con, const char *s, unsigned n)
  296. {
  297. struct uart_port *port = sunhv_port;
  298. int i;
  299. for (i = 0; i < n; i++) {
  300. if (*s == '\n')
  301. sunhv_console_putchar(port, '\r');
  302. sunhv_console_putchar(port, *s++);
  303. }
  304. }
  305. static int sunhv_console_setup(struct console *con, char *options)
  306. {
  307. return 0;
  308. }
  309. static struct console sunhv_console = {
  310. .name = "ttyS",
  311. .write = sunhv_console_write,
  312. .device = uart_console_device,
  313. .setup = sunhv_console_setup,
  314. .flags = CON_PRINTBUFFER,
  315. .index = -1,
  316. .data = &sunhv_reg,
  317. };
  318. static void __init sunhv_console_init(void)
  319. {
  320. if (con_is_present())
  321. return;
  322. sunhv_console.index = 0;
  323. register_console(&sunhv_console);
  324. }
  325. static int __init sunhv_init(void)
  326. {
  327. struct uart_port *port;
  328. int ret;
  329. if (tlb_type != hypervisor)
  330. return -ENODEV;
  331. port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
  332. if (unlikely(!port))
  333. return -ENOMEM;
  334. port->line = 0;
  335. port->ops = &sunhv_pops;
  336. port->type = PORT_SUNHV;
  337. port->uartclk = ( 29491200 / 16 ); /* arbitrary */
  338. /* XXX Get interrupt. XXX */
  339. if (request_irq(0 /* XXX */, sunhv_interrupt,
  340. SA_SHIRQ, "serial(sunhv)", port)) {
  341. printk("sunhv: Cannot get IRQ %x\n",
  342. 0 /* XXX */);
  343. kfree(port);
  344. return -ENODEV;
  345. }
  346. sunhv_reg.minor = sunserial_current_minor;
  347. sunhv_reg.nr = 1;
  348. sunhv_reg.cons = &sunhv_console;
  349. ret = uart_register_driver(&sunhv_reg);
  350. if (ret < 0) {
  351. free_irq(0 /* XXX */, up);
  352. kfree(port);
  353. return ret;
  354. }
  355. sunhv_port = port;
  356. sunserial_current_minor += 1;
  357. sunhv_console_init();
  358. uart_add_one_port(&sunhv_reg, port);
  359. return 0;
  360. }
  361. static void __exit sunhv_exit(void)
  362. {
  363. struct uart_port *port = sunhv_port;
  364. BUG_ON(!port);
  365. uart_remove_one_port(&sunhv_reg, port);
  366. free_irq(0 /* XXX */, port);
  367. sunserial_current_minor -= 1;
  368. uart_unregister_driver(&sunhv_reg);
  369. kfree(sunhv_port);
  370. sunhv_port = NULL;
  371. }
  372. module_init(sunhv_init);
  373. module_exit(sunhv_exit);
  374. MODULE_AUTHOR("David S. Miller");
  375. MODULE_DESCRIPTION("SUN4V Hypervisor console driver")
  376. MODULE_LICENSE("GPL");