uart_core.c revision 120380
1/*
2 * Copyright (c) 2003 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/dev/uart/uart_core.c 120380 2003-09-23 09:55:21Z nyan $");
29
30#ifndef KLD_MODULE
31#include "opt_comconsole.h"
32#include "opt_ddb.h"
33#endif
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/bus.h>
38#include <sys/conf.h>
39#include <sys/cons.h>
40#include <sys/fcntl.h>
41#include <sys/interrupt.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/queue.h>
45#include <sys/reboot.h>
46#include <machine/bus.h>
47#include <sys/rman.h>
48#include <sys/termios.h>
49#include <sys/tty.h>
50#include <machine/resource.h>
51#include <machine/stdarg.h>
52
53#include <ddb/ddb.h>
54
55#include <dev/uart/uart.h>
56#include <dev/uart/uart_bus.h>
57#include <dev/uart/uart_cpu.h>
58
59#include "uart_if.h"
60
61devclass_t uart_devclass;
62char uart_driver_name[] = "uart";
63
64SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs =
65    SLIST_HEAD_INITIALIZER(uart_sysdevs);
66
67MALLOC_DEFINE(M_UART, "UART", "UART driver");
68
69void
70uart_add_sysdev(struct uart_devinfo *di)
71{
72	SLIST_INSERT_HEAD(&uart_sysdevs, di, next);
73}
74
75/*
76 * A break condition has been detected. We treat the break condition as
77 * a special case that should not happen during normal operation. When
78 * the break condition is to be passed to higher levels in the form of
79 * a NUL character, we really want the break to be in the right place in
80 * the input stream. The overhead to achieve that is not in relation to
81 * the exceptional nature of the break condition, so we permit ourselves
82 * to be sloppy.
83 */
84static void
85uart_intr_break(struct uart_softc *sc)
86{
87
88#if defined(DDB) && defined(BREAK_TO_DEBUGGER)
89	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
90		breakpoint();
91		return;
92	}
93#endif
94	if (sc->sc_opened)
95		atomic_set_32(&sc->sc_ttypend, UART_IPEND_BREAK);
96}
97
98/*
99 * Handle a receiver overrun situation. We lost at least 1 byte in the
100 * input stream and it's our job to contain the situation. We grab as
101 * much of the data we can, but otherwise flush the receiver FIFO to
102 * create some breathing room. The net effect is that we avoid the
103 * overrun condition to happen for the next X characters, where X is
104 * related to the FIFO size at the cost of loosing data right away.
105 * So, instead of having multiple overrun interrupts in close proximity
106 * to each other and possibly pessimizing UART interrupt latency for
107 * other UARTs in a multiport configuration, we create a longer segment
108 * of missing characters by freeing up the FIFO.
109 * Each overrun condition is marked in the input buffer by a token. The
110 * token represents the loss of at least one, but possible more bytes in
111 * the input stream.
112 */
113static void
114uart_intr_overrun(struct uart_softc *sc)
115{
116
117	if (sc->sc_opened) {
118		UART_RECEIVE(sc);
119		if (uart_rx_put(sc, UART_STAT_OVERRUN))
120			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
121		atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY);
122	}
123	UART_FLUSH(sc, UART_FLUSH_RECEIVER);
124}
125
126/*
127 * Received data ready.
128 */
129static void
130uart_intr_rxready(struct uart_softc *sc)
131{
132	int rxp;
133
134	rxp = sc->sc_rxput;
135	UART_RECEIVE(sc);
136#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
137	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
138		while (rxp != sc->sc_rxput) {
139			if (db_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk))
140				breakpoint();
141			if (rxp == sc->sc_rxbufsz)
142				rxp = 0;
143		}
144	}
145#endif
146	if (sc->sc_opened)
147		atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY);
148	else
149		sc->sc_rxput = sc->sc_rxget;	/* Ignore received data. */
150}
151
152/*
153 * Line or modem status change (OOB signalling).
154 * We pass the signals to the software interrupt handler for further
155 * processing. Note that we merge the delta bits, but set the state
156 * bits. This is to avoid loosing state transitions due to having more
157 * than 1 hardware interrupt between software interrupts.
158 */
159static void
160uart_intr_sigchg(struct uart_softc *sc)
161{
162	int new, old, sig;
163
164	sig = UART_GETSIG(sc);
165
166	if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) {
167		if (sig & UART_SIG_DPPS) {
168			pps_capture(&sc->sc_pps);
169			pps_event(&sc->sc_pps, (sig & UART_SIG_PPS) ?
170			    PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
171		}
172	}
173
174	do {
175		old = sc->sc_ttypend;
176		new = old & ~UART_SIGMASK_STATE;
177		new |= sig & UART_IPEND_SIGMASK;
178		new |= UART_IPEND_SIGCHG;
179	} while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
180}
181
182/*
183 * The transmitter can accept more data.
184 */
185static void
186uart_intr_txidle(struct uart_softc *sc)
187{
188	if (sc->sc_txbusy) {
189		sc->sc_txbusy = 0;
190		atomic_set_32(&sc->sc_ttypend, UART_IPEND_TXIDLE);
191	}
192}
193
194static void
195uart_intr(void *arg)
196{
197	struct uart_softc *sc = arg;
198	int ipend;
199
200	if (sc->sc_leaving)
201		return;
202
203	do {
204		ipend = UART_IPEND(sc);
205		if (ipend == 0)
206			break;
207		if (ipend & UART_IPEND_OVERRUN)
208			uart_intr_overrun(sc);
209		if (ipend & UART_IPEND_BREAK)
210			uart_intr_break(sc);
211		if (ipend & UART_IPEND_RXREADY)
212			uart_intr_rxready(sc);
213		if (ipend & UART_IPEND_SIGCHG)
214			uart_intr_sigchg(sc);
215		if (ipend & UART_IPEND_TXIDLE)
216			uart_intr_txidle(sc);
217	} while (1);
218
219	if (sc->sc_opened && sc->sc_ttypend != 0)
220		swi_sched(sc->sc_softih, 0);
221}
222
223int
224uart_bus_probe(device_t dev, int regshft, int rclk, int rid)
225{
226	struct uart_softc *sc;
227	struct uart_devinfo *sysdev;
228	int error;
229
230	/*
231	 * Initialize the instance. Note that the instance (=softc) does
232	 * not necessarily match the hardware specific softc. We can't do
233	 * anything about it now, because we may not attach to the device.
234	 * Hardware drivers cannot use any of the class specific fields
235	 * while probing.
236	 */
237	sc = device_get_softc(dev);
238	kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class);
239	sc->sc_dev = dev;
240	if (device_get_desc(dev) == NULL)
241		device_set_desc(dev, sc->sc_class->name);
242
243	/*
244	 * Allocate the register resource. We assume that all UARTs have
245	 * a single register window in either I/O port space or memory
246	 * mapped I/O space. Any UART that needs multiple windows will
247	 * consequently not be supported by this driver as-is. We try I/O
248	 * port space first because that's the common case.
249	 */
250	sc->sc_rrid = rid;
251	sc->sc_rtype = SYS_RES_IOPORT;
252	sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
253	    0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
254	if (sc->sc_rres == NULL) {
255		sc->sc_rrid = rid;
256		sc->sc_rtype = SYS_RES_MEMORY;
257		sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
258		    &sc->sc_rrid, 0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
259		if (sc->sc_rres == NULL)
260			return (ENXIO);
261	}
262
263	/*
264	 * Fill in the bus access structure and compare this device with
265	 * a possible console device and/or a debug port. We set the flags
266	 * in the softc so that the hardware dependent probe can adjust
267	 * accordingly. In general, you don't want to permanently disrupt
268	 * console I/O.
269	 */
270	sc->sc_bas.iobase = rman_get_start(sc->sc_rres);
271	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
272	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
273	sc->sc_bas.regshft = regshft;
274	sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk;
275
276	SLIST_FOREACH(sysdev, &uart_sysdevs, next) {
277		if (uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) {
278			/* XXX check if ops matches class. */
279			sc->sc_sysdev = sysdev;
280			break;
281		}
282	}
283
284	error = UART_PROBE(sc);
285	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
286	return (error);
287}
288
289int
290uart_bus_attach(device_t dev)
291{
292	struct uart_softc *sc, *sc0;
293	const char *sep;
294	int error;
295
296	/*
297	 * The sc_class field defines the type of UART we're going to work
298	 * with and thus the size of the softc. Replace the generic softc
299	 * with one that matches the UART now that we're certain we handle
300	 * the device.
301	 */
302	sc0 = device_get_softc(dev);
303	if (sc0->sc_class->size > sizeof(*sc)) {
304		sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO);
305		bcopy(sc0, sc, sizeof(*sc));
306		device_set_softc(dev, sc);
307	} else
308		sc = sc0;
309
310	/*
311	 * Protect ourselves against interrupts while we're not completely
312	 * finished attaching and initializing. We don't expect interrupts
313	 * until after UART_ATTACH() though.
314	 */
315	sc->sc_leaving = 1;
316
317	mtx_init(&sc->sc_hwmtx, "uart_hwmtx", NULL, MTX_SPIN);
318
319	/*
320	 * Re-allocate. We expect that the softc contains the information
321	 * collected by uart_bus_probe() intact.
322	 */
323	sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
324	    0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
325	if (sc->sc_rres == NULL)
326		return (ENXIO);
327
328	sc->sc_bas.iobase = rman_get_start(sc->sc_rres);
329	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
330	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
331
332	sc->sc_irid = 0;
333	sc->sc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_irid,
334	    0, ~0, 1, RF_ACTIVE);
335	if (sc->sc_ires != NULL) {
336		error = BUS_SETUP_INTR(device_get_parent(dev), dev,
337		    sc->sc_ires, INTR_TYPE_TTY | INTR_FAST, uart_intr,
338		    sc, &sc->sc_icookie);
339		if (error)
340			error = BUS_SETUP_INTR(device_get_parent(dev), dev,
341			    sc->sc_ires, INTR_TYPE_TTY, uart_intr, sc,
342			    &sc->sc_icookie);
343		else
344			sc->sc_fastintr = 1;
345
346		if (error) {
347			device_printf(dev, "could not activate interrupt\n");
348			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
349			    sc->sc_ires);
350			sc->sc_ires = NULL;
351		}
352	}
353	if (sc->sc_ires == NULL) {
354		/* XXX no interrupt resource. Force polled mode. */
355		sc->sc_polled = 1;
356	}
357
358	sc->sc_rxbufsz = IBUFSIZ;
359	sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf),
360	    M_UART, M_WAITOK);
361	sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf),
362	    M_UART, M_WAITOK);
363
364	error = UART_ATTACH(sc);
365	if (error)
366		goto fail;
367
368	if (sc->sc_hwiflow || sc->sc_hwoflow) {
369		sep = "";
370		device_print_prettyname(dev);
371		if (sc->sc_hwiflow) {
372			printf("%sRTS iflow", sep);
373			sep = ", ";
374		}
375		if (sc->sc_hwoflow) {
376			printf("%sCTS oflow", sep);
377			sep = ", ";
378		}
379		printf("\n");
380	}
381
382	if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
383		sep = "";
384		device_print_prettyname(dev);
385		if (sc->sc_fastintr) {
386			printf("%sfast interrupt", sep);
387			sep = ", ";
388		}
389		if (sc->sc_polled) {
390			printf("%spolled mode", sep);
391			sep = ", ";
392		}
393		printf("\n");
394	}
395
396	if (sc->sc_sysdev != NULL) {
397		switch (sc->sc_sysdev->type) {
398		case UART_DEV_CONSOLE:
399			device_printf(dev, "console");
400			break;
401		case UART_DEV_DBGPORT:
402			device_printf(dev, "debug port");
403			break;
404		case UART_DEV_KEYBOARD:
405			device_printf(dev, "keyboard");
406			break;
407		default:
408			device_printf(dev, "unknown system device");
409			break;
410		}
411		printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate,
412		    "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits,
413		    sc->sc_sysdev->stopbits);
414	}
415
416	sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
417	pps_init(&sc->sc_pps);
418
419	error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL)
420	    ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc);
421	if (error)
422		goto fail;
423
424	sc->sc_leaving = 0;
425	uart_intr(sc);
426	return (0);
427
428 fail:
429	free(sc->sc_txbuf, M_UART);
430	free(sc->sc_rxbuf, M_UART);
431
432	if (sc->sc_ires != NULL) {
433		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
434		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
435		    sc->sc_ires);
436	}
437	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
438
439	return (error);
440}
441
442int
443uart_bus_detach(device_t dev)
444{
445	struct uart_softc *sc;
446
447	sc = device_get_softc(dev);
448
449	sc->sc_leaving = 1;
450
451	UART_DETACH(sc);
452
453	if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL)
454		(*sc->sc_sysdev->detach)(sc);
455	else
456		uart_tty_detach(sc);
457
458	free(sc->sc_txbuf, M_UART);
459	free(sc->sc_rxbuf, M_UART);
460
461	if (sc->sc_ires != NULL) {
462		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
463		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
464		    sc->sc_ires);
465	}
466	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
467
468	if (sc->sc_class->size > sizeof(*sc)) {
469		device_set_softc(dev, NULL);
470		free(sc, M_UART);
471	} else
472		device_set_softc(dev, NULL);
473
474	return (0);
475}
476