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