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