scc_core.c revision 160631
1/*-
2 * Copyright (c) 2004-2006 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/scc/scc_core.c 160631 2006-07-24 22:25:16Z marcel $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/queue.h>
37#include <sys/serial.h>
38
39#include <machine/bus.h>
40#include <machine/resource.h>
41#include <sys/rman.h>
42
43#include <dev/scc/scc_bfe.h>
44#include <dev/scc/scc_bus.h>
45
46#include "scc_if.h"
47
48devclass_t scc_devclass;
49char scc_driver_name[] = "scc";
50
51MALLOC_DEFINE(M_SCC, "SCC", "SCC driver");
52
53static void
54scc_bfe_intr(void *arg)
55{
56	struct scc_softc *sc = arg;
57	struct scc_chan *ch;
58	struct scc_class *cl;
59	struct scc_mode *m;
60	int c, i, ipend, isrc;
61
62	cl = sc->sc_class;
63	while (!sc->sc_leaving && (ipend = SCC_IPEND(sc)) != 0) {
64		i = 0, isrc = SER_INT_OVERRUN;
65		while (ipend) {
66			while (i < SCC_ISRCCNT && !(ipend & isrc))
67				i++, isrc <<= 1;
68			KASSERT(i < SCC_ISRCCNT, ("%s", __func__));
69			ipend &= ~isrc;
70			for (c = 0; c < cl->cl_channels; c++) {
71				ch = &sc->sc_chan[c];
72				if (!(ch->ch_ipend & isrc))
73					continue;
74				m = &ch->ch_mode[0];
75				if (m->ih_src[i] == NULL)
76					continue;
77				if ((*m->ih_src[i])(m->ih_arg))
78					ch->ch_ipend &= ~isrc;
79			}
80		}
81		for (c = 0; c < cl->cl_channels; c++) {
82			ch = &sc->sc_chan[c];
83			if (!ch->ch_ipend)
84				continue;
85			m = &ch->ch_mode[0];
86			if (m->ih != NULL)
87				(*m->ih)(m->ih_arg);
88			else
89				SCC_ICLEAR(sc, ch);
90		}
91	}
92}
93
94int
95scc_bfe_attach(device_t dev)
96{
97	struct resource_list_entry *rle;
98	struct scc_chan *ch;
99	struct scc_class *cl;
100	struct scc_mode *m;
101	struct scc_softc *sc, *sc0;
102	const char *sep;
103	bus_space_handle_t bh;
104	u_long base, size, start;
105	int c, error, mode, nintr, sysdev;
106
107	/*
108	 * The sc_class field defines the type of SCC we're going to work
109	 * with and thus the size of the softc. Replace the generic softc
110	 * with one that matches the SCC now that we're certain we handle
111	 * the device.
112	 */
113	sc0 = device_get_softc(dev);
114	cl = sc0->sc_class;
115	if (cl->size > sizeof(*sc)) {
116		sc = malloc(cl->size, M_SCC, M_WAITOK|M_ZERO);
117		bcopy(sc0, sc, sizeof(*sc));
118		device_set_softc(dev, sc);
119	} else
120		sc = sc0;
121
122	size = abs(cl->cl_range);
123
124	mtx_init(&sc->sc_hwmtx, "scc_hwmtx", NULL, MTX_SPIN);
125
126	/*
127	 * Re-allocate. We expect that the softc contains the information
128	 * collected by scc_bfe_probe() intact.
129	 */
130	sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
131	    0, ~0, cl->cl_channels * size, RF_ACTIVE);
132	if (sc->sc_rres == NULL)
133		return (ENXIO);
134	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
135	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
136
137	/*
138	 * Allocate interrupt resources. There may be a different interrupt
139	 * per channel. We allocate them all...
140	 */
141	sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels,
142	    M_SCC, M_WAITOK | M_ZERO);
143	nintr = 0;
144	for (c = 0; c < cl->cl_channels; c++) {
145		ch = &sc->sc_chan[c];
146		ch->ch_irid = c;
147		ch->ch_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
148		    &ch->ch_irid, RF_ACTIVE | RF_SHAREABLE);
149		if (ch->ch_ires != NULL)
150			nintr++;
151	}
152
153	/*
154	 * Create the control structures for our children. Probe devices
155	 * and query them to see if we can reset the hardware.
156	 */
157	sysdev = 0;
158	base = rman_get_start(sc->sc_rres);
159	start = base + ((cl->cl_range < 0) ? size * (cl->cl_channels - 1) : 0);
160	for (c = 0; c < cl->cl_channels; c++) {
161		ch = &sc->sc_chan[c];
162		resource_list_init(&ch->ch_rlist);
163		ch->ch_nr = c + 1;
164
165		resource_list_add(&ch->ch_rlist, sc->sc_rtype, 0, start,
166		    start + size - 1, size);
167		rle = resource_list_find(&ch->ch_rlist, sc->sc_rtype, 0);
168		rle->res = &ch->ch_rres;
169		bus_space_subregion(rman_get_bustag(sc->sc_rres),
170		    rman_get_bushandle(sc->sc_rres), start - base, size, &bh);
171		rman_set_bushandle(rle->res, bh);
172		rman_set_bustag(rle->res, rman_get_bustag(sc->sc_rres));
173
174		resource_list_add(&ch->ch_rlist, SYS_RES_IRQ, 0, c, c, 1);
175		rle = resource_list_find(&ch->ch_rlist, SYS_RES_IRQ, 0);
176		rle->res = (ch->ch_ires != NULL) ? ch->ch_ires :
177			    sc->sc_chan[0].ch_ires;
178
179		for (mode = 0; mode < SCC_NMODES; mode++) {
180			m = &ch->ch_mode[mode];
181			m->m_chan = ch;
182			m->m_mode = 1U << mode;
183			if ((cl->cl_modes & m->m_mode) == 0 || ch->ch_sysdev)
184				continue;
185			m->m_dev = device_add_child(dev, NULL, -1);
186			device_set_ivars(m->m_dev, (void *)m);
187			error = device_probe_child(dev, m->m_dev);
188			if (!error) {
189				m->m_probed = 1;
190				m->m_sysdev = SERDEV_SYSDEV(m->m_dev) ? 1 : 0;
191				ch->ch_sysdev |= m->m_sysdev;
192			}
193		}
194
195		start += (cl->cl_range < 0) ? -size : size;
196		sysdev |= ch->ch_sysdev;
197	}
198
199	/*
200	 * Have the hardware driver initialize the hardware. Tell it
201	 * whether or not a hardware reset should be performed.
202	 */
203	if (bootverbose) {
204		device_printf(dev, "%sresetting hardware\n",
205		    (sysdev) ? "not " : "");
206	}
207	error = SCC_ATTACH(sc, !sysdev);
208	if (error)
209		goto fail;
210
211	/*
212	 * Setup our interrupt handler. Make it FAST under the assumption
213	 * that our children's are fast as well. We make it MPSAFE as soon
214	 * as a child sets up a MPSAFE interrupt handler.
215	 * Of course, if we can't setup a fast handler, we make it MPSAFE
216	 * right away. If we have multiple interrupt resources, we don't
217	 * use fast handlers, because we need to serialize the interrupts.
218	 */
219	for (c = 0; c < cl->cl_channels; c++) {
220		ch = &sc->sc_chan[c];
221		if (ch->ch_ires == NULL)
222			continue;
223		if (nintr == 1)
224			error = bus_setup_intr(dev, ch->ch_ires,
225			    INTR_TYPE_TTY | INTR_FAST, scc_bfe_intr, sc,
226			    &ch->ch_icookie);
227		if (nintr > 1 || error) {
228			error = bus_setup_intr(dev, ch->ch_ires,
229			    INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
230			    &ch->ch_icookie);
231		} else
232			sc->sc_fastintr = 1;
233
234		if (error) {
235			device_printf(dev, "could not activate interrupt\n");
236			bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
237			    ch->ch_ires);
238			ch->ch_ires = NULL;
239			nintr--;
240		}
241	}
242	sc->sc_polled = (nintr == 0) ? 1 : 0;
243
244	/*
245	 * Attach all child devices that were probed successfully.
246	 */
247	for (c = 0; c < cl->cl_channels; c++) {
248		ch = &sc->sc_chan[c];
249		for (mode = 0; mode < SCC_NMODES; mode++) {
250			m = &ch->ch_mode[mode];
251			if (!m->m_probed)
252				continue;
253			error = device_attach(m->m_dev);
254			if (error)
255				continue;
256			m->m_attached = 1;
257		}
258	}
259
260	if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
261		sep = "";
262		device_print_prettyname(dev);
263		if (sc->sc_fastintr) {
264			printf("%sfast interrupt", sep);
265			sep = ", ";
266		}
267		if (sc->sc_polled) {
268			printf("%spolled mode", sep);
269			sep = ", ";
270		}
271		printf("\n");
272	}
273
274	return (0);
275
276 fail:
277	for (c = 0; c < cl->cl_channels; c++) {
278		ch = &sc->sc_chan[c];
279		if (ch->ch_ires == NULL)
280			continue;
281		bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
282		    ch->ch_ires);
283	}
284	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
285	return (error);
286}
287
288int
289scc_bfe_detach(device_t dev)
290{
291	struct scc_chan *ch;
292	struct scc_class *cl;
293	struct scc_mode *m;
294	struct scc_softc *sc;
295	int chan, error, mode;
296
297	sc = device_get_softc(dev);
298	cl = sc->sc_class;
299
300	/* Detach our children. */
301	error = 0;
302	for (chan = 0; chan < cl->cl_channels; chan++) {
303		ch = &sc->sc_chan[chan];
304		for (mode = 0; mode < SCC_NMODES; mode++) {
305			m = &ch->ch_mode[mode];
306			if (!m->m_attached)
307				continue;
308			if (device_detach(m->m_dev) != 0)
309				error = ENXIO;
310			else
311				m->m_attached = 0;
312		}
313	}
314
315	if (error)
316		return (error);
317
318	for (chan = 0; chan < cl->cl_channels; chan++) {
319		ch = &sc->sc_chan[chan];
320		if (ch->ch_ires == NULL)
321			continue;
322		bus_teardown_intr(dev, ch->ch_ires, ch->ch_icookie);
323		bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
324		    ch->ch_ires);
325	}
326	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
327
328	free(sc->sc_chan, M_SCC);
329
330	mtx_destroy(&sc->sc_hwmtx);
331	return (0);
332}
333
334int
335scc_bfe_probe(device_t dev, u_int regshft, u_int rclk)
336{
337	struct scc_softc *sc;
338	struct scc_class *cl;
339	u_long size;
340	int error;
341
342	/*
343	 * Initialize the instance. Note that the instance (=softc) does
344	 * not necessarily match the hardware specific softc. We can't do
345	 * anything about it now, because we may not attach to the device.
346	 * Hardware drivers cannot use any of the class specific fields
347	 * while probing.
348	 */
349	sc = device_get_softc(dev);
350	cl = sc->sc_class;
351	kobj_init((kobj_t)sc, (kobj_class_t)cl);
352	sc->sc_dev = dev;
353	if (device_get_desc(dev) == NULL)
354		device_set_desc(dev, cl->name);
355
356	size = abs(cl->cl_range);
357
358	/*
359	 * Allocate the register resource. We assume that all SCCs have a
360	 * single register window in either I/O port space or memory mapped
361	 * I/O space. Any SCC that needs multiple windows will consequently
362	 * not be supported by this driver as-is.
363	 */
364	sc->sc_rrid = 0;
365	sc->sc_rtype = SYS_RES_MEMORY;
366	sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
367	    0, ~0, cl->cl_channels * size, RF_ACTIVE);
368	if (sc->sc_rres == NULL) {
369		sc->sc_rrid = 0;
370		sc->sc_rtype = SYS_RES_IOPORT;
371		sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
372		    &sc->sc_rrid, 0, ~0, cl->cl_channels * size, RF_ACTIVE);
373		if (sc->sc_rres == NULL)
374			return (ENXIO);
375	}
376
377	/*
378	 * Fill in the bus access structure and call the hardware specific
379	 * probe method.
380	 */
381	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
382	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
383	sc->sc_bas.range = size;
384	sc->sc_bas.rclk = rclk;
385	sc->sc_bas.regshft = regshft;
386
387	error = SCC_PROBE(sc);
388	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
389	return ((error == 0) ? BUS_PROBE_DEFAULT : error);
390}
391
392struct resource *
393scc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
394    u_long start, u_long end, u_long count, u_int flags)
395{
396	struct resource_list_entry *rle;
397	struct scc_chan *ch;
398	struct scc_mode *m;
399
400	if (device_get_parent(child) != dev)
401		return (NULL);
402
403	/* We only support default allocations. */
404	if (start != 0UL || end != ~0UL)
405		return (NULL);
406
407	m = device_get_ivars(child);
408	ch = m->m_chan;
409	rle = resource_list_find(&ch->ch_rlist, type, 0);
410	if (rle == NULL)
411		return (NULL);
412	*rid = 0;
413	return (rle->res);
414}
415
416int
417scc_bus_get_resource(device_t dev, device_t child, int type, int rid,
418    u_long *startp, u_long *countp)
419{
420	struct resource_list_entry *rle;
421	struct scc_chan *ch;
422	struct scc_mode *m;
423
424	if (device_get_parent(child) != dev)
425		return (EINVAL);
426
427	m = device_get_ivars(child);
428	ch = m->m_chan;
429	rle = resource_list_find(&ch->ch_rlist, type, rid);
430	if (rle == NULL)
431		return (EINVAL);
432
433	if (startp != NULL)
434		*startp = rle->start;
435	if (countp != NULL)
436		*countp = rle->count;
437	return (0);
438}
439
440int
441scc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
442{
443	struct scc_chan *ch;
444	struct scc_class *cl;
445	struct scc_mode *m;
446	struct scc_softc *sc;
447
448	if (device_get_parent(child) != dev)
449		return (EINVAL);
450
451	sc = device_get_softc(dev);
452	cl = sc->sc_class;
453	m = device_get_ivars(child);
454	ch = m->m_chan;
455
456	switch (index) {
457	case SCC_IVAR_CHANNEL:
458		*result = ch->ch_nr;
459		break;
460	case SCC_IVAR_CLASS:
461		*result = cl->cl_class;
462		break;
463	case SCC_IVAR_CLOCK:
464		*result = sc->sc_bas.rclk;
465		break;
466	case SCC_IVAR_MODE:
467		*result = m->m_mode;
468		break;
469	case SCC_IVAR_REGSHFT:
470		*result = sc->sc_bas.regshft;
471		break;
472	case SCC_IVAR_HWMTX:
473		*result = (uintptr_t)&sc->sc_hwmtx;
474		break;
475	default:
476		return (EINVAL);
477	}
478	return (0);
479}
480
481int
482scc_bus_release_resource(device_t dev, device_t child, int type, int rid,
483    struct resource *res)
484{
485	struct resource_list_entry *rle;
486	struct scc_chan *ch;
487	struct scc_mode *m;
488
489	if (device_get_parent(child) != dev)
490		return (EINVAL);
491
492	m = device_get_ivars(child);
493	ch = m->m_chan;
494	rle = resource_list_find(&ch->ch_rlist, type, rid);
495	return ((rle == NULL) ? EINVAL : 0);
496}
497
498int
499scc_bus_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
500    void (*ihand)(void *), void *arg, void **cookiep)
501{
502	struct scc_chan *ch;
503	struct scc_mode *m;
504	struct scc_softc *sc;
505	int c, i, isrc;
506
507	if (device_get_parent(child) != dev)
508		return (EINVAL);
509
510	/* Interrupt handlers must be FAST or MPSAFE. */
511	if ((flags & (INTR_FAST|INTR_MPSAFE)) == 0)
512		return (EINVAL);
513
514	sc = device_get_softc(dev);
515	if (sc->sc_polled)
516		return (ENXIO);
517
518	if (sc->sc_fastintr && !(flags & INTR_FAST)) {
519		sc->sc_fastintr = 0;
520		for (c = 0; c < sc->sc_class->cl_channels; c++) {
521			ch = &sc->sc_chan[c];
522			if (ch->ch_ires == NULL)
523				continue;
524			bus_teardown_intr(dev, ch->ch_ires, ch->ch_icookie);
525			bus_setup_intr(dev, ch->ch_ires,
526			    INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
527			    &ch->ch_icookie);
528		}
529	}
530
531	m = device_get_ivars(child);
532	m->m_hasintr = 1;
533	m->m_fastintr = (flags & INTR_FAST) ? 1 : 0;
534	m->ih = ihand;
535	m->ih_arg = arg;
536
537	i = 0, isrc = SER_INT_OVERRUN;
538	while (i < SCC_ISRCCNT) {
539		m->ih_src[i] = SERDEV_IHAND(child, isrc);
540		if (m->ih_src[i] != NULL)
541			m->ih = NULL;
542		i++, isrc <<= 1;
543	}
544	return (0);
545}
546
547int
548scc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
549    void *cookie)
550{
551	struct scc_mode *m;
552	int i;
553
554	if (device_get_parent(child) != dev)
555		return (EINVAL);
556
557	m = device_get_ivars(child);
558	if (!m->m_hasintr)
559		return (EINVAL);
560
561	m->m_hasintr = 0;
562	m->m_fastintr = 0;
563	m->ih = NULL;
564	m->ih_arg = NULL;
565	for (i = 0; i < SCC_ISRCCNT; i++)
566		m->ih_src[i] = NULL;
567	return (0);
568}
569