]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/cmn600.c
pmap: Convert boolean_t to bool.
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / cmn600.c
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
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
132 cmn600_pmc_unregister(int unit)
133 {
134
135         cmn600_pmcs[unit].arg = NULL;
136         cmn600_npmcs--;
137 }
138
139 int
140 cmn600_pmc_nunits(void)
141 {
142
143         return (cmn600_npmcs);
144 }
145
146 int
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
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
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
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
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
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 *
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 *
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
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
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
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
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 *
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         if (node == NULL)
336                 return (NULL);
337
338         node->sc = sc;
339         node->nd_offset = node_offset;
340         node->nd_parent = parent;
341         node->nd_read4 = cmn600_node_read4;
342         node->nd_read8 = cmn600_node_read8;
343         node->nd_write4 = cmn600_node_write4;
344         node->nd_write8 = cmn600_node_write8;
345
346         val = node->nd_read8(node, POR_CFGM_NODE_INFO);
347         node->nd_type = FLD(val, POR_CFGM_NODE_INFO_NODE_TYPE);
348         node->nd_id = FLD(val, POR_CFGM_NODE_INFO_NODE_ID);
349         node->nd_logical_id = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID);
350
351         val = node->nd_read8(node, POR_CFGM_CHILD_INFO);
352         node->nd_child_count = FLD(val, POR_CFGM_CHILD_INFO_CHILD_COUNT);
353         child_offset = FLD(val, POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET);
354
355         if (parent == NULL) {
356                 /* Find XP node with Id 8. It have to be last in a row. */
357                 for (i = 0; i < node->nd_child_count; i++) {
358                         val = node->nd_read8(node, child_offset + (i * 8));
359                         val &= POR_CFGM_CHILD_POINTER_BASE_MASK;
360                         val = RD8(sc, val + POR_CFGM_NODE_INFO);
361
362                         if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8)
363                                 continue;
364
365                         sc->sc_mesh_x = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID);
366                         sc->sc_mesh_y = node->nd_child_count / sc->sc_mesh_x;
367                         if (bootverbose)
368                                 printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x,
369                                     sc->sc_mesh_y);
370
371                         if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4))
372                                 sc->sc_longid = 1;
373                         break;
374                 }
375
376                 val = node->nd_read8(node, POR_INFO_GLOBAL);
377                 sc->sc_r2 = (val & POR_INFO_GLOBAL_R2_ENABLE) ? 1 : 0;
378                 val = node->nd_read4(node, POR_CFGM_PERIPH_ID_2_PERIPH_ID_3);
379                 sc->sc_rev = FLD(val, POR_CFGM_PERIPH_ID_2_REV);
380                 if (bootverbose)
381                         printf("  Rev: %d, R2_ENABLE = %s\n", sc->sc_rev,
382                             sc->sc_r2 ? "true" : "false");
383         }
384         node->nd_sub = FLD(node->nd_id, NODE_ID_SUB);
385         node->nd_port = FLD(node->nd_id, NODE_ID_PORT);
386         node->nd_paired = 0;
387         if (sc->sc_longid == 1) {
388                 node->nd_x = FLD(node->nd_id, NODE_ID_X3B);
389                 node->nd_y = FLD(node->nd_id, NODE_ID_Y3B);
390         } else {
391                 node->nd_x = FLD(node->nd_id, NODE_ID_X2B);
392                 node->nd_y = FLD(node->nd_id, NODE_ID_Y2B);
393         }
394
395         if (bootverbose) {
396                 cmn600_dump_node(node, lvl);
397         }
398
399         node->nd_children = (struct cmn600_node **)mallocarray(
400             node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF,
401             M_WAITOK);
402         if (node->nd_children == NULL)
403                 goto FAIL;
404         for (i = 0; i < node->nd_child_count; i++) {
405                 val = node->nd_read8(node, child_offset + (i * 8));
406                 node->nd_children[i] = cmn600_create_node(sc, val &
407                     POR_CFGM_CHILD_POINTER_BASE_MASK, node, lvl + 1);
408         }
409         switch (node->nd_type) {
410         case NODE_TYPE_DTC:
411                 sc->sc_dtcnode = node;
412                 break;
413         case NODE_TYPE_DVM:
414                 sc->sc_dvmnode = node;
415                 break;
416         case NODE_TYPE_XP:
417                 sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node;
418                 break;
419         default:
420                 break;
421         }
422         return (node);
423 FAIL:
424         free(node, M_DEVBUF);
425         return (NULL);
426 }
427
428 static void
429 cmn600_destroy_node(struct cmn600_node *node)
430 {
431         int i;
432
433         for (i = 0; i < node->nd_child_count; i++) {
434                 if (node->nd_children[i] == NULL)
435                         continue;
436                 cmn600_destroy_node(node->nd_children[i]);
437         }
438         free(node->nd_children, M_DEVBUF);
439         free(node, M_DEVBUF);
440 }
441
442 static int
443 cmn600_find_node(struct cmn600_softc *sc, int node_id, int type,
444     struct cmn600_node **node)
445 {
446         struct cmn600_node *xp, *child;
447         uint8_t xp_xy;
448         int i;
449
450         switch (type) {
451         case NODE_TYPE_INVALID:
452                 return (ENXIO);
453         case NODE_TYPE_CFG:
454                 *node = sc->sc_rootnode;
455                 return (0);
456         case NODE_TYPE_DTC:
457                 *node = sc->sc_dtcnode;
458                 return (0);
459         case NODE_TYPE_DVM:
460                 *node = sc->sc_dvmnode;
461                 return (0);
462         default:
463                 break;
464         }
465
466         xp_xy = node_id >> NODE_ID_X2B_SHIFT;
467         if (xp_xy >= 64)
468                 return (ENXIO);
469         if (sc->sc_xpnodes[xp_xy] == NULL)
470                 return (ENOENT);
471
472         switch (type) {
473         case NODE_TYPE_XP:
474                 *node = sc->sc_xpnodes[xp_xy];
475                 return (0);
476         default:
477                 xp = sc->sc_xpnodes[xp_xy];
478                 for (i = 0; i < xp->nd_child_count; i++) {
479                         child = xp->nd_children[i];
480                         if (child->nd_id == node_id && child->nd_type == type) {
481                                 *node = child;
482                                 return (0);
483                         }
484                 }
485         }
486         return (ENOENT);
487 }
488
489 int
490 pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter)
491 {
492         struct cmn600_node *node;
493         struct cmn600_softc *sc;
494         uint32_t new, old;
495         int i, ret;
496
497         sc = (struct cmn600_softc *)arg;
498         switch (node_type) {
499         case NODE_TYPE_CXLA:
500                 break;
501         default:
502                 node_type = NODE_TYPE_XP;
503                 /* Parent XP node has always zero port and device bits. */
504                 nodeid &= ~0x07;
505         }
506         ret = cmn600_find_node(sc, nodeid, node_type, &node);
507         if (ret != 0)
508                 return (ret);
509         for (i = 0; i < 4; i++) {
510                 new = old = node->nd_paired;
511                 if (old == 0xf)
512                         return (EBUSY);
513                 if ((old & (1 << i)) != 0)
514                         continue;
515                 new |= 1 << i;
516                 if (atomic_cmpset_32(&node->nd_paired, old, new) != 0)
517                         break;
518         }
519         *counter = i;
520         return (0);
521 }
522
523 int
524 pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter)
525 {
526         struct cmn600_node *node;
527         struct cmn600_softc *sc;
528         uint32_t new, old;
529         int ret;
530
531         sc = (struct cmn600_softc *)arg;
532         switch (node_type) {
533         case NODE_TYPE_CXLA:
534                 break;
535         default:
536                 node_type = NODE_TYPE_XP;
537         }
538         ret = cmn600_find_node(sc, nodeid, node_type, &node);
539         if (ret != 0)
540                 return (ret);
541
542         do {
543                 new = old = node->nd_paired;
544                 new &= ~(1 << counter);
545         } while (atomic_cmpset_32(&node->nd_paired, old, new) == 0);
546         return (0);
547 }
548
549 uint32_t
550 pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg)
551 {
552         struct cmn600_node *node;
553         struct cmn600_softc *sc;
554         int ret;
555
556         sc = (struct cmn600_softc *)arg;
557         ret = cmn600_find_node(sc, nodeid, node_type, &node);
558         if (ret != 0)
559                 return (UINT32_MAX);
560         return (cmn600_node_read4(node, reg));
561 }
562
563 int
564 pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val)
565 {
566         struct cmn600_node *node;
567         struct cmn600_softc *sc;
568         int ret;
569
570         sc = (struct cmn600_softc *)arg;
571         ret = cmn600_find_node(sc, nodeid, node_type, &node);
572         if (ret != 0)
573                 return (ret);
574         cmn600_node_write4(node, reg, val);
575         return (0);
576 }
577
578 uint64_t
579 pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg)
580 {
581         struct cmn600_node *node;
582         struct cmn600_softc *sc;
583         int ret;
584
585         sc = (struct cmn600_softc *)arg;
586         ret = cmn600_find_node(sc, nodeid, node_type, &node);
587         if (ret != 0)
588                 return (UINT64_MAX);
589         return (cmn600_node_read8(node, reg));
590 }
591
592 int
593 pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
594 {
595         struct cmn600_node *node;
596         struct cmn600_softc *sc;
597         int ret;
598
599         sc = (struct cmn600_softc *)arg;
600         ret = cmn600_find_node(sc, nodeid, node_type, &node);
601         if (ret != 0)
602                 return (ret);
603         cmn600_node_write8(node, reg, val);
604         return (0);
605 }
606
607 int
608 pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
609 {
610         struct cmn600_node *node;
611         struct cmn600_softc *sc;
612         int ret;
613
614         sc = (struct cmn600_softc *)arg;
615         ret = cmn600_find_node(sc, nodeid, node_type, &node);
616         if (ret != 0)
617                 return (ret);
618         cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val);
619         return (0);
620 }
621
622 int
623 pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
624 {
625         struct cmn600_node *node;
626         struct cmn600_softc *sc;
627         int ret;
628
629         sc = (struct cmn600_softc *)arg;
630         ret = cmn600_find_node(sc, nodeid, node_type, &node);
631         if (ret != 0)
632                 return (ret);
633         cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val);
634         return (0);
635 }
636
637 int
638 pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask,
639     uint64_t val)
640 {
641         struct cmn600_node *node;
642         struct cmn600_softc *sc;
643         int ret;
644
645         sc = (struct cmn600_softc *)arg;
646         ret = cmn600_find_node(sc, nodeid, node_type, &node);
647         if (ret != 0)
648                 return (ret);
649         cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) |
650             val);
651         return (0);
652 }
653
654 static int
655 cmn600_acpi_probe(device_t dev)
656 {
657         int err;
658
659         err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL);
660         if (err <= 0)
661                 device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network");
662
663         return (err);
664 }
665
666 static int
667 cmn600_acpi_attach(device_t dev)
668 {
669         struct sysctl_ctx_list *ctx;
670         struct sysctl_oid_list *child;
671         struct cmn600_softc *sc;
672         int cpu, domain, i, u;
673         const char *dname;
674         rman_res_t count, periph_base, rootnode_base;
675         struct cmn600_node *node;
676
677         dname = device_get_name(dev);
678         sc = device_get_softc(dev);
679         sc->sc_dev = dev;
680         u = device_get_unit(dev);
681         sc->sc_unit = u;
682         domain = 0;
683
684         if ((resource_int_value(dname, u, "domain", &domain) == 0 ||
685             bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) {
686                 sc->sc_domain = domain;
687         }
688         if (domain == -1) /* NUMA not supported. Use single domain. */
689                 domain = 0;
690         sc->sc_domain = domain;
691         device_printf(dev, "domain=%d\n", sc->sc_domain);
692
693         cpu = CPU_FFS(&cpuset_domain[domain]) - 1;
694
695         i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res);
696         if (i != 0) {
697                 device_printf(dev, "cannot allocate resources for device (%d)\n",
698                     i);
699                 return (i);
700         }
701
702         bus_get_resource(dev, cmn600_res_spec[0].type, cmn600_res_spec[0].rid,
703             &periph_base, &count);
704         bus_get_resource(dev, cmn600_res_spec[1].type, cmn600_res_spec[1].rid,
705             &rootnode_base, &count);
706         rootnode_base -= periph_base;
707         if (bootverbose)
708                 printf("ROOTNODE at %lx x %lx\n", rootnode_base, count);
709
710         sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0);
711         ctx = device_get_sysctl_ctx(sc->sc_dev);
712
713         child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev));
714         SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dump_nodes", CTLTYPE_INT |
715             CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, cmn600_sysctl_dump_nodes,
716             "U", "Dump CMN-600 nodes tree");
717
718         node = sc->sc_dtcnode;
719         if (node == NULL)
720                 return (ENXIO);
721
722         cmn600_pmc_register(sc->sc_unit, (void *)sc, domain);
723
724         node->nd_write8(node, POR_DT_PMCR, 0);
725         node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL);
726         node->nd_write8(node, POR_DT_PMCR, POR_DT_PMCR_OVFL_INTR_EN);
727         node->nd_write8(node, POR_DT_DTC_CTL, POR_DT_DTC_CTL_DT_EN);
728
729         if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE,
730             cmn600_intr, NULL, sc, &sc->sc_ih)) {
731                 bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
732                 device_printf(dev, "cannot setup interrupt handler\n");
733                 cmn600_acpi_detach(dev);
734                 return (ENXIO);
735         }
736         if (bus_bind_intr(dev, sc->sc_res[2], cpu)) {
737                 bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih);
738                 bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
739                 device_printf(dev, "cannot setup interrupt handler\n");
740                 cmn600_acpi_detach(dev);
741                 return (ENXIO);
742         }
743         return (0);
744 }
745
746 static int
747 cmn600_acpi_detach(device_t dev)
748 {
749         struct cmn600_softc *sc;
750         struct cmn600_node *node;
751
752         sc = device_get_softc(dev);
753         if (sc->sc_res[2] != NULL) {
754                 bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih);
755         }
756
757         node = sc->sc_dtcnode;
758         node->nd_write4(node, POR_DT_DTC_CTL,
759             node->nd_read4(node, POR_DT_DTC_CTL) & ~POR_DT_DTC_CTL_DT_EN);
760         node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL);
761
762         cmn600_pmc_unregister(sc->sc_unit);
763         cmn600_destroy_node(sc->sc_rootnode);
764         bus_release_resources(dev, cmn600_res_spec, sc->sc_res);
765
766         return (0);
767 }
768
769 int
770 cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit,
771     int i))
772 {
773         struct cmn600_softc *sc;
774
775         sc = (struct cmn600_softc *) arg;
776         sc->sc_pmu_ih = handler;
777         return (0);
778 }
779
780 static int
781 cmn600_intr(void *arg)
782 {
783         struct cmn600_node *node;
784         struct cmn600_softc *sc;
785         struct trapframe *tf;
786         uint64_t mask, ready, val;
787         int i;
788         
789         tf = PCPU_GET(curthread)->td_intr_frame;
790         sc = (struct cmn600_softc *) arg;
791         node = sc->sc_dtcnode;
792         val = node->nd_read8(node, POR_DT_PMOVSR);
793         if (val & POR_DT_PMOVSR_CYCLE_COUNTER)
794                 node->nd_write8(node, POR_DT_PMOVSR_CLR,
795                     POR_DT_PMOVSR_CYCLE_COUNTER);
796         if (val & POR_DT_PMOVSR_EVENT_COUNTERS) {
797                 for (ready = 0, i = 0; i < 8; i++) {
798                         mask = 1 << i;
799                         if ((val & mask) == 0)
800                                 continue;
801                         if (sc->sc_pmu_ih != NULL)
802                                 sc->sc_pmu_ih(tf, sc->sc_unit, i);
803                         ready |= mask;
804
805                 }
806                 node->nd_write8(node, POR_DT_PMOVSR_CLR, ready);
807         }
808
809         return (FILTER_HANDLED);
810 }
811
812 static device_method_t cmn600_acpi_methods[] = {
813         /* Device interface */
814         DEVMETHOD(device_probe,                 cmn600_acpi_probe),
815         DEVMETHOD(device_attach,                cmn600_acpi_attach),
816         DEVMETHOD(device_detach,                cmn600_acpi_detach),
817
818         /* End */
819         DEVMETHOD_END
820 };
821
822 static driver_t cmn600_acpi_driver = {
823         "cmn600",
824         cmn600_acpi_methods,
825         sizeof(struct cmn600_softc),
826 };
827
828 DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, 0, 0);
829 MODULE_VERSION(cmn600, 1);