aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 14:14:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 14:14:33 -0400
commit4de9ad9bc08b4953fc03336ad38908496e2f8826 (patch)
treebd44add223061a58317034a0d6c9686d95d12fba /drivers/tty
parent576c25eb5954035b64112188d9a2683144600f3d (diff)
parent06da6629e68ddc8ffe2933d33b3681f09104b3f1 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
Pull Tile arch updates from Chris Metcalf: "These changes bring in a bunch of new functionality that has been maintained internally at Tilera over the last year, plus other stray bits of work that I've taken into the tile tree from other folks. The changes include some PCI root complex work, interrupt-driven console support, support for performing fast-path unaligned data fixups by kernel-based JIT code generation, CONFIG_PREEMPT support, vDSO support for gettimeofday(), a serial driver for the tilegx on-chip UART, KGDB support, more optimized string routines, support for ftrace and kprobes, improved ASLR, and many bug fixes. We also remove support for the old TILE64 chip, which is no longer buildable" * git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile: (85 commits) tile: refresh tile defconfig files tile: rework <asm/cmpxchg.h> tile PCI RC: make default consistent DMA mask 32-bit tile: add null check for kzalloc in tile/kernel/setup.c tile: make __write_once a synonym for __read_mostly tile: remove support for TILE64 tile: use asm-generic/bitops/builtin-*.h tile: eliminate no-op "noatomichash" boot argument tile: use standard tile_bundle_bits type in traps.c tile: simplify code referencing hypervisor API addresses tile: change <asm/system.h> to <asm/switch_to.h> in comments tile: mark pcibios_init() as __init tile: check for correct compiler earlier in asm-offsets.c tile: use standard 'generic-y' model for <asm/hw_irq.h> tile: use asm-generic version of <asm/local64.h> tile PCI RC: add comment about "PCI hole" problem tile: remove DEBUG_EXTRA_FLAGS kernel config option tile: add virt_to_kpte() API and clean up and document behavior tile: support FRAME_POINTER tile: support reporting Tilera hypervisor statistics ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/hvc_tile.c149
-rw-r--r--drivers/tty/serial/Kconfig9
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/tilegx.c708
4 files changed, 861 insertions, 6 deletions
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
index 7a84a0595477..af8cdaa1dcb9 100644
--- a/drivers/tty/hvc/hvc_tile.c
+++ b/drivers/tty/hvc/hvc_tile.c
@@ -18,16 +18,46 @@
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/err.h> 19#include <linux/err.h>
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
21#include <linux/moduleparam.h> 23#include <linux/moduleparam.h>
24#include <linux/platform_device.h>
22#include <linux/types.h> 25#include <linux/types.h>
23 26
27#include <asm/setup.h>
28#include <arch/sim_def.h>
29
24#include <hv/hypervisor.h> 30#include <hv/hypervisor.h>
25 31
26#include "hvc_console.h" 32#include "hvc_console.h"
27 33
34static int use_sim_console;
35static int __init sim_console(char *str)
36{
37 use_sim_console = 1;
38 return 0;
39}
40early_param("sim_console", sim_console);
41
42int tile_console_write(const char *buf, int count)
43{
44 if (unlikely(use_sim_console)) {
45 int i;
46 for (i = 0; i < count; ++i)
47 __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
48 (buf[i] << _SIM_CONTROL_OPERATOR_BITS));
49 __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
50 (SIM_PUTC_FLUSH_BINARY <<
51 _SIM_CONTROL_OPERATOR_BITS));
52 return 0;
53 } else {
54 return hv_console_write((HV_VirtAddr)buf, count);
55 }
56}
57
28static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) 58static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
29{ 59{
30 return hv_console_write((HV_VirtAddr)buf, count); 60 return tile_console_write(buf, count);
31} 61}
32 62
33static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) 63static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
@@ -44,25 +74,132 @@ static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
44 return i; 74 return i;
45} 75}
46 76
77#ifdef __tilegx__
78/*
79 * IRQ based callbacks.
80 */
81static int hvc_tile_notifier_add_irq(struct hvc_struct *hp, int irq)
82{
83 int rc;
84 int cpu = raw_smp_processor_id(); /* Choose an arbitrary cpu */
85 HV_Coord coord = { .x = cpu_x(cpu), .y = cpu_y(cpu) };
86
87 rc = notifier_add_irq(hp, irq);
88 if (rc)
89 return rc;
90
91 /*
92 * Request that the hypervisor start sending us interrupts.
93 * If the hypervisor returns an error, we still return 0, so that
94 * we can fall back to polling.
95 */
96 if (hv_console_set_ipi(KERNEL_PL, irq, coord) < 0)
97 notifier_del_irq(hp, irq);
98
99 return 0;
100}
101
102static void hvc_tile_notifier_del_irq(struct hvc_struct *hp, int irq)
103{
104 HV_Coord coord = { 0, 0 };
105
106 /* Tell the hypervisor to stop sending us interrupts. */
107 hv_console_set_ipi(KERNEL_PL, -1, coord);
108
109 notifier_del_irq(hp, irq);
110}
111
112static void hvc_tile_notifier_hangup_irq(struct hvc_struct *hp, int irq)
113{
114 hvc_tile_notifier_del_irq(hp, irq);
115}
116#endif
117
47static const struct hv_ops hvc_tile_get_put_ops = { 118static const struct hv_ops hvc_tile_get_put_ops = {
48 .get_chars = hvc_tile_get_chars, 119 .get_chars = hvc_tile_get_chars,
49 .put_chars = hvc_tile_put_chars, 120 .put_chars = hvc_tile_put_chars,
121#ifdef __tilegx__
122 .notifier_add = hvc_tile_notifier_add_irq,
123 .notifier_del = hvc_tile_notifier_del_irq,
124 .notifier_hangup = hvc_tile_notifier_hangup_irq,
125#endif
126};
127
128
129#ifdef __tilegx__
130static int hvc_tile_probe(struct platform_device *pdev)
131{
132 struct hvc_struct *hp;
133 int tile_hvc_irq;
134
135 /* Create our IRQ and register it. */
136 tile_hvc_irq = create_irq();
137 if (tile_hvc_irq < 0)
138 return -ENXIO;
139
140 tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);
141 hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);
142 if (IS_ERR(hp)) {
143 destroy_irq(tile_hvc_irq);
144 return PTR_ERR(hp);
145 }
146 dev_set_drvdata(&pdev->dev, hp);
147
148 return 0;
149}
150
151static int hvc_tile_remove(struct platform_device *pdev)
152{
153 int rc;
154 struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
155
156 rc = hvc_remove(hp);
157 if (rc == 0)
158 destroy_irq(hp->data);
159
160 return rc;
161}
162
163static void hvc_tile_shutdown(struct platform_device *pdev)
164{
165 struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
166
167 hvc_tile_notifier_del_irq(hp, hp->data);
168}
169
170static struct platform_device hvc_tile_pdev = {
171 .name = "hvc-tile",
172 .id = 0,
173};
174
175static struct platform_driver hvc_tile_driver = {
176 .probe = hvc_tile_probe,
177 .remove = hvc_tile_remove,
178 .shutdown = hvc_tile_shutdown,
179 .driver = {
180 .name = "hvc-tile",
181 .owner = THIS_MODULE,
182 }
50}; 183};
184#endif
51 185
52static int __init hvc_tile_console_init(void) 186static int __init hvc_tile_console_init(void)
53{ 187{
54 extern void disable_early_printk(void);
55 hvc_instantiate(0, 0, &hvc_tile_get_put_ops); 188 hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
56 add_preferred_console("hvc", 0, NULL); 189 add_preferred_console("hvc", 0, NULL);
57 disable_early_printk();
58 return 0; 190 return 0;
59} 191}
60console_initcall(hvc_tile_console_init); 192console_initcall(hvc_tile_console_init);
61 193
62static int __init hvc_tile_init(void) 194static int __init hvc_tile_init(void)
63{ 195{
64 struct hvc_struct *s; 196#ifndef __tilegx__
65 s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); 197 struct hvc_struct *hp;
66 return IS_ERR(s) ? PTR_ERR(s) : 0; 198 hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
199 return IS_ERR(hp) ? PTR_ERR(hp) : 0;
200#else
201 platform_device_register(&hvc_tile_pdev);
202 return platform_driver_register(&hvc_tile_driver);
203#endif
67} 204}
68device_initcall(hvc_tile_init); 205device_initcall(hvc_tile_init);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index cc4c8682b47b..47c6e7b9e150 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1439,6 +1439,15 @@ config SERIAL_EFM32_UART_CONSOLE
1439 depends on SERIAL_EFM32_UART=y 1439 depends on SERIAL_EFM32_UART=y
1440 select SERIAL_CORE_CONSOLE 1440 select SERIAL_CORE_CONSOLE
1441 1441
1442config SERIAL_TILEGX
1443 tristate "TILE-Gx on-chip serial port support"
1444 depends on TILEGX
1445 select TILE_GXIO_UART
1446 select SERIAL_CORE
1447 ---help---
1448 This device provides access to the on-chip UARTs on the TILE-Gx
1449 processor.
1450
1442config SERIAL_ARC 1451config SERIAL_ARC
1443 tristate "ARC UART driver support" 1452 tristate "ARC UART driver support"
1444 select SERIAL_CORE 1453 select SERIAL_CORE
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 47b679c547e9..3068c7722087 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
66obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o 66obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
67obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o 67obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
68obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o 68obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o
69obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o
69obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o 70obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
70obj-$(CONFIG_SERIAL_QE) += ucc_uart.o 71obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
71obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o 72obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c
new file mode 100644
index 000000000000..f92d7e6bd876
--- /dev/null
+++ b/drivers/tty/serial/tilegx.c
@@ -0,0 +1,708 @@
1/*
2 * Copyright 2013 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * TILEGx UART driver.
15 */
16
17#include <linux/delay.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/io.h>
21#include <linux/irq.h>
22#include <linux/module.h>
23#include <linux/serial_core.h>
24#include <linux/tty.h>
25#include <linux/tty_flip.h>
26
27#include <gxio/common.h>
28#include <gxio/iorpc_globals.h>
29#include <gxio/iorpc_uart.h>
30#include <gxio/kiorpc.h>
31
32#include <hv/drv_uart_intf.h>
33
34/*
35 * Use device name ttyS, major 4, minor 64-65.
36 * This is the usual serial port name, 8250 conventional range.
37 */
38#define TILEGX_UART_MAJOR TTY_MAJOR
39#define TILEGX_UART_MINOR 64
40#define TILEGX_UART_NAME "ttyS"
41#define DRIVER_NAME_STRING "TILEGx_Serial"
42#define TILEGX_UART_REF_CLK 125000000; /* REF_CLK is always 125 MHz. */
43
44struct tile_uart_port {
45 /* UART port. */
46 struct uart_port uart;
47
48 /* GXIO device context. */
49 gxio_uart_context_t context;
50
51 /* UART access mutex. */
52 struct mutex mutex;
53
54 /* CPU receiving interrupts. */
55 int irq_cpu;
56};
57
58static struct tile_uart_port tile_uart_ports[TILEGX_UART_NR];
59static struct uart_driver tilegx_uart_driver;
60
61
62/*
63 * Read UART rx fifo, and insert the chars into tty buffer.
64 */
65static void receive_chars(struct tile_uart_port *tile_uart,
66 struct tty_struct *tty)
67{
68 int i;
69 char c;
70 UART_FIFO_COUNT_t count;
71 gxio_uart_context_t *context = &tile_uart->context;
72 struct tty_port *port = tty->port;
73
74 count.word = gxio_uart_read(context, UART_FIFO_COUNT);
75 for (i = 0; i < count.rfifo_count; i++) {
76 c = (char)gxio_uart_read(context, UART_RECEIVE_DATA);
77 tty_insert_flip_char(port, c, TTY_NORMAL);
78 }
79}
80
81
82/*
83 * Drain the Rx FIFO, called by interrupt handler.
84 */
85static void handle_receive(struct tile_uart_port *tile_uart)
86{
87 struct tty_port *port = &tile_uart->uart.state->port;
88 struct tty_struct *tty = tty_port_tty_get(port);
89 gxio_uart_context_t *context = &tile_uart->context;
90
91 if (!tty)
92 return;
93
94 /* First read UART rx fifo. */
95 receive_chars(tile_uart, tty);
96
97 /* Reset RFIFO_WE interrupt. */
98 gxio_uart_write(context, UART_INTERRUPT_STATUS,
99 UART_INTERRUPT_MASK__RFIFO_WE_MASK);
100
101 /* Final read, if any chars comes between the first read and
102 * the interrupt reset.
103 */
104 receive_chars(tile_uart, tty);
105
106 spin_unlock(&tile_uart->uart.lock);
107 tty_flip_buffer_push(port);
108 spin_lock(&tile_uart->uart.lock);
109 tty_kref_put(tty);
110}
111
112
113/*
114 * Push one char to UART Write FIFO.
115 * Return 0 on success, -1 if write filo is full.
116 */
117static int tilegx_putchar(gxio_uart_context_t *context, char c)
118{
119 UART_FLAG_t flag;
120 flag.word = gxio_uart_read(context, UART_FLAG);
121 if (flag.wfifo_full)
122 return -1;
123
124 gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c);
125 return 0;
126}
127
128
129/*
130 * Send chars to UART Write FIFO; called by interrupt handler.
131 */
132static void handle_transmit(struct tile_uart_port *tile_uart)
133{
134 unsigned char ch;
135 struct uart_port *port;
136 struct circ_buf *xmit;
137 gxio_uart_context_t *context = &tile_uart->context;
138
139 /* First reset WFIFO_RE interrupt. */
140 gxio_uart_write(context, UART_INTERRUPT_STATUS,
141 UART_INTERRUPT_MASK__WFIFO_RE_MASK);
142
143 port = &tile_uart->uart;
144 xmit = &port->state->xmit;
145 if (port->x_char) {
146 if (tilegx_putchar(context, port->x_char))
147 return;
148 port->x_char = 0;
149 port->icount.tx++;
150 }
151
152 if (uart_circ_empty(xmit) || uart_tx_stopped(port))
153 return;
154
155 while (!uart_circ_empty(xmit)) {
156 ch = xmit->buf[xmit->tail];
157 if (tilegx_putchar(context, ch))
158 break;
159 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
160 port->icount.tx++;
161 }
162
163 /* Reset WFIFO_RE interrupt. */
164 gxio_uart_write(context, UART_INTERRUPT_STATUS,
165 UART_INTERRUPT_MASK__WFIFO_RE_MASK);
166
167 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
168 uart_write_wakeup(port);
169}
170
171
172/*
173 * UART Interrupt handler.
174 */
175static irqreturn_t tilegx_interrupt(int irq, void *dev_id)
176{
177 unsigned long flags;
178 UART_INTERRUPT_STATUS_t intr_stat;
179 struct tile_uart_port *tile_uart;
180 gxio_uart_context_t *context;
181 struct uart_port *port = dev_id;
182 irqreturn_t ret = IRQ_NONE;
183
184 spin_lock_irqsave(&port->lock, flags);
185
186 tile_uart = container_of(port, struct tile_uart_port, uart);
187 context = &tile_uart->context;
188 intr_stat.word = gxio_uart_read(context, UART_INTERRUPT_STATUS);
189
190 if (intr_stat.rfifo_we) {
191 handle_receive(tile_uart);
192 ret = IRQ_HANDLED;
193 }
194 if (intr_stat.wfifo_re) {
195 handle_transmit(tile_uart);
196 ret = IRQ_HANDLED;
197 }
198
199 spin_unlock_irqrestore(&port->lock, flags);
200 return ret;
201}
202
203
204/*
205 * Return TIOCSER_TEMT when transmitter FIFO is empty.
206 */
207static u_int tilegx_tx_empty(struct uart_port *port)
208{
209 int ret;
210 UART_FLAG_t flag;
211 struct tile_uart_port *tile_uart;
212 gxio_uart_context_t *context;
213
214 tile_uart = container_of(port, struct tile_uart_port, uart);
215 if (!mutex_trylock(&tile_uart->mutex))
216 return 0;
217 context = &tile_uart->context;
218
219 flag.word = gxio_uart_read(context, UART_FLAG);
220 ret = (flag.wfifo_empty) ? TIOCSER_TEMT : 0;
221 mutex_unlock(&tile_uart->mutex);
222
223 return ret;
224}
225
226
227/*
228 * Set state of the modem control output lines.
229 */
230static void tilegx_set_mctrl(struct uart_port *port, u_int mctrl)
231{
232 /* N/A */
233}
234
235
236/*
237 * Get state of the modem control input lines.
238 */
239static u_int tilegx_get_mctrl(struct uart_port *port)
240{
241 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
242}
243
244
245/*
246 * Stop transmitting.
247 */
248static void tilegx_stop_tx(struct uart_port *port)
249{
250 /* N/A */
251}
252
253
254/*
255 * Start transmitting.
256 */
257static void tilegx_start_tx(struct uart_port *port)
258{
259 unsigned char ch;
260 struct circ_buf *xmit;
261 struct tile_uart_port *tile_uart;
262 gxio_uart_context_t *context;
263
264 tile_uart = container_of(port, struct tile_uart_port, uart);
265 if (!mutex_trylock(&tile_uart->mutex))
266 return;
267 context = &tile_uart->context;
268 xmit = &port->state->xmit;
269 if (port->x_char) {
270 if (tilegx_putchar(context, port->x_char))
271 return;
272 port->x_char = 0;
273 port->icount.tx++;
274 }
275
276 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
277 mutex_unlock(&tile_uart->mutex);
278 return;
279 }
280
281 while (!uart_circ_empty(xmit)) {
282 ch = xmit->buf[xmit->tail];
283 if (tilegx_putchar(context, ch))
284 break;
285 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
286 port->icount.tx++;
287 }
288
289 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
290 uart_write_wakeup(port);
291
292 mutex_unlock(&tile_uart->mutex);
293}
294
295
296/*
297 * Stop receiving - port is in process of being closed.
298 */
299static void tilegx_stop_rx(struct uart_port *port)
300{
301 int err;
302 struct tile_uart_port *tile_uart;
303 gxio_uart_context_t *context;
304 int cpu;
305
306 tile_uart = container_of(port, struct tile_uart_port, uart);
307 if (!mutex_trylock(&tile_uart->mutex))
308 return;
309
310 context = &tile_uart->context;
311 cpu = tile_uart->irq_cpu;
312 err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu),
313 KERNEL_PL, -1);
314 mutex_unlock(&tile_uart->mutex);
315}
316
317
318/*
319 * Enable modem status interrupts.
320 */
321static void tilegx_enable_ms(struct uart_port *port)
322{
323 /* N/A */
324}
325
326/*
327 * Control the transmission of a break signal.
328 */
329static void tilegx_break_ctl(struct uart_port *port, int break_state)
330{
331 /* N/A */
332}
333
334
335/*
336 * Perform initialization and enable port for reception.
337 */
338static int tilegx_startup(struct uart_port *port)
339{
340 struct tile_uart_port *tile_uart;
341 gxio_uart_context_t *context;
342 int ret = 0;
343 int cpu = raw_smp_processor_id(); /* pick an arbitrary cpu */
344
345 tile_uart = container_of(port, struct tile_uart_port, uart);
346 if (mutex_lock_interruptible(&tile_uart->mutex))
347 return -EBUSY;
348 context = &tile_uart->context;
349
350 /* Now open the hypervisor device if we haven't already. */
351 if (context->fd < 0) {
352 UART_INTERRUPT_MASK_t intr_mask;
353
354 /* Initialize UART device. */
355 ret = gxio_uart_init(context, port->line);
356 if (ret) {
357 ret = -ENXIO;
358 goto err;
359 }
360
361 /* Create our IRQs. */
362 port->irq = create_irq();
363 if (port->irq < 0)
364 goto err_uart_dest;
365 tile_irq_activate(port->irq, TILE_IRQ_PERCPU);
366
367 /* Register our IRQs. */
368 ret = request_irq(port->irq, tilegx_interrupt, 0,
369 tilegx_uart_driver.driver_name, port);
370 if (ret)
371 goto err_dest_irq;
372
373 /* Request that the hardware start sending us interrupts. */
374 tile_uart->irq_cpu = cpu;
375 ret = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu),
376 KERNEL_PL, port->irq);
377 if (ret)
378 goto err_free_irq;
379
380 /* Enable UART Tx/Rx Interrupt. */
381 intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK);
382 intr_mask.wfifo_re = 0;
383 intr_mask.rfifo_we = 0;
384 gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word);
385
386 /* Reset the Tx/Rx interrupt in case it's set. */
387 gxio_uart_write(context, UART_INTERRUPT_STATUS,
388 UART_INTERRUPT_MASK__WFIFO_RE_MASK |
389 UART_INTERRUPT_MASK__RFIFO_WE_MASK);
390 }
391
392 mutex_unlock(&tile_uart->mutex);
393 return ret;
394
395err_free_irq:
396 free_irq(port->irq, port);
397err_dest_irq:
398 destroy_irq(port->irq);
399err_uart_dest:
400 gxio_uart_destroy(context);
401 ret = -ENXIO;
402err:
403 mutex_unlock(&tile_uart->mutex);
404 return ret;
405}
406
407
408/*
409 * Release kernel resources if it is the last close, disable the port,
410 * free IRQ and close the port.
411 */
412static void tilegx_shutdown(struct uart_port *port)
413{
414 int err;
415 UART_INTERRUPT_MASK_t intr_mask;
416 struct tile_uart_port *tile_uart;
417 gxio_uart_context_t *context;
418 int cpu;
419
420 tile_uart = container_of(port, struct tile_uart_port, uart);
421 if (mutex_lock_interruptible(&tile_uart->mutex))
422 return;
423 context = &tile_uart->context;
424
425 /* Disable UART Tx/Rx Interrupt. */
426 intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK);
427 intr_mask.wfifo_re = 1;
428 intr_mask.rfifo_we = 1;
429 gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word);
430
431 /* Request that the hardware stop sending us interrupts. */
432 cpu = tile_uart->irq_cpu;
433 err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu),
434 KERNEL_PL, -1);
435
436 if (port->irq > 0) {
437 free_irq(port->irq, port);
438 destroy_irq(port->irq);
439 port->irq = 0;
440 }
441
442 gxio_uart_destroy(context);
443
444 mutex_unlock(&tile_uart->mutex);
445}
446
447
448/*
449 * Flush the buffer.
450 */
451static void tilegx_flush_buffer(struct uart_port *port)
452{
453 /* N/A */
454}
455
456
457/*
458 * Change the port parameters.
459 */
460static void tilegx_set_termios(struct uart_port *port,
461 struct ktermios *termios, struct ktermios *old)
462{
463 int err;
464 UART_DIVISOR_t divisor;
465 UART_TYPE_t type;
466 unsigned int baud;
467 struct tile_uart_port *tile_uart;
468 gxio_uart_context_t *context;
469
470 tile_uart = container_of(port, struct tile_uart_port, uart);
471 if (!mutex_trylock(&tile_uart->mutex))
472 return;
473 context = &tile_uart->context;
474
475 /* Open the hypervisor device if we haven't already. */
476 if (context->fd < 0) {
477 err = gxio_uart_init(context, port->line);
478 if (err) {
479 mutex_unlock(&tile_uart->mutex);
480 return;
481 }
482 }
483
484 divisor.word = gxio_uart_read(context, UART_DIVISOR);
485 type.word = gxio_uart_read(context, UART_TYPE);
486
487 /* Divisor. */
488 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
489 divisor.divisor = uart_get_divisor(port, baud);
490
491 /* Byte size. */
492 if ((termios->c_cflag & CSIZE) == CS7)
493 type.dbits = UART_TYPE__DBITS_VAL_SEVEN_DBITS;
494 else
495 type.dbits = UART_TYPE__DBITS_VAL_EIGHT_DBITS;
496
497 /* Parity. */
498 if (termios->c_cflag & PARENB) {
499 /* Mark or Space parity. */
500 if (termios->c_cflag & CMSPAR)
501 if (termios->c_cflag & PARODD)
502 type.ptype = UART_TYPE__PTYPE_VAL_MARK;
503 else
504 type.ptype = UART_TYPE__PTYPE_VAL_SPACE;
505 else if (termios->c_cflag & PARODD)
506 type.ptype = UART_TYPE__PTYPE_VAL_ODD;
507 else
508 type.ptype = UART_TYPE__PTYPE_VAL_EVEN;
509 } else
510 type.ptype = UART_TYPE__PTYPE_VAL_NONE;
511
512 /* Stop bits. */
513 if (termios->c_cflag & CSTOPB)
514 type.sbits = UART_TYPE__SBITS_VAL_TWO_SBITS;
515 else
516 type.sbits = UART_TYPE__SBITS_VAL_ONE_SBITS;
517
518 /* Set the uart paramters. */
519 gxio_uart_write(context, UART_DIVISOR, divisor.word);
520 gxio_uart_write(context, UART_TYPE, type.word);
521
522 mutex_unlock(&tile_uart->mutex);
523}
524
525
526/*
527 * Return string describing the specified port.
528 */
529static const char *tilegx_type(struct uart_port *port)
530{
531 return port->type == PORT_TILEGX ? DRIVER_NAME_STRING : NULL;
532}
533
534
535/*
536 * Release the resources being used by 'port'.
537 */
538static void tilegx_release_port(struct uart_port *port)
539{
540 /* Nothing to release. */
541}
542
543
544/*
545 * Request the resources being used by 'port'.
546 */
547static int tilegx_request_port(struct uart_port *port)
548{
549 /* Always present. */
550 return 0;
551}
552
553
554/*
555 * Configure/autoconfigure the port.
556 */
557static void tilegx_config_port(struct uart_port *port, int flags)
558{
559 if (flags & UART_CONFIG_TYPE)
560 port->type = PORT_TILEGX;
561}
562
563
564/*
565 * Verify the new serial_struct (for TIOCSSERIAL).
566 */
567static int tilegx_verify_port(struct uart_port *port,
568 struct serial_struct *ser)
569{
570 if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_TILEGX))
571 return -EINVAL;
572
573 return 0;
574}
575
576#ifdef CONFIG_CONSOLE_POLL
577
578/*
579 * Console polling routines for writing and reading from the uart while
580 * in an interrupt or debug context.
581 */
582
583static int tilegx_poll_get_char(struct uart_port *port)
584{
585 UART_FIFO_COUNT_t count;
586 gxio_uart_context_t *context;
587 struct tile_uart_port *tile_uart;
588
589 tile_uart = container_of(port, struct tile_uart_port, uart);
590 context = &tile_uart->context;
591 count.word = gxio_uart_read(context, UART_FIFO_COUNT);
592 if (count.rfifo_count == 0)
593 return NO_POLL_CHAR;
594 return (char)gxio_uart_read(context, UART_RECEIVE_DATA);
595}
596
597static void tilegx_poll_put_char(struct uart_port *port, unsigned char c)
598{
599 gxio_uart_context_t *context;
600 struct tile_uart_port *tile_uart;
601
602 tile_uart = container_of(port, struct tile_uart_port, uart);
603 context = &tile_uart->context;
604 gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c);
605}
606
607#endif /* CONFIG_CONSOLE_POLL */
608
609
610static const struct uart_ops tilegx_ops = {
611 .tx_empty = tilegx_tx_empty,
612 .set_mctrl = tilegx_set_mctrl,
613 .get_mctrl = tilegx_get_mctrl,
614 .stop_tx = tilegx_stop_tx,
615 .start_tx = tilegx_start_tx,
616 .stop_rx = tilegx_stop_rx,
617 .enable_ms = tilegx_enable_ms,
618 .break_ctl = tilegx_break_ctl,
619 .startup = tilegx_startup,
620 .shutdown = tilegx_shutdown,
621 .flush_buffer = tilegx_flush_buffer,
622 .set_termios = tilegx_set_termios,
623 .type = tilegx_type,
624 .release_port = tilegx_release_port,
625 .request_port = tilegx_request_port,
626 .config_port = tilegx_config_port,
627 .verify_port = tilegx_verify_port,
628#ifdef CONFIG_CONSOLE_POLL
629 .poll_get_char = tilegx_poll_get_char,
630 .poll_put_char = tilegx_poll_put_char,
631#endif
632};
633
634
635static void tilegx_init_ports(void)
636{
637 int i;
638 struct uart_port *port;
639
640 for (i = 0; i < TILEGX_UART_NR; i++) {
641 port = &tile_uart_ports[i].uart;
642 port->ops = &tilegx_ops;
643 port->line = i;
644 port->type = PORT_TILEGX;
645 port->uartclk = TILEGX_UART_REF_CLK;
646 port->flags = UPF_BOOT_AUTOCONF;
647
648 tile_uart_ports[i].context.fd = -1;
649 mutex_init(&tile_uart_ports[i].mutex);
650 }
651}
652
653
654static struct uart_driver tilegx_uart_driver = {
655 .owner = THIS_MODULE,
656 .driver_name = DRIVER_NAME_STRING,
657 .dev_name = TILEGX_UART_NAME,
658 .major = TILEGX_UART_MAJOR,
659 .minor = TILEGX_UART_MINOR,
660 .nr = TILEGX_UART_NR,
661};
662
663
664static int __init tilegx_init(void)
665{
666 int i;
667 int ret;
668 struct tty_driver *tty_drv;
669
670 ret = uart_register_driver(&tilegx_uart_driver);
671 if (ret)
672 return ret;
673 tty_drv = tilegx_uart_driver.tty_driver;
674 tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
675 tty_drv->init_termios.c_ispeed = 115200;
676 tty_drv->init_termios.c_ospeed = 115200;
677
678 tilegx_init_ports();
679
680 for (i = 0; i < TILEGX_UART_NR; i++) {
681 struct uart_port *port = &tile_uart_ports[i].uart;
682 ret = uart_add_one_port(&tilegx_uart_driver, port);
683 }
684
685 return 0;
686}
687
688
689static void __exit tilegx_exit(void)
690{
691 int i;
692 struct uart_port *port;
693
694 for (i = 0; i < TILEGX_UART_NR; i++) {
695 port = &tile_uart_ports[i].uart;
696 uart_remove_one_port(&tilegx_uart_driver, port);
697 }
698
699 uart_unregister_driver(&tilegx_uart_driver);
700}
701
702
703module_init(tilegx_init);
704module_exit(tilegx_exit);
705
706MODULE_AUTHOR("Tilera Corporation");
707MODULE_DESCRIPTION("TILEGx serial port driver");
708MODULE_LICENSE("GPL");