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