1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/ddi_impldefs.h>
33 #include <sys/obpdefs.h>
34 #include <sys/cmn_err.h>
35 #include <sys/errno.h>
36 #include <sys/kmem.h>
37 #include <sys/debug.h>
38 #include <sys/sysmacros.h>
39 #include <sys/machsystm.h>
40 #include <vm/hat_sfmmu.h>
41 #include <sys/autoconf.h>
42 #include <sys/open.h>
43 #include <sys/stat.h>
44 #include <sys/modctl.h>
45 #include <sys/fhc.h>
46 #include <sys/ac.h>
47 #include <sys/cpu_module.h>
48 #include <sys/x_call.h>
49 #include <sys/fpu/fpusystm.h>
50 #include <sys/lgrp.h>
51
52 /* Useful debugging Stuff */
53 #include <sys/nexusdebug.h>
54
55 /*
56 * Function prototypes
57 */
58
59 static int ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
60 void **result);
61 static int ac_attach(dev_info_t *, ddi_attach_cmd_t);
62 static int ac_detach(dev_info_t *, ddi_detach_cmd_t);
63 static int ac_open(dev_t *, int, int, cred_t *);
64 static int ac_close(dev_t, int, int, cred_t *);
65 static int ac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
66
67 static void ac_add_kstats(struct ac_soft_state *);
68 static void ac_del_kstats(struct ac_soft_state *);
69 static int ac_misc_kstat_update(kstat_t *, int);
70 static void ac_add_picN_kstats(dev_info_t *dip);
71 static int ac_counters_kstat_update(kstat_t *, int);
72 static void ac_get_memory_status(struct ac_soft_state *, enum ac_bank_id);
73 static void ac_eval_memory_status(struct ac_soft_state *, enum ac_bank_id);
74 static void ac_ecache_flush(uint64_t, uint64_t);
75 static int ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
76 static int ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
77 static int ac_reset_timeout(int rw);
78 static void ac_timeout(void *);
79 static int ac_enter_transition(void);
80 static void ac_exit_transition(void);
81
82
83 int ac_add_memory(ac_cfga_pkt_t *);
84 int ac_del_memory(ac_cfga_pkt_t *);
85 int ac_mem_stat(ac_cfga_pkt_t *, int);
86 int ac_mem_test_start(ac_cfga_pkt_t *, int);
87 int ac_mem_test_stop(ac_cfga_pkt_t *, int);
88 int ac_mem_test_read(ac_cfga_pkt_t *, int);
89 int ac_mem_test_write(ac_cfga_pkt_t *, int);
90 void ac_mem_test_stop_on_close(uint_t, uint_t);
91 /*
92 * ac audit message events
93 */
94 typedef enum {
95 AC_AUDIT_OSTATE_CONFIGURE,
96 AC_AUDIT_OSTATE_UNCONFIGURE,
97 AC_AUDIT_OSTATE_SUCCEEDED,
98 AC_AUDIT_OSTATE_CONFIGURE_FAILED,
99 AC_AUDIT_OSTATE_UNCONFIGURE_FAILED
100 } ac_audit_evt_t;
101 static void ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt);
102 static char *ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event);
103
104 /* The memory ioctl interface version of this driver. */
105 static ac_mem_version_t ac_mem_version = AC_MEM_ADMIN_VERSION;
106
107 static int ac_mem_exercise(ac_cfga_pkt_t *, int);
108
109 /*
110 * Configuration data structures
111 */
112 static struct cb_ops ac_cb_ops = {
113 ac_open, /* open */
114 ac_close, /* close */
115 nulldev, /* strategy */
116 nulldev, /* print */
117 nodev, /* dump */
118 nulldev, /* read */
119 nulldev, /* write */
120 ac_ioctl, /* ioctl */
121 nodev, /* devmap */
122 nodev, /* mmap */
123 nodev, /* segmap */
124 nochpoll, /* poll */
125 ddi_prop_op, /* cb_prop_op */
126 0, /* streamtab */
127 D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */
128 CB_REV, /* rev */
129 nodev, /* cb_aread */
130 nodev /* cb_awrite */
131 };
132
133 static struct dev_ops ac_ops = {
134 DEVO_REV, /* devo_rev, */
135 0, /* refcnt */
136 ac_info, /* getinfo */
137 nulldev, /* identify */
138 nulldev, /* probe */
139 ac_attach, /* attach */
140 ac_detach, /* detach */
141 nulldev, /* reset */
142 &ac_cb_ops, /* cb_ops */
143 (struct bus_ops *)0, /* bus_ops */
144 nulldev, /* power */
145 ddi_quiesce_not_needed, /* quiesce */
146 };
147
148 /*
149 * Driver globals
150 */
151 void *acp; /* ac soft state hook */
152 static kstat_t *ac_picN_ksp[AC_NUM_PICS]; /* performance picN kstats */
153 static int ac_attachcnt = 0; /* number of instances attached */
154 static kmutex_t ac_attachcnt_mutex; /* ac_attachcnt lock - attach/detach */
155 static kmutex_t ac_hot_plug_mode_mutex;
156 static timeout_id_t ac_hot_plug_timeout;
157 static int ac_hot_plug_timeout_interval = 10;
158
159 #define AC_GETSOFTC(I) \
160 ((struct ac_soft_state *)ddi_get_soft_state(acp, (I)))
161
162 extern struct mod_ops mod_driverops;
163
164 static struct modldrv modldrv = {
165 &mod_driverops, /* Type of module. This one is a driver */
166 "AC Leaf", /* name of module */
167 &ac_ops, /* driver ops */
168 };
169
170 static struct modlinkage modlinkage = {
171 MODREV_1,
172 (void *)&modldrv,
173 NULL
174 };
175
176 #ifndef lint
177 char _depends_on[] = "drv/fhc";
178 #endif /* lint */
179
180 /*
181 * These are the module initialization routines.
182 */
183
184 int
_init(void)185 _init(void)
186 {
187 int error;
188
189 if ((error = ddi_soft_state_init(&acp, sizeof (struct ac_soft_state),
190 1)) != 0)
191 return (error);
192
193 if ((error = mod_install(&modlinkage)) != 0) {
194 ddi_soft_state_fini(&acp);
195 return (error);
196 }
197 /* Initialize global mutex */
198 mutex_init(&ac_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
199 mutex_init(&ac_hot_plug_mode_mutex, NULL, MUTEX_DRIVER, NULL);
200 return (0);
201 }
202
203 int
_fini(void)204 _fini(void)
205 {
206 int error;
207
208 if ((error = mod_remove(&modlinkage)) == 0) {
209 ddi_soft_state_fini(&acp);
210 mutex_destroy(&ac_attachcnt_mutex);
211 mutex_destroy(&ac_hot_plug_mode_mutex);
212 }
213 return (error);
214 }
215
216 int
_info(struct modinfo * modinfop)217 _info(struct modinfo *modinfop)
218 {
219 return (mod_info(&modlinkage, modinfop));
220 }
221
222 /* ARGSUSED */
223 static int
ac_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)224 ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
225 {
226 dev_t dev;
227 int instance;
228
229 if (infocmd == DDI_INFO_DEVT2INSTANCE) {
230 dev = (dev_t)arg;
231 instance = AC_GETINSTANCE(getminor(dev));
232 *result = (void *)(uintptr_t)instance;
233 return (DDI_SUCCESS);
234 }
235 return (DDI_FAILURE);
236 }
237
238 static int
ac_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)239 ac_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
240 {
241 int instance;
242 struct ac_soft_state *softsp;
243 struct bd_list *list = NULL;
244
245 switch (cmd) {
246 case DDI_ATTACH:
247 break;
248
249 case DDI_RESUME:
250 return (DDI_SUCCESS);
251
252 default:
253 return (DDI_FAILURE);
254 }
255
256 instance = ddi_get_instance(devi);
257
258 if (ddi_soft_state_zalloc(acp, instance) != DDI_SUCCESS) {
259 cmn_err(CE_WARN, "ddi_soft_state_zalloc failed for ac%d",
260 instance);
261 return (DDI_FAILURE);
262 }
263
264 softsp = ddi_get_soft_state(acp, instance);
265
266 /* Set the dip in the soft state */
267 softsp->dip = devi;
268
269 /* Get the board number from this nodes parent */
270 softsp->pdip = ddi_get_parent(softsp->dip);
271 if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
272 DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
273 cmn_err(CE_WARN, "ac%d: unable to retrieve %s property",
274 instance, OBP_BOARDNUM);
275 goto bad;
276 }
277
278 DPRINTF(AC_ATTACH_DEBUG, ("ac%d: devi= 0x%p\n,"
279 " softsp=0x%p\n", instance, (void *)devi, (void *)softsp));
280
281 /* map in the registers for this device. */
282 if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0)) {
283 cmn_err(CE_WARN, "ac%d: unable to map registers", instance);
284 goto bad;
285 }
286
287 /* Setup the pointers to the hardware registers */
288 softsp->ac_id = (uint32_t *)softsp->ac_base;
289 softsp->ac_memctl = (uint64_t *)((char *)softsp->ac_base +
290 AC_OFF_MEMCTL);
291 softsp->ac_memdecode0 = (uint64_t *)((char *)softsp->ac_base +
292 AC_OFF_MEMDEC0);
293 softsp->ac_memdecode1 = (uint64_t *)((char *)softsp->ac_base +
294 AC_OFF_MEMDEC1);
295 softsp->ac_counter = (uint64_t *)((char *)softsp->ac_base +
296 AC_OFF_CNTR);
297 softsp->ac_mccr = (uint32_t *)((char *)softsp->ac_base +
298 AC_OFF_MCCR);
299
300 /* nothing to suspend/resume here */
301 (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
302 "pm-hardware-state", "no-suspend-resume");
303
304 /* setup the the AC counter registers to allow for hotplug. */
305 list = fhc_bdlist_lock(softsp->board);
306
307 if (list == NULL) {
308 cmn_err(CE_PANIC, "ac%d: Board %d not found in database",
309 instance, softsp->board);
310 }
311
312 /* set the AC rev into the bd list structure */
313 list->sc.ac_compid = *softsp->ac_id;
314
315 list->ac_softsp = softsp;
316
317 if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
318 /* Create the minor nodes */
319 if (ddi_create_minor_node(devi, NAME_BANK0, S_IFCHR,
320 (AC_PUTINSTANCE(instance) | 0),
321 DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
322 cmn_err(CE_WARN, "ac%d: \"%s\" "
323 "ddi_create_minor_node failed", instance,
324 NAME_BANK0);
325 }
326 if (ddi_create_minor_node(devi, NAME_BANK1, S_IFCHR,
327 (AC_PUTINSTANCE(instance) | 1),
328 DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
329 cmn_err(CE_WARN, "ac%d: \"%s\" "
330 "ddi_create_minor_node failed", instance,
331 NAME_BANK0);
332 }
333
334 /* purge previous fhc pa database entries */
335 fhc_del_memloc(softsp->board);
336
337 /* Inherit Memory Bank Status */
338 ac_get_memory_status(softsp, Bank0);
339 ac_get_memory_status(softsp, Bank1);
340 /* Final Memory Bank Status evaluation and messaging */
341 ac_eval_memory_status(softsp, Bank0);
342 ac_eval_memory_status(softsp, Bank1);
343 }
344
345 fhc_bdlist_unlock();
346
347 /* create the kstats for this device. */
348 ac_add_kstats(softsp);
349
350 ddi_report_dev(devi);
351
352 return (DDI_SUCCESS);
353
354 bad:
355 ddi_soft_state_free(acp, instance);
356 return (DDI_FAILURE);
357 }
358
359 /* ARGSUSED */
360 static int
ac_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)361 ac_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
362 {
363 int instance;
364 struct ac_soft_state *softsp;
365 struct bd_list *list;
366
367 /* get the instance of this devi */
368 instance = ddi_get_instance(devi);
369
370 /* get the soft state pointer for this device node */
371 softsp = ddi_get_soft_state(acp, instance);
372
373 switch (cmd) {
374 case DDI_SUSPEND:
375 return (DDI_SUCCESS);
376
377 case DDI_DETACH:
378 list = fhc_bdlist_lock(softsp->board);
379
380 if (fhc_bd_detachable(softsp->board))
381 break;
382 else
383 fhc_bdlist_unlock();
384 /* FALLTHROUGH */
385
386 default:
387 return (DDI_FAILURE);
388 }
389
390 ASSERT(list->ac_softsp == softsp);
391
392 if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
393 int cpui;
394
395 /*
396 * Test to see if memory is in use on a CPU/MEM board.
397 * In the case of a DR operation this condition
398 * will have been assured when the board was unconfigured.
399 */
400 if (softsp->bank[Bank0].busy != 0 ||
401 softsp->bank[Bank0].ostate == SYSC_CFGA_OSTATE_CONFIGURED ||
402 softsp->bank[Bank1].busy != 0 ||
403 softsp->bank[Bank1].ostate == SYSC_CFGA_OSTATE_CONFIGURED) {
404 fhc_bdlist_unlock();
405 return (DDI_FAILURE);
406 }
407 /*
408 * CPU busy test is done by the DR sequencer before
409 * device detach called.
410 */
411
412 /*
413 * Flush all E-caches to remove references to this
414 * board's memory.
415 *
416 * Do this one CPU at a time to avoid stalls and timeouts
417 * due to all CPUs flushing concurrently.
418 * xc_one returns silently for non-existant CPUs.
419 */
420 for (cpui = 0; cpui < NCPU; cpui++)
421 xc_one(cpui, ac_ecache_flush, 0, 0);
422 }
423
424 list->ac_softsp = NULL;
425
426 /* delete the kstat for this driver. */
427 ac_del_kstats(softsp);
428
429 /* unmap the registers */
430 ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0);
431
432 fhc_bdlist_unlock();
433
434 /* Remove the minor nodes. */
435 ddi_remove_minor_node(devi, NULL);
436
437 /* free the soft state structure */
438 ddi_soft_state_free(acp, instance);
439 ddi_prop_remove_all(devi);
440
441 return (DDI_SUCCESS);
442 }
443
444 /* ARGSUSED */
445 static int
ac_open(dev_t * devp,int flag,int otyp,cred_t * credp)446 ac_open(dev_t *devp, int flag, int otyp, cred_t *credp)
447 {
448 int instance;
449 dev_t dev;
450 struct ac_soft_state *softsp;
451 struct bd_list *board;
452 int vis;
453
454 dev = *devp;
455 instance = AC_GETINSTANCE(getminor(dev));
456 softsp = AC_GETSOFTC(instance);
457
458 /* Is the instance attached? */
459 if (softsp == NULL) {
460 #ifdef DEBUG
461 cmn_err(CE_WARN, "ac%d device not attached", instance);
462 #endif /* DEBUG */
463 return (ENXIO);
464 }
465
466 /*
467 * If the board is not configured, hide the memory APs
468 */
469 board = fhc_bdlist_lock(softsp->board);
470 vis = (board != NULL) && MEM_BOARD_VISIBLE(board);
471 fhc_bdlist_unlock();
472
473 if (!vis)
474 return (ENXIO);
475
476 /* verify that otyp is appropriate */
477 if (otyp != OTYP_CHR) {
478 return (EINVAL);
479 }
480
481 return (DDI_SUCCESS);
482 }
483
484 /* ARGSUSED */
485 static int
ac_close(dev_t devt,int flag,int otyp,cred_t * credp)486 ac_close(dev_t devt, int flag, int otyp, cred_t *credp)
487 {
488 struct ac_soft_state *softsp;
489 int instance;
490
491 instance = AC_GETINSTANCE(getminor(devt));
492 softsp = AC_GETSOFTC(instance);
493 ASSERT(softsp != NULL);
494 ac_mem_test_stop_on_close(softsp->board, AC_GETBANK(getminor(devt)));
495 return (DDI_SUCCESS);
496 }
497
498 static int
ac_pkt_init(ac_cfga_pkt_t * pkt,intptr_t arg,int flag)499 ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
500 {
501 #ifdef _MULTI_DATAMODEL
502 if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
503 ac_cfga_cmd32_t ac_cmd32;
504
505 if (ddi_copyin((void *)arg, &ac_cmd32,
506 sizeof (ac_cfga_cmd32_t), flag) != 0) {
507 return (EFAULT);
508 }
509 pkt->cmd_cfga.force = ac_cmd32.force;
510 pkt->cmd_cfga.test = ac_cmd32.test;
511 pkt->cmd_cfga.arg = ac_cmd32.arg;
512 pkt->cmd_cfga.errtype = ac_cmd32.errtype;
513 pkt->cmd_cfga.outputstr =
514 (char *)(uintptr_t)ac_cmd32.outputstr;
515 pkt->cmd_cfga.private =
516 (void *)(uintptr_t)ac_cmd32.private;
517 } else
518 #endif /* _MULTI_DATAMODEL */
519 if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
520 sizeof (ac_cfga_cmd_t), flag) != 0) {
521 return (EFAULT);
522 }
523 pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
524 return (0);
525 }
526
527 static int
ac_pkt_fini(ac_cfga_pkt_t * pkt,intptr_t arg,int flag)528 ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
529 {
530 int ret = TRUE;
531
532 #ifdef _MULTI_DATAMODEL
533 if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
534
535 if (ddi_copyout(&(pkt->cmd_cfga.errtype),
536 (void *)&(((ac_cfga_cmd32_t *)arg)->errtype),
537 sizeof (ac_err_t), flag) != 0) {
538 ret = FALSE;
539 }
540 } else
541 #endif
542 if (ddi_copyout(&(pkt->cmd_cfga.errtype),
543 (void *)&(((ac_cfga_cmd_t *)arg)->errtype),
544 sizeof (ac_err_t), flag) != 0) {
545 ret = FALSE;
546 }
547
548 if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
549 (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
550 SYSC_OUTPUT_LEN, flag) != 0))) {
551 ret = FALSE;
552 }
553
554 kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
555 return (ret);
556 }
557
558 /* ARGSUSED */
559 static int
ac_ioctl(dev_t devt,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)560 ac_ioctl(
561 dev_t devt,
562 int cmd,
563 intptr_t arg,
564 int flag,
565 cred_t *cred_p,
566 int *rval_p)
567 {
568 struct ac_soft_state *softsp;
569 ac_cfga_pkt_t cfga_pkt, *pkt;
570 int instance;
571 int retval;
572
573 instance = AC_GETINSTANCE(getminor(devt));
574 softsp = AC_GETSOFTC(instance);
575 if (softsp == NULL) {
576 #ifdef DEBUG
577 cmn_err(CE_NOTE, "ac%d device not attached", instance);
578 #endif /* DEBUG */
579 return (ENXIO);
580 }
581
582 /*
583 * Dispose of the easy ones first.
584 */
585 switch (cmd) {
586 case AC_MEM_ADMIN_VER:
587 /*
588 * Specify the revision of this ioctl interface driver.
589 */
590 if (ddi_copyout(&ac_mem_version, (void *)arg,
591 sizeof (ac_mem_version_t), flag) != 0)
592 return (EFAULT);
593 return (DDI_SUCCESS);
594
595 case AC_MEM_CONFIGURE:
596 case AC_MEM_UNCONFIGURE:
597 case AC_MEM_STAT:
598 case AC_MEM_TEST_START:
599 case AC_MEM_TEST_STOP:
600 case AC_MEM_TEST_READ:
601 case AC_MEM_TEST_WRITE:
602 case AC_MEM_EXERCISE:
603 break;
604
605 default:
606 return (ENOTTY);
607 }
608 if (cmd != AC_MEM_STAT && !fpu_exists) {
609 return (ENOTSUP);
610 }
611
612 pkt = &cfga_pkt;
613 if ((retval = ac_pkt_init(pkt, arg, flag)) != 0)
614 return (retval);
615 pkt->softsp = softsp;
616 pkt->bank = AC_GETBANK(getminor(devt));
617
618 switch (cmd) {
619 case AC_MEM_CONFIGURE:
620 if ((flag & FWRITE) == 0) {
621 retval = EBADF;
622 break;
623 }
624
625 if (pkt->cmd_cfga.private != NULL) {
626 retval = EINVAL;
627 break;
628 }
629 ac_policy_audit_messages(AC_AUDIT_OSTATE_CONFIGURE, pkt);
630 retval = ac_add_memory(pkt);
631 if (!retval)
632 ac_policy_audit_messages(
633 AC_AUDIT_OSTATE_SUCCEEDED, pkt);
634 else
635 ac_policy_audit_messages(
636 AC_AUDIT_OSTATE_CONFIGURE_FAILED, pkt);
637 break;
638
639 case AC_MEM_UNCONFIGURE:
640 if ((flag & FWRITE) == 0) {
641 retval = EBADF;
642 break;
643 }
644
645 if (pkt->cmd_cfga.private != NULL) {
646 retval = EINVAL;
647 break;
648 }
649 ac_policy_audit_messages(AC_AUDIT_OSTATE_UNCONFIGURE, pkt);
650 retval = ac_del_memory(pkt);
651 if (!retval) {
652 ac_policy_audit_messages(
653 AC_AUDIT_OSTATE_SUCCEEDED, pkt);
654 } else
655 ac_policy_audit_messages(
656 AC_AUDIT_OSTATE_UNCONFIGURE_FAILED, pkt);
657 break;
658
659 case AC_MEM_STAT:
660 /*
661 * Query usage of a bank of memory.
662 */
663 retval = ac_mem_stat(pkt, flag);
664 break;
665
666 case AC_MEM_TEST_START:
667 if ((flag & FWRITE) == 0) {
668 retval = EBADF;
669 break;
670 }
671
672 retval = ac_mem_test_start(pkt, flag);
673 break;
674
675 case AC_MEM_TEST_STOP:
676 if ((flag & FWRITE) == 0) {
677 retval = EBADF;
678 break;
679 }
680
681 retval = ac_mem_test_stop(pkt, flag);
682 break;
683
684 case AC_MEM_TEST_READ:
685 /*
686 * read a 'page' (or less) of memory safely.
687 */
688 if ((flag & FWRITE) == 0) {
689 retval = EBADF;
690 break;
691 }
692
693 retval = ac_mem_test_read(pkt, flag);
694 break;
695
696 case AC_MEM_TEST_WRITE:
697 /*
698 * write a 'page' (or less) of memory safely.
699 */
700 if ((flag & FWRITE) == 0) {
701 retval = EBADF;
702 break;
703 }
704
705 retval = ac_mem_test_write(pkt, flag);
706 break;
707
708 case AC_MEM_EXERCISE:
709 retval = ac_mem_exercise(pkt, flag);
710 break;
711
712 default:
713 ASSERT(0);
714 retval = ENOTTY;
715 break;
716 }
717
718 if (ac_pkt_fini(pkt, arg, flag) != TRUE)
719 retval = EFAULT;
720
721 return (retval);
722 }
723
724 static void
ac_add_kstats(struct ac_soft_state * softsp)725 ac_add_kstats(struct ac_soft_state *softsp)
726 {
727 struct kstat *ac_ksp, *ac_counters_ksp;
728 struct ac_kstat *ac_named_ksp;
729 struct kstat_named *ac_counters_named_data;
730
731 /*
732 * create the unix-misc kstat for address controller
733 * using the board number as the instance.
734 */
735 if ((ac_ksp = kstat_create("unix", softsp->board,
736 AC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
737 sizeof (struct ac_kstat) / sizeof (kstat_named_t),
738 KSTAT_FLAG_PERSISTENT)) == NULL) {
739 cmn_err(CE_WARN, "ac%d: kstat_create failed",
740 ddi_get_instance(softsp->dip));
741 return;
742 }
743
744 ac_named_ksp = (struct ac_kstat *)(ac_ksp->ks_data);
745
746 /* initialize the named kstats */
747 kstat_named_init(&ac_named_ksp->ac_memctl,
748 MEMCTL_KSTAT_NAMED,
749 KSTAT_DATA_UINT64);
750
751 kstat_named_init(&ac_named_ksp->ac_memdecode0,
752 MEMDECODE0_KSTAT_NAMED,
753 KSTAT_DATA_UINT64);
754
755 kstat_named_init(&ac_named_ksp->ac_memdecode1,
756 MEMDECODE1_KSTAT_NAMED,
757 KSTAT_DATA_UINT64);
758
759 kstat_named_init(&ac_named_ksp->ac_mccr,
760 MCCR_KSTAT_NAMED,
761 KSTAT_DATA_UINT32);
762
763 kstat_named_init(&ac_named_ksp->ac_counter,
764 CNTR_KSTAT_NAMED,
765 KSTAT_DATA_UINT64);
766
767 kstat_named_init(&ac_named_ksp->ac_bank0_status,
768 BANK_0_KSTAT_NAMED,
769 KSTAT_DATA_CHAR);
770
771 kstat_named_init(&ac_named_ksp->ac_bank1_status,
772 BANK_1_KSTAT_NAMED,
773 KSTAT_DATA_CHAR);
774
775 ac_ksp->ks_update = ac_misc_kstat_update;
776 ac_ksp->ks_private = (void *)softsp;
777 softsp->ac_ksp = ac_ksp;
778 kstat_install(ac_ksp);
779
780 /*
781 * Create the picN kstats if we are the first instance
782 * to attach. We use ac_attachcnt as a count of how
783 * many instances have attached. This is protected by
784 * a mutex.
785 */
786 mutex_enter(&ac_attachcnt_mutex);
787 if (ac_attachcnt == 0)
788 ac_add_picN_kstats(softsp->dip);
789
790 ac_attachcnt ++;
791 mutex_exit(&ac_attachcnt_mutex);
792
793 /*
794 * Create the "counter" kstat for each AC instance.
795 * This provides access to the %pcr and %pic
796 * registers for that instance.
797 *
798 * The size of this kstat is AC_NUM_PICS + 1 for %pcr
799 */
800 if ((ac_counters_ksp = kstat_create("ac",
801 ddi_get_instance(softsp->dip), "counters",
802 "bus", KSTAT_TYPE_NAMED, AC_NUM_PICS + 1,
803 KSTAT_FLAG_WRITABLE)) == NULL) {
804
805 cmn_err(CE_WARN, "ac%d counters: kstat_create failed",
806 ddi_get_instance(softsp->dip));
807 return;
808 }
809 ac_counters_named_data =
810 (struct kstat_named *)(ac_counters_ksp->ks_data);
811
812 /* initialize the named kstats */
813 kstat_named_init(&ac_counters_named_data[0],
814 "pcr", KSTAT_DATA_UINT64);
815
816 kstat_named_init(&ac_counters_named_data[1],
817 "pic0", KSTAT_DATA_UINT64);
818
819 kstat_named_init(&ac_counters_named_data[2],
820 "pic1", KSTAT_DATA_UINT64);
821
822 ac_counters_ksp->ks_update = ac_counters_kstat_update;
823 ac_counters_ksp->ks_private = (void *)softsp;
824 kstat_install(ac_counters_ksp);
825
826 /* update the sofstate */
827 softsp->ac_counters_ksp = ac_counters_ksp;
828 }
829
830 /*
831 * called from ac_add_kstats() to create a kstat for each %pic
832 * that the AC supports. These (read-only) kstats export the
833 * event names and %pcr masks that each %pic supports.
834 *
835 * if we fail to create any of these kstats we must remove any
836 * that we have already created and return;
837 *
838 * NOTE: because all AC's use the same events we only need to
839 * create the picN kstats once. All instances can use
840 * the same picN kstats.
841 *
842 * The flexibility exists to allow each device specify it's
843 * own events by creating picN kstats with the instance number
844 * set to ddi_get_instance(softsp->dip).
845 *
846 * When searching for a picN kstat for a device you should
847 * first search for a picN kstat using the instance number
848 * of the device you are interested in. If that fails you
849 * should use the first picN kstat found for that device.
850 */
851 static void
ac_add_picN_kstats(dev_info_t * dip)852 ac_add_picN_kstats(dev_info_t *dip)
853 {
854 typedef struct ac_event_mask {
855 char *event_name;
856 uint64_t pcr_mask;
857 } ac_event_mask_t;
858
859 /*
860 * AC Performance Events.
861 *
862 * We declare an array of event-names and event-masks.
863 */
864 ac_event_mask_t ac_events_arr[] = {
865 {"mem_bank0_rds", 0x1}, {"mem_bank0_wrs", 0x2},
866 {"mem_bank0_stall", 0x3}, {"mem_bank1_rds", 0x4},
867 {"mem_bank1_wrs", 0x5}, {"mem_bank1_stall", 0x6},
868 {"clock_cycles", 0x7}, {"addr_pkts", 0x8},
869 {"data_pkts", 0x9}, {"flow_ctl_cyc", 0xa},
870 {"fast_arb_pkts", 0xb}, {"bus_cont_cyc", 0xc},
871 {"data_bus_can", 0xd}, {"ac_addr_pkts", 0xe},
872 {"ac_data_pkts", 0xf}, {"rts_pkts", 0x10},
873 {"rtsa_pkts", 0x11}, {"rto_pkts", 0x12},
874 {"rs_pkts", 0x13}, {"wb_pkts", 0x14},
875 {"ws_pkts", 0x15}, {"rio_pkts", 0x16},
876 {"rbio_pkts", 0x17}, {"wio_pkts", 0x18},
877 {"wbio_pkts", 0x19}, {"upa_a_rds_m", 0x1a},
878 {"upa_a_rdo_v", 0x1b}, {"upa_b_rds_m", 0x1c},
879 {"upa_b_rdo_v", 0x1d}, {"upa_a_preqs_fr", 0x20},
880 {"upa_a_sreqs_to", 0x21}, {"upa_a_preqs_to", 0x22},
881 {"upa_a_rds_fr", 0x23}, {"upa_a_rdsa_fr", 0x24},
882 {"upa_a_rdo_fr", 0x25}, {"upa_a_rdd_fr", 0x26},
883 {"upa_a_rio_rbio", 0x27}, {"upa_a_wio_wbio", 0x28},
884 {"upa_a_cpb_to", 0x29}, {"upa_a_inv_to", 0x2a},
885 {"upa_a_hits_buff", 0x2b}, {"upa_a_wb", 0x2c},
886 {"upa_a_wi", 0x2d}, {"upa_b_preqs_fr", 0x30},
887 {"upa_b_sreqs_to", 0x31}, {"upa_b_preqs_to", 0x32},
888 {"upa_b_rds_fr", 0x33}, {"upa_b_rdsa_fr", 0x34},
889 {"upa_b_rdo_fr", 0x35}, {"upa_b_rdd_fr", 0x36},
890 {"upa_b_rio_rbio", 0x37}, {"upa_b_wio_wbio", 0x38},
891 {"upa_b_cpb_to", 0x39}, {"upa_b_inv_to", 0x3a},
892 {"upa_b_hits_buff", 0x3b}, {"upa_b_wb", 0x3c},
893 {"upa_b_wi", 0x3d}
894 };
895
896 #define AC_NUM_EVENTS sizeof (ac_events_arr) / sizeof (ac_events_arr[0])
897
898 /*
899 * array of clear masks for each pic.
900 * These masks are used to clear the %pcr bits for
901 * each pic.
902 */
903 ac_event_mask_t ac_clear_pic[AC_NUM_PICS] = {
904 /* pic0 */
905 {"clear_pic", (uint64_t)~(0x3f)},
906 /* pic1 */
907 {"clear_pic", (uint64_t)~(0x3f << 8)}
908 };
909
910 struct kstat_named *ac_pic_named_data;
911 int event, pic;
912 char pic_name[30];
913 int instance = ddi_get_instance(dip);
914 int pic_shift = 0;
915
916 for (pic = 0; pic < AC_NUM_PICS; pic++) {
917 /*
918 * create the picN kstat. The size of this kstat is
919 * AC_NUM_EVENTS + 1 for the clear_event_mask
920 */
921 (void) sprintf(pic_name, "pic%d", pic); /* pic0, pic1 ... */
922 if ((ac_picN_ksp[pic] = kstat_create("ac",
923 instance, pic_name, "bus", KSTAT_TYPE_NAMED,
924 AC_NUM_EVENTS + 1, NULL)) == NULL) {
925
926 cmn_err(CE_WARN, "ac %s: kstat_create failed",
927 pic_name);
928
929 /* remove pic0 kstat if pic1 create fails */
930 if (pic == 1) {
931 kstat_delete(ac_picN_ksp[0]);
932 ac_picN_ksp[0] = NULL;
933 }
934 return;
935 }
936 ac_pic_named_data =
937 (struct kstat_named *)(ac_picN_ksp[pic]->ks_data);
938
939 /*
940 * when we are storing pcr_masks we need to shift bits
941 * left by 8 for pic1 events.
942 */
943 if (pic == 1)
944 pic_shift = 8;
945
946 /*
947 * for each picN event we need to write a kstat record
948 * (name = EVENT, value.ui64 = PCR_MASK)
949 */
950 for (event = 0; event < AC_NUM_EVENTS; event ++) {
951
952 /* pcr_mask */
953 ac_pic_named_data[event].value.ui64 =
954 ac_events_arr[event].pcr_mask << pic_shift;
955
956 /* event-name */
957 kstat_named_init(&ac_pic_named_data[event],
958 ac_events_arr[event].event_name,
959 KSTAT_DATA_UINT64);
960 }
961
962 /*
963 * we add the clear_pic event and mask as the last
964 * record in the kstat
965 */
966 /* pcr mask */
967 ac_pic_named_data[AC_NUM_EVENTS].value.ui64 =
968 ac_clear_pic[pic].pcr_mask;
969
970 /* event-name */
971 kstat_named_init(&ac_pic_named_data[AC_NUM_EVENTS],
972 ac_clear_pic[pic].event_name,
973 KSTAT_DATA_UINT64);
974
975 kstat_install(ac_picN_ksp[pic]);
976 }
977 }
978
979
980 static void
ac_del_kstats(struct ac_soft_state * softsp)981 ac_del_kstats(struct ac_soft_state *softsp)
982 {
983 struct kstat *ac_ksp;
984 int pic;
985
986 /* remove "misc" kstat */
987 ac_ksp = softsp->ac_ksp;
988 softsp->ac_ksp = NULL;
989 if (ac_ksp != NULL) {
990 ASSERT(ac_ksp->ks_private == (void *)softsp);
991 kstat_delete(ac_ksp);
992 }
993
994 /* remove "bus" kstat */
995 ac_ksp = softsp->ac_counters_ksp;
996 softsp->ac_counters_ksp = NULL;
997 if (ac_ksp != NULL) {
998 ASSERT(ac_ksp->ks_private == (void *)softsp);
999 kstat_delete(ac_ksp);
1000 }
1001
1002 /*
1003 * if we are the last instance to detach we need to
1004 * remove the picN kstats. We use ac_attachcnt as a
1005 * count of how many instances are still attached. This
1006 * is protected by a mutex.
1007 */
1008 mutex_enter(&ac_attachcnt_mutex);
1009 ac_attachcnt --;
1010 if (ac_attachcnt == 0) {
1011 for (pic = 0; pic < AC_NUM_PICS; pic++) {
1012 if (ac_picN_ksp[pic] != (kstat_t *)NULL) {
1013 kstat_delete(ac_picN_ksp[pic]);
1014 ac_picN_ksp[pic] = NULL;
1015 }
1016 }
1017 }
1018 mutex_exit(&ac_attachcnt_mutex);
1019 }
1020
1021 static enum ac_bank_status
ac_kstat_stat(sysc_cfga_rstate_t rst,sysc_cfga_ostate_t ost)1022 ac_kstat_stat(sysc_cfga_rstate_t rst, sysc_cfga_ostate_t ost)
1023 {
1024 switch (rst) {
1025 case SYSC_CFGA_RSTATE_EMPTY:
1026 return (StNoMem);
1027 case SYSC_CFGA_RSTATE_DISCONNECTED:
1028 return (StBad);
1029 case SYSC_CFGA_RSTATE_CONNECTED:
1030 switch (ost) {
1031 case SYSC_CFGA_OSTATE_UNCONFIGURED:
1032 return (StSpare);
1033 case SYSC_CFGA_OSTATE_CONFIGURED:
1034 return (StActive);
1035 default:
1036 return (StUnknown);
1037 }
1038 default:
1039 return (StUnknown);
1040 }
1041 }
1042
1043 static enum ac_bank_condition
ac_kstat_cond(sysc_cfga_cond_t cond)1044 ac_kstat_cond(sysc_cfga_cond_t cond)
1045 {
1046 switch (cond) {
1047 case SYSC_CFGA_COND_UNKNOWN:
1048 return (ConUnknown);
1049 case SYSC_CFGA_COND_OK:
1050 return (ConOK);
1051 case SYSC_CFGA_COND_FAILING:
1052 return (ConFailing);
1053 case SYSC_CFGA_COND_FAILED:
1054 return (ConFailed);
1055 case SYSC_CFGA_COND_UNUSABLE:
1056 return (ConBad);
1057 default:
1058 return (ConUnknown);
1059 }
1060 }
1061
1062 static int
ac_misc_kstat_update(kstat_t * ksp,int rw)1063 ac_misc_kstat_update(kstat_t *ksp, int rw)
1064 {
1065 struct ac_kstat *acksp;
1066 struct ac_soft_state *softsp;
1067
1068 acksp = (struct ac_kstat *)ksp->ks_data;
1069 softsp = (struct ac_soft_state *)ksp->ks_private;
1070 /* Need the NULL check in case kstat is about to be deleted. */
1071 ASSERT(softsp->ac_ksp == NULL || ksp == softsp->ac_ksp);
1072
1073 /* this is a read-only kstat. Bail out on a write */
1074 if (rw == KSTAT_WRITE) {
1075 return (EACCES);
1076 } else {
1077 /*
1078 * copy the current state of the hardware into the
1079 * kstat structure.
1080 */
1081 acksp->ac_memctl.value.ui64 = *softsp->ac_memctl;
1082 acksp->ac_memdecode0.value.ui64 = *softsp->ac_memdecode0;
1083 acksp->ac_memdecode1.value.ui64 = *softsp->ac_memdecode1;
1084 acksp->ac_mccr.value.ui32 = *softsp->ac_mccr;
1085 acksp->ac_counter.value.ui64 = *softsp->ac_counter;
1086 acksp->ac_bank0_status.value.c[0] =
1087 ac_kstat_stat(softsp->bank[0].rstate,
1088 softsp->bank[0].ostate);
1089 acksp->ac_bank0_status.value.c[1] =
1090 ac_kstat_cond(softsp->bank[0].condition);
1091 acksp->ac_bank1_status.value.c[0] =
1092 ac_kstat_stat(softsp->bank[1].rstate,
1093 softsp->bank[1].ostate);
1094 acksp->ac_bank1_status.value.c[1] =
1095 ac_kstat_cond(softsp->bank[1].condition);
1096 }
1097 return (0);
1098 }
1099
1100 static int
ac_counters_kstat_update(kstat_t * ksp,int rw)1101 ac_counters_kstat_update(kstat_t *ksp, int rw)
1102 {
1103 struct kstat_named *ac_counters_data;
1104 struct ac_soft_state *softsp;
1105 uint64_t pic_register;
1106
1107 ac_counters_data = (struct kstat_named *)ksp->ks_data;
1108 softsp = (struct ac_soft_state *)ksp->ks_private;
1109
1110 /*
1111 * We need to start/restart the ac_timeout that will
1112 * return the AC counters to hot-plug mode after the
1113 * ac_hot_plug_timeout_interval has expired. We tell
1114 * ac_reset_timeout() whether this is a kstat_read or a
1115 * kstat_write call. If this fails we reject the kstat
1116 * operation.
1117 */
1118 if (ac_reset_timeout(rw) != 0)
1119 return (-1);
1120
1121
1122 if (rw == KSTAT_WRITE) {
1123 /*
1124 * Write the %pcr value to the softsp->ac_mccr.
1125 * This interface does not support writing to the
1126 * %pic.
1127 */
1128 *softsp->ac_mccr =
1129 (uint32_t)ac_counters_data[0].value.ui64;
1130 } else {
1131 /*
1132 * Read %pcr and %pic register values and write them
1133 * into counters kstat.
1134 */
1135
1136 /* pcr */
1137 ac_counters_data[0].value.ui64 = *softsp->ac_mccr;
1138
1139 pic_register = *softsp->ac_counter;
1140 /*
1141 * ac pic register:
1142 * (63:32) = pic1
1143 * (31:00) = pic0
1144 */
1145
1146 /* pic0 */
1147 ac_counters_data[1].value.ui64 =
1148 AC_COUNTER_TO_PIC0(pic_register);
1149 /* pic1 */
1150 ac_counters_data[2].value.ui64 =
1151 AC_COUNTER_TO_PIC1(pic_register);
1152 }
1153 return (0);
1154 }
1155
1156 /*
1157 * Decode the memory state given to us and plug it into the soft state
1158 */
1159 static void
ac_get_memory_status(struct ac_soft_state * softsp,enum ac_bank_id id)1160 ac_get_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1161 {
1162 char *property = (id == Bank0) ? AC_BANK0_STATUS : AC_BANK1_STATUS;
1163 char *propval;
1164 int proplen;
1165 uint64_t memdec = (id == Bank0) ?
1166 *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1167 uint_t grp_size;
1168
1169 softsp->bank[id].busy = 0;
1170 softsp->bank[id].status_change = ddi_get_time();
1171
1172 if (GRP_SIZE_IS_SET(memdec)) {
1173 grp_size = GRP_SPANMB(memdec);
1174
1175 /* determine the memory bank size (in MB) */
1176 softsp->bank[id].real_size = softsp->bank[id].use_size =
1177 (id == Bank0) ? (grp_size / INTLV0(*softsp->ac_memctl)) :
1178 (grp_size / INTLV1(*softsp->ac_memctl));
1179 } else {
1180 softsp->bank[id].real_size = softsp->bank[id].use_size = 0;
1181 }
1182
1183 /*
1184 * decode the memory bank property. set condition based
1185 * on the values.
1186 */
1187 if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
1188 DDI_PROP_DONTPASS, property, (caddr_t)&propval, &proplen) ==
1189 DDI_PROP_SUCCESS) {
1190 if (strcmp(propval, AC_BANK_NOMEM) == 0) {
1191 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1192 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1193 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1194 } else if (strcmp(propval, AC_BANK_OK) == 0) {
1195 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1196 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1197 softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1198 } else if (strcmp(propval, AC_BANK_SPARE) == 0) {
1199 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1200 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1201 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1202 } else if (strcmp(propval, AC_BANK_FAILED) == 0) {
1203 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1204 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1205 softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1206 } else {
1207 cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1208 "unknown %smemory state [%s]",
1209 ddi_get_instance(softsp->dip), softsp->board, id,
1210 (memdec & AC_MEM_VALID) ? "connected " : "",
1211 propval);
1212 if (memdec & AC_MEM_VALID) {
1213 softsp->bank[id].rstate =
1214 SYSC_CFGA_RSTATE_CONNECTED;
1215 softsp->bank[id].ostate =
1216 SYSC_CFGA_OSTATE_CONFIGURED;
1217 softsp->bank[id].condition =
1218 SYSC_CFGA_COND_OK;
1219 } else {
1220 softsp->bank[id].rstate =
1221 SYSC_CFGA_RSTATE_DISCONNECTED;
1222 softsp->bank[id].ostate =
1223 SYSC_CFGA_OSTATE_UNCONFIGURED;
1224 softsp->bank[id].condition =
1225 SYSC_CFGA_COND_UNUSABLE;
1226 }
1227 }
1228
1229 kmem_free(propval, proplen);
1230 } else {
1231 /* we don't have the property, deduce the state of memory */
1232 if (memdec & AC_MEM_VALID) {
1233 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1234 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1235 softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1236 } else {
1237 /* could be an i/o board... */
1238 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1239 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1240 softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1241 }
1242 }
1243
1244 /* we assume that all other bank statuses are NOT valid */
1245 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1246 if ((memdec & AC_MEM_VALID) != 0) {
1247 uint64_t base_pa;
1248
1249 ASSERT((*softsp->ac_memctl & AC_CSR_REFEN) != 0);
1250 /* register existence in the memloc database */
1251 base_pa = GRP_REALBASE(memdec);
1252 fhc_add_memloc(softsp->board, base_pa, grp_size);
1253 }
1254 }
1255 }
1256
1257 static void
ac_eval_memory_status(struct ac_soft_state * softsp,enum ac_bank_id id)1258 ac_eval_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1259 {
1260 uint64_t memdec = (id == Bank0) ?
1261 *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1262 uint64_t base_pa;
1263
1264 /*
1265 * Downgrade the status of any bank that did not get
1266 * programmed.
1267 */
1268 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED &&
1269 softsp->bank[id].ostate == SYSC_CFGA_OSTATE_UNCONFIGURED &&
1270 (memdec & AC_MEM_VALID) == 0) {
1271 cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1272 "spare memory bank not valid - it was ",
1273 ddi_get_instance(softsp->dip), softsp->board, id);
1274 cmn_err(CE_WARN, "misconfigured by the system "
1275 "firmware. Disabling...");
1276 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1277 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1278 softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1279 }
1280 /*
1281 * Log a message about good banks.
1282 */
1283 if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1284 ASSERT((memdec & AC_MEM_VALID) != 0);
1285 base_pa = GRP_REALBASE(memdec);
1286
1287 cmn_err(CE_CONT, "?ac%d board %d bank %d: "
1288 "base 0x%" PRIx64 " size %dmb rstate %d "
1289 "ostate %d condition %d\n",
1290 ddi_get_instance(softsp->dip),
1291 softsp->board, id, base_pa, softsp->bank[id].real_size,
1292 softsp->bank[id].rstate, softsp->bank[id].ostate,
1293 softsp->bank[id].condition);
1294 }
1295 }
1296
1297 /*ARGSUSED*/
1298 static void
ac_ecache_flush(uint64_t a,uint64_t b)1299 ac_ecache_flush(uint64_t a, uint64_t b)
1300 {
1301 cpu_flush_ecache();
1302 }
1303
1304 static char *
ac_ostate_typestr(sysc_cfga_ostate_t ostate,ac_audit_evt_t event)1305 ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event)
1306 {
1307 char *type_str;
1308
1309 switch (ostate) {
1310 case SYSC_CFGA_OSTATE_UNCONFIGURED:
1311 switch (event) {
1312 case AC_AUDIT_OSTATE_UNCONFIGURE:
1313 type_str = "unconfiguring";
1314 break;
1315 case AC_AUDIT_OSTATE_SUCCEEDED:
1316 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1317 type_str = "unconfigured";
1318 break;
1319 default:
1320 type_str = "unconfigure?";
1321 break;
1322 }
1323 break;
1324 case SYSC_CFGA_OSTATE_CONFIGURED:
1325 switch (event) {
1326 case AC_AUDIT_OSTATE_CONFIGURE:
1327 type_str = "configuring";
1328 break;
1329 case AC_AUDIT_OSTATE_SUCCEEDED:
1330 case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1331 type_str = "configured";
1332 break;
1333 default:
1334 type_str = "configure?";
1335 break;
1336 }
1337 break;
1338
1339 default:
1340 type_str = "undefined occupant state";
1341 break;
1342 }
1343 return (type_str);
1344 }
1345
1346 static void
ac_policy_audit_messages(ac_audit_evt_t event,ac_cfga_pkt_t * pkt)1347 ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt)
1348 {
1349 struct ac_soft_state *softsp = pkt->softsp;
1350
1351 switch (event) {
1352 case AC_AUDIT_OSTATE_CONFIGURE:
1353 cmn_err(CE_NOTE,
1354 "%s memory bank %d in slot %d",
1355 ac_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
1356 event), pkt->bank,
1357 softsp->board);
1358 break;
1359 case AC_AUDIT_OSTATE_UNCONFIGURE:
1360 cmn_err(CE_NOTE,
1361 "%s memory bank %d in slot %d",
1362 ac_ostate_typestr(
1363 SYSC_CFGA_OSTATE_UNCONFIGURED,
1364 event), pkt->bank,
1365 softsp->board);
1366 break;
1367 case AC_AUDIT_OSTATE_SUCCEEDED:
1368 cmn_err(CE_NOTE,
1369 "memory bank %d in slot %d is %s",
1370 pkt->bank, softsp->board,
1371 ac_ostate_typestr(
1372 softsp->bank[pkt->bank].ostate,
1373 event));
1374 break;
1375 case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1376 cmn_err(CE_NOTE,
1377 "memory bank %d in slot %d not %s",
1378 pkt->bank,
1379 softsp->board,
1380 ac_ostate_typestr(
1381 SYSC_CFGA_OSTATE_CONFIGURED,
1382 event));
1383 break;
1384 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1385 cmn_err(CE_NOTE,
1386 "memory bank %d in slot %d not %s",
1387 pkt->bank,
1388 softsp->board,
1389 ac_ostate_typestr(
1390 SYSC_CFGA_OSTATE_UNCONFIGURED,
1391 event));
1392 break;
1393 default:
1394 cmn_err(CE_NOTE,
1395 "unknown audit of memory bank %d in slot %d",
1396 pkt->bank, softsp->board);
1397 break;
1398 }
1399 }
1400
1401 #include <vm/page.h>
1402 #include <vm/hat.h>
1403
1404 static int
ac_mem_exercise(ac_cfga_pkt_t * pkt,int flag)1405 ac_mem_exercise(ac_cfga_pkt_t *pkt, int flag)
1406 {
1407 struct ac_mem_info *mem_info;
1408 pfn_t base;
1409 pgcnt_t npgs;
1410
1411 mem_info = &pkt->softsp->bank[pkt->bank];
1412 if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1413 uint64_t base_pa, bank_size;
1414 uint64_t decode;
1415
1416 decode = (pkt->bank == Bank0) ?
1417 *pkt->softsp->ac_memdecode0 : *pkt->softsp->ac_memdecode1;
1418 base_pa = GRP_REALBASE(decode);
1419 bank_size = GRP_UK2SPAN(decode);
1420
1421 base = base_pa >> PAGESHIFT;
1422 npgs = bank_size >> PAGESHIFT;
1423 } else {
1424 base = 0;
1425 npgs = 0;
1426 }
1427 switch (pkt->cmd_cfga.arg) {
1428 case AC_MEMX_RELOCATE_ALL: {
1429 pfn_t pfn, pglim;
1430 struct ac_memx_relocate_stats rstat;
1431
1432 if (npgs == 0 ||
1433 mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
1434 return (EINVAL);
1435 }
1436 if (mem_info->busy != FALSE) {
1437 return (EBUSY);
1438 }
1439 bzero(&rstat, sizeof (rstat));
1440 rstat.base = (uint_t)base;
1441 rstat.npgs = (uint_t)npgs;
1442 pglim = base + npgs;
1443 for (pfn = base; pfn < pglim; pfn++) {
1444 page_t *pp, *pp_repl;
1445
1446 retry:
1447 pp = page_numtopp_nolock(pfn);
1448 if (pp != NULL) {
1449 if (!page_trylock(pp, SE_EXCL)) {
1450 pp = NULL;
1451 rstat.nolock++;
1452 }
1453 if (pp != NULL && page_pptonum(pp) != pfn) {
1454 page_unlock(pp);
1455 goto retry;
1456 }
1457 } else {
1458 rstat.nopaget++;
1459 }
1460 if (pp != NULL && PP_ISFREE(pp)) {
1461 page_unlock(pp);
1462 rstat.isfree++;
1463 pp = NULL;
1464 }
1465 if (pp != NULL) {
1466 spgcnt_t npgs;
1467 int result;
1468
1469 pp_repl = NULL;
1470 result = page_relocate(&pp, &pp_repl, 1, 1,
1471 &npgs, NULL);
1472 if (result == 0) {
1473 while (npgs-- > 0) {
1474 page_t *tpp;
1475
1476 ASSERT(pp_repl != NULL);
1477 tpp = pp_repl;
1478 page_sub(&pp_repl, tpp);
1479 page_unlock(tpp);
1480 }
1481
1482 rstat.reloc++;
1483 } else {
1484 page_unlock(pp);
1485 rstat.noreloc++;
1486 }
1487 }
1488 }
1489 if (pkt->cmd_cfga.private != NULL && ddi_copyout(&rstat,
1490 pkt->cmd_cfga.private, sizeof (rstat), flag) != 0)
1491 return (EFAULT);
1492 return (DDI_SUCCESS);
1493 }
1494
1495 default:
1496 return (EINVAL);
1497 }
1498 }
1499
1500 static int
ac_reset_timeout(int rw)1501 ac_reset_timeout(int rw)
1502 {
1503 mutex_enter(&ac_hot_plug_mode_mutex);
1504
1505 if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1506 (rw == KSTAT_READ)) {
1507 /*
1508 * We are in hot-plug mode. A kstat_read is not
1509 * going to affect this. return 0 to allow the
1510 * kstat_read to continue.
1511 */
1512 mutex_exit(&ac_hot_plug_mode_mutex);
1513 return (0);
1514
1515 } else if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1516 (rw == KSTAT_WRITE)) {
1517 /*
1518 * There are no pending timeouts and we have received a
1519 * kstat_write request so we must be transitioning
1520 * from "hot-plug" mode to non "hot-plug" mode.
1521 * Try to lock all boards before allowing the kstat_write.
1522 */
1523 if (ac_enter_transition() == TRUE)
1524 fhc_bdlist_unlock();
1525 else {
1526 /* cannot lock boards so fail */
1527 mutex_exit(&ac_hot_plug_mode_mutex);
1528 return (-1);
1529 }
1530
1531 /*
1532 * We need to display a Warning about hot-plugging any
1533 * boards. This message is only needed when we are
1534 * transitioning out of "hot-plug" mode.
1535 */
1536 cmn_err(CE_WARN, "This machine is being taken out of "
1537 "hot-plug mode.");
1538 cmn_err(CE_CONT, "Do not attempt to hot-plug boards "
1539 "or power supplies in this system until further notice.");
1540
1541 } else if (ac_hot_plug_timeout != (timeout_id_t)NULL) {
1542 /*
1543 * There is a pending timeout so we must already be
1544 * in non "hot-plug" mode. It doesn't matter if the
1545 * kstat request is a read or a write.
1546 *
1547 * We need to cancel the existing timeout.
1548 */
1549 (void) untimeout(ac_hot_plug_timeout);
1550 ac_hot_plug_timeout = NULL;
1551 }
1552
1553 /*
1554 * create a new timeout.
1555 */
1556 ac_hot_plug_timeout = timeout(ac_timeout, NULL,
1557 drv_usectohz(ac_hot_plug_timeout_interval * 1000000));
1558
1559 mutex_exit(&ac_hot_plug_mode_mutex);
1560 return (0);
1561 }
1562
1563 static void
ac_timeout(void * arg)1564 ac_timeout(void *arg)
1565 {
1566 struct ac_soft_state *softsp;
1567 fhc_bd_t *board;
1568
1569 #ifdef lint
1570 arg = arg;
1571 #endif /* lint */
1572
1573 ac_hot_plug_timeout = (timeout_id_t)NULL;
1574
1575 (void) fhc_bdlist_lock(-1);
1576
1577 /*
1578 * Foreach ac in the board list we need to
1579 * re-program the pcr into "hot-plug" mode.
1580 * We also program the pic register with the
1581 * bus pause timing
1582 */
1583 board = fhc_bd_first();
1584 while (board != NULL) {
1585 softsp = board->ac_softsp;
1586 if (softsp == NULL) {
1587 /*
1588 * This board must not have an AC.
1589 * Skip it and move on.
1590 */
1591 board = fhc_bd_next(board);
1592 continue;
1593 }
1594 /* program the pcr into hot-plug mode */
1595 *softsp->ac_mccr = AC_CLEAR_PCR(*softsp->ac_mccr);
1596 *softsp->ac_mccr = AC_SET_HOT_PLUG(*softsp->ac_mccr);
1597
1598 /* program the pic with the bus pause time value */
1599 *softsp->ac_counter = AC_SET_PIC_BUS_PAUSE(softsp->board);
1600
1601 /* get the next board */
1602 board = fhc_bd_next(board);
1603 }
1604
1605 ac_exit_transition();
1606
1607 fhc_bdlist_unlock();
1608
1609 /*
1610 * It is now safe to start hot-plugging again. We need
1611 * to display a message.
1612 */
1613 cmn_err(CE_NOTE, "This machine is now in hot-plug mode.");
1614 cmn_err(CE_CONT, "Board and power supply hot-plug operations "
1615 "can be resumed.");
1616 }
1617
1618 /*
1619 * This function will acquire the lock and set the in_transition
1620 * bit for all the slots. If the slots are being used,
1621 * we return FALSE; else set in_transition and return TRUE.
1622 */
1623 static int
ac_enter_transition(void)1624 ac_enter_transition(void)
1625 {
1626 fhc_bd_t *list;
1627 sysc_cfga_stat_t *sysc_stat_lk;
1628
1629 /* mutex lock the structure */
1630 (void) fhc_bdlist_lock(-1);
1631
1632 list = fhc_bd_clock();
1633
1634 /* change the in_transition bit */
1635 sysc_stat_lk = &list->sc;
1636 if (sysc_stat_lk->in_transition == TRUE) {
1637 fhc_bdlist_unlock();
1638 return (FALSE);
1639 } else {
1640 sysc_stat_lk->in_transition = TRUE;
1641 return (TRUE);
1642 }
1643 }
1644
1645 /*
1646 * clear the in_transition bit for all the slots.
1647 */
1648 static void
ac_exit_transition(void)1649 ac_exit_transition(void)
1650 {
1651 fhc_bd_t *list;
1652 sysc_cfga_stat_t *sysc_stat_lk;
1653
1654 ASSERT(fhc_bdlist_locked());
1655
1656 list = fhc_bd_clock();
1657
1658 sysc_stat_lk = &list->sc;
1659 ASSERT(sysc_stat_lk->in_transition == TRUE);
1660 sysc_stat_lk->in_transition = FALSE;
1661 }
1662