xref: /freebsd/sys/arm64/arm64/cmn600.c (revision 4d3fc8b0)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 ARM Ltd
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, 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,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 /* Arm CoreLink CMN-600 Coherent Mesh Network Driver */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include "opt_acpi.h"
36 
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/proc.h>
43 #include <sys/rman.h>
44 #include <sys/smp.h>
45 #include <sys/sysctl.h>
46 
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
49 
50 #include <contrib/dev/acpica/include/acpi.h>
51 #include <dev/acpica/acpivar.h>
52 
53 #include <machine/cmn600_reg.h>
54 
55 #define	RD4(sc, r)		bus_read_4((sc)->sc_res[0], (r))
56 #define	RD8(sc, r)		bus_read_8((sc)->sc_res[0], (r))
57 #define	WR4(sc, r, v)		bus_write_4((sc)->sc_res[0], (r), (v))
58 #define	WR8(sc, r, v)		bus_write_8((sc)->sc_res[0], (r), (v))
59 #define	FLD(v, n)		(((v) & n ## _MASK) >> n ## _SHIFT)
60 
61 static char *cmn600_ids[] = {
62 	"ARMHC600",
63 	NULL
64 };
65 
66 static struct resource_spec cmn600_res_spec[] = {
67 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
68 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL },
69 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
70 	{ -1, 0 }
71 };
72 
73 struct cmn600_node;
74 
75 typedef uint64_t (*nd_read_8_t)(struct cmn600_node *, uint32_t);
76 typedef uint32_t (*nd_read_4_t)(struct cmn600_node *, uint32_t);
77 typedef void (*nd_write_8_t)(struct cmn600_node *, uint32_t, uint64_t);
78 typedef void (*nd_write_4_t)(struct cmn600_node *, uint32_t, uint32_t);
79 
80 struct cmn600_node {
81 	struct cmn600_softc	*sc;
82 	off_t			 nd_offset;
83 	int			 nd_type;
84 	uint16_t		 nd_id;
85 	uint16_t		 nd_logical_id;
86 	uint8_t			 nd_x, nd_y, nd_port, nd_sub;
87 	uint16_t		 nd_child_count;
88 	uint32_t		 nd_paired;
89 	struct cmn600_node	*nd_parent;
90 	nd_read_8_t		 nd_read8;
91 	nd_read_4_t		 nd_read4;
92 	nd_write_8_t		 nd_write8;
93 	nd_write_4_t		 nd_write4;
94 	struct cmn600_node	**nd_children;
95 };
96 
97 struct cmn600_softc {
98 	device_t	 sc_dev;
99 	int		 sc_unit;
100 	int		 sc_domain;
101 	int		 sc_longid;
102 	int		 sc_mesh_x;
103 	int		 sc_mesh_y;
104 	struct resource *sc_res[3];
105 	void		*sc_ih;
106 	int		 sc_r2;
107 	int		 sc_rev;
108 	struct cmn600_node *sc_rootnode;
109 	struct cmn600_node *sc_dtcnode;
110 	struct cmn600_node *sc_dvmnode;
111 	struct cmn600_node *sc_xpnodes[64];
112 	int (*sc_pmu_ih)(struct trapframe *tf, int unit, int i);
113 };
114 
115 static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX];
116 static int cmn600_npmcs = 0;
117 
118 static int cmn600_acpi_detach(device_t dev);
119 static int cmn600_intr(void *arg);
120 
121 static void
122 cmn600_pmc_register(int unit, void *arg, int domain)
123 {
124 
125 	if (unit >= CMN600_UNIT_MAX) {
126 		/* TODO */
127 		return;
128 	}
129 
130 	cmn600_pmcs[unit].arg = arg;
131 	cmn600_pmcs[unit].domain = domain;
132 	cmn600_npmcs++;
133 }
134 
135 static void
136 cmn600_pmc_unregister(int unit)
137 {
138 
139 	cmn600_pmcs[unit].arg = NULL;
140 	cmn600_npmcs--;
141 }
142 
143 int
144 cmn600_pmc_nunits(void)
145 {
146 
147 	return (cmn600_npmcs);
148 }
149 
150 int
151 cmn600_pmc_getunit(int unit, void **arg, int *domain)
152 {
153 
154 	if (unit >= cmn600_npmcs)
155 		return (EINVAL);
156 	if (cmn600_pmcs[unit].arg == NULL)
157 		return (EINVAL);
158 	*arg = cmn600_pmcs[unit].arg;
159 	*domain = cmn600_pmcs[unit].domain;
160 	return (0);
161 }
162 
163 int
164 pmu_cmn600_rev(void *arg)
165 {
166 	struct cmn600_softc *sc;
167 
168 	sc = (struct cmn600_softc *)arg;
169 	switch (sc->sc_rev) {
170 	case 0x0:
171 		return (0x100);
172 	case 0x1:
173 		return (0x101);
174 	case 0x2:
175 		return (0x102);
176 	case 0x3:
177 		return (0x103);
178 	case 0x4:
179 		return (0x200);
180 	case 0x5:
181 		return (0x300);
182 	case 0x6:
183 		return (0x301);
184 	}
185 	return (0x302); /* Unknown revision. */
186 }
187 
188 static uint64_t
189 cmn600_node_read8(struct cmn600_node *nd, uint32_t reg)
190 {
191 
192 	return (RD8(nd->sc, nd->nd_offset + reg));
193 }
194 
195 static void
196 cmn600_node_write8(struct cmn600_node *nd, uint32_t reg, uint64_t val)
197 {
198 
199 	WR8(nd->sc, nd->nd_offset + reg, val);
200 }
201 
202 static uint32_t
203 cmn600_node_read4(struct cmn600_node *nd, uint32_t reg)
204 {
205 
206 	return (RD4(nd->sc, nd->nd_offset + reg));
207 }
208 
209 static void
210 cmn600_node_write4(struct cmn600_node *nd, uint32_t reg, uint32_t val)
211 {
212 
213 	WR4(nd->sc, nd->nd_offset + reg, val);
214 }
215 
216 static const char *
217 cmn600_node_type_str(int type)
218 {
219 
220 #define	NAME_OF(t, n)	case NODE_TYPE_ ## t: return n
221 	switch (type) {
222 	NAME_OF(INVALID, "<invalid node>");
223 	NAME_OF(DVM, "DVM");
224 	NAME_OF(CFG, "CFG");
225 	NAME_OF(DTC, "DTC");
226 	NAME_OF(HN_I, "HN-I");
227 	NAME_OF(HN_F, "HN-F");
228 	NAME_OF(XP, "XP");
229 	NAME_OF(SBSX, "SBSX");
230 	NAME_OF(RN_I, "RN-I");
231 	NAME_OF(RN_D, "RN-D");
232 	NAME_OF(RN_SAM, "RN-SAM");
233 	NAME_OF(CXRA, "CXRA");
234 	NAME_OF(CXHA, "CXHA");
235 	NAME_OF(CXLA, "CXLA");
236 	default:
237 		return "<unknown node>";
238 	}
239 #undef	NAME_OF
240 }
241 
242 static const char *
243 cmn600_xpport_dev_type_str(uint8_t type)
244 {
245 
246 #define	NAME_OF(t, n)	case POR_MXP_PX_INFO_DEV_TYPE_ ## t: return n
247 	switch (type) {
248 	NAME_OF(RN_I, "RN-I");
249 	NAME_OF(RN_D, "RN-D");
250 	NAME_OF(RN_F_CHIB, "RN-F CHIB");
251 	NAME_OF(RN_F_CHIB_ESAM, "RN-F CHIB ESAM");
252 	NAME_OF(RN_F_CHIA, "RN-F CHIA");
253 	NAME_OF(RN_F_CHIA_ESAM, "RN-F CHIA ESAM");
254 	NAME_OF(HN_T, "HN-T");
255 	NAME_OF(HN_I, "HN-I");
256 	NAME_OF(HN_D, "HN-D");
257 	NAME_OF(SN_F, "SN-F");
258 	NAME_OF(SBSX, "SBSX");
259 	NAME_OF(HN_F, "HN-F");
260 	NAME_OF(CXHA, "CXHA");
261 	NAME_OF(CXRA, "CXRA");
262 	NAME_OF(CXRH, "CXRH");
263 	default:
264 		return "<unknown>";
265 	}
266 #undef	NAME_OF
267 }
268 
269 static void
270 cmn600_dump_node(struct cmn600_node *node, int lvl)
271 {
272 	int i;
273 
274 	for (i = 0; i < lvl; i++) printf("    ");
275 	printf("%s [%dx%d:%d:%d] id: 0x%x @0x%lx Logical Id: 0x%x",
276 	    cmn600_node_type_str(node->nd_type), node->nd_x, node->nd_y,
277 	    node->nd_port, node->nd_sub, node->nd_id, node->nd_offset,
278 	    node->nd_logical_id);
279 	if (node->nd_child_count > 0)
280 		printf(", Children: %d", node->nd_child_count);
281 	printf("\n");
282 	if (node->nd_type == NODE_TYPE_XP)
283 		printf("\tPort 0: %s\n\tPort 1: %s\n",
284 		    cmn600_xpport_dev_type_str(node->nd_read4(node,
285 			POR_MXP_P0_INFO) & 0x1f),
286 		    cmn600_xpport_dev_type_str(node->nd_read4(node,
287 			POR_MXP_P1_INFO) & 0x1f));
288 }
289 
290 static void
291 cmn600_dump_node_recursive(struct cmn600_node *node, int lvl)
292 {
293 	int i;
294 
295 	cmn600_dump_node(node, lvl);
296 	for (i = 0; i < node->nd_child_count; i++) {
297 		cmn600_dump_node_recursive(node->nd_children[i], lvl + 1);
298 	}
299 }
300 
301 static void
302 cmn600_dump_nodes_tree(struct cmn600_softc *sc)
303 {
304 
305 	device_printf(sc->sc_dev, " nodes:\n");
306 	cmn600_dump_node_recursive(sc->sc_rootnode, 0);
307 }
308 
309 static int
310 cmn600_sysctl_dump_nodes(SYSCTL_HANDLER_ARGS)
311 {
312 	struct cmn600_softc *sc;
313 	uint32_t val;
314 	int err;
315 
316 	sc = (struct cmn600_softc *)arg1;
317 	val = 0;
318 	err = sysctl_handle_int(oidp, &val, 0, req);
319 
320 	if (err)
321 		return (err);
322 
323 	if (val != 0)
324 		cmn600_dump_nodes_tree(sc);
325 
326 	return (0);
327 }
328 
329 static struct cmn600_node *
330 cmn600_create_node(struct cmn600_softc *sc, off_t node_offset,
331     struct cmn600_node *parent, int lvl)
332 {
333 	struct cmn600_node *node;
334 	off_t child_offset;
335 	uint64_t val;
336 	int i;
337 
338 	node = malloc(sizeof(struct cmn600_node), M_DEVBUF, M_WAITOK);
339 	if (node == NULL)
340 		return (NULL);
341 
342 	node->sc = sc;
343 	node->nd_offset = node_offset;
344 	node->nd_parent = parent;
345 	node->nd_read4 = cmn600_node_read4;
346 	node->nd_read8 = cmn600_node_read8;
347 	node->nd_write4 = cmn600_node_write4;
348 	node->nd_write8 = cmn600_node_write8;
349 
350 	val = node->nd_read8(node, POR_CFGM_NODE_INFO);
351 	node->nd_type = FLD(val, POR_CFGM_NODE_INFO_NODE_TYPE);
352 	node->nd_id = FLD(val, POR_CFGM_NODE_INFO_NODE_ID);
353 	node->nd_logical_id = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID);
354 
355 	val = node->nd_read8(node, POR_CFGM_CHILD_INFO);
356 	node->nd_child_count = FLD(val, POR_CFGM_CHILD_INFO_CHILD_COUNT);
357 	child_offset = FLD(val, POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET);
358 
359 	if (parent == NULL) {
360 		/* Find XP node with Id 8. It have to be last in a row. */
361 		for (i = 0; i < node->nd_child_count; i++) {
362 			val = node->nd_read8(node, child_offset + (i * 8));
363 			val &= POR_CFGM_CHILD_POINTER_BASE_MASK;
364 			val = RD8(sc, val + POR_CFGM_NODE_INFO);
365 
366 			if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8)
367 				continue;
368 
369 			sc->sc_mesh_x = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID);
370 			sc->sc_mesh_y = node->nd_child_count / sc->sc_mesh_x;
371 			if (bootverbose)
372 				printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x,
373 				    sc->sc_mesh_y);
374 
375 			if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4))
376 				sc->sc_longid = 1;
377 			break;
378 		}
379 
380 		val = node->nd_read8(node, POR_INFO_GLOBAL);
381 		sc->sc_r2 = (val & POR_INFO_GLOBAL_R2_ENABLE) ? 1 : 0;
382 		val = node->nd_read4(node, POR_CFGM_PERIPH_ID_2_PERIPH_ID_3);
383 		sc->sc_rev = FLD(val, POR_CFGM_PERIPH_ID_2_REV);
384 		if (bootverbose)
385 			printf("  Rev: %d, R2_ENABLE = %s\n", sc->sc_rev,
386 			    sc->sc_r2 ? "true" : "false");
387 	}
388 	node->nd_sub = FLD(node->nd_id, NODE_ID_SUB);
389 	node->nd_port = FLD(node->nd_id, NODE_ID_PORT);
390 	node->nd_paired = 0;
391 	if (sc->sc_longid == 1) {
392 		node->nd_x = FLD(node->nd_id, NODE_ID_X3B);
393 		node->nd_y = FLD(node->nd_id, NODE_ID_Y3B);
394 	} else {
395 		node->nd_x = FLD(node->nd_id, NODE_ID_X2B);
396 		node->nd_y = FLD(node->nd_id, NODE_ID_Y2B);
397 	}
398 
399 	if (bootverbose) {
400 		cmn600_dump_node(node, lvl);
401 	}
402 
403 	node->nd_children = (struct cmn600_node **)mallocarray(
404 	    node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF,
405 	    M_WAITOK);
406 	if (node->nd_children == NULL)
407 		goto FAIL;
408 	for (i = 0; i < node->nd_child_count; i++) {
409 		val = node->nd_read8(node, child_offset + (i * 8));
410 		node->nd_children[i] = cmn600_create_node(sc, val &
411 		    POR_CFGM_CHILD_POINTER_BASE_MASK, node, lvl + 1);
412 	}
413 	switch (node->nd_type) {
414 	case NODE_TYPE_DTC:
415 		sc->sc_dtcnode = node;
416 		break;
417 	case NODE_TYPE_DVM:
418 		sc->sc_dvmnode = node;
419 		break;
420 	case NODE_TYPE_XP:
421 		sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node;
422 		break;
423 	default:
424 		break;
425 	}
426 	return (node);
427 FAIL:
428 	free(node, M_DEVBUF);
429 	return (NULL);
430 }
431 
432 static void
433 cmn600_destroy_node(struct cmn600_node *node)
434 {
435 	int i;
436 
437 	for (i = 0; i < node->nd_child_count; i++) {
438 		if (node->nd_children[i] == NULL)
439 			continue;
440 		cmn600_destroy_node(node->nd_children[i]);
441 	}
442 	free(node->nd_children, M_DEVBUF);
443 	free(node, M_DEVBUF);
444 }
445 
446 static int
447 cmn600_find_node(struct cmn600_softc *sc, int node_id, int type,
448     struct cmn600_node **node)
449 {
450 	struct cmn600_node *xp, *child;
451 	uint8_t xp_xy;
452 	int i;
453 
454 	switch (type) {
455 	case NODE_TYPE_INVALID:
456 		return (ENXIO);
457 	case NODE_TYPE_CFG:
458 		*node = sc->sc_rootnode;
459 		return (0);
460 	case NODE_TYPE_DTC:
461 		*node = sc->sc_dtcnode;
462 		return (0);
463 	case NODE_TYPE_DVM:
464 		*node = sc->sc_dvmnode;
465 		return (0);
466 	default:
467 		break;
468 	}
469 
470 	xp_xy = node_id >> NODE_ID_X2B_SHIFT;
471 	if (xp_xy >= 64)
472 		return (ENXIO);
473 	if (sc->sc_xpnodes[xp_xy] == NULL)
474 		return (ENOENT);
475 
476 	switch (type) {
477 	case NODE_TYPE_XP:
478 		*node = sc->sc_xpnodes[xp_xy];
479 		return (0);
480 	default:
481 		xp = sc->sc_xpnodes[xp_xy];
482 		for (i = 0; i < xp->nd_child_count; i++) {
483 			child = xp->nd_children[i];
484 			if (child->nd_id == node_id && child->nd_type == type) {
485 				*node = child;
486 				return (0);
487 			}
488 		}
489 	}
490 	return (ENOENT);
491 }
492 
493 int
494 pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter)
495 {
496 	struct cmn600_node *node;
497 	struct cmn600_softc *sc;
498 	uint32_t new, old;
499 	int i, ret;
500 
501 	sc = (struct cmn600_softc *)arg;
502 	switch (node_type) {
503 	case NODE_TYPE_CXLA:
504 		break;
505 	default:
506 		node_type = NODE_TYPE_XP;
507 		/* Parent XP node has always zero port and device bits. */
508 		nodeid &= ~0x07;
509 	}
510 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
511 	if (ret != 0)
512 		return (ret);
513 	for (i = 0; i < 4; i++) {
514 		new = old = node->nd_paired;
515 		if (old == 0xf)
516 			return (EBUSY);
517 		if ((old & (1 << i)) != 0)
518 			continue;
519 		new |= 1 << i;
520 		if (atomic_cmpset_32(&node->nd_paired, old, new) != 0)
521 			break;
522 	}
523 	*counter = i;
524 	return (0);
525 }
526 
527 int
528 pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter)
529 {
530 	struct cmn600_node *node;
531 	struct cmn600_softc *sc;
532 	uint32_t new, old;
533 	int ret;
534 
535 	sc = (struct cmn600_softc *)arg;
536 	switch (node_type) {
537 	case NODE_TYPE_CXLA:
538 		break;
539 	default:
540 		node_type = NODE_TYPE_XP;
541 	}
542 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
543 	if (ret != 0)
544 		return (ret);
545 
546 	do {
547 		new = old = node->nd_paired;
548 		new &= ~(1 << counter);
549 	} while (atomic_cmpset_32(&node->nd_paired, old, new) == 0);
550 	return (0);
551 }
552 
553 uint32_t
554 pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg)
555 {
556 	struct cmn600_node *node;
557 	struct cmn600_softc *sc;
558 	int ret;
559 
560 	sc = (struct cmn600_softc *)arg;
561 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
562 	if (ret != 0)
563 		return (UINT32_MAX);
564 	return (cmn600_node_read4(node, reg));
565 }
566 
567 int
568 pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val)
569 {
570 	struct cmn600_node *node;
571 	struct cmn600_softc *sc;
572 	int ret;
573 
574 	sc = (struct cmn600_softc *)arg;
575 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
576 	if (ret != 0)
577 		return (ret);
578 	cmn600_node_write4(node, reg, val);
579 	return (0);
580 }
581 
582 uint64_t
583 pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg)
584 {
585 	struct cmn600_node *node;
586 	struct cmn600_softc *sc;
587 	int ret;
588 
589 	sc = (struct cmn600_softc *)arg;
590 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
591 	if (ret != 0)
592 		return (UINT64_MAX);
593 	return (cmn600_node_read8(node, reg));
594 }
595 
596 int
597 pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
598 {
599 	struct cmn600_node *node;
600 	struct cmn600_softc *sc;
601 	int ret;
602 
603 	sc = (struct cmn600_softc *)arg;
604 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
605 	if (ret != 0)
606 		return (ret);
607 	cmn600_node_write8(node, reg, val);
608 	return (0);
609 }
610 
611 int
612 pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
613 {
614 	struct cmn600_node *node;
615 	struct cmn600_softc *sc;
616 	int ret;
617 
618 	sc = (struct cmn600_softc *)arg;
619 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
620 	if (ret != 0)
621 		return (ret);
622 	cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val);
623 	return (0);
624 }
625 
626 int
627 pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
628 {
629 	struct cmn600_node *node;
630 	struct cmn600_softc *sc;
631 	int ret;
632 
633 	sc = (struct cmn600_softc *)arg;
634 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
635 	if (ret != 0)
636 		return (ret);
637 	cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val);
638 	return (0);
639 }
640 
641 int
642 pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask,
643     uint64_t val)
644 {
645 	struct cmn600_node *node;
646 	struct cmn600_softc *sc;
647 	int ret;
648 
649 	sc = (struct cmn600_softc *)arg;
650 	ret = cmn600_find_node(sc, nodeid, node_type, &node);
651 	if (ret != 0)
652 		return (ret);
653 	cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) |
654 	    val);
655 	return (0);
656 }
657 
658 static int
659 cmn600_acpi_probe(device_t dev)
660 {
661 	int err;
662 
663 	err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL);
664 	if (err <= 0)
665 		device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network");
666 
667 	return (err);
668 }
669 
670 static int
671 cmn600_acpi_attach(device_t dev)
672 {
673 	struct sysctl_ctx_list *ctx;
674 	struct sysctl_oid_list *child;
675 	struct cmn600_softc *sc;
676 	int cpu, domain, i, u;
677 	const char *dname;
678 	rman_res_t count, periph_base, rootnode_base;
679 	struct cmn600_node *node;
680 
681 	dname = device_get_name(dev);
682 	sc = device_get_softc(dev);
683 	sc->sc_dev = dev;
684 	u = device_get_unit(dev);
685 	sc->sc_unit = u;
686 	domain = 0;
687 
688 	if ((resource_int_value(dname, u, "domain", &domain) == 0 ||
689 	    bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) {
690 		sc->sc_domain = domain;
691 	}
692 	if (domain == -1) /* NUMA not supported. Use single domain. */
693 		domain = 0;
694 	sc->sc_domain = domain;
695 	device_printf(dev, "domain=%d\n", sc->sc_domain);
696 
697 	cpu = CPU_FFS(&cpuset_domain[domain]) - 1;
698 
699 	i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res);
700 	if (i != 0) {
701 		device_printf(dev, "cannot allocate resources for device (%d)\n",
702 		    i);
703 		return (i);
704 	}
705 
706 	bus_get_resource(dev, cmn600_res_spec[0].type, cmn600_res_spec[0].rid,
707 	    &periph_base, &count);
708 	bus_get_resource(dev, cmn600_res_spec[1].type, cmn600_res_spec[1].rid,
709 	    &rootnode_base, &count);
710 	rootnode_base -= periph_base;
711 	if (bootverbose)
712 		printf("ROOTNODE at %lx x %lx\n", rootnode_base, count);
713 
714 	sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0);
715 	ctx = device_get_sysctl_ctx(sc->sc_dev);
716 
717 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev));
718 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dump_nodes", CTLTYPE_INT |
719 	    CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, cmn600_sysctl_dump_nodes,
720 	    "U", "Dump CMN-600 nodes tree");
721 
722 	node = sc->sc_dtcnode;
723 	if (node == NULL)
724 		return (ENXIO);
725 
726 	cmn600_pmc_register(sc->sc_unit, (void *)sc, domain);
727 
728 	node->nd_write8(node, POR_DT_PMCR, 0);
729 	node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL);
730 	node->nd_write8(node, POR_DT_PMCR, POR_DT_PMCR_OVFL_INTR_EN);
731 	node->nd_write8(node, POR_DT_DTC_CTL, POR_DT_DTC_CTL_DT_EN);
732 
733 	if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE,
734 	    cmn600_intr, NULL, sc, &sc->sc_ih)) {
735 		bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
736 		device_printf(dev, "cannot setup interrupt handler\n");
737 		cmn600_acpi_detach(dev);
738 		return (ENXIO);
739 	}
740 	if (bus_bind_intr(dev, sc->sc_res[2], cpu)) {
741 		bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih);
742 		bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
743 		device_printf(dev, "cannot setup interrupt handler\n");
744 		cmn600_acpi_detach(dev);
745 		return (ENXIO);
746 	}
747 	return (0);
748 }
749 
750 static int
751 cmn600_acpi_detach(device_t dev)
752 {
753 	struct cmn600_softc *sc;
754 	struct cmn600_node *node;
755 
756 	sc = device_get_softc(dev);
757 	if (sc->sc_res[2] != NULL) {
758 		bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih);
759 	}
760 
761 	node = sc->sc_dtcnode;
762 	node->nd_write4(node, POR_DT_DTC_CTL,
763 	    node->nd_read4(node, POR_DT_DTC_CTL) & ~POR_DT_DTC_CTL_DT_EN);
764 	node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL);
765 
766 	cmn600_pmc_unregister(sc->sc_unit);
767 	cmn600_destroy_node(sc->sc_rootnode);
768 	bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
769 
770 	return (0);
771 }
772 
773 int
774 cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit,
775     int i))
776 {
777 	struct cmn600_softc *sc;
778 
779 	sc = (struct cmn600_softc *) arg;
780 	sc->sc_pmu_ih = handler;
781 	return (0);
782 }
783 
784 static int
785 cmn600_intr(void *arg)
786 {
787 	struct cmn600_node *node;
788 	struct cmn600_softc *sc;
789 	struct trapframe *tf;
790 	uint64_t mask, ready, val;
791 	int i;
792 
793 	tf = PCPU_GET(curthread)->td_intr_frame;
794 	sc = (struct cmn600_softc *) arg;
795 	node = sc->sc_dtcnode;
796 	val = node->nd_read8(node, POR_DT_PMOVSR);
797 	if (val & POR_DT_PMOVSR_CYCLE_COUNTER)
798 		node->nd_write8(node, POR_DT_PMOVSR_CLR,
799 		    POR_DT_PMOVSR_CYCLE_COUNTER);
800 	if (val & POR_DT_PMOVSR_EVENT_COUNTERS) {
801 		for (ready = 0, i = 0; i < 8; i++) {
802 			mask = 1 << i;
803 			if ((val & mask) == 0)
804 				continue;
805 			if (sc->sc_pmu_ih != NULL)
806 				sc->sc_pmu_ih(tf, sc->sc_unit, i);
807 			ready |= mask;
808 
809 		}
810 		node->nd_write8(node, POR_DT_PMOVSR_CLR, ready);
811 	}
812 
813 	return (FILTER_HANDLED);
814 }
815 
816 static device_method_t cmn600_acpi_methods[] = {
817 	/* Device interface */
818 	DEVMETHOD(device_probe,			cmn600_acpi_probe),
819 	DEVMETHOD(device_attach,		cmn600_acpi_attach),
820 	DEVMETHOD(device_detach,		cmn600_acpi_detach),
821 
822 	/* End */
823 	DEVMETHOD_END
824 };
825 
826 static driver_t cmn600_acpi_driver = {
827 	"cmn600",
828 	cmn600_acpi_methods,
829 	sizeof(struct cmn600_softc),
830 };
831 
832 DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, 0, 0);
833 MODULE_VERSION(cmn600, 1);
834