Sun Jun 11 16:19:27 2017 UTC ()
Use fdtbus_intr_establish to hook in block interrupts instead of
intr_establish.


(jmcneill)
diff -r1.6 -r1.7 src/sys/arch/arm/samsung/exynos_combiner.c

cvs diff -r1.6 -r1.7 src/sys/arch/arm/samsung/exynos_combiner.c (expand / switch to unified diff)

--- src/sys/arch/arm/samsung/exynos_combiner.c 2016/01/05 21:53:48 1.6
+++ src/sys/arch/arm/samsung/exynos_combiner.c 2017/06/11 16:19:27 1.7
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: exynos_combiner.c,v 1.6 2016/01/05 21:53:48 marty Exp $ */ 1/* $NetBSD: exynos_combiner.c,v 1.7 2017/06/11 16:19:27 jmcneill Exp $ */
2 2
3/*- 3/*-
4* Copyright (c) 2015 The NetBSD Foundation, Inc. 4* Copyright (c) 2015 The NetBSD Foundation, Inc.
5* All rights reserved. 5* All rights reserved.
6* 6*
7* This code is derived from software contributed to The NetBSD Foundation 7* This code is derived from software contributed to The NetBSD Foundation
8* by Marty Fouts 8* by Marty Fouts
9* 9*
10* Redistribution and use in source and binary forms, with or without 10* Redistribution and use in source and binary forms, with or without
11* modification, are permitted provided that the following conditions 11* modification, are permitted provided that the following conditions
12* are met: 12* are met:
13* 1. Redistributions of source code must retain the above copyright 13* 1. Redistributions of source code must retain the above copyright
14* notice, this list of conditions and the following disclaimer. 14* notice, this list of conditions and the following disclaimer.
@@ -24,27 +24,27 @@ @@ -24,27 +24,27 @@
24* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29* POSSIBILITY OF SUCH DAMAGE. 29* POSSIBILITY OF SUCH DAMAGE.
30*/ 30*/
31 31
32#include "opt_exynos.h" 32#include "opt_exynos.h"
33#include "opt_arm_debug.h" 33#include "opt_arm_debug.h"
34#include "gpio.h" 34#include "gpio.h"
35 35
36#include <sys/cdefs.h> 36#include <sys/cdefs.h>
37__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.6 2016/01/05 21:53:48 marty Exp $"); 37__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.7 2017/06/11 16:19:27 jmcneill Exp $");
38 38
39#include <sys/param.h> 39#include <sys/param.h>
40#include <sys/bus.h> 40#include <sys/bus.h>
41#include <sys/device.h> 41#include <sys/device.h>
42#include <sys/intr.h> 42#include <sys/intr.h>
43#include <sys/systm.h> 43#include <sys/systm.h>
44#include <sys/kmem.h> 44#include <sys/kmem.h>
45 45
46#include <arm/cortex/gic_intr.h> 46#include <arm/cortex/gic_intr.h>
47 47
48#include <arm/samsung/exynos_reg.h> 48#include <arm/samsung/exynos_reg.h>
49#include <arm/samsung/exynos_intr.h> 49#include <arm/samsung/exynos_intr.h>
50 50
@@ -56,33 +56,35 @@ __KERNEL_RCSID(1, "$NetBSD: exynos_combi @@ -56,33 +56,35 @@ __KERNEL_RCSID(1, "$NetBSD: exynos_combi
56#define COMBINER_IMSR_OFFSET 0x0C 56#define COMBINER_IMSR_OFFSET 0x0C
57#define COMBINER_GROUP_SIZE 0x10 57#define COMBINER_GROUP_SIZE 0x10
58#define COMBINER_IRQS_PER_BLOCK 8 58#define COMBINER_IRQS_PER_BLOCK 8
59#define COMBINER_BLOCKS_PER_GROUP 4 59#define COMBINER_BLOCKS_PER_GROUP 4
60#define COMBINER_N_BLOCKS 32 60#define COMBINER_N_BLOCKS 32
61 61
62struct exynos_combiner_softc; 62struct exynos_combiner_softc;
63 63
64struct exynos_combiner_irq_entry { 64struct exynos_combiner_irq_entry {
65 int irq_no; 65 int irq_no;
66 int (*irq_handler)(void *); 66 int (*irq_handler)(void *);
67 void * irq_arg; 67 void * irq_arg;
68 struct exynos_combiner_irq_entry *irq_next; 68 struct exynos_combiner_irq_entry *irq_next;
 69 bool irq_mpsafe;
69}; 70};
70 71
71struct exynos_combiner_irq_block { 72struct exynos_combiner_irq_block {
72 int irq_block_no; 73 int irq_block_no;
73 struct exynos_combiner_softc *irq_sc; 74 struct exynos_combiner_softc *irq_sc;
74 struct exynos_combiner_irq_entry *irq_entries; 75 struct exynos_combiner_irq_entry *irq_entries;
75 struct exynos_combiner_irq_block *irq_block_next; 76 struct exynos_combiner_irq_block *irq_block_next;
 77 void *irq_ih;
76}; 78};
77 79
78struct exynos_combiner_softc { 80struct exynos_combiner_softc {
79 device_t sc_dev; 81 device_t sc_dev;
80 bus_space_tag_t sc_bst; 82 bus_space_tag_t sc_bst;
81 bus_space_handle_t sc_bsh; 83 bus_space_handle_t sc_bsh;
82 int sc_phandle; 84 int sc_phandle;
83 struct exynos_combiner_irq_block *irq_blocks; 85 struct exynos_combiner_irq_block *irq_blocks;
84}; 86};
85 87
86static int exynos_combiner_match(device_t, cfdata_t, void *); 88static int exynos_combiner_match(device_t, cfdata_t, void *);
87static void exynos_combiner_attach(device_t, device_t, void *); 89static void exynos_combiner_attach(device_t, device_t, void *);
88 90
@@ -163,116 +165,124 @@ exynos_combiner_new_block(struct exynos_ @@ -163,116 +165,124 @@ exynos_combiner_new_block(struct exynos_
163static struct exynos_combiner_irq_block * 165static struct exynos_combiner_irq_block *
164exynos_combiner_get_block(struct exynos_combiner_softc *sc, int block) 166exynos_combiner_get_block(struct exynos_combiner_softc *sc, int block)
165{ 167{
166 for (struct exynos_combiner_irq_block *b = sc->irq_blocks; 168 for (struct exynos_combiner_irq_block *b = sc->irq_blocks;
167 b; b = b->irq_block_next) { 169 b; b = b->irq_block_next) {
168 if (b->irq_block_no == block) 170 if (b->irq_block_no == block)
169 return b; 171 return b;
170 } 172 }
171 return NULL; 173 return NULL;
172} 174}
173 175
174static struct exynos_combiner_irq_entry * 176static struct exynos_combiner_irq_entry *
175exynos_combiner_new_irq(struct exynos_combiner_irq_block *block, 177exynos_combiner_new_irq(struct exynos_combiner_irq_block *block,
176 int irq, int (*func)(void *), void *arg) 178 int irq, bool mpsafe, int (*func)(void *), void *arg)
177{ 179{
178 struct exynos_combiner_irq_entry * n = kmem_zalloc(sizeof(*n), 180 struct exynos_combiner_irq_entry * n = kmem_zalloc(sizeof(*n),
179 KM_SLEEP); 181 KM_SLEEP);
180 n->irq_no = irq; 182 n->irq_no = irq;
181 n->irq_handler = func; 183 n->irq_handler = func;
182 n->irq_next = block->irq_entries; 184 n->irq_next = block->irq_entries;
183 n->irq_arg = arg; 185 n->irq_arg = arg;
 186 n->irq_mpsafe = mpsafe;
184 block->irq_entries = n; 187 block->irq_entries = n;
185 return n; 188 return n;
186} 189}
187 190
188static struct exynos_combiner_irq_entry * 191static struct exynos_combiner_irq_entry *
189exynos_combiner_get_irq(struct exynos_combiner_irq_block *b, int irq) 192exynos_combiner_get_irq(struct exynos_combiner_irq_block *b, int irq)
190{ 193{
191 for (struct exynos_combiner_irq_entry *p = b->irq_entries; p; 194 for (struct exynos_combiner_irq_entry *p = b->irq_entries; p;
192 p = p->irq_next) { 195 p = p->irq_next) {
193 if (p->irq_no == irq) 196 if (p->irq_no == irq)
194 return p; 197 return p;
195 } 198 }
196 return NULL; 199 return NULL;
197} 200}
198 201
199static int exynos_combiner_irq(void *cookie) 202static int
 203exynos_combiner_irq(void *cookie)
200{ 204{
201 struct exynos_combiner_irq_block *blockp = cookie; 205 struct exynos_combiner_irq_block *blockp = cookie;
202 struct exynos_combiner_softc *sc = blockp->irq_sc; 206 struct exynos_combiner_softc *sc = blockp->irq_sc;
203 int intr = blockp->irq_block_no; 207 int intr = blockp->irq_block_no;
204 int iblock =  208 int iblock =
205 intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE 209 intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE
206 + COMBINER_IESR_OFFSET; 210 + COMBINER_IESR_OFFSET;
207 int istatus = 211 int istatus =
208 bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock); 212 bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock);
209 istatus >>= (intr % 4) *8; 213 istatus >>= (intr % 4) *8;
210 for (int irq = 0; irq < 8; irq++) { 214 for (int irq = 0; irq < 8; irq++) {
211 if (istatus & 1 << irq) { 215 if (istatus & 1 << irq) {
212 struct exynos_combiner_irq_entry *e = 216 struct exynos_combiner_irq_entry *e =
213 exynos_combiner_get_irq(blockp, irq); 217 exynos_combiner_get_irq(blockp, irq);
214 if (e) 218 if (e) {
 219 if (!e->irq_mpsafe)
 220 KERNEL_LOCK(1, curlwp);
215 e->irq_handler(e->irq_arg); 221 e->irq_handler(e->irq_arg);
216 else 222 if (!e->irq_mpsafe)
 223 KERNEL_UNLOCK_ONE(curlwp);
 224 } else
217 printf("%s: Unexpected irq %d, %d\n", __func__, 225 printf("%s: Unexpected irq %d, %d\n", __func__,
218 intr, irq); 226 intr, irq);
219 } 227 }
220 } 228 }
221 return 0; 229 return 0;
222} 230}
223 231
224static void * 232static void *
225exynos_combiner_establish(device_t dev, u_int *specifier, 233exynos_combiner_establish(device_t dev, u_int *specifier,
226 int ipl, int flags, 234 int ipl, int flags,
227 int (*func)(void *), void *arg) 235 int (*func)(void *), void *arg)
228{ 236{
229 struct exynos_combiner_softc * const sc = device_private(dev); 237 struct exynos_combiner_softc * const sc = device_private(dev);
230 struct exynos_combiner_irq_block *blockp; 238 struct exynos_combiner_irq_block *blockp;
231 struct exynos_combiner_irq_entry *entryp; 239 struct exynos_combiner_irq_entry *entryp;
 240 const bool mpsafe = (flags & FDT_INTR_MPSAFE) != 0;
232 241
233 const u_int intr = be32toh(specifier[0]); 242 const u_int intr = be32toh(specifier[0]);
234 const u_int irq = be32toh(specifier[1]); 243 const u_int irq = be32toh(specifier[1]);
235 244
236 int iblock =  245 int iblock =
237 intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE 246 intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE
238 + COMBINER_IESR_OFFSET; 247 + COMBINER_IESR_OFFSET;
239 248
240 blockp = exynos_combiner_get_block(sc, intr); 249 blockp = exynos_combiner_get_block(sc, intr);
241 if (!blockp) { 250 if (!blockp) {
242 blockp = exynos_combiner_new_block(sc, intr); 251 blockp = exynos_combiner_new_block(sc, intr);
243 KASSERT(blockp); 252 KASSERT(blockp);
244 intr_establish(intr, ipl, IST_LEVEL, exynos_combiner_irq, 253 blockp->irq_ih = fdtbus_intr_establish(sc->sc_phandle, intr,
245 blockp); 254 IPL_VM /* XXX */, FDT_INTR_MPSAFE, exynos_combiner_irq,
 255 blockp);
246 } 256 }
247 257
248 entryp = exynos_combiner_get_irq(blockp, irq); 258 entryp = exynos_combiner_get_irq(blockp, irq);
249 if (entryp) 259 if (entryp)
250 return NULL; 260 return NULL;
251 entryp = exynos_combiner_new_irq(blockp, irq, func, arg); 261 entryp = exynos_combiner_new_irq(blockp, irq, mpsafe, func, arg);
252 KASSERT(entryp); 262 KASSERT(entryp);
253 263
254 int istatus = 264 int istatus =
255 bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock); 265 bus_space_read_4(sc->sc_bst, sc->sc_bsh, iblock);
256 istatus |= 1 << (irq + ((intr % 4) * 8)); 266 istatus |= 1 << (irq + ((intr % 4) * 8));
257 bus_space_write_4(sc->sc_bst, sc->sc_bsh, iblock, istatus); 267 bus_space_write_4(sc->sc_bst, sc->sc_bsh, iblock, istatus);
258 return (void *)istatus; 268 return (void *)istatus;
259} 269}
260 270
261static void 271static void
262exynos_combiner_disestablish(device_t dev, void *ih) 272exynos_combiner_disestablish(device_t dev, void *ih)
263{ 273{
264 /* MJF: Find the ih and disable the handler. */ 274 /* MJF: Find the ih and disable the handler. */
265 intr_disestablish(ih); 275 panic("exynos_combiner_disestablish not implemented");
266} 276}
267 277
268static bool 278static bool
269exynos_combiner_intrstr(device_t dev, u_int *specifier, char *buf, 279exynos_combiner_intrstr(device_t dev, u_int *specifier, char *buf,
270 size_t buflen) 280 size_t buflen)
271{ 281{
272 282
273 /* 1st cell is the interrupt block */ 283 /* 1st cell is the interrupt block */
274 /* 2nd cell is the interrupt number */ 284 /* 2nd cell is the interrupt number */
275 285
276 const u_int intr = be32toh(specifier[0]); 286 const u_int intr = be32toh(specifier[0]);
277 const u_int irq = be32toh(specifier[1]); 287 const u_int irq = be32toh(specifier[1]);
278 288