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