]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/atheros/ar531x/apb.c
Merge ^/head r313896 through r314128.
[FreeBSD/FreeBSD.git] / sys / mips / atheros / ar531x / apb.c
1 /*-
2  * Copyright (c) 2016, Hiroki Mori
3  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "opt_platform.h"
30 #include "opt_ar531x.h"
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/interrupt.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/rman.h>
42 #include <sys/malloc.h>
43 #include <sys/pcpu.h>
44 #include <sys/proc.h>
45 #include <sys/pmc.h>
46 #include <sys/pmckern.h>
47
48 #include <machine/bus.h>
49 #ifdef INTRNG
50 #include <machine/intr.h>
51 #else
52 #include <machine/intr_machdep.h>
53 #endif
54
55 #ifdef INTRNG
56 #include "pic_if.h"
57
58 #define PIC_INTR_ISRC(sc, irq)  (&(sc)->pic_irqs[(irq)].isrc)
59 #endif
60
61 #include <mips/atheros/ar531x/apbvar.h>
62 #include <mips/atheros/ar531x/ar5315reg.h>
63 #include <mips/atheros/ar531x/ar5312reg.h>
64 #include <mips/atheros/ar531x/ar5315_setup.h>
65
66 #ifdef AR531X_APB_DEBUG
67 #define dprintf printf
68 #else 
69 #define dprintf(x, arg...)
70 #endif  /* AR531X_APB_DEBUG */
71
72 static int      apb_activate_resource(device_t, device_t, int, int,
73                     struct resource *);
74 static device_t apb_add_child(device_t, u_int, const char *, int);
75 static struct resource *
76                 apb_alloc_resource(device_t, device_t, int, int *, rman_res_t,
77                     rman_res_t, rman_res_t, u_int);
78 static int      apb_attach(device_t);
79 static int      apb_deactivate_resource(device_t, device_t, int, int,
80                     struct resource *);
81 static struct resource_list *
82                 apb_get_resource_list(device_t, device_t);
83 static void     apb_hinted_child(device_t, const char *, int);
84 static int      apb_filter(void *);
85 static int      apb_probe(device_t);
86 static int      apb_release_resource(device_t, device_t, int, int,
87                     struct resource *);
88 #ifndef INTRNG
89 static int      apb_setup_intr(device_t, device_t, struct resource *, int,
90                     driver_filter_t *, driver_intr_t *, void *, void **);
91 static int      apb_teardown_intr(device_t, device_t, struct resource *,
92                     void *);
93 #endif
94
95 static void 
96 apb_mask_irq(void *source)
97 {
98         unsigned int irq = (unsigned int)source;
99         uint32_t reg;
100
101         if(ar531x_soc >= AR531X_SOC_AR5315) {
102                 reg = ATH_READ_REG(AR5315_SYSREG_BASE +
103                         AR5315_SYSREG_MISC_INTMASK);
104                 ATH_WRITE_REG(AR5315_SYSREG_BASE
105                         + AR5315_SYSREG_MISC_INTMASK, reg & ~(1 << irq));
106         } else {
107                 reg = ATH_READ_REG(AR5312_SYSREG_BASE +
108                         AR5312_SYSREG_MISC_INTMASK);
109                 ATH_WRITE_REG(AR5312_SYSREG_BASE
110                         + AR5312_SYSREG_MISC_INTMASK, reg & ~(1 << irq));
111         }
112 }
113
114 static void 
115 apb_unmask_irq(void *source)
116 {
117         uint32_t reg;
118         unsigned int irq = (unsigned int)source;
119
120         if(ar531x_soc >= AR531X_SOC_AR5315) {
121                 reg = ATH_READ_REG(AR5315_SYSREG_BASE +
122                         AR5315_SYSREG_MISC_INTMASK);
123                 ATH_WRITE_REG(AR5315_SYSREG_BASE +
124                         AR5315_SYSREG_MISC_INTMASK, reg | (1 << irq));
125         } else {
126                 reg = ATH_READ_REG(AR5312_SYSREG_BASE +
127                         AR5312_SYSREG_MISC_INTMASK);
128                 ATH_WRITE_REG(AR5312_SYSREG_BASE +
129                         AR5312_SYSREG_MISC_INTMASK, reg | (1 << irq));
130         }
131 }
132
133 #ifdef INTRNG
134 static int
135 apb_pic_register_isrcs(struct apb_softc *sc)
136 {
137         int error;
138         uint32_t irq;
139         struct intr_irqsrc *isrc;
140         const char *name;
141
142         name = device_get_nameunit(sc->apb_dev);
143         for (irq = 0; irq < APB_NIRQS; irq++) {
144                 sc->pic_irqs[irq].irq = irq;
145                 isrc = PIC_INTR_ISRC(sc, irq);
146                 error = intr_isrc_register(isrc, sc->apb_dev, 0, "%s", name);
147                 if (error != 0) {
148                         /* XXX call intr_isrc_deregister */
149                         device_printf(sc->apb_dev, "%s failed", __func__);
150                         return (error);
151                 }
152         }
153
154         return (0);
155 }
156
157 static inline intptr_t
158 pic_xref(device_t dev)
159 {
160         return (0);
161 }
162 #endif
163
164 static int
165 apb_probe(device_t dev)
166 {
167 #ifdef INTRNG
168         device_set_desc(dev, "APB Bus bridge INTRNG");
169 #else
170         device_set_desc(dev, "APB Bus bridge");
171 #endif
172
173         return (0);
174 }
175
176 static int
177 apb_attach(device_t dev)
178 {
179         struct apb_softc *sc = device_get_softc(dev);
180 #ifdef INTRNG
181         intptr_t xref = pic_xref(dev);
182         int miscirq;
183 #else
184         int rid = 0;
185 #endif
186
187         sc->apb_dev = dev;
188
189         sc->apb_mem_rman.rm_type = RMAN_ARRAY;
190         sc->apb_mem_rman.rm_descr = "APB memory window";
191
192         if(ar531x_soc >= AR531X_SOC_AR5315) {
193                 if (rman_init(&sc->apb_mem_rman) != 0 ||
194                     rman_manage_region(&sc->apb_mem_rman, 
195                         AR5315_APB_BASE, 
196                         AR5315_APB_BASE + AR5315_APB_SIZE - 1) != 0)
197                         panic("apb_attach: failed to set up memory rman");
198         } else {
199                 if (rman_init(&sc->apb_mem_rman) != 0 ||
200                     rman_manage_region(&sc->apb_mem_rman, 
201                         AR5312_APB_BASE, 
202                         AR5312_APB_BASE + AR5312_APB_SIZE - 1) != 0)
203                         panic("apb_attach: failed to set up memory rman");
204         }
205
206         sc->apb_irq_rman.rm_type = RMAN_ARRAY;
207         sc->apb_irq_rman.rm_descr = "APB IRQ";
208
209         if (rman_init(&sc->apb_irq_rman) != 0 ||
210             rman_manage_region(&sc->apb_irq_rman, 
211                         APB_IRQ_BASE, APB_IRQ_END) != 0)
212                 panic("apb_attach: failed to set up IRQ rman");
213
214 #ifndef INTRNG
215         if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 
216             RF_SHAREABLE | RF_ACTIVE)) == NULL) {
217                 device_printf(dev, "unable to allocate IRQ resource\n");
218                 return (ENXIO);
219         }
220
221         if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC, 
222             apb_filter, NULL, sc, &sc->sc_misc_ih))) {
223                 device_printf(dev,
224                     "WARNING: unable to register interrupt handler\n");
225                 return (ENXIO);
226         }
227 #else
228         /* Register the interrupts */
229         if (apb_pic_register_isrcs(sc) != 0) {
230                 device_printf(dev, "could not register PIC ISRCs\n");
231                 return (ENXIO);
232         }
233
234         /*
235          * Now, when everything is initialized, it's right time to
236          * register interrupt controller to interrupt framefork.
237          */
238         if (intr_pic_register(dev, xref) == NULL) {
239                 device_printf(dev, "could not register PIC\n");
240                 return (ENXIO);
241         }
242
243         if(ar531x_soc >= AR531X_SOC_AR5315) {
244                 miscirq = AR5315_CPU_IRQ_MISC;
245         } else {
246                 miscirq = AR5312_IRQ_MISC;
247         }
248         cpu_establish_hardintr("aric", apb_filter, NULL, sc, miscirq,
249             INTR_TYPE_MISC, NULL);
250 #endif
251
252         /* mask all misc interrupt */
253         if(ar531x_soc >= AR531X_SOC_AR5315) {
254                 ATH_WRITE_REG(AR5315_SYSREG_BASE
255                         + AR5315_SYSREG_MISC_INTMASK, 0);
256         } else {
257                 ATH_WRITE_REG(AR5312_SYSREG_BASE
258                         + AR5312_SYSREG_MISC_INTMASK, 0);
259         }
260
261         bus_generic_probe(dev);
262         bus_enumerate_hinted_children(dev);
263         bus_generic_attach(dev);
264
265         return (0);
266 }
267
268 static struct resource *
269 apb_alloc_resource(device_t bus, device_t child, int type, int *rid,
270     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
271 {
272         struct apb_softc                *sc = device_get_softc(bus);
273         struct apb_ivar                 *ivar = device_get_ivars(child);
274         struct resource                 *rv;
275         struct resource_list_entry      *rle;
276         struct rman                     *rm;
277         int                              isdefault, needactivate, passthrough;
278
279         isdefault = (RMAN_IS_DEFAULT_RANGE(start, end));
280         needactivate = flags & RF_ACTIVE;
281         /*
282          * Pass memory requests to nexus device
283          */
284         passthrough = (device_get_parent(child) != bus);
285         rle = NULL;
286
287         dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %jd, %d)\n",
288             __func__, bus, child, type, *rid, (void *)(intptr_t)start,
289             (void *)(intptr_t)end, count, flags);
290
291         if (passthrough)
292                 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
293                     rid, start, end, count, flags));
294
295         /*
296          * If this is an allocation of the "default" range for a given RID,
297          * and we know what the resources for this device are (ie. they aren't
298          * maintained by a child bus), then work out the start/end values.
299          */
300
301         if (isdefault) {
302                 rle = resource_list_find(&ivar->resources, type, *rid);
303                 if (rle == NULL) {
304                         return (NULL);
305                 }
306
307                 if (rle->res != NULL) {
308                         panic("%s: resource entry is busy", __func__);
309                 }
310                 start = rle->start;
311                 end = rle->end;
312                 count = rle->count;
313
314                 dprintf("%s: default resource (%p, %p, %jd)\n",
315                     __func__, (void *)(intptr_t)start,
316                     (void *)(intptr_t)end, count);
317         }
318
319         switch (type) {
320         case SYS_RES_IRQ:
321                 rm = &sc->apb_irq_rman;
322                 break;
323         case SYS_RES_MEMORY:
324                 rm = &sc->apb_mem_rman;
325                 break;
326         default:
327                 printf("%s: unknown resource type %d\n", __func__, type);
328                 return (0);
329         }
330
331         rv = rman_reserve_resource(rm, start, end, count, flags, child);
332         if (rv == NULL) {
333                 printf("%s: could not reserve resource %d\n", __func__, type);
334                 return (0);
335         }
336
337         rman_set_rid(rv, *rid);
338
339         if (needactivate) {
340                 if (bus_activate_resource(child, type, *rid, rv)) {
341                         printf("%s: could not activate resource\n", __func__);
342                         rman_release_resource(rv);
343                         return (0);
344                 }
345         }
346
347         return (rv);
348 }
349
350 static int
351 apb_activate_resource(device_t bus, device_t child, int type, int rid,
352     struct resource *r)
353 {
354
355         /* XXX: should we mask/unmask IRQ here? */
356         return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
357                 type, rid, r));
358 }
359
360 static int
361 apb_deactivate_resource(device_t bus, device_t child, int type, int rid,
362     struct resource *r)
363 {
364
365         /* XXX: should we mask/unmask IRQ here? */
366         return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
367                 type, rid, r));
368 }
369
370 static int
371 apb_release_resource(device_t dev, device_t child, int type,
372     int rid, struct resource *r)
373 {
374         struct resource_list *rl;
375         struct resource_list_entry *rle;
376
377         rl = apb_get_resource_list(dev, child);
378         if (rl == NULL)
379                 return (EINVAL);
380         rle = resource_list_find(rl, type, rid);
381         if (rle == NULL)
382                 return (EINVAL);
383         rman_release_resource(r);
384         rle->res = NULL;
385
386         return (0);
387 }
388
389
390 static int
391 apb_setup_intr(device_t bus, device_t child, struct resource *ires,
392                 int flags, driver_filter_t *filt, driver_intr_t *handler,
393                 void *arg, void **cookiep)
394 {
395         struct apb_softc *sc = device_get_softc(bus);
396         int error;
397         int irq;
398 #ifndef INTRNG
399         struct intr_event *event;
400 #endif
401
402 #ifdef INTRNG
403         struct intr_irqsrc *isrc;
404         const char *name;
405         
406         if ((rman_get_flags(ires) & RF_SHAREABLE) == 0)
407                 flags |= INTR_EXCL;
408
409         irq = rman_get_start(ires);
410         isrc = PIC_INTR_ISRC(sc, irq);
411         if(isrc->isrc_event == 0) {
412                 error = intr_event_create(&isrc->isrc_event, (void *)irq,
413                     0, irq, apb_mask_irq, apb_unmask_irq,
414                     NULL, NULL, "apb intr%d:", irq);
415                 if(error != 0)
416                         return(error);
417         }
418         name = device_get_nameunit(child);
419         error = intr_event_add_handler(isrc->isrc_event, name, filt, handler,
420             arg, intr_priority(flags), flags, cookiep);
421         return(error);
422 #else
423         irq = rman_get_start(ires);
424
425         if (irq > APB_IRQ_END)
426                 panic("%s: bad irq %d", __func__, irq);
427
428         event = sc->sc_eventstab[irq];
429         if (event == NULL) {
430                 error = intr_event_create(&event, (void *)irq, 0, irq, 
431                     apb_mask_irq, apb_unmask_irq,
432                     NULL, NULL,
433                     "apb intr%d:", irq);
434
435                 if (error == 0) {
436                         sc->sc_eventstab[irq] = event;
437                         sc->sc_intr_counter[irq] =
438                             mips_intrcnt_create(event->ie_name);
439                 }
440                 else
441                         return (error);
442         }
443
444         intr_event_add_handler(event, device_get_nameunit(child), filt,
445             handler, arg, intr_priority(flags), flags, cookiep);
446         mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname);
447
448         apb_unmask_irq((void*)irq);
449
450         return (0);
451 #endif
452 }
453
454 #ifndef INTRNG
455 static int
456 apb_teardown_intr(device_t dev, device_t child, struct resource *ires,
457     void *cookie)
458 {
459 #ifdef INTRNG
460          return (intr_teardown_irq(child, ires, cookie));
461 #else
462         struct apb_softc *sc = device_get_softc(dev);
463         int irq, result;
464
465         irq = rman_get_start(ires);
466         if (irq > APB_IRQ_END)
467                 panic("%s: bad irq %d", __func__, irq);
468
469         if (sc->sc_eventstab[irq] == NULL)
470                 panic("Trying to teardown unoccupied IRQ");
471
472         apb_mask_irq((void*)irq);
473
474         result = intr_event_remove_handler(cookie);
475         if (!result)
476                 sc->sc_eventstab[irq] = NULL;
477
478         return (result);
479 #endif
480 }
481
482
483 static int
484 apb_filter(void *arg)
485 {
486         struct apb_softc *sc = arg;
487         struct intr_event *event;
488         uint32_t reg, irq;
489
490         if(ar531x_soc >= AR531X_SOC_AR5315)
491                 reg = ATH_READ_REG(AR5315_SYSREG_BASE +
492                         AR5315_SYSREG_MISC_INTSTAT);
493         else
494                 reg = ATH_READ_REG(AR5312_SYSREG_BASE +
495                         AR5312_SYSREG_MISC_INTSTAT);
496
497         for (irq = 0; irq < APB_NIRQS; irq++) {
498                 if (reg & (1 << irq)) {
499
500                         if(ar531x_soc >= AR531X_SOC_AR5315) {
501                                 ATH_WRITE_REG(AR5315_SYSREG_BASE +
502                                     AR5315_SYSREG_MISC_INTSTAT,
503                                     reg & ~(1 << irq));
504                         } else {
505                                 ATH_WRITE_REG(AR5312_SYSREG_BASE +
506                                     AR5312_SYSREG_MISC_INTSTAT,
507                                     reg & ~(1 << irq));
508                         }
509
510                         event = sc->sc_eventstab[irq];
511                         if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
512                                 if(irq == 1 && ar531x_soc < AR531X_SOC_AR5315) {
513                                         ATH_READ_REG(AR5312_SYSREG_BASE +
514                                                 AR5312_SYSREG_AHBPERR);
515                                         ATH_READ_REG(AR5312_SYSREG_BASE +
516                                                 AR5312_SYSREG_AHBDMAE);
517                                 }
518                                 /* Ignore non handle interrupts */
519                                 if (irq != 0 && irq != 6)
520                                         printf("Stray APB IRQ %d\n", irq);
521
522                                 continue;
523                         }
524
525                         intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame);
526                         mips_intrcnt_inc(sc->sc_intr_counter[irq]);
527                 }
528         }
529
530         return (FILTER_HANDLED);
531 }
532 #else
533 static int
534 apb_filter(void *arg)
535 {
536         struct apb_softc *sc = arg;
537         struct thread *td;
538         uint32_t i, intr;
539
540         td = curthread;
541         /* Workaround: do not inflate intr nesting level */
542         td->td_intr_nesting_level--;
543
544         if(ar531x_soc >= AR531X_SOC_AR5315)
545                 intr = ATH_READ_REG(AR5315_SYSREG_BASE +
546                         AR5315_SYSREG_MISC_INTSTAT);
547         else
548                 intr = ATH_READ_REG(AR5312_SYSREG_BASE +
549                         AR5312_SYSREG_MISC_INTSTAT);
550
551         while ((i = fls(intr)) != 0) {
552                 i--;
553                 intr &= ~(1u << i);
554
555                 if(i == 1 && ar531x_soc < AR531X_SOC_AR5315) {
556                         ATH_READ_REG(AR5312_SYSREG_BASE +
557                             AR5312_SYSREG_AHBPERR);
558                         ATH_READ_REG(AR5312_SYSREG_BASE +
559                             AR5312_SYSREG_AHBDMAE);
560                 }
561
562                 if (intr_isrc_dispatch(PIC_INTR_ISRC(sc, i),
563                     curthread->td_intr_frame) != 0) {
564                         device_printf(sc->apb_dev,
565                             "Stray interrupt %u detected\n", i);
566                         apb_mask_irq((void*)i);
567                         continue;
568                 }
569         }
570
571         KASSERT(i == 0, ("all interrupts handled"));
572
573         td->td_intr_nesting_level++;
574
575         return (FILTER_HANDLED);
576
577 }
578
579 #endif
580
581 static void
582 apb_hinted_child(device_t bus, const char *dname, int dunit)
583 {
584         device_t                child;
585         long                    maddr;
586         int                     msize;
587         int                     irq;
588         int                     result;
589         int                     mem_hints_count;
590
591         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
592
593         /*
594          * Set hard-wired resources for hinted child using
595          * specific RIDs.
596          */
597         mem_hints_count = 0;
598         if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
599                 mem_hints_count++;
600         if (resource_int_value(dname, dunit, "msize", &msize) == 0)
601                 mem_hints_count++;
602
603         /* check if all info for mem resource has been provided */
604         if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
605                 printf("Either maddr or msize hint is missing for %s%d\n",
606                     dname, dunit);
607         } else if (mem_hints_count) {
608                 result = bus_set_resource(child, SYS_RES_MEMORY, 0,
609                     maddr, msize);
610                 if (result != 0)
611                         device_printf(bus, 
612                             "warning: bus_set_resource() failed\n");
613         }
614
615         if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
616                 result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
617                 if (result != 0)
618                         device_printf(bus,
619                             "warning: bus_set_resource() failed\n");
620         }
621 }
622
623 static device_t
624 apb_add_child(device_t bus, u_int order, const char *name, int unit)
625 {
626         device_t                child;
627         struct apb_ivar *ivar;
628
629         ivar = malloc(sizeof(struct apb_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
630         if (ivar == NULL) {
631                 printf("Failed to allocate ivar\n");
632                 return (0);
633         }
634         resource_list_init(&ivar->resources);
635
636         child = device_add_child_ordered(bus, order, name, unit);
637         if (child == NULL) {
638                 printf("Can't add child %s%d ordered\n", name, unit);
639                 return (0);
640         }
641
642         device_set_ivars(child, ivar);
643
644         return (child);
645 }
646
647 /*
648  * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
649  * Provides pointer to resource_list for these routines
650  */
651 static struct resource_list *
652 apb_get_resource_list(device_t dev, device_t child)
653 {
654         struct apb_ivar *ivar;
655
656         ivar = device_get_ivars(child);
657         return (&(ivar->resources));
658 }
659
660 #ifdef INTRNG
661 static void
662 apb_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
663 {
664         u_int irq;
665
666         irq = ((struct apb_pic_irqsrc *)isrc)->irq;
667         apb_unmask_irq((void*)irq);
668 }
669
670 static void
671 apb_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
672 {
673         u_int irq;
674
675         irq = ((struct apb_pic_irqsrc *)isrc)->irq;
676         apb_mask_irq((void*)irq);
677 }
678
679 static void
680 apb_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
681 {
682         apb_pic_disable_intr(dev, isrc);
683 }
684
685 static void
686 apb_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
687 {
688         apb_pic_enable_intr(dev, isrc);
689 }
690
691 static void
692 apb_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
693 {
694         uint32_t reg, irq;
695
696         irq = ((struct apb_pic_irqsrc *)isrc)->irq;
697         if(ar531x_soc >= AR531X_SOC_AR5315) {
698                 reg = ATH_READ_REG(AR5315_SYSREG_BASE +
699                         AR5315_SYSREG_MISC_INTSTAT);
700                 ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT,
701                     reg & ~(1 << irq));
702         } else {
703                 reg = ATH_READ_REG(AR5312_SYSREG_BASE +
704                         AR5312_SYSREG_MISC_INTSTAT);
705                 ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT,
706                     reg & ~(1 << irq));
707         }
708 }
709
710 static int
711 apb_pic_map_intr(device_t dev, struct intr_map_data *data,
712     struct intr_irqsrc **isrcp)
713 {
714         return (ENOTSUP);
715 }
716
717 #endif
718
719 static device_method_t apb_methods[] = {
720         DEVMETHOD(bus_activate_resource,        apb_activate_resource),
721         DEVMETHOD(bus_add_child,                apb_add_child),
722         DEVMETHOD(bus_alloc_resource,           apb_alloc_resource),
723         DEVMETHOD(bus_deactivate_resource,      apb_deactivate_resource),
724         DEVMETHOD(bus_get_resource_list,        apb_get_resource_list),
725         DEVMETHOD(bus_hinted_child,             apb_hinted_child),
726         DEVMETHOD(bus_release_resource,         apb_release_resource),
727         DEVMETHOD(device_attach,                apb_attach),
728         DEVMETHOD(device_probe,                 apb_probe),
729         DEVMETHOD(bus_get_resource,             bus_generic_rl_get_resource),
730         DEVMETHOD(bus_set_resource,             bus_generic_rl_set_resource),
731 #ifdef INTRNG
732         DEVMETHOD(pic_disable_intr,             apb_pic_disable_intr),
733         DEVMETHOD(pic_enable_intr,              apb_pic_enable_intr),
734         DEVMETHOD(pic_map_intr,                 apb_pic_map_intr),
735         DEVMETHOD(pic_post_filter,              apb_pic_post_filter),
736         DEVMETHOD(pic_post_ithread,             apb_pic_post_ithread),
737         DEVMETHOD(pic_pre_ithread,              apb_pic_pre_ithread),
738
739 //      DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
740 #else
741         DEVMETHOD(bus_teardown_intr,            apb_teardown_intr),
742 #endif
743         DEVMETHOD(bus_setup_intr,               apb_setup_intr),
744
745         DEVMETHOD_END
746 };
747
748 static driver_t apb_driver = {
749         "apb",
750         apb_methods,
751         sizeof(struct apb_softc),
752 };
753 static devclass_t apb_devclass;
754
755 EARLY_DRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0,
756     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);