Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / res_mau.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: res_mau.c
5*
6* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
7*
8* - Do no alter or remove copyright notices
9*
10* - Redistribution and use of this software in source and binary forms, with
11* or without modification, are permitted provided that the following
12* conditions are met:
13*
14* - Redistribution of source code must retain the above copyright notice,
15* this list of conditions and the following disclaimer.
16*
17* - Redistribution in binary form must reproduce the above copyright notice,
18* this list of conditions and the following disclaimer in the
19* documentation and/or other materials provided with the distribution.
20*
21* Neither the name of Sun Microsystems, Inc. or the names of contributors
22* may be used to endorse or promote products derived from this software
23* without specific prior written permission.
24*
25* This software is provided "AS IS," without a warranty of any kind.
26* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
27* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
28* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
29* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
30* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
31* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
32* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
33* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
34* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
35* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
36* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*
38* You acknowledge that this software is not designed, licensed or
39* intended for use in the design, construction, operation or maintenance of
40* any nuclear facility.
41*
42* ========== Copyright Header End ============================================
43*/
44/*
45 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
46 * Use is subject to license terms.
47 */
48
49#pragma ident "@(#)res_mau.c 1.7 07/06/07 SMI"
50
51#ifdef CONFIG_CRYPTO /* Compiled in if the CRYPTO option selected */
52
53#include <stdarg.h>
54
55#include <sys/htypes.h>
56#include <traps.h>
57#include <cache.h>
58#include <mmu.h>
59#include <sun4v/asi.h>
60#include <vdev_intr.h>
61#include <ncs.h>
62#include <cyclic.h>
63#include <support.h>
64#include <strand.h>
65#include <vcpu.h>
66#include <guest.h>
67#include <pcie.h>
68#include <vdev_ops.h>
69#include <fpga.h>
70#include <ldc.h>
71#include <config.h>
72#include <offsets.h>
73#include <hvctl.h>
74#include <md.h>
75#include <abort.h>
76#include <hypervisor.h>
77#include <proto.h>
78
79/*
80 * (re)-configuration code to handle HV MAU resources
81 */
82
83/*
84 * resource processing support
85 */
86
87extern void c_unconfig_mau(vcpu_t *, guest_t *);
88extern void c_setup_mau(vcpu_t *, uint64_t, config_t *);
89
90static void res_mau_commit_config(mau_t *maup);
91static void res_mau_commit_unconfig(mau_t *maup);
92static void res_mau_commit_modify(mau_t *maup);
93
94static hvctl_status_t res_mau_parse_1(bin_md_t *mdp, md_element_t *maunodep,
95 hvctl_res_error_t *fail_codep, int *fail_res_idp);
96
97static void setup_a_mau(vcpu_t *vcpup, mau_t *maup, uint64_t ino);
98
99/*
100 * mau support functions.
101 */
102void
103res_mau_prep()
104{
105 mau_t *mp;
106 int i;
107
108 mp = config.config_m.maus;
109
110 for (i = 0; i < NMAUS; i++, mp++) {
111 mp->pip.res.flags = (mp->state == MAU_STATE_UNCONFIGURED) ?
112 RESF_Noop : RESF_Unconfig;
113 mp->pip.cpuset = 0;
114 }
115}
116
117
118hvctl_status_t
119res_mau_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep,
120 md_element_t **failnodepp, int *fail_res_idp)
121{
122 md_element_t *mdep;
123 uint64_t arc_token;
124 uint64_t node_token;
125 md_element_t *maunodep;
126
127 mdp = (bin_md_t *)config.parse_hvmd;
128
129 mdep = md_find_node(mdp, NULL, MDNAME(maus));
130 if (mdep == NULL) {
131 DBG_MAU(c_printf("Missing maus node in HVMD\n"));
132 *failnodepp = NULL;
133 *fail_res_idp = 0;
134 return (HVctl_st_badmd);
135 }
136
137 arc_token = MDARC(MDNAME(fwd));
138 node_token = MDNODE(MDNAME(mau));
139
140 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
141 arc_token, node_token, &maunodep))) {
142 hvctl_status_t status;
143 status = res_mau_parse_1(mdp, maunodep, fail_codep,
144 fail_res_idp);
145 if (status != HVctl_st_ok) {
146 *failnodepp = maunodep;
147 return (status);
148 }
149 }
150 return (HVctl_st_ok);
151}
152
153hvctl_status_t
154res_mau_parse_1(bin_md_t *mdp, md_element_t *maunodep,
155 hvctl_res_error_t *fail_codep, int *fail_res_idp)
156{
157 uint64_t strand_id, thread_id, mau_id, gid, ino;
158 mau_t *maup = NULL;
159 md_element_t *guestnodep, *cpunodep, *mdep;
160
161 DBG_MAU(md_dump_node(mdp, maunodep));
162
163 mdep = maunodep;
164
165 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
166 MDARC(MDNAME(back)), MDNODE(MDNAME(cpu)), &cpunodep))) {
167
168 if (!md_node_get_val(mdp, cpunodep, MDNAME(pid), &strand_id)) {
169 DBG_MAU(c_printf("Missing PID in cpu node\n"));
170 *fail_codep = HVctl_e_mau_missing_strandid;
171 goto fail;
172 }
173
174 if (strand_id >= NSTRANDS) {
175 DBG_MAU(c_printf("Invalid PID in cpu node\n"));
176 *fail_codep = HVctl_e_mau_invalid_strandid;
177 goto fail;
178 }
179
180 if (maup == NULL) {
181 mau_id = strand_id >> STRANDID_2_COREID_SHIFT;
182 ASSERT(mau_id < NMAUS);
183 maup = config.config_m.maus;
184 maup = &(maup[mau_id]);
185 maup->pip.cpuset = 0;
186 *fail_res_idp = mau_id;
187 DBG_MAU(c_printf("res_mau_parse_1(0x%x)\n", mau_id));
188 }
189
190 thread_id = strand_id & NSTRANDS_PER_CORE_MASK;
191
192 maup->pip.cpuset |= (1 << thread_id);
193
194 if (NULL == md_find_node_by_arc(mdp, cpunodep,
195 MDARC(MDNAME(back)), MDNODE(MDNAME(guest)),
196 &guestnodep)) {
197 DBG_MAU(c_printf("Missing back arc to guest node in "
198 "cpu node\n"));
199 *fail_codep = HVctl_e_mau_missing_guest;
200 goto fail;
201 }
202
203 if (!md_node_get_val(mdp, guestnodep, MDNAME(resource_id),
204 &gid)) {
205 DBG_MAU(c_printf(
206 "Missing resource_id in guest node\n"));
207 *fail_codep = HVctl_e_guest_missing_id;
208 goto fail;
209 }
210 if (gid >= NGUESTS) {
211 DBG_MAU(c_printf(
212 "Invalid resource_id in guest node\n"));
213 *fail_codep = HVctl_e_guest_invalid_id;
214 goto fail;
215 }
216 /* FIXME: check that all cpus belong to same guest */
217 maup->pip.guestid = gid;
218 }
219
220 /* Get ino value for this mau */
221 if (!md_node_get_val(mdp, maunodep, MDNAME(ino), &ino)) {
222 DBG_MAU(c_printf("WARNING: Missing ino in mau node\n"));
223 *fail_codep = HVctl_e_mau_missing_ino;
224 goto fail;
225 }
226
227 DBG_MAU(c_printf("Virtual mau 0x%x in guest 0x%x ino 0x%x\n",
228 mau_id, gid, ino));
229
230
231 /*
232 * Now determine the delta - if relevent...
233 */
234 maup->pip.pid = mau_id;
235 maup->pip.ino = ino;
236
237 /*
238 * We can configure an unconfigured MAU.
239 * Cannot (yet) support the dynamic re-binding of
240 * a configured / running mau, except to modify the
241 * set of vcpus bound to it, which is handled as part of unconfig
242 * or config.
243 */
244 DBG_MAU(c_printf("\t\tCurrent mau status = 0x%x\n", maup->state));
245
246 if (maup->state == MAU_STATE_UNCONFIGURED) {
247 DBG_MAU(c_printf("\t\tElected to config mau\n"));
248 maup->pip.res.flags = RESF_Config;
249 } else {
250 if (maup->pid == maup->pip.pid &&
251 maup->guest->guestid == gid &&
252 maup->ino == ino &&
253 maup->cpuset != maup->pip.cpuset) {
254 DBG_MAU(c_printf("\t\tElected to modify mau\n"));
255 maup->pip.res.flags = RESF_Modify;
256 } else if (maup->pid == maup->pip.pid &&
257 maup->guest->guestid == gid &&
258 maup->ino == ino) {
259 DBG_MAU(c_printf("\t\tElected to ignore mau\n"));
260 maup->pip.res.flags = RESF_Noop;
261 } else {
262 DBG_MAU(c_printf("\t\tFailed MD update - no "
263 "rebind live\n"));
264 *fail_codep = HVctl_e_mau_rebind_na;
265 goto fail;
266 }
267 }
268
269 return (HVctl_st_ok);
270fail:;
271 return (HVctl_st_badmd);
272}
273
274hvctl_status_t
275res_mau_postparse(hvctl_res_error_t *res_error, int *fail_res_id)
276{
277 return (HVctl_st_ok);
278}
279
280void
281res_mau_commit(int flag)
282{
283 mau_t *mp;
284 int i;
285
286 mp = config.config_m.maus;
287
288 for (i = 0; i < NMAUS; i++, mp++) {
289 /* if not this ops turn move on */
290 DBG_MAU(c_printf("res_mau_commit: mauid 0x%x : state 0x%x : "
291 "flags 0x%x - opflag 0x%x\n",
292 mp->pid, mp->state, mp->pip.res.flags, flag));
293
294 if (mp->pip.res.flags != flag)
295 continue;
296
297 switch (mp->pip.res.flags) {
298 case RESF_Noop:
299 DBG_MAU(c_printf("mau 0x%x : noop\n", i));
300 break;
301 case RESF_Unconfig:
302 DBG_MAU(c_printf("mau 0x%x : unconfig\n", i));
303 res_mau_commit_unconfig(mp);
304 break;
305 case RESF_Config:
306 DBG_MAU(c_printf("mau 0x%x : config\n", i));
307 res_mau_commit_config(mp);
308 break;
309 case RESF_Rebind:
310 DBG_MAU(c_printf("mau 0x%x : rebind\n", i));
311 ASSERT(0); /* not supported */
312 break;
313 case RESF_Modify:
314 DBG_MAU(c_printf("mau 0x%x : modify\n", i));
315 res_mau_commit_modify(mp);
316 break;
317 default:
318 ASSERT(0);
319 }
320
321 mp->pip.res.flags = RESF_Noop; /* cleanup */
322 }
323}
324
325bool_t
326strand_in_vcpu_list(uint64_t strand_id, vcpu_t *vcpu_list, uint64_t *found_idx)
327{
328 int i;
329
330 for (i = 0; i < NVCPUS; ++i) {
331 if (vcpu_list[i].strand && vcpu_list[i].strand->id ==
332 strand_id) {
333 if (found_idx != NULL)
334 *found_idx = i;
335 return (true);
336 }
337 }
338 return (false);
339}
340
341void
342res_mau_commit_config(mau_t *maup)
343{
344 guest_t *guestp;
345 vcpu_t *cpup;
346 uint64_t strand_num, vcpu_num;
347 int i;
348
349 DBG_MAU(c_printf("res_mau_commit_config\n"));
350
351 /*
352 * Assign the mau its bound vcpu.
353 * Note: this does not schedule the mau.
354 */
355 maup->pid = maup->pip.pid;
356
357 guestp = config.guests;
358 guestp = &(guestp[maup->pip.guestid]);
359 ASSERT(guestp->guestid == maup->pip.guestid);
360 ASSERT(guestp->maus[maup->pid] == NULL);
361 guestp->maus[maup->pid] = maup;
362
363 /*
364 * Initialise the remainder of the mau struct. Need to do this
365 * once for each cpu bound to this mau.
366 */
367
368 /*
369 * Loop through the cpus attached to this mau.
370 * FIXME: make independent of cpu arch
371 */
372 strand_num = maup->pid << STRANDID_2_COREID_SHIFT;
373 for (i = 0; i < NSTRANDS_PER_CORE; ++i, ++strand_num) {
374 /* Skip cpus not being bound to this mau */
375 if ((maup->pip.cpuset & (1 << i)) == 0) {
376 DBG_MAU(c_printf("Skipping thread id %d for mau %d "
377 "(pip.cpuset 0x%x)\n",
378 i, maup->pid, maup->pip.cpuset));
379 continue;
380 }
381 cpup = config.vcpus;
382
383 /* Convert strand to vid */
384 if (strand_in_vcpu_list(strand_num, cpup, &vcpu_num)) {
385 cpup = &(cpup[vcpu_num]);
386 } else {
387 DBG_MAU(c_printf(
388 "strand 0x%x not found!\n", strand_num));
389 c_hvabort();
390 }
391
392 cpup->maup = maup;
393
394 DBG_MAU(c_printf("\tBinding mau (pid = 0x%x) to vcpu 0x%x on "
395 "strand 0x%x in guest 0x%x\n",
396 maup->pid, vcpu_num, strand_num, maup->pip.guestid));
397
398 setup_a_mau(cpup, maup, maup->pip.ino);
399 config_a_guest_device_vino(maup->guest, maup->pip.ino,
400 DEVOPS_VDEV);
401 }
402}
403
404void
405init_mau(mau_t *maup)
406{
407#ifdef ERRATA_192
408 maup->store_in_progr = 0;
409 maup->enable_cwq = 0;
410#endif
411 maup->queue.mq_base_ra = 0;
412 maup->queue.mq_base = 0;
413 maup->queue.mq_end = 0;
414 maup->queue.mq_head = 0;
415 maup->queue.mq_tail = 0;
416 maup->queue.mq_nentries = 0;
417 maup->queue.mq_busy = 0;
418}
419
420void
421unconfig_strand_from_mau(mau_t *maup, uint64_t strand_num)
422{
423 int thread_id;
424
425 /*
426 * Check if already unconfigured!
427 */
428 ASSERT(maup->guest->maus[maup->pid] != NULL);
429 ASSERT(maup->state != MAU_STATE_UNCONFIGURED);
430
431 thread_id = strand_num & NSTRANDS_PER_CORE_MASK;
432
433 /*
434 * Force the cpu_active entry to 0.
435 * It is possible to come through the unconfig sequence
436 * without having gone through stop_mau. However, we
437 * assured that when we come into unconfig_mau that the
438 * respective cpu is stopped.
439 */
440 maup->cpu_active[thread_id] = 0;
441
442 /*
443 * Remove cpu from MAU's cpuset and if this
444 * is the last one, then clear the queue structure.
445 */
446 DBG_MAU(c_printf(
447"\tunconfig_strand_from_mau: mau %d thread %d (strand %d) guest %d\n",
448 maup->pid, thread_id, strand_num, maup->guest->guestid));
449
450 maup->cpuset &= ~(1 << thread_id);
451
452 DBG_MAU(c_printf("\tnew cpuset: %d\n", maup->cpuset));
453
454 if (maup->cpuset == 0) {
455 init_mau(maup);
456 maup->state = MAU_STATE_UNCONFIGURED;
457 maup->guest->maus[maup->pid] = NULL;
458 maup->guest = NULL;
459 }
460}
461
462void
463res_mau_commit_unconfig(mau_t *maup)
464{
465 vcpu_t *cpup;
466 uint64_t strand_num, vcpu_num;
467 int i;
468
469 ASSERT(maup->state == MAU_STATE_RUNNING ||
470 maup->state == MAU_STATE_ERROR);
471
472 ASSERT(maup->guest != NULL);
473
474 strand_num = maup->pid << STRANDID_2_COREID_SHIFT;
475 for (i = 0; i < NSTRANDS_PER_CORE; ++i, ++strand_num) {
476 /* Skip cpus not bound to this mau */
477 if ((maup->cpuset & (1 << i)) == 0) {
478 DBG_MAU(c_printf(
479 "Skipping thread id %d (strand 0x%x) for "
480 "mau %d (cpuset 0x%x)\n",
481 i, strand_num, maup->pid, maup->cpuset));
482 continue;
483 }
484
485 cpup = config.vcpus;
486
487 /* Convert strand to vid */
488 DBG_MAU(c_printf(
489 "\tUnconfig mau (pid = 0x%x) from strand 0x%x in "
490 "guest 0x%x\n", maup->pid, strand_num,
491 maup->guest->guestid));
492
493 if (strand_in_vcpu_list(strand_num, cpup, &vcpu_num)) {
494 cpup = &(cpup[vcpu_num]);
495 DBG_MAU(c_printf("\tstrand 0x%x is vcpu 0x%x\n",
496 strand_num, vcpu_num));
497 } else {
498 DBG_MAU(c_printf(
499 "strand 0x%x not found!\n", strand_num));
500 c_hvabort();
501 }
502
503 unconfig_a_guest_device_vino(maup->guest, maup->ino,
504 DEVOPS_VDEV);
505 unconfig_strand_from_mau(maup, strand_num);
506 }
507}
508
509vcpu_t *
510mau_to_vcpu(mau_t *maup, int strand_id)
511{
512 vcpu_t *cpup;
513 int i;
514
515 /*
516 * Walk all vcpus bound to guest which owns mau, and find
517 * one with strand_id passed in.
518 */
519 for (i = 0; i < NVCPUS; ++i) {
520 cpup = maup->guest->vcpus[i];
521
522 /* Is vcpu mapped to guest? */
523 if (cpup == NULL)
524 continue;
525
526 ASSERT(cpup->strand != NULL);
527 if (cpup->strand->id == strand_id) {
528 DBG_MAU(c_printf(
529 "\tmau_to_vcpu: mau %d strand %d is vcpu %d\n",
530 maup->pid, strand_id, cpup->vid));
531 return (cpup);
532 }
533 }
534
535 return (NULL);
536}
537
538/*
539 * The only allowed modification on a mau is the list of vcpus which
540 * are bound to it.
541 */
542void
543res_mau_commit_modify(mau_t *maup)
544{
545 uint64_t strand_id, thread_id;
546
547 ASSERT(maup->state == MAU_STATE_RUNNING ||
548 maup->state == MAU_STATE_ERROR);
549 ASSERT(maup->guest != NULL);
550
551 /*
552 * Compare old & new cpusets, configuring or unconfiguring
553 * cpu->mau bindings as appropriate.
554 */
555 /*
556 * We can't determine which cpu->mau bindings to unconfigure
557 * by walking the available vcpus, as they've already been
558 * unconfigured, so we find them by comparing the old & new
559 * cpuset mask values.
560 */
561 strand_id = maup->pid << STRANDID_2_COREID_SHIFT;
562 for (thread_id = 0; thread_id < NSTRANDS_PER_CORE;
563 ++thread_id, ++strand_id) {
564 uint64_t mask = 1LL << thread_id;
565
566 if ((maup->cpuset & mask) == (maup->pip.cpuset & mask)) {
567 DBG_MAU(c_printf(
568 "\tIgnoring mau (pid = 0x%x) on strand "
569 "0x%x in guest 0x%x\n",
570 maup->pid, strand_id, maup->pip.guestid));
571 continue;
572 }
573 /* Configure? */
574 if ((maup->pip.cpuset & mask) != 0) {
575 vcpu_t *cpup;
576
577 cpup = mau_to_vcpu(maup, strand_id);
578 ASSERT(cpup != NULL);
579 cpup->maup = maup;
580
581 DBG_MAU(c_printf("\tBinding mau (pid = 0x%x) to strand "
582 "0x%x in guest 0x%x\n",
583 maup->pid, strand_id, maup->pip.guestid));
584
585 setup_a_mau(cpup, maup, maup->pip.ino);
586 } else {
587 /* Unconfigure */
588 DBG_MAU(c_printf("\tUnbinding mau %d from strand 0x%x "
589 "in guest 0x%x\n",
590 maup->pid, strand_id, maup->guest->guestid));
591 unconfig_strand_from_mau(maup, strand_id);
592 }
593 }
594}
595
596/*
597 * Setup an MAU ...
598 *
599 * FIXME: bunch of wierd stuff here .. check this is done right.
600 * This is a copy of config_a_mau in reconf.c. The reconf.c version
601 * will go away when we handle delayed reconfig.
602 */
603static void
604setup_a_mau(vcpu_t *vcpup, mau_t *maup, uint64_t ino)
605{
606 c_setup_mau(vcpup, ino, &config);
607 maup->guest = vcpup->guest;
608}
609
610/*
611 * Initialise MAUs
612 */
613void
614init_mau_crypto_units()
615{
616 mau_t *maup;
617 int i, j;
618
619 config.config_m.maus = &maus[0];
620
621 maup = (mau_t *)config.config_m.maus;
622 for (i = 0; i < NMAUS; i++) {
623 maup[i].handle = 0LL;
624#ifdef ERRATA_192
625 maup[i].store_in_progr = 0LL;
626 maup[i].enable_cwq = 0LL;
627#endif
628 maup[i].res_id = i;
629 maup[i].cpuset = 0LL;
630 for (j = 0; j < NSTRANDS_PER_CORE; j++) {
631 maup[i].cpu_active[j] = 0;
632 }
633 maup[i].state = MAU_STATE_UNCONFIGURED;
634 }
635}
636
637#endif