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