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