1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * CPU support routines for DR
29 */
30
31 #include <sys/note.h>
32 #include <sys/debug.h>
33 #include <sys/types.h>
34 #include <sys/errno.h>
35 #include <sys/cred.h>
36 #include <sys/dditypes.h>
37 #include <sys/devops.h>
38 #include <sys/modctl.h>
39 #include <sys/poll.h>
40 #include <sys/conf.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43 #include <sys/sunndi.h>
44 #include <sys/ndi_impldefs.h>
45 #include <sys/stat.h>
46 #include <sys/kmem.h>
47 #include <sys/processor.h>
48 #include <sys/cpuvar.h>
49 #include <sys/mem_config.h>
50 #include <sys/promif.h>
51 #include <sys/x_call.h>
52 #include <sys/cpu_sgnblk_defs.h>
53 #include <sys/membar.h>
54 #include <sys/stack.h>
55 #include <sys/sysmacros.h>
56 #include <sys/machsystm.h>
57 #include <sys/spitregs.h>
58
59 #include <sys/archsystm.h>
60 #include <vm/hat_sfmmu.h>
61 #include <sys/pte.h>
62 #include <sys/mmu.h>
63 #include <sys/x_call.h>
64 #include <sys/cpu_module.h>
65 #include <sys/cpu_impl.h>
66
67 #include <sys/autoconf.h>
68 #include <sys/cmn_err.h>
69
70 #include <sys/dr.h>
71 #include <sys/dr_util.h>
72
73 #ifdef _STARFIRE
74 #include <sys/starfire.h>
75 extern struct cpu *SIGBCPU;
76 #else
77 /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */
78 static char *dr_ie_fmt = "dr_cpu.c %d";
79 #endif /* _STARFIRE */
80
81 int
dr_cpu_unit_is_sane(dr_board_t * bp,dr_cpu_unit_t * cp)82 dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp)
83 {
84 #ifdef DEBUG
85 processorid_t cpuid;
86
87 /*
88 * cpuid and unit number should never be different
89 * than they were at discovery/connect time
90 */
91 ASSERT(drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid) == 0);
92
93 ASSERT(cp->sbc_cm.sbdev_bp == bp);
94 ASSERT(cp->sbc_cm.sbdev_type == SBD_COMP_CPU);
95 ASSERT(cp->sbc_cpu_id == cpuid);
96 #else
97 _NOTE(ARGUNUSED(bp))
98 _NOTE(ARGUNUSED(cp))
99 #endif
100
101 return (1);
102 }
103
104 static int
dr_errno2ecode(int error)105 dr_errno2ecode(int error)
106 {
107 int rv;
108
109 switch (error) {
110 case EBUSY:
111 rv = ESBD_BUSY;
112 break;
113 case EINVAL:
114 rv = ESBD_INVAL;
115 break;
116 case EALREADY:
117 rv = ESBD_ALREADY;
118 break;
119 case ENODEV:
120 rv = ESBD_NODEV;
121 break;
122 case ENOMEM:
123 rv = ESBD_NOMEM;
124 break;
125 default:
126 rv = ESBD_INVAL;
127 }
128
129 return (rv);
130 }
131
132 static void
dr_cpu_set_prop(dr_cpu_unit_t * cp)133 dr_cpu_set_prop(dr_cpu_unit_t *cp)
134 {
135 sbd_error_t *err;
136 dev_info_t *dip;
137 uint64_t clock_freq;
138 int ecache_size = 0;
139 char *cache_str = NULL;
140
141 err = drmach_get_dip(cp->sbc_cm.sbdev_id, &dip);
142 if (err) {
143 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
144 return;
145 }
146
147 if (dip == NULL) {
148 #ifndef _STARFIRE
149 /*
150 * Do not report an error on Starfire since
151 * the dip will not be created until after
152 * the CPU has been configured.
153 */
154 DR_DEV_INTERNAL_ERROR(&cp->sbc_cm);
155 #endif /* !_STARFIRE */
156 return;
157 }
158
159 /* read in the CPU speed */
160
161 /*
162 * If the property is not found in the CPU node, it has to be
163 * kept in the core or cmp node so we just keep looking.
164 */
165 clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
166 "clock-frequency", 0);
167
168 ASSERT(clock_freq != 0);
169
170 /*
171 * The ecache property string is not the same
172 * for all CPU implementations.
173 */
174
175 switch (cp->sbc_cpu_impl) {
176 case BLACKBIRD_IMPL:
177 case CHEETAH_IMPL:
178 case CHEETAH_PLUS_IMPL:
179 cache_str = "ecache-size";
180 break;
181 case JAGUAR_IMPL:
182 case OLYMPUS_C_IMPL:
183 case JUPITER_IMPL:
184 cache_str = "l2-cache-size";
185 break;
186 case PANTHER_IMPL:
187 cache_str = "l3-cache-size";
188 break;
189 default:
190 cmn_err(CE_WARN, "Unknown cpu implementation=0x%x",
191 cp->sbc_cpu_impl);
192 ASSERT(0);
193 break;
194 }
195
196 if (cache_str != NULL) {
197 /* read in the ecache size */
198 /*
199 * If the property is not found in the CPU node,
200 * it has to be kept in the core or cmp node so
201 * we just keep looking.
202 */
203
204 ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
205 cache_str, 0);
206 }
207
208 ASSERT(ecache_size != 0);
209
210 /* convert to the proper units */
211 cp->sbc_speed = (clock_freq + 500000) / 1000000;
212 cp->sbc_ecache = ecache_size / (1024 * 1024);
213 }
214
215 void
dr_init_cpu_unit(dr_cpu_unit_t * cp)216 dr_init_cpu_unit(dr_cpu_unit_t *cp)
217 {
218 sbd_error_t *err;
219 dr_state_t new_state;
220 int cpuid;
221 int impl;
222
223 if (DR_DEV_IS_ATTACHED(&cp->sbc_cm)) {
224 new_state = DR_STATE_CONFIGURED;
225 cp->sbc_cm.sbdev_cond = SBD_COND_OK;
226 } else if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) {
227 new_state = DR_STATE_CONNECTED;
228 cp->sbc_cm.sbdev_cond = SBD_COND_OK;
229 } else {
230 new_state = DR_STATE_EMPTY;
231 cp->sbc_cm.sbdev_cond = SBD_COND_UNKNOWN;
232 }
233
234 if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) {
235 err = drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid);
236 if (err) {
237 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
238 new_state = DR_STATE_FATAL;
239 goto done;
240 }
241
242 err = drmach_cpu_get_impl(cp->sbc_cm.sbdev_id, &impl);
243 if (err) {
244 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
245 new_state = DR_STATE_FATAL;
246 goto done;
247 }
248 } else {
249 cp->sbc_cpu_id = -1;
250 cp->sbc_cpu_impl = -1;
251 goto done;
252 }
253
254 cp->sbc_cpu_id = cpuid;
255 cp->sbc_cpu_impl = impl;
256
257 /* if true at init time, it must always be true */
258 ASSERT(dr_cpu_unit_is_sane(cp->sbc_cm.sbdev_bp, cp));
259
260 mutex_enter(&cpu_lock);
261 if ((cpuid >= 0) && cpu[cpuid])
262 cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags;
263 else
264 cp->sbc_cpu_flags = P_OFFLINE | P_POWEROFF;
265 mutex_exit(&cpu_lock);
266
267 dr_cpu_set_prop(cp);
268
269 done:
270 /* delay transition until fully initialized */
271 dr_device_transition(&cp->sbc_cm, new_state);
272 }
273
274 int
dr_pre_attach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)275 dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
276 {
277 int i;
278 int curr_cpu;
279 int next_cpu;
280 static fn_t f = "dr_pre_attach_cpu";
281
282 PR_CPU("%s...\n", f);
283
284 for (next_cpu = 0, i = 0; i < devnum; i++) {
285 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
286
287 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
288
289 /*
290 * Print a console message for each attachment
291 * point. For CMP devices, this means that only
292 * one message should be printed, no matter how
293 * many cores are actually present.
294 */
295 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum,
296 SBD_COMP_CPU);
297 if (curr_cpu >= next_cpu) {
298 cmn_err(CE_CONT, "OS configure %s",
299 up->sbc_cm.sbdev_path);
300 next_cpu = curr_cpu + 1;
301 }
302
303 if (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED) {
304 /*
305 * If we're coming from the UNCONFIGURED
306 * state then the cpu's sigblock will
307 * still be mapped in. Need to unmap it
308 * before continuing with attachment.
309 */
310 PR_CPU("%s: unmapping sigblk for cpu %d\n", f,
311 up->sbc_cpu_id);
312
313 CPU_SGN_MAPOUT(up->sbc_cpu_id);
314 }
315 }
316
317 /*
318 * Block out status threads while creating
319 * devinfo tree branches
320 */
321 dr_lock_status(hp->h_bd);
322 ndi_devi_enter(ddi_root_node(), (int *)(&hp->h_ndi));
323 mutex_enter(&cpu_lock);
324
325 return (0);
326 }
327
328 /*ARGSUSED*/
329 void
dr_attach_cpu(dr_handle_t * hp,dr_common_unit_t * cp)330 dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp)
331 {
332 sbd_error_t *err;
333 processorid_t cpuid;
334 int rv;
335
336 ASSERT(MUTEX_HELD(&cpu_lock));
337
338 err = drmach_configure(cp->sbdev_id, 0);
339 if (err) {
340 DRERR_SET_C(&cp->sbdev_error, &err);
341 return;
342 }
343
344 err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
345 if (err) {
346 DRERR_SET_C(&cp->sbdev_error, &err);
347
348 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
349 if (err)
350 sbd_err_clear(&err);
351 } else if ((rv = cpu_configure(cpuid)) != 0) {
352 dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv));
353 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
354 if (err)
355 sbd_err_clear(&err);
356 }
357 }
358
359 /*
360 * dr_post_attach_cpu
361 *
362 * sbd error policy: Does not stop on error. Processes all units in list.
363 */
364 int
dr_post_attach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)365 dr_post_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
366 {
367 int i;
368 int errflag = 0;
369 static fn_t f = "dr_post_attach_cpu";
370
371 PR_CPU("%s...\n", f);
372
373 /* Startup and online newly-attached CPUs */
374 for (i = 0; i < devnum; i++) {
375 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
376 struct cpu *cp;
377
378 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
379
380 cp = cpu_get(up->sbc_cpu_id);
381 if (cp == NULL) {
382 cmn_err(CE_WARN, "%s: cpu_get failed for cpu %d",
383 f, up->sbc_cpu_id);
384 continue;
385 }
386
387 if (cpu_is_poweredoff(cp)) {
388 if (cpu_poweron(cp) != 0) {
389 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTART);
390 errflag = 1;
391 }
392 PR_CPU("%s: cpu %d powered ON\n", f, up->sbc_cpu_id);
393 }
394
395 if (cpu_is_offline(cp)) {
396 PR_CPU("%s: onlining cpu %d...\n", f, up->sbc_cpu_id);
397
398 if (cpu_online(cp) != 0) {
399 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_ONLINE);
400 errflag = 1;
401 }
402 }
403
404 }
405
406 mutex_exit(&cpu_lock);
407 ndi_devi_exit(ddi_root_node(), hp->h_ndi);
408 dr_unlock_status(hp->h_bd);
409
410 if (errflag)
411 return (-1);
412 else
413 return (0);
414 }
415
416 /*
417 * dr_pre_release_cpu
418 *
419 * sbd error policy: Stops on first error.
420 */
421 int
dr_pre_release_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)422 dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
423 {
424 int c, cix, i, lastoffline = -1, rv = 0;
425 processorid_t cpuid;
426 struct cpu *cp;
427 dr_cpu_unit_t *up;
428 dr_devset_t devset;
429 sbd_dev_stat_t *ds;
430 static fn_t f = "dr_pre_release_cpu";
431 int cpu_flags = 0;
432
433 devset = DR_DEVS_PRESENT(hp->h_bd);
434
435 /* allocate status struct storage. */
436 ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) *
437 MAX_CPU_UNITS_PER_BOARD, KM_SLEEP);
438
439 cix = dr_cpu_status(hp, devset, ds);
440
441 mutex_enter(&cpu_lock);
442
443 for (i = 0; i < devnum; i++) {
444 up = (dr_cpu_unit_t *)devlist[i];
445 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
446
447 /*
448 * The STARCAT platform borrows cpus for use by POST in
449 * iocage testing. These cpus cannot be unconfigured
450 * while they are in use for the iocage.
451 * This check determines if a CPU is currently in use
452 * for iocage testing, and if so, returns a "Device busy"
453 * error.
454 */
455 for (c = 0; c < cix; c++) {
456 if (ds[c].d_cpu.cs_unit == up->sbc_cm.sbdev_unum) {
457 if (ds[c].d_cpu.cs_busy) {
458 dr_dev_err(CE_WARN, &up->sbc_cm,
459 ESBD_BUSY);
460 rv = -1;
461 break;
462 }
463 }
464 }
465 if (c < cix)
466 break;
467 cpuid = up->sbc_cpu_id;
468 if ((cp = cpu_get(cpuid)) == NULL) {
469 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
470 rv = -1;
471 break;
472 }
473
474 /* used by dr_cancel_cpu during error flow */
475 up->sbc_cpu_flags = cp->cpu_flags;
476
477 if (CPU_ACTIVE(cp)) {
478 if (dr_cmd_flags(hp) & SBD_FLAG_FORCE)
479 cpu_flags = CPU_FORCED;
480
481 PR_CPU("%s: offlining cpu %d\n", f, cpuid);
482 if (cpu_offline(cp, cpu_flags)) {
483 PR_CPU("%s: failed to offline cpu %d\n", f,
484 cpuid);
485 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
486 if (disp_bound_threads(cp, 0)) {
487 cmn_err(CE_WARN, "%s: thread(s) bound "
488 "to cpu %d", f, cp->cpu_id);
489 }
490 rv = -1;
491 break;
492 } else
493 lastoffline = i;
494 }
495
496 if (!rv) {
497 sbd_error_t *err;
498
499 err = drmach_release(up->sbc_cm.sbdev_id);
500 if (err) {
501 DRERR_SET_C(&up->sbc_cm.sbdev_error, &err);
502 rv = -1;
503 break;
504 }
505 }
506 }
507
508 mutex_exit(&cpu_lock);
509
510 if (rv) {
511 /*
512 * Need to unwind others since at this level (pre-release)
513 * the device state has not yet transitioned and failures
514 * will prevent us from reaching the "post" release
515 * function where states are normally transitioned.
516 */
517 for (i = lastoffline; i >= 0; i--) {
518 up = (dr_cpu_unit_t *)devlist[i];
519 (void) dr_cancel_cpu(up);
520 }
521 }
522
523 kmem_free(ds, sizeof (sbd_dev_stat_t) * MAX_CPU_UNITS_PER_BOARD);
524 return (rv);
525 }
526
527 /*
528 * dr_pre_detach_cpu
529 *
530 * sbd error policy: Stops on first error.
531 */
532 int
dr_pre_detach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)533 dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
534 {
535 _NOTE(ARGUNUSED(hp))
536
537 int i;
538 int curr_cpu;
539 int next_cpu;
540 int cpu_flags = 0;
541 static fn_t f = "dr_pre_detach_cpu";
542
543 PR_CPU("%s...\n", f);
544
545 /*
546 * Block out status threads while destroying devinfo tree
547 * branches
548 */
549 dr_lock_status(hp->h_bd);
550 mutex_enter(&cpu_lock);
551
552 for (next_cpu = 0, i = 0; i < devnum; i++) {
553 dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i];
554 struct cpu *cp;
555
556 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up));
557
558 cp = cpu_get(up->sbc_cpu_id);
559 if (cp == NULL)
560 continue;
561
562 /*
563 * Print a console message for each attachment
564 * point. For CMP devices, this means that only
565 * one message should be printed, no matter how
566 * many cores are actually present.
567 */
568 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum,
569 SBD_COMP_CPU);
570 if (curr_cpu >= next_cpu) {
571 cmn_err(CE_CONT, "OS unconfigure %s\n",
572 up->sbc_cm.sbdev_path);
573 next_cpu = curr_cpu + 1;
574 }
575
576 /*
577 * CPUs were offlined during Release.
578 */
579 if (cpu_is_poweredoff(cp)) {
580 PR_CPU("%s: cpu %d already powered OFF\n",
581 f, up->sbc_cpu_id);
582 continue;
583 }
584
585 if (!cpu_is_offline(cp)) {
586 if (dr_cmd_flags(hp) & SBD_FLAG_FORCE)
587 cpu_flags = CPU_FORCED;
588 /* cpu was onlined after release. Offline it again */
589 PR_CPU("%s: offlining cpu %d\n", f, up->sbc_cpu_id);
590 if (cpu_offline(cp, cpu_flags)) {
591 PR_CPU("%s: failed to offline cpu %d\n",
592 f, up->sbc_cpu_id);
593 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE);
594 if (disp_bound_threads(cp, 0)) {
595 cmn_err(CE_WARN, "%s: thread(s) bound "
596 "to cpu %d", f, cp->cpu_id);
597 }
598 goto err;
599 }
600 }
601 if (cpu_poweroff(cp) != 0) {
602 dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTOP);
603 goto err;
604 } else {
605 PR_CPU("%s: cpu %d powered OFF\n", f, up->sbc_cpu_id);
606 }
607 }
608
609 return (0);
610
611 err:
612 mutex_exit(&cpu_lock);
613 dr_unlock_status(hp->h_bd);
614 return (-1);
615 }
616
617 /*ARGSUSED*/
618 void
dr_detach_cpu(dr_handle_t * hp,dr_common_unit_t * cp)619 dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp)
620 {
621 sbd_error_t *err;
622 processorid_t cpuid;
623 int rv;
624
625 ASSERT(MUTEX_HELD(&cpu_lock));
626
627 err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
628 if (err) {
629 DRERR_SET_C(&cp->sbdev_error, &err);
630 } else if ((rv = cpu_unconfigure(cpuid)) != 0) {
631 dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv));
632 } else {
633 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY);
634 if (err) {
635 DRERR_SET_C(&cp->sbdev_error, &err);
636 }
637 }
638 }
639
640 /*ARGSUSED1*/
641 int
dr_post_detach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)642 dr_post_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
643 {
644 static fn_t f = "dr_post_detach_cpu";
645
646 PR_CPU("%s...\n", f);
647 hp->h_ndi = 0;
648
649 mutex_exit(&cpu_lock);
650 dr_unlock_status(hp->h_bd);
651
652 return (0);
653 }
654
655 static void
dr_fill_cpu_stat(dr_cpu_unit_t * cp,drmach_status_t * pstat,sbd_cpu_stat_t * csp)656 dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp)
657 {
658 ASSERT(cp && pstat && csp);
659
660 /* Fill in the common status information */
661 bzero((caddr_t)csp, sizeof (*csp));
662 csp->cs_type = cp->sbc_cm.sbdev_type;
663 csp->cs_unit = cp->sbc_cm.sbdev_unum;
664 (void) strncpy(csp->cs_name, pstat->type, sizeof (csp->cs_name));
665 csp->cs_cond = cp->sbc_cm.sbdev_cond;
666 csp->cs_busy = cp->sbc_cm.sbdev_busy | pstat->busy;
667 csp->cs_time = cp->sbc_cm.sbdev_time;
668 csp->cs_ostate = cp->sbc_cm.sbdev_ostate;
669 csp->cs_suspend = 0;
670
671 /* CPU specific status data */
672 csp->cs_cpuid = cp->sbc_cpu_id;
673
674 #ifdef _STARFIRE
675 csp->cs_isbootproc = (SIGBCPU->cpu_id == cp->sbc_cpu_id) ? 1 : 0;
676 #endif /* _STARFIRE */
677
678 /*
679 * If the speed and ecache properties have not been
680 * cached yet, read them in from the device tree.
681 */
682 if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0))
683 dr_cpu_set_prop(cp);
684
685 /* use the cached speed and ecache values */
686 csp->cs_speed = cp->sbc_speed;
687 csp->cs_ecache = cp->sbc_ecache;
688
689 mutex_enter(&cpu_lock);
690 if (!cpu_get(csp->cs_cpuid)) {
691 /* ostate must be UNCONFIGURED */
692 csp->cs_cm.c_ostate = SBD_STAT_UNCONFIGURED;
693 }
694 mutex_exit(&cpu_lock);
695 }
696
697 static void
dr_fill_cmp_stat(sbd_cpu_stat_t * csp,int ncores,int impl,sbd_cmp_stat_t * psp)698 dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp)
699 {
700 int core;
701
702 ASSERT(csp && psp && (ncores >= 1));
703
704 bzero((caddr_t)psp, sizeof (*psp));
705
706 /*
707 * Fill in the common status information based
708 * on the data for the first core.
709 */
710 psp->ps_type = SBD_COMP_CMP;
711 psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP);
712 (void) strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name));
713 psp->ps_cond = csp->cs_cond;
714 psp->ps_busy = csp->cs_busy;
715 psp->ps_time = csp->cs_time;
716 psp->ps_ostate = csp->cs_ostate;
717 psp->ps_suspend = csp->cs_suspend;
718
719 /* CMP specific status data */
720 *psp->ps_cpuid = csp->cs_cpuid;
721 psp->ps_ncores = 1;
722 psp->ps_speed = csp->cs_speed;
723 psp->ps_ecache = csp->cs_ecache;
724
725 /*
726 * Walk through the data for the remaining cores.
727 * Make any adjustments to the common status data,
728 * or the shared CMP specific data if necessary.
729 */
730 for (core = 1; core < ncores; core++) {
731
732 /*
733 * The following properties should be the same
734 * for all the cores of the CMP.
735 */
736 ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM(csp[core].cs_unit,
737 SBD_COMP_CMP));
738 ASSERT(psp->ps_speed == csp[core].cs_speed);
739
740 psp->ps_cpuid[core] = csp[core].cs_cpuid;
741 psp->ps_ncores++;
742
743 /*
744 * Jaguar has a split ecache, so the ecache
745 * for each core must be added together to
746 * get the total ecache for the whole chip.
747 */
748 if (IS_JAGUAR(impl)) {
749 psp->ps_ecache += csp[core].cs_ecache;
750 }
751
752 /* adjust time if necessary */
753 if (csp[core].cs_time > psp->ps_time) {
754 psp->ps_time = csp[core].cs_time;
755 }
756
757 psp->ps_busy |= csp[core].cs_busy;
758
759 /*
760 * If any of the cores are configured, the
761 * entire CMP is marked as configured.
762 */
763 if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) {
764 psp->ps_ostate = csp[core].cs_ostate;
765 }
766 }
767 }
768
769 int
dr_cpu_status(dr_handle_t * hp,dr_devset_t devset,sbd_dev_stat_t * dsp)770 dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp)
771 {
772 int cmp;
773 int core;
774 int ncpu;
775 dr_board_t *bp;
776 sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP];
777 int impl;
778
779 bp = hp->h_bd;
780 ncpu = 0;
781
782 devset &= DR_DEVS_PRESENT(bp);
783
784 /*
785 * Treat every CPU as a CMP. In the case where the
786 * device is not a CMP, treat it as a CMP with only
787 * one core.
788 */
789 for (cmp = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) {
790
791 int ncores;
792 dr_cpu_unit_t *cp;
793 drmach_status_t pstat;
794 sbd_error_t *err;
795 sbd_cmp_stat_t *psp;
796
797 if ((devset & DEVSET(SBD_COMP_CMP, cmp)) == 0) {
798 continue;
799 }
800
801 ncores = 0;
802
803 for (core = 0; core < MAX_CORES_PER_CMP; core++) {
804
805 cp = dr_get_cpu_unit(bp, DR_CMP_CORE_UNUM(cmp, core));
806
807 if (cp->sbc_cm.sbdev_state == DR_STATE_EMPTY) {
808 /* present, but not fully initialized */
809 continue;
810 }
811
812 ASSERT(dr_cpu_unit_is_sane(hp->h_bd, cp));
813
814 /* skip if not present */
815 if (cp->sbc_cm.sbdev_id == (drmachid_t)0) {
816 continue;
817 }
818
819 /* fetch platform status */
820 err = drmach_status(cp->sbc_cm.sbdev_id, &pstat);
821 if (err) {
822 DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err);
823 continue;
824 }
825
826 dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]);
827 /*
828 * We should set impl here because the last core
829 * found might be EMPTY or not present.
830 */
831 impl = cp->sbc_cpu_impl;
832 }
833
834 if (ncores == 0) {
835 continue;
836 }
837
838 /*
839 * Store the data to the outgoing array. If the
840 * device is a CMP, combine all the data for the
841 * cores into a single stat structure.
842 *
843 * The check for a CMP device uses the last core
844 * found, assuming that all cores will have the
845 * same implementation.
846 */
847
848 if (CPU_IMPL_IS_CMP(impl)) {
849 psp = (sbd_cmp_stat_t *)dsp;
850 dr_fill_cmp_stat(cstat, ncores, impl, psp);
851 } else {
852 ASSERT(ncores == 1);
853 bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t));
854 }
855
856 dsp++;
857 ncpu++;
858 }
859
860 return (ncpu);
861 }
862
863 /*
864 * Cancel previous release operation for cpu.
865 * For cpus this means simply bringing cpus that
866 * were offline back online. Note that they had
867 * to have been online at the time there were
868 * released.
869 */
870 int
dr_cancel_cpu(dr_cpu_unit_t * up)871 dr_cancel_cpu(dr_cpu_unit_t *up)
872 {
873 int rv = 0;
874 static fn_t f = "dr_cancel_cpu";
875
876 ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up));
877
878 if (cpu_flagged_active(up->sbc_cpu_flags)) {
879 struct cpu *cp;
880
881 /*
882 * CPU had been online, go ahead
883 * bring it back online.
884 */
885 PR_CPU("%s: bringing cpu %d back ONLINE\n", f, up->sbc_cpu_id);
886
887 mutex_enter(&cpu_lock);
888 cp = cpu[up->sbc_cpu_id];
889
890 if (cpu_is_poweredoff(cp)) {
891 if (cpu_poweron(cp)) {
892 cmn_err(CE_WARN, "%s: failed to power-on "
893 "cpu %d", f, up->sbc_cpu_id);
894 rv = -1;
895 }
896 }
897
898 if (cpu_is_offline(cp)) {
899 if (cpu_online(cp)) {
900 cmn_err(CE_WARN, "%s: failed to online cpu %d",
901 f, up->sbc_cpu_id);
902 rv = -1;
903 }
904 }
905
906 if (cpu_is_online(cp)) {
907 if (cpu_flagged_nointr(up->sbc_cpu_flags)) {
908 if (cpu_intr_disable(cp) != 0) {
909 cmn_err(CE_WARN, "%s: failed to "
910 "disable interrupts on cpu %d", f,
911 up->sbc_cpu_id);
912 }
913 }
914 }
915
916 mutex_exit(&cpu_lock);
917 }
918
919 return (rv);
920 }
921
922 int
dr_disconnect_cpu(dr_cpu_unit_t * up)923 dr_disconnect_cpu(dr_cpu_unit_t *up)
924 {
925 sbd_error_t *err;
926 static fn_t f = "dr_disconnect_cpu";
927
928 PR_CPU("%s...\n", f);
929
930 ASSERT((up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) ||
931 (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED));
932
933 ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up));
934
935 if (up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) {
936 /*
937 * Cpus were never brought in and so are still
938 * effectively disconnected, so nothing to do here.
939 */
940 PR_CPU("%s: cpu %d never brought in\n", f, up->sbc_cpu_id);
941 return (0);
942 }
943
944 err = drmach_cpu_disconnect(up->sbc_cm.sbdev_id);
945 if (err == NULL)
946 return (0);
947 else {
948 DRERR_SET_C(&up->sbc_cm.sbdev_error, &err);
949 return (-1);
950 }
951 /*NOTREACHED*/
952 }
953