]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/ti/ti_pruss.c
Mark more nodes as CTLFLAG_MPSAFE or CTLFLAG_NEEDGIANT (17 of many)
[FreeBSD/FreeBSD.git] / sys / arm / ti / ti_pruss.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org>
5  * Copyright (c) 2017 Manuel Stuehn
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/poll.h>
33 #include <sys/time.h>
34 #include <sys/uio.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/fcntl.h>
38 #include <sys/bus.h>
39 #include <sys/conf.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/module.h>
43 #include <sys/malloc.h>
44 #include <sys/mutex.h>
45 #include <sys/rman.h>
46 #include <sys/types.h>
47 #include <sys/sysctl.h>
48 #include <sys/event.h>
49 #include <sys/selinfo.h>
50 #include <machine/bus.h>
51 #include <machine/cpu.h>
52 #include <machine/frame.h>
53 #include <machine/intr.h>
54 #include <machine/atomic.h>
55
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/ofw_bus.h>
58 #include <dev/ofw/ofw_bus_subr.h>
59
60 #include <arm/ti/ti_prcm.h>
61 #include <arm/ti/ti_pruss.h>
62
63 #ifdef DEBUG
64 #define DPRINTF(fmt, ...)       do {    \
65         printf("%s: ", __func__);       \
66         printf(fmt, __VA_ARGS__);       \
67 } while (0)
68 #else
69 #define DPRINTF(fmt, ...)
70 #endif
71
72 static d_open_t                 ti_pruss_irq_open;
73 static d_read_t                 ti_pruss_irq_read;
74 static d_poll_t                 ti_pruss_irq_poll;
75
76 static device_probe_t           ti_pruss_probe;
77 static device_attach_t          ti_pruss_attach;
78 static device_detach_t          ti_pruss_detach;
79 static void                     ti_pruss_intr(void *);
80 static d_open_t                 ti_pruss_open;
81 static d_mmap_t                 ti_pruss_mmap;
82 static void                     ti_pruss_irq_kqread_detach(struct knote *);
83 static int                      ti_pruss_irq_kqevent(struct knote *, long);
84 static d_kqfilter_t             ti_pruss_irq_kqfilter;
85 static void                     ti_pruss_privdtor(void *data);
86
87 #define TI_PRUSS_PRU_IRQS 2
88 #define TI_PRUSS_HOST_IRQS 8
89 #define TI_PRUSS_IRQS (TI_PRUSS_HOST_IRQS+TI_PRUSS_PRU_IRQS)
90 #define TI_PRUSS_EVENTS 64
91 #define NOT_SET_STR "NONE"
92 #define TI_TS_ARRAY 16
93
94 struct ctl
95 {
96         size_t cnt;
97         size_t idx;
98 };
99
100 struct ts_ring_buf
101 {
102         struct ctl ctl;
103         uint64_t ts[TI_TS_ARRAY];
104 };
105
106 struct ti_pruss_irqsc
107 {
108         struct mtx              sc_mtx;
109         struct cdev             *sc_pdev;
110         struct selinfo          sc_selinfo;
111         int8_t                  channel;
112         int8_t                  last;
113         int8_t                  event;
114         bool                    enable;
115         struct ts_ring_buf      tstamps;
116 };
117
118 static struct cdevsw ti_pruss_cdevirq = {
119         .d_version =    D_VERSION,
120         .d_name =       "ti_pruss_irq",
121         .d_open =       ti_pruss_irq_open,
122         .d_read =       ti_pruss_irq_read,
123         .d_poll =       ti_pruss_irq_poll,
124         .d_kqfilter =   ti_pruss_irq_kqfilter,
125 };
126
127 struct ti_pruss_softc {
128         struct mtx              sc_mtx;
129         struct resource         *sc_mem_res;
130         struct resource         *sc_irq_res[TI_PRUSS_HOST_IRQS];
131         void                    *sc_intr[TI_PRUSS_HOST_IRQS];
132         struct ti_pruss_irqsc   sc_irq_devs[TI_PRUSS_IRQS];
133         bus_space_tag_t         sc_bt;
134         bus_space_handle_t      sc_bh;
135         struct cdev             *sc_pdev;
136         struct selinfo          sc_selinfo;
137         bool                    sc_glob_irqen;
138 };
139
140 static struct cdevsw ti_pruss_cdevsw = {
141         .d_version =    D_VERSION,
142         .d_name =       "ti_pruss",
143         .d_open =       ti_pruss_open,
144         .d_mmap =       ti_pruss_mmap,
145 };
146
147 static device_method_t ti_pruss_methods[] = {
148         DEVMETHOD(device_probe,         ti_pruss_probe),
149         DEVMETHOD(device_attach,        ti_pruss_attach),
150         DEVMETHOD(device_detach,        ti_pruss_detach),
151
152         DEVMETHOD_END
153 };
154
155 static driver_t ti_pruss_driver = {
156         "ti_pruss",
157         ti_pruss_methods,
158         sizeof(struct ti_pruss_softc)
159 };
160
161 static devclass_t ti_pruss_devclass;
162
163 DRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, ti_pruss_devclass, 0, 0);
164 MODULE_DEPEND(ti_pruss, ti_prcm, 1, 1, 1);
165
166 static struct resource_spec ti_pruss_irq_spec[] = {
167         { SYS_RES_IRQ,      0,  RF_ACTIVE },
168         { SYS_RES_IRQ,      1,  RF_ACTIVE },
169         { SYS_RES_IRQ,      2,  RF_ACTIVE },
170         { SYS_RES_IRQ,      3,  RF_ACTIVE },
171         { SYS_RES_IRQ,      4,  RF_ACTIVE },
172         { SYS_RES_IRQ,      5,  RF_ACTIVE },
173         { SYS_RES_IRQ,      6,  RF_ACTIVE },
174         { SYS_RES_IRQ,      7,  RF_ACTIVE },
175         { -1,               0,  0 }
176 };
177 CTASSERT(TI_PRUSS_HOST_IRQS == nitems(ti_pruss_irq_spec) - 1);
178
179 static int
180 ti_pruss_irq_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
181 {
182         struct ctl* irqs;
183         struct ti_pruss_irqsc *sc;
184         sc = dev->si_drv1;
185
186         irqs = malloc(sizeof(struct ctl), M_DEVBUF, M_WAITOK);
187         if (!irqs)
188             return (ENOMEM);
189
190         irqs->cnt = sc->tstamps.ctl.cnt;
191         irqs->idx = sc->tstamps.ctl.idx;
192
193         return devfs_set_cdevpriv(irqs, ti_pruss_privdtor);
194 }
195
196 static void
197 ti_pruss_privdtor(void *data)
198 {
199     free(data, M_DEVBUF);
200 }
201
202 static int
203 ti_pruss_irq_poll(struct cdev *dev, int events, struct thread *td)
204 {
205         struct ctl* irqs;
206         struct ti_pruss_irqsc *sc;
207         sc = dev->si_drv1;
208
209         devfs_get_cdevpriv((void**)&irqs);
210
211         if (events & (POLLIN | POLLRDNORM)) {
212                 if (sc->tstamps.ctl.cnt != irqs->cnt)
213                         return events & (POLLIN | POLLRDNORM);
214                 else
215                         selrecord(td, &sc->sc_selinfo);
216         }
217         return 0;
218 }
219
220 static int
221 ti_pruss_irq_read(struct cdev *cdev, struct uio *uio, int ioflag)
222 {
223         const size_t ts_len = sizeof(uint64_t);
224         struct ti_pruss_irqsc* irq;
225         struct ctl* priv;
226         int error = 0;
227         size_t idx;
228         ssize_t level;
229
230         irq = cdev->si_drv1;
231
232         if (uio->uio_resid < ts_len)
233                 return (EINVAL);
234
235         error = devfs_get_cdevpriv((void**)&priv);
236         if (error)
237             return (error);
238
239         mtx_lock(&irq->sc_mtx);
240
241         if (irq->tstamps.ctl.cnt - priv->cnt > TI_TS_ARRAY)
242         {
243                 priv->cnt = irq->tstamps.ctl.cnt;
244                 priv->idx = irq->tstamps.ctl.idx;
245                 mtx_unlock(&irq->sc_mtx);
246                 return (ENXIO);
247         }
248
249         do {
250                 idx = priv->idx;
251                 level = irq->tstamps.ctl.idx - idx;
252                 if (level < 0)
253                         level += TI_TS_ARRAY;
254
255                 if (level == 0) {
256                         if (ioflag & O_NONBLOCK) {
257                                 mtx_unlock(&irq->sc_mtx);
258                                 return (EWOULDBLOCK);
259                         }
260
261                         error = msleep(irq, &irq->sc_mtx, PCATCH | PDROP,
262                                 "pruirq", 0);
263                         if (error)
264                                 return error;
265
266                         mtx_lock(&irq->sc_mtx);
267                 }
268         }while(level == 0);
269
270         mtx_unlock(&irq->sc_mtx);
271
272         error = uiomove(&irq->tstamps.ts[idx], ts_len, uio);
273
274         if (++idx == TI_TS_ARRAY)
275                 idx = 0;
276         priv->idx = idx;
277
278         atomic_add_32(&priv->cnt, 1);
279
280         return (error);
281 }
282
283 static struct ti_pruss_irq_arg {
284         int                    irq;
285         struct ti_pruss_softc *sc;
286 } ti_pruss_irq_args[TI_PRUSS_IRQS];
287
288 static __inline uint32_t
289 ti_pruss_reg_read(struct ti_pruss_softc *sc, uint32_t reg)
290 {
291         return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
292 }
293
294 static __inline void
295 ti_pruss_reg_write(struct ti_pruss_softc *sc, uint32_t reg, uint32_t val)
296 {
297         bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
298 }
299
300 static __inline void
301 ti_pruss_interrupts_clear(struct ti_pruss_softc *sc)
302 {
303         /* disable global interrupt */
304         ti_pruss_reg_write(sc, PRUSS_INTC_GER, 0 );
305
306         /* clear all events */
307         ti_pruss_reg_write(sc, PRUSS_INTC_SECR0, 0xFFFFFFFF);
308         ti_pruss_reg_write(sc, PRUSS_INTC_SECR1, 0xFFFFFFFF);
309
310         /* disable all host interrupts */
311         ti_pruss_reg_write(sc, PRUSS_INTC_HIER, 0);
312 }
313
314 static __inline int
315 ti_pruss_interrupts_enable(struct ti_pruss_softc *sc, int8_t irq, bool enable)
316 {
317         if (enable && ((sc->sc_irq_devs[irq].channel == -1) ||
318             (sc->sc_irq_devs[irq].event== -1)))
319         {
320                 device_printf( sc->sc_pdev->si_drv1,
321                         "Interrupt chain not fully configured, not possible to enable\n" );
322                 return (EINVAL);
323         }
324
325         sc->sc_irq_devs[irq].enable = enable;
326
327         if (sc->sc_irq_devs[irq].sc_pdev) {
328                 destroy_dev(sc->sc_irq_devs[irq].sc_pdev);
329                 sc->sc_irq_devs[irq].sc_pdev = NULL;
330         }
331
332         if (enable) {
333                 sc->sc_irq_devs[irq].sc_pdev = make_dev(&ti_pruss_cdevirq, 0, UID_ROOT, GID_WHEEL,
334                     0600, "pruss%d.irq%d", device_get_unit(sc->sc_pdev->si_drv1), irq);
335                 sc->sc_irq_devs[irq].sc_pdev->si_drv1 = &sc->sc_irq_devs[irq];
336
337                 sc->sc_irq_devs[irq].tstamps.ctl.idx = 0;
338         }
339
340         uint32_t reg = enable ? PRUSS_INTC_HIEISR : PRUSS_INTC_HIDISR;
341         ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].channel);
342
343         reg = enable ? PRUSS_INTC_EISR : PRUSS_INTC_EICR;
344         ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].event );
345
346         return (0);
347 }
348
349 static __inline void
350 ti_pruss_map_write(struct ti_pruss_softc *sc, uint32_t basereg, uint8_t index, uint8_t content)
351 {
352         const size_t regadr = basereg + index & ~0x03;
353         const size_t bitpos = (index & 0x03) * 8;
354         uint32_t rmw = ti_pruss_reg_read(sc, regadr);
355         rmw = (rmw & ~( 0xF << bitpos)) | ( (content & 0xF) << bitpos);
356         ti_pruss_reg_write(sc, regadr, rmw);
357 }
358
359 static int
360 ti_pruss_event_map( SYSCTL_HANDLER_ARGS )
361 {
362         struct ti_pruss_softc *sc;
363         const int8_t irq = arg2;
364         int err;
365         char event[sizeof(NOT_SET_STR)];
366
367         sc = arg1;
368
369         if(sc->sc_irq_devs[irq].event == -1)
370                 bcopy(NOT_SET_STR, event, sizeof(event));
371         else
372                 snprintf(event, sizeof(event), "%d", sc->sc_irq_devs[irq].event);
373
374         err = sysctl_handle_string(oidp, event, sizeof(event), req);
375         if(err != 0)
376                 return (err);
377
378         if (req->newptr) {  // write event
379                 if (strcmp(NOT_SET_STR, event) == 0) {
380                         ti_pruss_interrupts_enable(sc, irq, false);
381                         sc->sc_irq_devs[irq].event = -1;
382                 } else {
383                         if (sc->sc_irq_devs[irq].channel == -1) {
384                                 device_printf( sc->sc_pdev->si_drv1,
385                                         "corresponding channel not configured\n");
386                                 return (ENXIO);
387                         }
388
389                         const int8_t channelnr = sc->sc_irq_devs[irq].channel;
390                         const int8_t eventnr = strtol( event, NULL, 10 ); // TODO: check if strol is valid
391                         if (eventnr > TI_PRUSS_EVENTS || eventnr < 0) {
392                                 device_printf( sc->sc_pdev->si_drv1,
393                                         "Event number %d not valid (0 - %d)",
394                                         channelnr, TI_PRUSS_EVENTS -1);
395                                 return (EINVAL);
396                         }
397
398                         sc->sc_irq_devs[irq].channel = channelnr;
399                         sc->sc_irq_devs[irq].event = eventnr;
400
401                         // event[nr] <= channel
402                         ti_pruss_map_write(sc, PRUSS_INTC_CMR_BASE,
403                             eventnr, channelnr);
404                 }
405         }
406         return (err);
407 }
408
409 static int
410 ti_pruss_channel_map(SYSCTL_HANDLER_ARGS)
411 {
412         struct ti_pruss_softc *sc;
413         int err;
414         char channel[sizeof(NOT_SET_STR)];
415         const int8_t irq = arg2;
416
417         sc = arg1;
418
419         if (sc->sc_irq_devs[irq].channel == -1)
420                 bcopy(NOT_SET_STR, channel, sizeof(channel));
421         else
422                 snprintf(channel, sizeof(channel), "%d", sc->sc_irq_devs[irq].channel);
423
424         err = sysctl_handle_string(oidp, channel, sizeof(channel), req);
425         if (err != 0)
426                 return (err);
427
428         if (req->newptr) { // write event
429                 if (strcmp(NOT_SET_STR, channel) == 0) {
430                         ti_pruss_interrupts_enable(sc, irq, false);
431                         ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR,
432                             sc->sc_irq_devs[irq].channel);
433                         sc->sc_irq_devs[irq].channel = -1;
434                 } else {
435                         const int8_t channelnr = strtol(channel, NULL, 10); // TODO: check if strol is valid
436                         if (channelnr > TI_PRUSS_IRQS || channelnr < 0)
437                         {
438                                 device_printf(sc->sc_pdev->si_drv1,
439                                         "Channel number %d not valid (0 - %d)",
440                                         channelnr, TI_PRUSS_IRQS-1);
441                                 return (EINVAL);
442                         }
443
444                         sc->sc_irq_devs[irq].channel = channelnr;
445                         sc->sc_irq_devs[irq].last = -1;
446
447                         // channel[nr] <= irqnr
448                         ti_pruss_map_write(sc, PRUSS_INTC_HMR_BASE,
449                                 irq, channelnr);
450                 }
451         }
452
453         return (err);
454 }
455
456 static int
457 ti_pruss_interrupt_enable(SYSCTL_HANDLER_ARGS)
458 {
459         struct ti_pruss_softc *sc;
460         int err;
461         bool irqenable;
462         const int8_t irq = arg2;
463
464         sc = arg1;
465         irqenable = sc->sc_irq_devs[arg2].enable;
466
467         err = sysctl_handle_bool(oidp, &irqenable, arg2, req);
468         if (err != 0)
469                 return (err);
470
471         if (req->newptr) // write enable
472                 return ti_pruss_interrupts_enable(sc, irq, irqenable);
473
474         return (err);
475 }
476
477 static int
478 ti_pruss_global_interrupt_enable(SYSCTL_HANDLER_ARGS)
479 {
480         struct ti_pruss_softc *sc;
481         int err;
482         bool glob_irqen;
483
484         sc = arg1;
485         glob_irqen = sc->sc_glob_irqen;
486
487         err = sysctl_handle_bool(oidp, &glob_irqen, arg2, req);
488         if (err != 0)
489                 return (err);
490
491         if (req->newptr) {
492                 sc->sc_glob_irqen = glob_irqen;
493                 ti_pruss_reg_write(sc, PRUSS_INTC_GER, glob_irqen);
494         }
495
496         return (err);
497 }
498 static int
499 ti_pruss_probe(device_t dev)
500 {
501
502         if (!ofw_bus_status_okay(dev))
503                 return (ENXIO);
504
505         if (ofw_bus_is_compatible(dev, "ti,pruss-v1") ||
506             ofw_bus_is_compatible(dev, "ti,pruss-v2")) {
507                 device_set_desc(dev, "TI Programmable Realtime Unit Subsystem");
508                 return (BUS_PROBE_DEFAULT);
509         }
510
511         return (ENXIO);
512 }
513
514 static int
515 ti_pruss_attach(device_t dev)
516 {
517         struct ti_pruss_softc *sc;
518         int rid, i;
519
520         if (ti_prcm_clk_enable(PRUSS_CLK) != 0) {
521                 device_printf(dev, "could not enable PRUSS clock\n");
522                 return (ENXIO);
523         }
524         sc = device_get_softc(dev);
525         rid = 0;
526         mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF);
527         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
528             RF_ACTIVE);
529         if (sc->sc_mem_res == NULL) {
530                 device_printf(dev, "could not allocate memory resource\n");
531                 return (ENXIO);
532         }
533
534         struct sysctl_ctx_list *clist = device_get_sysctl_ctx(dev);
535         if (!clist)
536                 return (EINVAL);
537
538         struct sysctl_oid *poid;
539         poid = device_get_sysctl_tree( dev );
540         if (!poid)
541                 return (EINVAL);
542
543         sc->sc_glob_irqen = false;
544         struct sysctl_oid *irq_root = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(poid),
545             OID_AUTO, "irq", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
546             "PRUSS Host Interrupts");
547         SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(poid), OID_AUTO,
548             "global_interrupt_enable",
549             CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
550             sc, 0, ti_pruss_global_interrupt_enable,
551             "CU", "Global interrupt enable");
552
553         sc->sc_bt = rman_get_bustag(sc->sc_mem_res);
554         sc->sc_bh = rman_get_bushandle(sc->sc_mem_res);
555         if (bus_alloc_resources(dev, ti_pruss_irq_spec, sc->sc_irq_res) != 0) {
556                 device_printf(dev, "could not allocate interrupt resource\n");
557                 ti_pruss_detach(dev);
558                 return (ENXIO);
559         }
560
561         ti_pruss_interrupts_clear(sc);
562
563         for (i = 0; i < TI_PRUSS_IRQS; i++) {
564                 char name[8];
565                 snprintf(name, sizeof(name), "%d", i);
566
567                 struct sysctl_oid *irq_nodes = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(irq_root),
568                     OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
569                     "PRUSS Interrupts");
570                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
571                     "channel", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
572                     sc, i, ti_pruss_channel_map,
573                     "A", "Channel attached to this irq");
574                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
575                     "event", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
576                     sc, i, ti_pruss_event_map,
577                     "A", "Event attached to this irq");
578                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
579                     "enable", CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
580                     sc, i, ti_pruss_interrupt_enable,
581                     "CU", "Enable/Disable interrupt");
582
583                 sc->sc_irq_devs[i].event = -1;
584                 sc->sc_irq_devs[i].channel = -1;
585                 sc->sc_irq_devs[i].tstamps.ctl.idx = 0;
586
587                 if (i < TI_PRUSS_HOST_IRQS) {
588                         ti_pruss_irq_args[i].irq = i;
589                         ti_pruss_irq_args[i].sc = sc;
590                         if (bus_setup_intr(dev, sc->sc_irq_res[i],
591                             INTR_MPSAFE | INTR_TYPE_MISC,
592                             NULL, ti_pruss_intr, &ti_pruss_irq_args[i],
593                             &sc->sc_intr[i]) != 0) {
594                                 device_printf(dev,
595                                     "unable to setup the interrupt handler\n");
596                                 ti_pruss_detach(dev);
597
598                                 return (ENXIO);
599                         }
600                         mtx_init(&sc->sc_irq_devs[i].sc_mtx, "TI PRUSS IRQ", NULL, MTX_DEF);
601                         knlist_init_mtx(&sc->sc_irq_devs[i].sc_selinfo.si_note, &sc->sc_irq_devs[i].sc_mtx);
602                 }
603         }
604
605         if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV)
606                 device_printf(dev, "AM33xx PRU-ICSS\n");
607
608         sc->sc_pdev = make_dev(&ti_pruss_cdevsw, 0, UID_ROOT, GID_WHEEL,
609             0600, "pruss%d", device_get_unit(dev));
610         sc->sc_pdev->si_drv1 = dev;
611
612         /*  Acc. to datasheet always write 1 to polarity registers */
613         ti_pruss_reg_write(sc, PRUSS_INTC_SIPR0, 0xFFFFFFFF);
614         ti_pruss_reg_write(sc, PRUSS_INTC_SIPR1, 0xFFFFFFFF);
615
616         /* Acc. to datasheet always write 0 to event type registers */
617         ti_pruss_reg_write(sc, PRUSS_INTC_SITR0, 0);
618         ti_pruss_reg_write(sc, PRUSS_INTC_SITR1, 0);
619
620         return (0);
621 }
622
623 static int
624 ti_pruss_detach(device_t dev)
625 {
626         struct ti_pruss_softc *sc = device_get_softc(dev);
627
628         ti_pruss_interrupts_clear(sc);
629
630         for (int i = 0; i < TI_PRUSS_HOST_IRQS; i++) {
631                 ti_pruss_interrupts_enable( sc, i, false );
632
633                 if (sc->sc_intr[i])
634                         bus_teardown_intr(dev, sc->sc_irq_res[i], sc->sc_intr[i]);
635                 if (sc->sc_irq_res[i])
636                         bus_release_resource(dev, SYS_RES_IRQ,
637                             rman_get_rid(sc->sc_irq_res[i]),
638                             sc->sc_irq_res[i]);
639                 knlist_clear(&sc->sc_irq_devs[i].sc_selinfo.si_note, 0);
640                 mtx_lock(&sc->sc_irq_devs[i].sc_mtx);
641                 if (!knlist_empty(&sc->sc_irq_devs[i].sc_selinfo.si_note))
642                         printf("IRQ %d KQueue not empty!\n", i );
643                 mtx_unlock(&sc->sc_irq_devs[i].sc_mtx);
644                 knlist_destroy(&sc->sc_irq_devs[i].sc_selinfo.si_note);
645                 mtx_destroy(&sc->sc_irq_devs[i].sc_mtx);
646         }
647
648         mtx_destroy(&sc->sc_mtx);
649         if (sc->sc_mem_res)
650                 bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res),
651                     sc->sc_mem_res);
652         if (sc->sc_pdev)
653                 destroy_dev(sc->sc_pdev);
654
655         return (0);
656 }
657
658 static void
659 ti_pruss_intr(void *arg)
660 {
661         int val;
662         struct ti_pruss_irq_arg *iap = arg;
663         struct ti_pruss_softc *sc = iap->sc;
664         /*
665          * Interrupts pr1_host_intr[0:7] are mapped to
666          * Host-2 to Host-9 of PRU-ICSS IRQ-controller.
667          */
668         const int pru_int = iap->irq + TI_PRUSS_PRU_IRQS;
669         const int pru_int_mask = (1 << pru_int);
670         const int pru_channel = sc->sc_irq_devs[pru_int].channel;
671         const int pru_event = sc->sc_irq_devs[pru_channel].event;
672
673         val = ti_pruss_reg_read(sc, PRUSS_INTC_HIER);
674         if (!(val & pru_int_mask))
675                 return;
676
677         ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR, pru_int);
678         ti_pruss_reg_write(sc, PRUSS_INTC_SICR, pru_event);
679         ti_pruss_reg_write(sc, PRUSS_INTC_HIEISR, pru_int);
680
681         struct ti_pruss_irqsc* irq = &sc->sc_irq_devs[pru_channel];
682         size_t wr = irq->tstamps.ctl.idx;
683
684         struct timespec ts;
685         nanouptime(&ts);
686         irq->tstamps.ts[wr] = ts.tv_sec * 1000000000 + ts.tv_nsec;
687
688         if (++wr == TI_TS_ARRAY)
689                 wr = 0;
690         atomic_add_32(&irq->tstamps.ctl.cnt, 1);
691
692         irq->tstamps.ctl.idx = wr;
693
694         KNOTE_UNLOCKED(&irq->sc_selinfo.si_note, pru_int);
695         wakeup(irq);
696         selwakeup(&irq->sc_selinfo);
697 }
698
699 static int
700 ti_pruss_open(struct cdev *cdev __unused, int oflags __unused,
701     int devtype __unused, struct thread *td __unused)
702 {
703         return (0);
704 }
705
706 static int
707 ti_pruss_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
708     int nprot, vm_memattr_t *memattr)
709 {
710         device_t dev = cdev->si_drv1;
711         struct ti_pruss_softc *sc = device_get_softc(dev);
712
713         if (offset >= rman_get_size(sc->sc_mem_res))
714                 return (ENOSPC);
715         *paddr = rman_get_start(sc->sc_mem_res) + offset;
716         *memattr = VM_MEMATTR_UNCACHEABLE;
717
718         return (0);
719 }
720
721 static struct filterops ti_pruss_kq_read = {
722         .f_isfd = 1,
723         .f_detach = ti_pruss_irq_kqread_detach,
724         .f_event = ti_pruss_irq_kqevent,
725 };
726
727 static void
728 ti_pruss_irq_kqread_detach(struct knote *kn)
729 {
730         struct ti_pruss_irqsc *sc = kn->kn_hook;
731
732         knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
733 }
734
735 static int
736 ti_pruss_irq_kqevent(struct knote *kn, long hint)
737 {
738     struct ti_pruss_irqsc* irq_sc;
739     int notify;
740
741     irq_sc = kn->kn_hook;
742
743     if (hint > 0)
744         kn->kn_data = hint - 2;
745
746     if (hint > 0 || irq_sc->last > 0)
747         notify = 1;
748     else
749         notify = 0;
750
751     irq_sc->last = hint;
752
753     return (notify);
754 }
755
756 static int
757 ti_pruss_irq_kqfilter(struct cdev *cdev, struct knote *kn)
758 {
759         struct ti_pruss_irqsc *sc = cdev->si_drv1;
760
761         switch (kn->kn_filter) {
762         case EVFILT_READ:
763                 kn->kn_hook = sc;
764                 kn->kn_fop = &ti_pruss_kq_read;
765                 knlist_add(&sc->sc_selinfo.si_note, kn, 0);
766                 break;
767         default:
768                 return (EINVAL);
769         }
770
771         return (0);
772 }