Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/samsung Cleanup of combiner driver and make it ...



details:   https://anonhg.NetBSD.org/src/rev/4b6c582ea4e1
branches:  trunk
changeset: 323820:4b6c582ea4e1
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Jul 02 12:18:32 2018 +0000

description:
Cleanup of combiner driver and make it work (at least for MCT).

diffstat:

 sys/arch/arm/samsung/exynos_combiner.c |  161 +++++++++++++++++---------------
 1 files changed, 84 insertions(+), 77 deletions(-)

diffs (282 lines):

diff -r f9de46a1b5dd -r 4b6c582ea4e1 sys/arch/arm/samsung/exynos_combiner.c
--- a/sys/arch/arm/samsung/exynos_combiner.c    Mon Jul 02 12:17:05 2018 +0000
+++ b/sys/arch/arm/samsung/exynos_combiner.c    Mon Jul 02 12:18:32 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: exynos_combiner.c,v 1.7 2017/06/11 16:19:27 jmcneill Exp $ */
+/*     $NetBSD: exynos_combiner.c,v 1.8 2018/07/02 12:18:32 jmcneill Exp $ */
 
 /*-
 * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
 #include "gpio.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.7 2017/06/11 16:19:27 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.8 2018/07/02 12:18:32 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,14 +50,13 @@
 
 #include <dev/fdt/fdtvar.h>
 
-#define COMBINER_IESR_OFFSET   0x00
-#define COMBINER_IECR_OFFSET   0x04
-#define COMBINER_ISTR_OFFSET   0x08
-#define COMBINER_IMSR_OFFSET   0x0C
-#define COMBINER_GROUP_SIZE    0x10
-#define COMBINER_IRQS_PER_BLOCK   8
-#define COMBINER_BLOCKS_PER_GROUP 4
-#define COMBINER_N_BLOCKS        32
+#define        COMBINER_GROUP_BASE(group)      (((group) / 4) * 0x10)
+#define        COMBINER_GROUP_MASK(group)      (0xff << (((group) % 4) * 8))
+
+#define        COMBINER_IESR_REG(group)        (COMBINER_GROUP_BASE(group) + 0x00)
+#define        COMBINER_IECR_REG(group)        (COMBINER_GROUP_BASE(group) + 0x04)
+#define        COMBINER_ISTR_REG(group)        (COMBINER_GROUP_BASE(group) + 0x08)
+#define        COMBINER_IMSR_REG(group)        (COMBINER_GROUP_BASE(group) + 0x0c)
 
 struct exynos_combiner_softc;
 
@@ -69,12 +68,13 @@
        bool                            irq_mpsafe;
 };
 
-struct exynos_combiner_irq_block {
-       int irq_block_no;
+struct exynos_combiner_irq_group {
+       int irq_group_no;
        struct exynos_combiner_softc    *irq_sc;
        struct exynos_combiner_irq_entry *irq_entries;
-       struct exynos_combiner_irq_block *irq_block_next;
+       struct exynos_combiner_irq_group *irq_group_next;
        void *irq_ih;
+       int irq_ipl;
 };
 
 struct exynos_combiner_softc {
@@ -82,7 +82,7 @@
        bus_space_tag_t         sc_bst;
        bus_space_handle_t      sc_bsh;
        int                     sc_phandle;
-       struct exynos_combiner_irq_block *irq_blocks;
+       struct exynos_combiner_irq_group *irq_groups;
 };
 
 static int exynos_combiner_match(device_t, cfdata_t, void *);
@@ -129,7 +129,6 @@
        sc->sc_dev = self;
        sc->sc_phandle = faa->faa_phandle;
        sc->sc_bst = faa->faa_bst;
-       sc->irq_blocks = NULL;
 
        error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
        if (error) {
@@ -145,53 +144,53 @@
                return;
        }
 
-       aprint_normal(" @ 0x%08x: interrupt combiner", (uint)addr);
        aprint_naive("\n");
-       aprint_normal("\n");
+       aprint_normal(" @ 0x%08x: interrupt combiner\n", (uint)addr);
 
 }
 
-static struct exynos_combiner_irq_block *
-exynos_combiner_new_block(struct exynos_combiner_softc *sc, int block_no)
+static struct exynos_combiner_irq_group *
+exynos_combiner_new_group(struct exynos_combiner_softc *sc, int group_no)
 {
-       struct exynos_combiner_irq_block *n = kmem_zalloc(sizeof(*n),
+       struct exynos_combiner_irq_group *n = kmem_zalloc(sizeof(*n),
                                                          KM_SLEEP);
-       n->irq_block_no = block_no;
-       n->irq_block_next = sc->irq_blocks;
-       sc->irq_blocks = n;
+       n->irq_group_no = group_no;
+       n->irq_group_next = sc->irq_groups;
+       n->irq_sc = sc;
+       sc->irq_groups = n;
        return n;
 }
                          
-static struct exynos_combiner_irq_block *
-exynos_combiner_get_block(struct exynos_combiner_softc *sc, int block)
+static struct exynos_combiner_irq_group *
+exynos_combiner_get_group(struct exynos_combiner_softc *sc, int group_no)
 {
-       for (struct exynos_combiner_irq_block *b = sc->irq_blocks;
-            b; b = b->irq_block_next) {
-               if (b->irq_block_no == block)
-                       return b;
+       for (struct exynos_combiner_irq_group *g = sc->irq_groups;
+            g; g = g->irq_group_next) {
+               if (g->irq_group_no == group_no)
+                       return g;
        }
        return NULL;
 }
 
 static struct exynos_combiner_irq_entry *
-exynos_combiner_new_irq(struct exynos_combiner_irq_block *block,
+exynos_combiner_new_irq(struct exynos_combiner_irq_group *group,
                        int irq, bool mpsafe, int (*func)(void *), void *arg)
 {
        struct exynos_combiner_irq_entry * n = kmem_zalloc(sizeof(*n),
                                                           KM_SLEEP);
        n->irq_no = irq;
        n->irq_handler = func;
-       n->irq_next = block->irq_entries;
+       n->irq_next = group->irq_entries;
        n->irq_arg = arg;
        n->irq_mpsafe = mpsafe;
-       block->irq_entries = n;
+       group->irq_entries = n;
        return n;
 }
 
 static struct exynos_combiner_irq_entry *
-exynos_combiner_get_irq(struct exynos_combiner_irq_block *b, int irq)
+exynos_combiner_get_irq(struct exynos_combiner_irq_group *g, int irq)
 {
-       for (struct exynos_combiner_irq_entry *p = b->irq_entries; p;
+       for (struct exynos_combiner_irq_entry *p = g->irq_entries; p;
             p = p->irq_next) {
                if (p->irq_no == irq)
                        return p;
@@ -202,31 +201,33 @@
 static int
 exynos_combiner_irq(void *cookie)
 {
-       struct exynos_combiner_irq_block *blockp = cookie;
-       struct exynos_combiner_softc *sc = blockp->irq_sc;
-       int intr = blockp->irq_block_no;
-       int iblock = 
-               intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE
-               + COMBINER_IESR_OFFSET;
-       int istatus =
-               bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock);
-       istatus >>= (intr % 4) *8;
+       struct exynos_combiner_irq_group *groupp = cookie;
+       struct exynos_combiner_softc *sc = groupp->irq_sc;
+       int rv = 0;
+
+       const int group_no = groupp->irq_group_no;
+
+       const uint32_t istr =
+           bus_space_read_4(sc->sc_bst, sc->sc_bsh, COMBINER_ISTR_REG(group_no));
+       const uint32_t istatus = __SHIFTOUT(istr, COMBINER_GROUP_MASK(group_no));
+
        for (int irq = 0; irq < 8; irq++) {
-               if (istatus & 1 << irq) {
+               if (istatus & __BIT(irq)) {
                        struct exynos_combiner_irq_entry *e =
-                               exynos_combiner_get_irq(blockp, irq);
+                               exynos_combiner_get_irq(groupp, irq);
                        if (e) {
                                if (!e->irq_mpsafe)
                                        KERNEL_LOCK(1, curlwp);
-                               e->irq_handler(e->irq_arg);
+                               rv += e->irq_handler(e->irq_arg);
                                if (!e->irq_mpsafe)
                                        KERNEL_UNLOCK_ONE(curlwp);
                        } else
-                               printf("%s: Unexpected irq %d, %d\n", __func__,
-                                      intr, irq);
+                               printf("%s: Unexpected irq (%d) on group %d\n", __func__,
+                                      irq, group_no);
                }
        }
-       return 0;
+
+       return !!rv;
 }
 
 static void *
@@ -235,37 +236,43 @@
                          int (*func)(void *), void *arg)
 {
        struct exynos_combiner_softc * const sc = device_private(dev);
-       struct exynos_combiner_irq_block *blockp;
+       struct exynos_combiner_irq_group *groupp;
        struct exynos_combiner_irq_entry *entryp;
        const bool mpsafe = (flags & FDT_INTR_MPSAFE) != 0;
-
-       const u_int intr = be32toh(specifier[0]);
-       const u_int irq = be32toh(specifier[1]);
+       uint32_t iesr;
 
-       int iblock = 
-               intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE
-               + COMBINER_IESR_OFFSET;
+       const u_int group = be32toh(specifier[0]);
+       const u_int intr = be32toh(specifier[1]);
 
-       blockp = exynos_combiner_get_block(sc, intr);
-       if (!blockp) {
-               blockp = exynos_combiner_new_block(sc, intr);
-               KASSERT(blockp);
-               blockp->irq_ih = fdtbus_intr_establish(sc->sc_phandle, intr,
-                   IPL_VM /* XXX */, FDT_INTR_MPSAFE, exynos_combiner_irq,
-                   blockp);
+       groupp = exynos_combiner_get_group(sc, group);
+       if (!groupp) {
+               groupp = exynos_combiner_new_group(sc, group);
+               if (arg == NULL) {
+                       groupp->irq_ih = fdtbus_intr_establish(sc->sc_phandle, group,
+                           ipl /* XXX */, flags, func, NULL);
+               } else {
+                       groupp->irq_ih = fdtbus_intr_establish(sc->sc_phandle, group,
+                           ipl /* XXX */, FDT_INTR_MPSAFE, exynos_combiner_irq,
+                           groupp);
+               }
+               KASSERT(groupp->irq_ih != NULL);
+               groupp->irq_ipl = ipl;
+       } else if (groupp->irq_ipl != ipl) {
+               aprint_error_dev(dev,
+                   "interrupt combiner cannot share interrupts with different ipl\n");
+               return NULL;
        }
 
-       entryp = exynos_combiner_get_irq(blockp, irq);
-       if (entryp)
+       if (exynos_combiner_get_irq(groupp, intr) != NULL)
                return NULL;
-       entryp = exynos_combiner_new_irq(blockp, irq, mpsafe, func, arg);
-       KASSERT(entryp);
+
+       entryp = exynos_combiner_new_irq(groupp, intr, mpsafe, func, arg);
 
-       int istatus =
-               bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock);
-       istatus |= 1 << (irq + ((intr % 4) * 8));
-       bus_space_write_4(sc->sc_bst, sc->sc_bsh, iblock, istatus);
-       return (void *)istatus;
+       iesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, COMBINER_IESR_REG(group));
+       iesr |= __SHIFTIN((1 << intr), COMBINER_GROUP_MASK(group));
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, COMBINER_IESR_REG(group), iesr);
+
+       return entryp;
 }
 
 static void
@@ -280,13 +287,13 @@
                        size_t buflen)
 {
 
-       /* 1st cell is the interrupt block */
-       /* 2nd cell is the interrupt number */
+       /* 1st cell is the combiner group number */
+       /* 2nd cell is the interrupt number within the group */
 
-       const u_int intr = be32toh(specifier[0]);
-       const u_int irq = be32toh(specifier[1]);
+       const u_int group = be32toh(specifier[0]);
+       const u_int intr = be32toh(specifier[1]);
 
-       snprintf(buf, buflen, "combiner intr %d irq %d", intr, irq);
+       snprintf(buf, buflen, "interrupt combiner group %d intr %d", group, intr);
 
        return true;
 }



Home | Main Index | Thread Index | Old Index