Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / reconf.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: reconf.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 "@(#)reconf.c 1.22 07/07/19 SMI"
50
51#include <stdarg.h>
52#include <sys/htypes.h>
53#include <hypervisor.h>
54#include <traps.h>
55#include <cache.h>
56#include <mmu.h>
57#include <sun4v/asi.h>
58#include <sun4v/errs_defs.h>
59#include <vdev_intr.h>
60#include <ncs.h>
61#include <cyclic.h>
62#include <support.h>
63#include <strand.h>
64#include <vcpu.h>
65#include <guest.h>
66#include <pcie.h>
67#include <vdev_ops.h>
68#include <fpga.h>
69#include <ldc.h>
70#include <config.h>
71#include <offsets.h>
72#include <hvctl.h>
73#include <md.h>
74#include <abort.h>
75#include <hypervisor.h>
76#include <proto.h>
77#include <debug.h>
78#include <util.h>
79#ifdef CONFIG_SVC
80#include <svc.h>
81#endif
82
83/*
84 * (re)-configuration code to handle HV resources
85 */
86static void config_a_hvldc(bin_md_t *mdp, md_element_t *hvldc_nodep);
87static void config_a_spldc(bin_md_t *mdp, md_element_t *spldc_nodep);
88static void config_a_vcpu(bin_md_t *mdp, md_element_t *cpunodep);
89static void config_a_guest(bin_md_t *mdp, md_element_t *guest_nodep);
90static void config_a_guest_ldc_endpoint(guest_t *guestp, bin_md_t *mdp,
91 md_element_t *ldce_nodep);
92
93uint64_t hv_debug_flags = (0x0);
94
95/*
96 * (re-)configuration code to support setup of the hypervisor based on
97 * the HV MD contents
98 */
99void
100config_basics(void)
101{
102 bin_md_t *mdp;
103 md_element_t *mdep;
104 md_element_t *rootnodep;
105 const uint64_t seconds_per_day = 24LL*60LL*60LL;
106 uint64_t val;
107 uint64_t content_version;
108
109 mdp = (bin_md_t *)config.parse_hvmd;
110
111 /*
112 * First find the root node
113 */
114 rootnodep = md_find_node(mdp, NULL, MDNAME(root));
115 if (rootnodep == NULL) {
116 DBG(c_printf("Missing root node in HVMD\n"));
117 c_hvabort();
118 }
119
120 /*
121 * Get content-version from the SP's MD.
122 */
123
124 if (!md_node_get_val(mdp, rootnodep, MDNAME(content_version),
125 &content_version)) {
126 DBG(c_printf("config-basics: MD content-version not found\n"));
127 c_hvabort();
128 }
129
130 /*
131 * Major numbers must be equal.
132 */
133
134 if (MDCONT_VER_MAJOR(content_version) != HV_MDCONT_VER_MAJOR) {
135 DBG(c_printf("config_basics: HV MD content-version mismatch: "
136 "supported major ver %x, found %x\n", HV_MDCONT_VER_MAJOR,
137 MDCONT_VER_MAJOR(content_version)));
138 c_hvabort();
139 }
140
141 DBG(c_printf("config_basics: HV MD content-version %x.%x \n",
142 MDCONT_VER_MAJOR(content_version),
143 MDCONT_VER_MINOR(content_version)));
144
145
146 /*
147 * Is there a HV Uart to use?
148 */
149#ifdef CONFIG_HVUART
150 if (!md_node_get_val(mdp, rootnodep, MDNAME(hvuart), &val))
151 val = 0;
152 config.hvuart_addr = val;
153#endif
154
155 /*
156 * Configure basic time stuff
157 *
158 * We'll warp and align tick/stick later if necessary
159 * when we start the other cpus.
160 */
161
162 if (!md_node_get_val(mdp, rootnodep, MDNAME(tod), &val))
163 val = 0;
164 config.tod = val;
165
166 /* default of divide by 1 */
167 if (!md_node_get_val(mdp, rootnodep, MDNAME(todfrequency), &val))
168 val = 1;
169 config.todfrequency = val;
170
171 if (!md_node_get_val(mdp, rootnodep, MDNAME(stickfrequency), &val))
172 val = 0;
173 config.stickfrequency = val;
174
175 config.cyclic_maxd = CYCLIC_MAX_DAYS * seconds_per_day *
176 config.stickfrequency;
177
178 /*
179 * Configure MMU HWTW mode
180 */
181 if (!md_node_get_val(mdp, rootnodep, MDNAME(sys_hwtw_mode), &val))
182 val = -1;
183 config.sys_hwtw_mode = val;
184
185#ifdef CONFIG_CLEANSER
186 /*
187 * Look for the "l2scrub_interval" property to initialize the interval
188 * for the L2 Cache Cleanser
189 */
190 if (!md_node_get_val(mdp, rootnodep, MDNAME(l2scrub_interval), &val))
191 /* using default if not present */
192 val = L2_CACHE_CLEANSER_INTERVAL;
193 /*
194 * convert internal value (max is 1000 secs) to ticks in terms of
195 * stick frequency
196 */
197 config.l2scrub_interval = MIN(val, 1000) * config.stickfrequency;
198 DBG(c_printf("l2scrub_interval = 0x%x\n", config.l2scrub_interval));
199
200 /*
201 * Look for the "l2scrub_entries" property to initialize the number of
202 * cache entries scrubbed by the L2 Cache Cleanser on each invocation
203 *
204 */
205 if (!md_node_get_val(mdp, rootnodep, MDNAME(l2scrub_entries), &val))
206 /* using default if not present */
207 val = L2_CACHE_CLEANSER_ENTRIES;
208 /*
209 * l2scrub_entries specifies the percentage of l2 cache entries.
210 * So a value of 100 (100%) means the whole L2 cache is cleansed
211 * on each invocation
212 */
213 val = MIN(val, L2_CACHE_CLEANSER_ENTRIES);
214 config.l2scrub_entries = (L2_CACHE_ENTRIES*val)/100;
215 DBG(c_printf("l2scrub_entries = 0x%x\n", config.l2scrub_entries));
216#endif
217
218 /*
219 * Poll frequency for CE errors
220 */
221 if (!md_node_get_val(mdp, rootnodep, MDNAME(cepollsec), &val))
222 val = 30; /* default value of 30 seconds */
223 config.ce_poll_time = val * seconds_per_day * config.stickfrequency;
224
225 if (md_find_node_by_arc(mdp, rootnodep,
226 MDARC(MDNAME(fwd)), MDNODE(MDNAME(guests)), &mdep) == NULL) {
227 DBG(c_printf("No guests node\n"));
228 c_hvabort();
229 }
230 config.guests_dtnode = mdep;
231
232 if (md_find_node_by_arc(mdp, rootnodep,
233 MDARC(MDNAME(fwd)), MDNODE(MDNAME(cpus)), &mdep) == NULL) {
234 DBG(c_printf("No cpus node\n"));
235 c_hvabort();
236 }
237 config.cpus_dtnode = mdep;
238
239 /*
240 * The ldc endpoints are bothersome ... there are multiple such nodes
241 * ones per guest, one in root for the HV itself, and another in
242 * root for the sp ! ... need to clean this up.. FIXME.
243 */
244
245 config.hv_ldcs_dtnode = (md_find_node_by_arc(mdp, rootnodep,
246 MDARC(MDNAME(fwd)), MDNODE(MDNAME(ldc_endpoints)),
247 &mdep) == NULL) ? NULL : mdep;
248
249 config.devs_dtnode = (md_find_node_by_arc(mdp, rootnodep,
250 MDARC(MDNAME(fwd)), MDNODE(MDNAME(devices)),
251 &mdep) == NULL) ? NULL : mdep;
252
253 if (!md_node_get_val(mdp, rootnodep, MDNAME(erpt_pa), &val)) val = 0;
254 config.erpt_pa = val;
255
256 if (!md_node_get_val(mdp, rootnodep, MDNAME(erpt_size), &val)) val = 0;
257 config.erpt_size = val;
258
259#ifdef PLX_ERRATUM_LINK_HACK
260 if (!md_node_get_val(mdp, rootnodep,
261 MDNAME(ignore_plx_link_hack), &val))
262 val = 0;
263 config.ignore_plx_link_hack = val;
264#endif
265
266 /*
267 * Initialize the max length we impose on any memory APIs to the guest.
268 */
269 config.memscrub_max = MEMSCRUB_MAX_DEFAULT;
270 DBG(c_printf("memscrubmax = 0x%x\n", config.memscrub_max));
271
272 /*
273 * Initialize the blackout time for correctable errors.
274 */
275 config.ce_blackout = 6 * config.stickfrequency; /* six seconds */
276 DBG(c_printf("ce_blackout = 0x%x\n", config.ce_blackout));
277
278 config.del_reconf_gid = INVALID_GID;
279 config.hvctl_ldc_lock = 0; /* FIXME: macro needed */
280 config.error_lock = 0; /* FIXME: macro needed */
281 config.fpga_status_lock = 0; /* FIXME: macro needed */
282 config.sram_erpt_buf_inuse = 0; /* FIXME: macro needed */
283
284 /*
285 * User-defined DEBUG PRINT ?
286 */
287 if (md_node_get_val(mdp, rootnodep, MDNAME(debugprintflags), &val))
288 hv_debug_flags = val;
289}
290
291#ifdef CONFIG_SVC
292
293/*
294 * Replace the old HVALLOC code with a simpler allocator only
295 * for service channels
296 */
297
298#define SVC_MTU 0x200
299static hv_svc_data_t hv_svc_data;
300static uint8_t svc_rx_buf[MAX_SVCS][SVC_MTU];
301static uint8_t svc_tx_buf[MAX_SVCS][SVC_MTU];
302
303static void
304config_a_svc(uint32_t sid, uint32_t xid, uint32_t flags, uint32_t mtu,
305 uint32_t ino)
306{
307 svc_ctrl_t *svcp;
308 int svcidx;
309
310 if (hv_svc_data.num_svcs >= MAX_SVCS) {
311 DBGSVC(c_printf("Too many services\n"));
312 c_hvabort(-1);
313 }
314
315 svcidx = hv_svc_data.num_svcs ++;
316
317 svcp = &(hv_svc_data.svcs[svcidx]);
318
319 DBGSVC(c_printf("SVC 0x%x @ 0x%x : sid=0x%x, xid=0x%x, mtu=0x%x, "
320 "flags=0x%x, ino=0x%x\n", svcidx, svcp, sid, xid, mtu, flags, ino));
321
322 if (mtu != SVC_MTU) {
323 DBGSVC(c_printf(
324 "SVC channels now constrained to MTU = 512 B\n"));
325 c_hvabort(-1);
326 }
327
328 svcp->sid = sid;
329 svcp->xid = xid;
330 svcp->config = flags;
331 svcp->mtu = mtu;
332 svcp->ino = ino;
333
334 /* assign the RX buffer */
335 if (flags & SVC_CFG_RX) {
336 svcp->recv.size = 0;
337 svcp->recv.next = svcp + 1; /* next svcp */
338 svcp->recv.pa = (uint64_t)&(svc_rx_buf[svcidx][0]);
339 DBGSVC(c_printf("\trecv pa @ 0x%x\n", svcp->recv.pa));
340 }
341
342 /* assign the TX buffer */
343 if (flags & SVC_CFG_TX) {
344 svcp->send.size = 0;
345 svcp->send.next = 0;
346 svcp->send.pa = (uint64_t)&(svc_tx_buf[svcidx][0]);
347 DBGSVC(c_printf("\tsend pa @ 0x%x\n", svcp->send.pa));
348 }
349}
350
351static void
352config_a_svcchan(bin_md_t *mdp, md_element_t *svc_nodep)
353{
354 uint64_t sid, xid, mtu, flags, ino;
355
356 DBGSVC(c_printf("service node @ 0x%x\n", (uint64_t)svc_nodep));
357 DBGSVC(md_dump_node(mdp, svc_nodep));
358
359 if (!md_node_get_val(mdp, svc_nodep, MDNAME(sid), &sid)) {
360 DBG(c_printf("Missing sid in service node\n"));
361 c_hvabort(-1);
362 }
363 if (!md_node_get_val(mdp, svc_nodep, MDNAME(xid), &xid)) {
364 DBG(c_printf("Missing xid in service node\n"));
365 c_hvabort(-1);
366 }
367 if (!md_node_get_val(mdp, svc_nodep, MDNAME(flags), &flags)) {
368 DBG(c_printf("Missing flags in service node\n"));
369 c_hvabort(-1);
370 }
371 if (!md_node_get_val(mdp, svc_nodep, MDNAME(mtu), &mtu)) {
372 DBG(c_printf("Missing mtu in service node\n"));
373 c_hvabort(-1);
374 }
375
376 if (flags & (SVC_CFG_RE | SVC_CFG_TE)) {
377 if (!md_node_get_val(mdp, svc_nodep, MDNAME(ino), &ino)) {
378 DBG(c_printf("Missing ino in service node\n"));
379 c_hvabort(-1);
380 }
381 } else {
382 ino = 0;
383 }
384
385 config_a_svc(sid, xid, flags, mtu, ino);
386}
387
388void
389config_svcchans(void)
390{
391 bin_md_t *mdp;
392 md_element_t *mdep, *svc_nodep, *rootnodep;
393 uint64_t arc_token;
394 uint64_t name_token;
395#ifdef CONFIG_FPGA
396 volatile uint16_t *fpgap;
397#endif
398 /* basic svc setup */
399
400 config.svc = &hv_svc_data;
401 hv_svc_data.num_svcs = 0;
402 DBGSVC(c_printf("Services @ 0x%x\n", &hv_svc_data));
403
404#ifdef CONFIG_FPGA
405 /* determine FPGA locations */
406 fpgap = (uint16_t *)(FPGA_Q_BASE + FPGA_QIN_BASE);
407 hv_svc_data.rxbase = FPGA_BASE + FPGA_SRAM_BASE + *fpgap;
408
409 fpgap = (uint16_t *)(FPGA_Q_BASE + FPGA_QOUT_BASE);
410 hv_svc_data.txbase = FPGA_BASE + FPGA_SRAM_BASE + *fpgap;
411
412#else
413 hv_svc_data.rxbase = -1;
414 hv_svc_data.txbase = -1;
415#endif
416
417 hv_svc_data.rxchannel = FPGA_QIN_BASE;
418 hv_svc_data.txchannel = FPGA_QOUT_BASE;
419
420 DBGSVC(c_printf("service rxbase=0x%x, rxchan=0x%x\n"
421 "\ttxbase=0x%x, txchan=0x%x\n",
422 hv_svc_data.rxbase, hv_svc_data.rxchannel,
423 hv_svc_data.txbase, hv_svc_data.txchannel));
424
425 /* permanent channels */
426
427 config_a_svc(VBSC_HV_ERRORS_SVC_SID, VBSC_HV_ERRORS_SVC_XID,
428 VBSC_HV_ERRORS_SVC_FLAGS, VBSC_HV_ERRORS_SVC_MTU, 0);
429
430 config_a_svc(VBSC_DEBUG_SVC_SID, VBSC_DEBUG_SVC_XID,
431 VBSC_DEBUG_SVC_FLAGS, VBSC_DEBUG_SVC_MTU, 0);
432
433 /* channels from the HVMD */
434
435 mdp = (bin_md_t *)config.parse_hvmd;
436
437 /*
438 * First find the root node
439 */
440 rootnodep = md_find_node(mdp, NULL, MDNAME(root));
441 if (rootnodep == NULL) {
442 DBG(c_printf("Missing root node in HVMD\n"));
443 c_hvabort();
444 }
445
446 if (md_find_node_by_arc(mdp, rootnodep, MDARC(MDNAME(services)),
447 MDNODE(MDNAME(services)), &mdep) == NULL)
448 mdep = NULL;
449
450 config.svcs_dtnode = mdep;
451
452 if (mdep == NULL)
453 return;
454
455 DBG(c_printf("svcs_dtnode @ 0x%x\n", config.svcs_dtnode));
456 DBG(md_dump_node(mdp, mdep));
457
458 arc_token = MDARC(MDNAME(service));
459 name_token = MDNODE(MDNAME(service));
460
461 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
462 arc_token, name_token, &svc_nodep))) {
463 config_a_svcchan(mdp, svc_nodep);
464 }
465}
466#endif
467
468void
469config_hv_ldcs(void)
470{
471 bin_md_t *mdp;
472 md_element_t *mdep, *hvldc_nodep;
473 uint64_t arc_token;
474 uint64_t name_token;
475
476 mdp = (bin_md_t *)config.parse_hvmd;
477
478 DBGHL(c_printf("LDC configuration:\n"));
479
480 mdep = config.hv_ldcs_dtnode;
481 if (mdep == NULL) {
482 DBG(c_printf("No LDC enpoints node - nothing to do\n"));
483 return;
484 }
485
486 DBGHL(md_dump_node(mdp, mdep));
487
488 arc_token = MDARC(MDNAME(fwd));
489 name_token = MDNODE(MDNAME(ldc_endpoint));
490
491 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
492 arc_token, name_token, &hvldc_nodep))) {
493 config_a_hvldc(mdp, hvldc_nodep);
494 }
495}
496
497static void
498config_a_hvldc(bin_md_t *mdp, md_element_t *hvldc_nodep)
499{
500 uint64_t chid, type;
501 uint64_t guestid, svc_id;
502 uint64_t tchan_id;
503 ldc_endpoint_t *hvep;
504
505 extern void hvctl_svc_callback(); /* FIXME: in a header */
506
507 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(svc_id), &svc_id)) {
508 /* Not a HV endpoint - skip it */
509 return;
510 }
511
512 DBGHL(c_printf("Configuring HV LDC endpoint\n"));
513 DBGHL(md_dump_node(mdp, hvldc_nodep));
514
515 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(channel), &chid)) {
516 DBG(c_printf("Missing channel id in HV LDC node\n"));
517 c_hvabort();
518 }
519 if (chid >= MAX_HV_LDC_CHANNELS) {
520 DBG(c_printf("Invalid channel id in HV LDC node\n"));
521 c_hvabort();
522 }
523
524 DBGHL(c_printf("\tHV endpoint 0x%x :", chid));
525
526 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_type), &type)) {
527 DBG(c_printf("Missing target_type in HV LDC node\n"));
528 c_hvabort();
529 }
530
531 hvep = config.hv_ldcs;
532 hvep = &(hvep[chid]);
533
534 hvep->channel_idx = chid;
535 hvep->target_type = type;
536
537 switch (type) {
538 case LDC_GUEST_ENDPOINT: /* guest<->HV LDC */
539 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_guest),
540 &guestid)) {
541 DBG(c_printf("Missing target_guest in HV LDC node\n"));
542 c_hvabort();
543 }
544
545 /* point to target guest */
546 hvep->target_guest = &(((guest_t *)config.guests)[guestid]);
547
548 DBGHL(c_printf("\tConnected to guest 0x%x endpoint ", guestid));
549 break;
550
551 case LDC_SP_ENDPOINT: /* HV<->SP LDC */
552 hvep->target_guest = NULL;
553 DBGHL(c_printf("\tConnected to SP endpoint "));
554 break;
555
556 default:
557 DBGHL(c_printf("Illegal target_type 0x%x\n", type));
558 c_hvabort();
559 }
560
561
562 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_channel),
563 &tchan_id)) {
564 DBG(c_printf("Missing target channel id in HV LDC node\n"));
565 c_hvabort();
566 }
567 if (tchan_id >= MAX_LDC_CHANNELS) {
568 DBG(c_printf("Invalid target channel id in HV LDC node\n"));
569 c_hvabort();
570 }
571
572 DBGHL(c_printf("0x%x ", tchan_id));
573
574 hvep->target_channel = tchan_id;
575
576
577 switch (svc_id) {
578 case LDC_HVCTL_SVC:
579 /*
580 * We don't yet allow for HVCTL channel between the
581 * hypervisor and SP. Maybe one day we will have a
582 * Zeus or Zeus-lite running on the SP and at that
583 * point we can remove this check.
584 */
585 if (hvep->target_type == LDC_SP_ENDPOINT) {
586 DBG(c_printf("No HVCTL LDC to the SP allowed yet\n"));
587 c_hvabort();
588 }
589
590 /*
591 * FIXME: Why did we save the endpoint number
592 * instead of a pointer to the endpoint ?
593 */
594 config.hvctl_ldc = chid; /* save the HVCTL channel id */
595
596 hvep->rx_cb = (uint64_t)&hvctl_svc_callback;
597 hvep->rx_cbarg = (uint64_t)&config;
598
599 DBGHL(c_printf(" for HVCTL service\n"));
600 break;
601
602 default:
603 DBGHL(c_printf("Unknown service type 0x%x\n", svc_id));
604 c_hvabort();
605
606 }
607
608 /* Mark channel as live */
609 hvep->is_live = 1;
610}
611
612void
613config_vcpus(void)
614{
615 bin_md_t *mdp;
616 md_element_t *mdep;
617 uint64_t arc_token;
618 uint64_t node_token;
619 md_element_t *cpunodep;
620
621 mdp = (bin_md_t *)config.parse_hvmd;
622
623 DBG(c_printf("\nCPU configuration:\n"));
624
625 mdep = config.cpus_dtnode;
626
627 DBGVCPU(md_dump_node(mdp, mdep));
628
629 arc_token = MDARC(MDNAME(fwd));
630 node_token = MDNODE(MDNAME(cpu));
631
632 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
633 arc_token, node_token, &cpunodep))) {
634 config_a_vcpu(mdp, cpunodep);
635 }
636}
637
638static void
639config_a_vcpu(bin_md_t *mdp, md_element_t *cpunodep)
640{
641 uint64_t resource_id, strand_id, vid, gid, parttag;
642 vcpu_t *vcpup;
643 strand_t *strandp;
644 md_element_t *guestnodep;
645 guest_t *guestp;
646
647 DBGVCPU(md_dump_node(mdp, cpunodep));
648
649 if (!md_node_get_val(mdp, cpunodep, MDNAME(resource_id),
650 &resource_id)) {
651 DBGVCPU(c_printf("Missing resource_id in cpu node\n"));
652 c_hvabort();
653 }
654
655 if (resource_id >= NVCPUS) {
656 DBGVCPU(c_printf("Invalid resource_id in cpu node\n"));
657 c_hvabort();
658 }
659
660 DBGVCPU(c_printf("config_a_vcpu(0x%x)\n", resource_id));
661
662 vcpup = config.vcpus;
663 vcpup = &(vcpup[resource_id]);
664
665 /*
666 * FIXME: rename pid prop to strandid
667 */
668 if (!md_node_get_val(mdp, cpunodep, MDNAME(pid), &strand_id)) {
669 DBGVCPU(c_printf("Missing strandid in cpu node\n"));
670 c_hvabort();
671 }
672
673 if (strand_id >= NSTRANDS) {
674 DBGVCPU(c_printf("Invalid strandid in cpu node\n"));
675 c_hvabort();
676 }
677
678 /*
679 * Assign the vcpu its carrier strand.
680 * Note: this does not schedule the cpu.
681 */
682 strandp = config.strands;
683 strandp = &(strandp[strand_id]);
684
685 vcpup->strand = strandp;
686 vcpup->strand_slot = 0; /* FIXME fixed for the moment */
687
688 /* Get virtual ID within guest */
689 if (!md_node_get_val(mdp, cpunodep, MDNAME(vid), &vid)) {
690 DBGVCPU(c_printf("Missing VID in cpu node\n"));
691 c_hvabort();
692 }
693 vcpup->vid = vid;
694 vcpup->devq_lock = 0;
695
696 if (NULL == md_find_node_by_arc(mdp, cpunodep,
697 MDARC(MDNAME(back)), MDNODE(MDNAME(guest)), &guestnodep)) {
698 DBGVCPU(
699 c_printf("Missing back arc to guest node in cpu node\n"));
700 c_hvabort();
701 }
702
703 if (!md_node_get_val(mdp, guestnodep, MDNAME(resource_id), &gid)) {
704 DBGVCPU(
705 c_printf("WARNING: Missing resource_id in guest node\n"));
706 c_hvabort();
707 }
708
709 if (gid >= NGUESTS) {
710 DBGVCPU(
711 c_printf("WARNING: Invalid resource_id in guest node\n"));
712 c_hvabort();
713 }
714
715 /* Get partid tag for this cpu */
716 if (!md_node_get_val(mdp, cpunodep, MDNAME(parttag), &parttag)) {
717 DBGVCPU(c_printf("WARNING: Missing parttag in cpu node - "
718 "using guest id 0x%x\n", gid));
719 parttag = gid; /* use guest ID if none given */
720 }
721 vcpup->parttag = parttag;
722
723 guestp = config.guests;
724 guestp = &(guestp[gid]);
725
726 guestp->guestid = gid; /* FIXME: This should be done earlier ! */
727 /* Should be an assert ... */
728
729 vcpup->guest = guestp;
730
731 /* reset the utilization yield stats for the VCPU */
732 c_bzero(&vcpup->util, sizeof (vcpup->util));
733
734 guestp->vcpus[vid] = vcpup;
735 DBG(c_printf("XXXX config_a_vcpu(0x%x) gid 0x%x guestp 0x%x \n",
736 resource_id, gid, guestp));
737
738 /*
739 * Assume guest rtba starts at the base of memory
740 * until the guest reconfigures this. The entry point
741 * is computed from this.
742 */
743 vcpup->rtba = guestp->real_base;
744
745 /* Assert the legacy entry point had better be the same */
746 ASSERT(guestp->entry == guestp->real_base);
747
748 DBGVCPU(c_printf("Virtual cpu 0x%x in guest 0x%x (pid 0x%x) "
749 "entry @ 0x%x rtba @ 0x%x\n",
750 vcpup->res_id, vcpup->guest->guestid, vcpup->vid,
751 guestp->entry, vcpup->rtba));
752
753
754 /*
755 * Reset the basic sun4v cpu state.
756 * FIXME: should be done by the strand as the CPU is started?
757 */
758
759 /*
760 * Guests entry point should be at the power on
761 * vector of the rtba - at least for the boot cpu.
762 */
763 vcpup->start_pc = vcpup->rtba + TT_POR*TRAPTABLE_ENTRY_SIZE;
764
765 reset_vcpu_state(vcpup);
766
767 /*
768 * check to see if the strand the VCPU is bound
769 * to is in active state, if not mark the VCPU
770 * in error
771 */
772 if (config.strand_active & (1LL<<strand_id)) {
773 vcpup->status = CPU_STATE_STOPPED;
774 } else {
775 vcpup->status = CPU_STATE_ERROR;
776 }
777}
778
779/*
780 * This function configures the basic saved state of a sun4v cpu - ready
781 * to be resurrected onto a strand for execution.
782 */
783void
784reset_vcpu_state(vcpu_t *vp)
785{
786 vcpustate_t *vsp;
787 int i;
788
789 /*
790 * Initialise the remainder of the vCPU struct
791 */
792
793 vp->mmu_area = 0LL;
794 vp->mmu_area_ra = 0LL;
795 vp->root = &config; /* FIXME: need this ? */
796
797 vsp = &(vp->state_save_area);
798
799 vp->launch_with_retry = false; /* enter guest with done */
800
801 /*
802 * Everything is null unless we configure it
803 * otherwise.
804 */
805 c_bzero(vsp, sizeof (*vsp));
806
807 /*
808 * We are going to return with a done or a retry
809 * so we setup with the tl & gl at the level above.
810 */
811 vsp->tl = MAXPTL +1;
812
813#define INITIAL_PSTATE ((uint64_t)(PSTATE_PRIV | PSTATE_MM_TSO))
814#define INITIAL_TSTATE(_x) ((INITIAL_PSTATE << TSTATE_PSTATE_SHIFT) | \
815 (((uint64_t)(_x)) << TSTATE_GL_SHIFT))
816#define INITIAL_HTSTATE(_x) (0)
817
818
819 /*
820 * We store the trapstack off by 1, so trapstack[0]
821 * corresponds to the trapstack registers when tl=1 etc.
822 */
823 for (i = 0; i < vsp->tl; i++) {
824 vsp->trapstack[i].htstate = INITIAL_HTSTATE(i);
825 vsp->trapstack[i].tstate = INITIAL_TSTATE(i);
826 vsp->trapstack[i].tpc = 0;
827 vsp->trapstack[i].tnpc = vp->start_pc;
828 vsp->trapstack[i].tt = 0;
829 }
830
831 vsp->gl = vsp->tl;
832
833 vsp->pil = PIL_15;
834
835 vsp->cansave = NWINDOWS - 2;
836 vsp->cleanwin = NWINDOWS - 2;
837
838 vp->ntsbs_ctx0 = 0;
839 vp->ntsbs_ctxn = 0;
840
841 vp->mmustat_area = 0;
842 vp->mmustat_area_ra = 0;
843
844 vp->ttrace_buf_size = 0;
845 vp->ttrace_buf_ra = 0;
846
847 vp->mmu_area = 0;
848 vp->mmu_area_ra = 0;
849
850 vp->cpuq_size = 0;
851 vp->cpuq_base_ra = 0;
852 vp->devq_size = 0;
853 vp->devq_base_ra = 0;
854 vp->errqr_size = 0;
855 vp->errqr_base_ra = 0;
856 vp->errqnr_size = 0;
857 vp->errqnr_base_ra = 0;
858
859 /* clear out the vcpu mailbox */
860 vp->command = CPU_CMD_READY;
861}
862
863#ifdef CONFIG_FPGA
864void
865config_sp_ldcs(void)
866{
867 md_element_t *spldc_nodep, *mdep;
868 uint64_t arc_token, node_token;
869 bin_md_t *mdp;
870
871 mdp = (bin_md_t *)config.parse_hvmd;
872
873 DBG(c_printf("config_sp_ldcs()\n"));
874
875 mdep = config.hv_ldcs_dtnode;
876 if (mdep == NULL) {
877 DBG(c_printf("No LDC enpoints node - nothing to do\n"));
878 return;
879 }
880
881 DBG(md_dump_node(mdp, mdep));
882
883 arc_token = MDARC(MDNAME(fwd));
884 node_token = MDNODE(MDNAME(ldc_endpoint));
885
886 /*
887 * Spin through the "ldc_endpoint" arcs in the
888 * ldc_endpoints node and config each endpoint !
889 * FIXME; what if already configured !
890 */
891 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
892 arc_token, node_token, &spldc_nodep))) {
893
894 config_a_spldc(mdp, spldc_nodep);
895 }
896}
897
898/*
899 * The domain manager does not have any information about the internal
900 * implementation of the SP LDCs, and specifically where they are
901 * located in SRAM. This requires a mechanism for the SP to inform
902 * the HV of the LDC SRAM queue details. Until we have this, the data
903 * will reside in this table.
904 */
905#ifdef CONFIG_SPLIT_SRAM_ERRATUM
906static sp_ldc_sram_ptrs_t sp_ldc_sram_data[MAX_SP_LDC_CHANNELS] = {
907 {0xfff0e04320, 0xfff0e00460, 4, 0xfff0e04361, 0xfff0e019a0, 4},
908 {0xfff0e04325, 0xfff0e005a0, 4, 0xfff0e04366, 0xfff0e01ae0, 4},
909 {0xfff0e0432a, 0xfff0e006e0, 4, 0xfff0e0436b, 0xfff0e01c20, 4},
910 {0xfff0e0432f, 0xfff0e00820, 4, 0xfff0e04370, 0xfff0e01d60, 4},
911 {0xfff0e04334, 0xfff0e00960, 4, 0xfff0e04375, 0xfff0e01ea0, 4},
912 {0xfff0e04339, 0xfff0e00aa0, 4, 0xfff0e0437a, 0xfff0e01fe0, 4},
913 {0xfff0e0433e, 0xfff0e00be0, 4, 0xfff0e0437f, 0xfff0e02120, 4},
914 {0xfff0e04343, 0xfff0e00d20, 4, 0xfff0e04384, 0xfff0e02260, 4},
915 {0xfff0e04348, 0xfff0e00e60, 4, 0xfff0e04389, 0xfff0e023a0, 4},
916 {0, 0, 0, 0, 0, 0},
917 {0, 0, 0, 0, 0, 0},
918 {0xfff0e04357, 0xfff0e01220, 4, 0xfff0e04398, 0xfff0e02760, 4},
919 {0xfff0e0435c, 0xfff0e01360, 4, 0xfff0e0439d, 0xfff0e028a0, 4},
920 {0, 0, 0, 0, 0, 0}
921};
922#endif
923
924static void
925config_a_spldc(bin_md_t *mdp, md_element_t *spldc_nodep)
926{
927 uint64_t chid;
928 uint64_t type, scr;
929 uint64_t guestid;
930 uint64_t tchan_id;
931 sp_ldc_endpoint_t *spep;
932#if defined(CONFIG_SPLIT_SRAM) && !defined(CONFIG_SPLIT_SRAM_ERRATUM)
933 uint64_t val;
934 md_element_t *ptrs_node;
935#endif
936
937 if (md_node_get_val(mdp, spldc_nodep, MDNAME(svc_id), &scr)) {
938 /* Not a SP endpoint - skip it */
939 return;
940 }
941 if (md_node_get_val(mdp, spldc_nodep, MDNAME(tx_ino), &scr)) {
942 /* Not a SP endpoint - skip it */
943 return;
944 }
945
946 DBGL(c_printf("Configuring SP LDC endpoint\n"));
947 DBGL(md_dump_node(mdp, spldc_nodep));
948
949 if (!md_node_get_val(mdp, spldc_nodep, MDNAME(channel), &chid)) {
950 DBG(c_printf("Missing channel id in SP LDC node\n"));
951 c_hvabort();
952 }
953
954 if (chid > config.sp_ldc_max_cid)
955 config.sp_ldc_max_cid = chid;
956
957 if (chid >= MAX_SP_LDC_CHANNELS) {
958 DBG(c_printf("Invalid channel id in SP LDC node\n"));
959 c_hvabort();
960 }
961
962 DBGL(c_printf("\tSP endpoint 0x%x :", chid));
963
964 if (!md_node_get_val(mdp, spldc_nodep, MDNAME(target_type), &type)) {
965 DBG(c_printf("Missing target_type in SP LDC node\n"));
966 c_hvabort();
967 }
968
969 spep = config.sp_ldcs;
970 spep = &(spep[chid]);
971 spep->target_type = type;
972
973 spep->channel_idx = chid;
974#ifdef CONFIG_SPLIT_SRAM
975
976#ifdef CONFIG_SPLIT_SRAM_ERRATUM
977 spep->tx_qd_pa = (sram_ldc_qd_t *)sp_ldc_sram_data[chid].inq_offset;
978 spep->tx_q_data_pa = (sram_ldc_q_data_t *)
979 sp_ldc_sram_data[chid].inq_data_offset;
980 spep->rx_qd_pa = (sram_ldc_qd_t *)sp_ldc_sram_data[chid].outq_offset;
981 spep->rx_q_data_pa = (sram_ldc_q_data_t *)
982 sp_ldc_sram_data[chid].outq_data_offset;
983#else
984 if (!md_find_node_by_arc(mdp, spldc_nodep, MDARC(MDNAME(fwd)),
985 MDNODE(MDNAME(sram_ptrs)), &ptrs_node)) {
986 DBG(c_printf("Missing sram_ptrs arc in SP LDC node\n"));
987 c_hvabort();
988 }
989 DBGL(md_dump_node(mdp, ptrs_node));
990
991 if (!md_node_get_val(mdp, ptrs_node, MDNAME(inq_offset), &val)) {
992 DBG(c_printf("Missing inq_offset in sram_ptrs node\n"));
993 c_hvabort();
994 }
995 spep->tx_qd_pa = (sram_ldc_qd_t *)val;
996
997 if (!md_node_get_val(mdp, ptrs_node, MDNAME(inq_data_offset), &val)) {
998 DBG(c_printf("Missing inq_data_offset in sram_ptrs node\n"));
999 c_hvabort();
1000 }
1001 spep->tx_q_data_pa = (sram_ldc_q_data_t *)val;
1002
1003 if (!md_node_get_val(mdp, ptrs_node, MDNAME(inq_num_pkts), &val)) {
1004 DBG(c_printf("Missing inq_num_pkts in sram_ptrs node\n"));
1005 c_hvabort();
1006 }
1007 /* FIXME: set num_pkts */
1008
1009 if (!md_node_get_val(mdp, ptrs_node, MDNAME(outq_offset), &val)) {
1010 DBG(c_printf("Missing outq_offset in sram_ptrs node\n"));
1011 c_hvabort();
1012 }
1013 spep->rx_qd_pa = (sram_ldc_qd_t *)val;
1014
1015 if (!md_node_get_val(mdp, ptrs_node, MDNAME(outq_data_offset), &val)) {
1016 DBG(c_printf("Missing outq_data_offset in sram_ptrs node\n"));
1017 c_hvabort();
1018 }
1019 spep->rx_q_data_pa = (sram_ldc_q_data_t *)val;
1020
1021 if (!md_node_get_val(mdp, ptrs_node, MDNAME(outq_num_pkts), &val)) {
1022 DBG(c_printf("Missing outq_num_pkts in sram_ptrs node\n"));
1023 c_hvabort();
1024 }
1025 /* FIXME: set num_pkts */
1026
1027#endif /* !CONFIG_SPLIT_SRAM_ERRATUM */
1028
1029#else /* !CONFIG_SPLIT_SRAM */
1030
1031 spep->tx_qd_pa = (sram_ldc_qd_t *)((SRAM_LDC_QD_SIZE * chid) +
1032 LDC_SRAM_CHANNEL_TXBASE);
1033 spep->rx_qd_pa = (sram_ldc_qd_t *)((SRAM_LDC_QD_SIZE * chid) +
1034 LDC_SRAM_CHANNEL_RXBASE);
1035
1036#endif /* CONFIG_SPLIT_SRAM */
1037
1038 switch (type) {
1039 case LDC_GUEST_ENDPOINT: /* guest<->SP LDC */
1040 if (!md_node_get_val(mdp, spldc_nodep, MDNAME(target_guest),
1041 &guestid)) {
1042 DBG(c_printf("Missing target_guest in SP LDC node\n"));
1043 c_hvabort();
1044 }
1045
1046 /* point to target guest */
1047 spep->target_guest = &(((guest_t *)config.guests)[guestid]);
1048
1049 DBGL(c_printf("\tConnected to guest 0x%x endpoint ", guestid));
1050 break;
1051
1052 case LDC_HV_ENDPOINT: /* HV<->SP LDC */
1053 /* Mark link status in SRAM as UP for SP<->HV channels */
1054 ((struct sram_ldc_qd *)spep->rx_qd_pa)->state = 1;
1055 DBGL(c_printf("\tConnected to HV endpoint "));
1056 break;
1057
1058 default:
1059 DBG(c_printf("Illegal target_type 0x%x\n", type));
1060 c_hvabort();
1061 }
1062
1063
1064 if (!md_node_get_val(mdp, spldc_nodep, MDNAME(target_channel),
1065 &tchan_id)) {
1066 DBG(c_printf("Missing target channel id in SP LDC node\n"));
1067 c_hvabort();
1068 }
1069
1070 if (tchan_id >= MAX_LDC_CHANNELS) {
1071 DBG(c_printf("Invalid target channel id in SP LDC node\n"));
1072 c_hvabort();
1073 }
1074
1075 DBGL(c_printf("0x%x ", tchan_id));
1076
1077 spep->target_channel = tchan_id;
1078
1079 spep->tx_lock = 0;
1080 spep->rx_lock = 0;
1081
1082 /* Zero out remainder of struct */
1083 spep->tx_scr_txhead = 0;
1084 spep->tx_scr_txtail = 0;
1085 spep->tx_scr_txsize = 0;
1086 spep->tx_scr_tx_qpa = 0;
1087 spep->tx_scr_rxhead = 0;
1088 spep->tx_scr_rxtail = 0;
1089 spep->tx_scr_rxsize = 0;
1090 spep->tx_scr_rx_qpa = 0;
1091 spep->tx_scr_target = 0;
1092
1093 spep->rx_scr_txhead = 0;
1094 spep->rx_scr_txtail = 0;
1095 spep->rx_scr_txsize = 0;
1096 spep->rx_scr_tx_qpa = 0;
1097 spep->rx_scr_rxhead = 0;
1098 spep->rx_scr_rxtail = 0;
1099 spep->rx_scr_rxsize = 0;
1100 spep->rx_scr_rx_qpa = 0;
1101 spep->rx_scr_target = 0;
1102
1103 /* Mark channel as live */
1104 spep->is_live = 1;
1105}
1106#endif
1107
1108void
1109config_guests(void)
1110{
1111 bin_md_t *mdp;
1112 md_element_t *mdep;
1113 uint64_t arc_token;
1114 uint64_t node_token;
1115 md_element_t *guest_nodep;
1116
1117 mdp = (bin_md_t *)config.parse_hvmd;
1118
1119 DBGG(c_printf("\nGuest configuration:\n"));
1120
1121 mdep = config.guests_dtnode;
1122
1123 DBGG(md_dump_node(mdp, mdep));
1124
1125 arc_token = MDARC(MDNAME(fwd));
1126 node_token = MDNODE(MDNAME(guest));
1127
1128 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep,
1129 arc_token, node_token, &guest_nodep))) {
1130 config_a_guest(mdp, guest_nodep);
1131 }
1132}
1133
1134static void
1135config_a_guest(bin_md_t *mdp, md_element_t *guest_nodep)
1136{
1137 uint64_t guest_id, ino, base_memsize;
1138 guest_t *guestp;
1139 int x;
1140 md_element_t *snet_nodep;
1141 uint64_t snet_ino;
1142 uint64_t snet_pa;
1143 md_element_t *devices_nodep;
1144 md_element_t *mblock_nodep;
1145 md_element_t *services_nodep;
1146 md_element_t *svc_nodep;
1147 uint64_t arc_token;
1148 uint64_t node_token;
1149 uint64_t cfg_handle;
1150 md_element_t *elemp;
1151 md_element_t *base_mblock;
1152
1153 DBGG(md_dump_node(mdp, guest_nodep));
1154
1155 if (!md_node_get_val(mdp, guest_nodep, MDNAME(resource_id),
1156 &guest_id)) {
1157 DBGG(c_printf("Missing resource_id in guest node\n"));
1158 c_hvabort();
1159 }
1160 if (guest_id >= NGUESTS) {
1161 DBGG(c_printf("Invalid resource_id in guest node\n"));
1162 c_hvabort();
1163 }
1164
1165 guestp = config.guests;
1166 guestp = &(guestp[guest_id]);
1167
1168 DBGG(c_printf("Guest 0x%x @ 0x%x\n", guest_id, (uint64_t)guestp));
1169
1170 /* init stuff necessary first time we touch a guest */
1171
1172 if (guestp->state == GUEST_STATE_UNCONFIGURED) {
1173
1174 reset_api_hcall_table(guestp);
1175 DBGG(c_printf("\tguest hcall table @ 0x%x\n",
1176 guestp->hcall_table));
1177
1178 reset_guest_perm_mappings(guestp);
1179
1180 reset_guest_ldc_mapins(guestp);
1181
1182 /* until we boot it ... */
1183 guestp->state = GUEST_STATE_STOPPED;
1184 }
1185
1186
1187 /*
1188 * Now fill in basic properties for this guest ...
1189 *
1190 * FIXME: These should be available is the guest is
1191 * live yes ?
1192 */
1193
1194#define GET_PROPERTY(_g_val, _mdp, _guest_nodep, _md_name) \
1195 do { \
1196 uint64_t _x; \
1197 if (!md_node_get_val(_mdp, _guest_nodep, \
1198 MDNAME(_md_name), &_x)) { \
1199 DBGG(c_printf("Missing "#_md_name " in " \
1200 "guest node\n")); \
1201 c_hvabort(); \
1202 } \
1203 _g_val = _x; \
1204 } while (0)
1205
1206 GET_PROPERTY(guestp->rom_base, mdp, guest_nodep, rombase);
1207 GET_PROPERTY(guestp->rom_size, mdp, guest_nodep, romsize);
1208
1209 /*
1210 * Assume entry point is at base of real memory.
1211 * Search all guest mblocks for lowest real memory address.
1212 */
1213 guestp->real_base = UINT64_MAX;
1214
1215 arc_token = MDARC(MDNAME(fwd));
1216 node_token = MDNODE(MDNAME(mblock));
1217
1218 base_mblock = NULL;
1219 elemp = guest_nodep;
1220
1221 while (NULL != (elemp = md_find_node_by_arc(mdp, elemp,
1222 arc_token, node_token, &mblock_nodep))) {
1223 uint64_t realbase, membase;
1224 if (!md_node_get_val(mdp, mblock_nodep, MDNAME(realbase),
1225 &realbase)) {
1226 DBG(c_printf("Missing realbase in mblock node\n"));
1227 c_hvabort();
1228 }
1229
1230 /*
1231 * Initialise guest real_base, real_limit and mem_offset
1232 * Note: real_limit/mem_offset are required for N2 MMu HWTW
1233 * FIXME: real_limit will not work for segmented memory
1234 */
1235 if (realbase < guestp->real_base) {
1236 guestp->real_base = realbase;
1237 base_mblock = mblock_nodep;
1238 if (!md_node_get_val(mdp, mblock_nodep, MDNAME(membase),
1239 &membase)) {
1240 membase = guestp->real_base;
1241 }
1242 guestp->mem_offset = membase - guestp->real_base;
1243 }
1244 if (!md_node_get_val(mdp, base_mblock, MDNAME(memsize),
1245 &base_memsize)) {
1246 base_memsize = 0;
1247 }
1248 if (guestp->real_limit < (realbase + base_memsize))
1249 guestp->real_limit = (realbase + base_memsize);
1250 }
1251
1252 DBG(c_printf("REAL BASE 0x%x LIMIT 0x%x MEM_OFFSET 0x%x\r\n",
1253 guestp->real_base, guestp->real_limit, guestp->mem_offset));
1254
1255 if (base_mblock == NULL) {
1256 DBG(c_printf("Missing mblock node in guest node\n"));
1257 c_hvabort();
1258 }
1259
1260 if (!md_node_get_val(mdp, base_mblock, MDNAME(memsize),
1261 &base_memsize)) {
1262 DBG(c_printf(
1263 "Missing memsize in mblock node\n"));
1264 c_hvabort();
1265 }
1266
1267 if (guestp->rom_size > base_memsize) {
1268 DBG(c_printf("ROM image does not fit in base guest mblock\n"));
1269 c_hvabort(-1);
1270 }
1271
1272 GET_PROPERTY(guestp->md_pa, mdp, guest_nodep, mdpa);
1273
1274#undef GET_PROPERTY
1275
1276#ifdef CONFIG_DISK
1277 guestp->disk.size = 0LL;
1278 if (!md_node_get_val(mdp, guest_nodep, MDNAME(diskpa),
1279 &guestp->disk.pa)) {
1280 guestp->disk.pa = -1LL;
1281 }
1282#endif
1283
1284 /*
1285 * Assume entry point is at base of real memory
1286 */
1287 guestp->entry = guestp->real_base;
1288
1289 /*
1290 * Compute the Guests MD size
1291 */
1292 config_guest_md(guestp);
1293
1294 /*
1295 * Check for a reset-reason property
1296 *
1297 * FIXME: How sensible is this in an LDoms world?
1298 * This is fine unless master start gets called somehow as
1299 * part of the guest reconfig - so dont do that unless
1300 * you really mean it !
1301 *
1302 * FIXME: Again - why re-do if guest configured already
1303 */
1304 if (!md_node_get_val(mdp, guest_nodep, MDNAME(reset_reason),
1305 &guestp->reset_reason)) {
1306 guestp->reset_reason = RESET_REASON_POR;
1307 }
1308
1309 /* FIXME: Map in range should be done another way */
1310 if (!md_node_get_val(mdp, guest_nodep, MDNAME(ldc_mapinrabase),
1311 &guestp->ldc_mapin_basera) ||
1312 !md_node_get_val(mdp, guest_nodep, MDNAME(ldc_mapinsize),
1313 &guestp->ldc_mapin_size)) {
1314 guestp->ldc_mapin_basera = LDC_MAPIN_BASERA;
1315 DBGG(c_printf("WARNING: default mapinrbase 0x%x selected\n",
1316 guestp->ldc_mapin_basera));
1317 guestp->ldc_mapin_size = LDC_MAPIN_RASIZE;
1318 DBGG(c_printf("WARNING: default mapinrsize 0x%x selected\n",
1319 guestp->ldc_mapin_size));
1320 }
1321
1322 /*
1323 * Look for the "perfctraccess" property. This property
1324 * must be present and set to a non-zero value for the
1325 * guest to have access to the JBUS/DRAM perf counters
1326 */
1327 if (!md_node_get_val(mdp, guest_nodep, MDNAME(perfctraccess),
1328 &guestp->perfreg_accessible)) {
1329 guestp->perfreg_accessible = 0;
1330 }
1331
1332 /*
1333 * Look for "diagpriv" property. This property enables
1334 * the guest to execute arbitrary hyperprivileged code.
1335 */
1336 if (!md_node_get_val(mdp, guest_nodep, MDNAME(diagpriv),
1337 &guestp->diagpriv)) {
1338#ifdef CONFIG_BRINGUP
1339 guestp->diagpriv = -1;
1340#else
1341 guestp->diagpriv = 0;
1342#endif
1343 }
1344
1345 /*
1346 * Look for "rngctlaccessible" property. This property enables
1347 * the guest to access the N2 RNG if available.
1348 */
1349 if (!md_node_get_val(mdp, guest_nodep, MDNAME(rngctlaccessible),
1350 &guestp->rng_ctl_accessible)) {
1351 guestp->rng_ctl_accessible = 0;
1352 }
1353
1354 /*
1355 * Look for "perfctrhtaccess" property. This property enables
1356 * the guest to access the N2 hyper-privileged events if available.
1357 */
1358 if (!md_node_get_val(mdp, guest_nodep, MDNAME(perfctrhtaccess),
1359 &guestp->perfreght_accessible)) {
1360 guestp->perfreght_accessible = 0;
1361 }
1362
1363 /*
1364 * Per guest TOD offset ...
1365 * FIXME: what if already live !
1366 */
1367 if (!md_node_get_val(mdp, guest_nodep, MDNAME(todoffset),
1368 &guestp->tod_offset)) {
1369 guestp->tod_offset = 0;
1370 }
1371
1372 /*
1373 * Now look for the guest devices ...
1374 * FIXME: Needs updating so devices can be DR'd in.
1375 */
1376 /*
1377 * Configure vino2inst and dev2inst by marking the entries reserved.
1378 * These will be filled from the MD properties later.
1379 */
1380 for (x = 0; x < NVINOS; x++) {
1381 guestp->vino2inst.vino[x] = DEVOPS_RESERVED;
1382 }
1383
1384 for (x = 0; x < NDEVIDS; x++) {
1385 guestp->dev2inst[x] = DEVOPS_RESERVED;
1386 }
1387
1388 DBG(c_printf("Setup guest devices\n"));
1389
1390 if (NULL != md_find_node_by_arc(mdp, guest_nodep, MDARC(MDNAME(fwd)),
1391 MDNODE(MDNAME(virtual_devices)), &devices_nodep)) {
1392 if (!md_node_get_val(mdp, devices_nodep, MDNAME(cfghandle),
1393 &cfg_handle)) {
1394 DBG(c_printf("Missing cfg_handle in device node\n"));
1395 c_hvabort();
1396 }
1397 config_guest_virtual_device(guestp, cfg_handle);
1398 } else {
1399 c_hvabort();
1400 }
1401
1402 if (NULL != md_find_node_by_arc(mdp, guest_nodep, MDARC(MDNAME(fwd)),
1403 MDNODE(MDNAME(channel_devices)), &devices_nodep)) {
1404 if (!md_node_get_val(mdp, devices_nodep, MDNAME(cfghandle),
1405 &cfg_handle)) {
1406 DBG(c_printf("Missing cfg_handle in device node\n"));
1407 c_hvabort();
1408 }
1409 config_guest_channel_device(guestp, cfg_handle);
1410 } else {
1411 c_hvabort();
1412 }
1413
1414#ifdef T1_FPGA_SNET
1415 if (NULL != md_find_node_by_arc(mdp, guest_nodep, MDARC(MDNAME(fwd)),
1416 MDNODE(MDNAME(snet)), &snet_nodep)) {
1417 if (!md_node_get_val(mdp, snet_nodep, MDNAME(snet_ino),
1418 &snet_ino)) {
1419 DBG(c_printf("Missing ino in snet node\n"));
1420 c_hvabort();
1421 }
1422 if (!md_node_get_val(mdp, snet_nodep, MDNAME(snet_pa),
1423 &snet_pa)) {
1424 DBG(c_printf("Missing pa in snet node\n"));
1425 c_hvabort();
1426 }
1427 config_a_guest_device_vino(guestp, snet_ino, DEVOPS_VDEV);
1428 guestp->snet.ino = snet_ino;
1429 guestp->snet.pa = snet_pa;
1430 }
1431#endif /* ifdef T1_FPGA_SNET */
1432
1433
1434#ifdef CONFIG_SVC
1435 /*
1436 * Find and setup svc channels for the guest.
1437 * we only enable the vinos here.
1438 */
1439 if (md_find_node_by_arc(mdp, guest_nodep,
1440 MDARC(MDNAME(services)), MDNODE(MDNAME(services)),
1441 &services_nodep) != NULL) {
1442
1443 arc_token = MDARC(MDNAME(service));
1444 node_token = MDNODE(MDNAME(service));
1445
1446 while (NULL != (services_nodep = md_find_node_by_arc(mdp,
1447 services_nodep, arc_token, node_token, &svc_nodep))) {
1448 if (!md_node_get_val(mdp, svc_nodep,
1449 MDNAME(ino), &ino)) {
1450 DBG(c_printf("Missing ino in service node\n"));
1451 c_hvabort(-1);
1452 }
1453 DBG(c_printf("Configuring service node 0x%x\n", ino));
1454 config_a_guest_device_vino(guestp, ino, DEVOPS_VDEV);
1455 }
1456 }
1457
1458#endif /* CONFIG_SVC */
1459
1460
1461 DBGG(c_printf("Initialize guest.ldc_endpoints\n"));
1462 /*
1463 * NOTE: we may bump this value as a side-effect of
1464 * adding new channels with config_a_guest_ldc_endpoint
1465 *
1466 * FIXME: Should we really care to track this - why not
1467 * just use the constant; MAX_LDC_CHANNELS
1468 */
1469 /* guestp->ldc_max_channel_idx = 0LL; */
1470 guestp->ldc_max_channel_idx = MAX_LDC_CHANNELS;
1471
1472 {
1473 md_element_t *ldce_nodep, *elemp;
1474 uint64_t arc_token;
1475 uint64_t node_token;
1476
1477 arc_token = MDARC(MDNAME(fwd));
1478 node_token = MDNODE(MDNAME(ldc_endpoint));
1479
1480 /*
1481 * Spin through the "ldc_endpoint" arcs in the
1482 * ldc_endpoints node and config each endpoint !
1483 * FIXME; what if already configured !
1484 */
1485
1486 elemp = guest_nodep;
1487 while (NULL != (elemp = md_find_node_by_arc(mdp, elemp,
1488 arc_token, node_token, &ldce_nodep))) {
1489 config_a_guest_ldc_endpoint(guestp, mdp, ldce_nodep);
1490 }
1491 }
1492
1493 /* Now figure out what kind of console this guest has */
1494
1495 /*
1496 * GAH FIXME:
1497 * Console type seems to be set as a side effect of
1498 * setting up the service or LDC channels .. not
1499 * during guest initialization. This needs to seriously
1500 * get fixed.
1501 */
1502
1503 DBGG(c_printf("End of guest setup\n"));
1504}
1505
1506/*
1507 * Based on the header info, compute the size of the
1508 * guests MD.
1509 */
1510void
1511config_guest_md(guest_t *guestp)
1512{
1513 bin_md_t *gmdp;
1514
1515 gmdp = (bin_md_t *)guestp->md_pa;
1516
1517 /*
1518 * Make sure we can handle the version ...
1519 * FIXME:
1520 * This is not really an abort scenario, the guest
1521 * might be able to handle this - we just dont know how
1522 * big it is ..
1523 */
1524 if (TR_MAJOR(ntoh32(gmdp->hdr.transport_version)) !=
1525 TR_MAJOR(MD_TRANSPORT_VERSION)) {
1526 DBG(c_printf("Guest MD major version mismatch\n"));
1527 c_hvabort();
1528 }
1529
1530 guestp->md_size = sizeof (gmdp->hdr) + ntoh32(gmdp->hdr.node_blk_sz) +
1531 ntoh32(gmdp->hdr.name_blk_sz) + ntoh32(gmdp->hdr.data_blk_sz);
1532}
1533
1534/*
1535 * Configure a guest's LDC endpoint.
1536 */
1537static void
1538config_a_guest_ldc_endpoint(guest_t *guestp, bin_md_t *mdp,
1539 md_element_t *ldce_nodep)
1540{
1541 uint64_t endpt_id;
1542 ldc_endpoint_t *ldc_ep;
1543 uint64_t target_type;
1544 uint64_t target_channel;
1545 uint64_t tx_ino;
1546 uint64_t rx_ino;
1547 uint64_t pvt_svc;
1548
1549 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(channel),
1550 &endpt_id)) {
1551 DBG(c_printf("Missing channel (endpoint number) in "
1552 "ldc_endpoint node\n"));
1553 c_hvabort();
1554 }
1555 ASSERT(endpt_id < MAX_LDC_CHANNELS);
1556
1557 DBG(c_printf("\tHas LDC endpoint 0x%x", endpt_id));
1558
1559 /*
1560 * NOTE; endpoint id may push up the max ID of the guests
1561 * channels. FIXME: isn't it better to remove this.
1562 */
1563 if (endpt_id >= guestp->ldc_max_channel_idx)
1564 guestp->ldc_max_channel_idx = endpt_id + 1LL;
1565
1566 ldc_ep = &(guestp->ldc_endpoint[endpt_id]);
1567
1568 /*
1569 * Bail out if the endpoint is already alive.
1570 */
1571 if (ldc_ep->is_live) {
1572 DBG(c_printf("\n\t\tAlready configured\n"));
1573 return;
1574 }
1575
1576 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_type),
1577 &target_type)) {
1578 DBG(c_printf("Missing target_type in ldc_endpoint node\n"));
1579 c_hvabort();
1580 }
1581 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_channel),
1582 &target_channel)) {
1583 DBG(c_printf("Missing target_channel in ldc_endpoint node\n"));
1584 c_hvabort();
1585 }
1586
1587 ldc_ep->target_type = target_type;
1588 ldc_ep->target_channel = target_channel;
1589
1590 switch (target_type) {
1591 uint64_t target_guest_id;
1592 guest_t *target_guestp;
1593 case LDC_HV_ENDPOINT:
1594 DBG(c_printf("\t\tConnected to HV endpoint 0x%x",
1595 target_channel));
1596 /* nothing more to do */
1597 break;
1598
1599 case LDC_GUEST_ENDPOINT:
1600 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_guest),
1601 &target_guest_id)) {
1602 DBG(c_printf("Missing target_guest in ldc_endpoint "
1603 "node\n"));
1604 c_hvabort();
1605 }
1606
1607 DBG(c_printf("\t\tConnected to guest 0x%x endpoint 0x%x",
1608 target_guest_id, target_channel));
1609
1610 target_guestp = config.guests;
1611 target_guestp = &(target_guestp[target_guest_id]);
1612 ldc_ep->target_guest = target_guestp;
1613 break;
1614
1615#ifdef CONFIG_FPGA
1616 case LDC_SP_ENDPOINT:
1617 DBG(c_printf("\t\tConnected to SP endpoint 0x%x",
1618 target_channel));
1619 break;
1620#endif
1621
1622 default:
1623 DBG(c_printf("Invalid target_type in ldc-endpoint node\n"));
1624 c_hvabort();
1625 }
1626
1627 if (md_node_get_val(mdp, ldce_nodep, MDNAME(private_svc), &pvt_svc)) {
1628
1629 ldc_ep->is_private = 1;
1630 ldc_ep->svc_id = pvt_svc;
1631
1632 switch (ldc_ep->svc_id) {
1633 case LDC_CONSOLE_SVC:
1634 break;
1635
1636 default:
1637 DBG(c_printf("Invalid private service type\n"));
1638 c_hvabort();
1639 }
1640
1641 } else {
1642 ldc_ep->is_private = 0;
1643
1644 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(tx_ino),
1645 &tx_ino)) {
1646 DBG(c_printf("Missing tx_ino in ldc_endpoint node\n"));
1647 c_hvabort();
1648 }
1649 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(rx_ino),
1650 &rx_ino)) {
1651 DBG(c_printf("Missing rx_ino in ldc_endpoint node\n"));
1652 c_hvabort();
1653 }
1654
1655 DBG(c_printf(" tx-ino 0x%x rx-ino 0x%x\n", tx_ino, rx_ino));
1656
1657 ldc_ep->tx_mapreg.ino = tx_ino;
1658 guestp->ldc_ino2endpoint[tx_ino].endpointp = ldc_ep;
1659 guestp->ldc_ino2endpoint[tx_ino].mapregp = &(ldc_ep->tx_mapreg);
1660
1661 config_a_guest_device_vino(guestp, tx_ino, DEVOPS_CDEV);
1662
1663 ldc_ep->rx_mapreg.ino = rx_ino;
1664 guestp->ldc_ino2endpoint[rx_ino].endpointp = ldc_ep;
1665 guestp->ldc_ino2endpoint[rx_ino].mapregp = &(ldc_ep->rx_mapreg);
1666
1667 config_a_guest_device_vino(guestp, rx_ino, DEVOPS_CDEV);
1668
1669 ldc_ep->tx_qbase_pa = 0;
1670 ldc_ep->tx_qsize = 0;
1671 ldc_ep->rx_qbase_pa = 0;
1672 ldc_ep->rx_qsize = 0;
1673 }
1674 /*
1675 * Configure remaining endpoint fields
1676 */
1677 ldc_ep->tx_qbase_ra = 0;
1678 ldc_ep->tx_qhead = 0;
1679 ldc_ep->tx_qtail = 0;
1680
1681 ldc_ep->rx_qbase_ra = 0;
1682 ldc_ep->rx_qhead = 0;
1683 ldc_ep->rx_qtail = 0;
1684
1685 ldc_ep->is_live = 1;
1686}
1687
1688/*
1689 * This code initializes a guest's LDC mapin structure.
1690 * We assume the guest is not in use during this time,
1691 * so the init code does not have to operate atomically.
1692 */
1693void
1694reset_guest_ldc_mapins(guest_t *guestp)
1695{
1696 int i;
1697
1698 DBG(c_printf("\tinit guest ldc mapin entries\n"));
1699
1700 guestp->ldc_mapin_free_idx = -1ULL;
1701
1702 for (i = LDC_NUM_MAPINS-1; i >= 0; i--) {
1703 guestp->ldc_mapin[i].perms = 0;
1704 guestp->ldc_mapin[i].ldc_mapin_next_idx =
1705 guestp->ldc_mapin_free_idx;
1706 guestp->ldc_mapin_free_idx = i;
1707 }
1708}
1709
1710/*
1711 * Initialize the API call table for a newly created guest
1712 */
1713void
1714reset_api_hcall_table(guest_t *guestp)
1715{
1716 uint64_t addr;
1717 int i;
1718 uint64_t *api_entryp;
1719 extern uint64_t hcall_tables[]; /* FIXME */
1720 extern void herr_badtrap();
1721 uint64_t fcn;
1722
1723 fcn = (uint64_t)((void *)herr_badtrap);
1724
1725 /*
1726 * First step - allocate a table.
1727 * FIXME: why is this not fixed in the guest structure.
1728 */
1729 addr = (uint64_t)&hcall_tables;
1730 /* align to cache line size ... FIXME: why ?! */
1731 addr = (addr + L2_LINE_SIZE-1)&~(L2_LINE_SIZE-1);
1732 addr += HCALL_TABLE_SIZE*guestp->guestid;
1733 guestp->hcall_table = addr;
1734
1735 /*
1736 * Clear out negotiated groups
1737 */
1738 for (i = 0; i < NUM_API_GROUPS; i++) {
1739 guestp->api_groups[i].version_num = 0;
1740 guestp->api_groups[i].verptr = NULL;
1741 }
1742
1743 /*
1744 * Init the jump table to point to a bad trap error
1745 */
1746 api_entryp = (uint64_t *)addr;
1747 for (i = 0; i < NUM_API_CALLS; i++) {
1748 *api_entryp++ = (uint64_t)fcn;
1749 }
1750}
1751
1752/*
1753 * Initialize the permanent mapping structure for a newly created guest.
1754 */
1755void
1756reset_guest_perm_mappings(guest_t *guestp)
1757{
1758 guestp->perm_mappings_lock = 0;
1759
1760 c_bzero(&(guestp->perm_mappings[0]),
1761 sizeof (guestp->perm_mappings[0]) * NPERMMAPPINGS);
1762
1763#ifdef PERMMAP_STATS
1764 guestp->perm_mappings_count = 0;
1765#endif
1766}
1767
1768/* ************************************************************************* */
1769
1770/*
1771 * The order in which resources are processed is important.
1772 * Rather than duplicate effort while parsing nodes, some
1773 * resources pick up information from others.
1774 */
1775
1776RES_PROTO(guest)
1777RES_PROTO(memory)
1778RES_PROTO(vcpu)
1779RES_PROTO(hv_ldc)
1780RES_PROTO(ldc)
1781#ifdef CONFIG_CRYPTO
1782RES_PROTO(mau)
1783RES_PROTO(cwq)
1784#endif
1785#ifdef CONFIG_PCIE
1786RES_PROTO(pcie_bus)
1787#endif
1788RES_PROTO(console)
1789#ifdef STANDALONE_NET_DEVICES
1790RES_PROTO(network_device)
1791#endif
1792
1793
1794typedef struct {
1795 char *namep;
1796 hvctl_res_t type;
1797 void (*prep)();
1798 hvctl_status_t (*parse)(bin_md_t *, hvctl_res_error_t *,
1799 md_element_t **, int *);
1800 hvctl_status_t (*postparse)(hvctl_res_error_t *, int *);
1801 void (*commit)(int flags);
1802} res_info_t;
1803
1804
1805#define RI(_name) { \
1806 .namep = #_name, \
1807 .type = HVctl_res_##_name, \
1808 .prep = &res_##_name##_prep, \
1809 .parse = &res_##_name##_parse, \
1810 .postparse = &res_##_name##_postparse, \
1811 .commit = &res_##_name##_commit, \
1812 }
1813
1814res_info_t resource_info[] = {
1815 RI(guest),
1816 RI(memory),
1817 RI(vcpu),
1818 RI(hv_ldc),
1819 RI(ldc),
1820 RI(console),
1821#ifdef CONFIG_CRYPTO
1822 RI(mau),
1823 RI(cwq),
1824#endif
1825#ifdef CONFIG_PCIE
1826 RI(pcie_bus),
1827#endif
1828#ifdef STANDALONE_NET_DEVICES
1829 RI(network_device),
1830#endif
1831 { NULL }
1832};
1833
1834#undef RI
1835
1836
1837void
1838reloc_resource_info(void)
1839{
1840 res_info_t *resp;
1841
1842 for (resp = resource_info; resp->namep != NULL; resp++) {
1843 resp->namep = (char *)reloc_ptr((void*)resp->namep);
1844 resp->prep = (void (*)())reloc_ptr((void*)resp->prep);
1845 resp->parse = (hvctl_status_t (*)(bin_md_t *,
1846 hvctl_res_error_t *, md_element_t **, int *))
1847 reloc_ptr((void*)resp->parse);
1848 resp->postparse = (hvctl_status_t (*)(hvctl_res_error_t *,
1849 int *)) reloc_ptr((void*)resp->postparse);
1850 resp->commit = (void (*)(int))reloc_ptr((void*)resp->commit);
1851 }
1852}
1853
1854/*
1855 * Phase 3 - commit phase
1856 */
1857void
1858commit_reconfig(void)
1859{
1860 res_info_t *resp;
1861
1862 /*
1863 * NOTE: This is brute force, but for each resource
1864 * can be made much faster by building a chain for
1865 * each op during the parse phase.
1866 * ... another day perhaps.
1867 */
1868
1869 /* unconfig is done in reverse order, find last resource */
1870 for (resp = resource_info; (resp + 1)->namep != NULL; resp++)
1871 /* LINTED */
1872 ;
1873
1874 for (; resp != &(resource_info[-1]); resp--) {
1875 DBG(c_printf("\nphase 3a : unconfig %s\n\n", resp->namep));
1876 resp->commit(RESF_Unconfig);
1877 }
1878
1879 for (resp = resource_info; resp->namep != NULL; resp++) {
1880 DBG(c_printf("\nphase 3b: config %s\n\n", resp->namep));
1881 resp->commit(RESF_Config);
1882 }
1883
1884 for (resp = resource_info; resp->namep != NULL; resp++) {
1885 DBG(c_printf("\nphase 3c: rebind %s\n\n", resp->namep));
1886 resp->commit(RESF_Rebind);
1887 }
1888
1889 for (resp = resource_info; resp->namep != NULL; resp++) {
1890 DBG(c_printf("\nphase 3d: modify %s\n\n", resp->namep));
1891 resp->commit(RESF_Modify);
1892 }
1893
1894 accept_hvmd();
1895}
1896
1897static void
1898init_reconfig_error_reply(hvctl_msg_t *replyp, int code)
1899{
1900 replyp->msg.rcfail.hvmdp = hton64(0);
1901 replyp->msg.rcfail.res = hton32(HVctl_res_guest);
1902 replyp->msg.rcfail.code = hton32(code);
1903 replyp->msg.rcfail.nodeidx = hton32(-1);
1904 replyp->msg.rcfail.resid = hton32(-1);
1905}
1906
1907/*
1908 * This is the core reconfiguration function employed by the hv
1909 * control channel.
1910 *
1911 * The operation basically divides into 7 steps, the relevent functions
1912 * are called for each resource type for each of the steps in turn.
1913 *
1914 * 1. prep phase - prepare structures for a reconfig
1915 * 2. parse phase - parse, cache and sanity check resource info based on MD
1916 * 2a parse - parse and cache resource info
1917 * 2b postparse - sanity check after all parsing is done
1918 * 3. commit phase - based on parse results commit operations.
1919 * 3a unconfig - in reverse priority order unconfig resources
1920 * 3b config - configure resources.
1921 * 3c rebind - rebind resources.
1922 * 3d modify - modify resources.
1923 *
1924 * In the commit phase doing the unconfigs first is important
1925 * since they need to be detached in reverse order from their
1926 * parent resources. For example, to add a cpu to a guest the guest
1927 * has to be configured first. For an unconfigure a guest should be
1928 * unconfigured *after* the cpus have been removed.
1929 *
1930 * Hence the inverse priority ordering in the resource management.
1931 */
1932hvctl_status_t
1933op_reconfig(hvctl_msg_t *cmdp, hvctl_msg_t *replyp, bool_t isdelayed)
1934{
1935 hvctl_status_t status;
1936 bin_md_t *mdp;
1937 md_element_t *mdep;
1938 md_element_t *rootnodep;
1939 res_info_t *resp;
1940 uint64_t guestid, content_version;
1941 guest_t *guestp;
1942
1943 /* Grab the new hvmd cookie given to us by Zeus */
1944 mdp = (bin_md_t *)ntoh64(cmdp->msg.reconfig.hvmdp);
1945
1946 DBG(c_printf("\nhvmd @ 0x%x\n", ntoh64(cmdp->msg.reconfig.hvmdp)));
1947
1948 if (isdelayed) {
1949 guestid = ntoh32(cmdp->msg.reconfig.guestid);
1950 if (guestid >= NGUESTS) {
1951 init_reconfig_error_reply(replyp,
1952 HVctl_e_guest_invalid_id);
1953 return (HVctl_st_einval);
1954 }
1955
1956 guestp = &((guest_t *)config.guests)[guestid];
1957 if (guestp->state == GUEST_STATE_UNCONFIGURED) {
1958 init_reconfig_error_reply(replyp,
1959 HVctl_e_guest_invalid_id);
1960 return (HVctl_st_einval);
1961 }
1962
1963 spinlock_enter(&config.del_reconf_lock);
1964
1965 DBG(c_printf("current delayed reconfig: guestid=0x%x\n",
1966 config.del_reconf_gid));
1967
1968 if (config.del_reconf_gid != INVALID_GID) {
1969 /* a delayed reconfig is pending */
1970 if (config.del_reconf_gid != guestid) {
1971 /* it's for a different guest, error */
1972 spinlock_exit(&config.del_reconf_lock);
1973 init_reconfig_error_reply(replyp,
1974 HVctl_e_guest_invalid_id);
1975 return (HVctl_st_eillegal);
1976 }
1977 }
1978 } else {
1979 spinlock_enter(&config.del_reconf_lock);
1980 if (config.del_reconf_gid != INVALID_GID) {
1981 /* no reconfig allowed if delayed reconfig is pending */
1982 spinlock_exit(&config.del_reconf_lock);
1983 init_reconfig_error_reply(replyp,
1984 HVctl_e_guest_invalid_id);
1985 return (HVctl_st_eillegal);
1986 }
1987 spinlock_exit(&config.del_reconf_lock);
1988 }
1989
1990 /* Setup the new HVMD */
1991 status = preparse_hvmd(mdp);
1992 if (status != HVctl_st_ok) {
1993 if (isdelayed) {
1994 /* cancel any pending delayed reconfig */
1995 config.del_reconf_gid = INVALID_GID;
1996 spinlock_exit(&config.del_reconf_lock);
1997 }
1998
1999 return (status);
2000 }
2001
2002 /*
2003 * First find the root node
2004 */
2005 rootnodep = md_find_node(mdp, NULL, MDNAME(root));
2006 if (rootnodep == NULL) {
2007 DBG(c_printf("Missing root node in HVMD\n"));
2008 return (HVctl_st_badmd);
2009 }
2010
2011 /*
2012 * Check content-version in the newly downloaded MD.
2013 */
2014
2015 if (!md_node_get_val(mdp, rootnodep, MDNAME(content_version),
2016 &content_version)) {
2017 DBG(c_printf("reconfig: HV MD Content version not found\n"));
2018 return (HVctl_st_mdnotsupp);
2019 }
2020
2021 /*
2022 * Major numbers must be equal.
2023 */
2024
2025 if (MDCONT_VER_MAJOR(content_version) != HV_MDCONT_VER_MAJOR) {
2026 DBG(c_printf("reconfig: HV MD content-version mismatch: "
2027 "supported major ver %x, found %x\n", HV_MDCONT_VER_MAJOR,
2028 MDCONT_VER_MAJOR(content_version)));
2029 return (HVctl_st_mdnotsupp);
2030 }
2031
2032 DBG(c_printf("reconfig: HV MD Content version %x.%x \n",
2033 MDCONT_VER_MAJOR(content_version),
2034 MDCONT_VER_MINOR(content_version)));
2035
2036 /* Phase 1 - prep each resource */
2037
2038 for (resp = resource_info; resp->namep != NULL; resp++) {
2039 DBG(c_printf("\nphase 1 : %s\n\n", resp->namep));
2040 resp->prep();
2041 }
2042
2043 /* Phase 2a - parse MD for each resource */
2044 /*
2045 * Note: when we move to a collective node for each
2046 * resource type in the HV MD we can move the basic
2047 * parse functions into this level.
2048 */
2049 for (resp = resource_info; resp->namep != NULL; resp++) {
2050 hvctl_res_error_t fail_code;
2051 md_element_t *failnodep;
2052 int fail_res_id;
2053
2054 DBG(c_printf("\nphase 2a : %s\n\n", resp->namep));
2055
2056 status = resp->parse(mdp, &fail_code, &failnodep, &fail_res_id);
2057 if (status != HVctl_st_ok) {
2058 int idx = failnodep != NULL ?
2059 failnodep - &mdp->elem[0] : 0;
2060 replyp->msg.rcfail.hvmdp = hton64((uint64_t)mdp);
2061 replyp->msg.rcfail.res = hton32(resp->type);
2062 replyp->msg.rcfail.code = hton32(fail_code);
2063 replyp->msg.rcfail.nodeidx = hton32(idx);
2064 replyp->msg.rcfail.resid = hton32(fail_res_id);
2065 DBG(c_printf("fail status 0x%x\n", status));
2066
2067 if (isdelayed) {
2068 /* cancel any pending delayed reconfig */
2069 config.del_reconf_gid = INVALID_GID;
2070 spinlock_exit(&config.del_reconf_lock);
2071 }
2072
2073 return (status);
2074 }
2075 }
2076
2077 /* Phase 2b - post parse sanity checking for each resource */
2078
2079 for (resp = resource_info; resp->namep != NULL; resp++) {
2080 hvctl_res_error_t fail_code;
2081 int fail_res_id;
2082
2083 DBG(c_printf("\nphase 2b : %s\n\n", resp->namep));
2084
2085 status = resp->postparse(&fail_code, &fail_res_id);
2086 if (status != HVctl_st_ok) {
2087 replyp->msg.rcfail.hvmdp = hton64((uint64_t)mdp);
2088 replyp->msg.rcfail.res = hton32(resp->type);
2089 replyp->msg.rcfail.code = hton32(fail_code);
2090 replyp->msg.rcfail.nodeidx = hton32(0);
2091 replyp->msg.rcfail.resid = hton32(fail_res_id);
2092 DBG(c_printf("fail status 0x%x\n", status));
2093
2094 if (isdelayed) {
2095 /* cancel any pending delayed reconfig */
2096 config.del_reconf_gid = INVALID_GID;
2097 spinlock_exit(&config.del_reconf_lock);
2098 }
2099
2100 return (status);
2101 }
2102 }
2103
2104 /* only get here if there were no errors */
2105
2106 if (isdelayed) {
2107 DBG(c_printf("setting delayed reconfig: guestid=0x%x\n",
2108 guestid));
2109 config.del_reconf_gid = guestid;
2110 spinlock_exit(&config.del_reconf_lock);
2111 } else {
2112 /*
2113 * Phase 3 - commit phase
2114 */
2115 commit_reconfig();
2116 }
2117
2118 return (HVctl_st_ok);
2119}
2120
2121/*
2122 * Cancel any outstanding delayed reconfiguration.
2123 */
2124/* ARGSUSED */
2125hvctl_status_t
2126op_cancel_reconfig(hvctl_msg_t *cmdp, hvctl_msg_t *replyp)
2127{
2128 hvctl_status_t status;
2129
2130 spinlock_enter(&config.del_reconf_lock);
2131
2132 if (config.del_reconf_gid == INVALID_GID) {
2133 status = HVctl_st_eillegal;
2134 } else {
2135 config.del_reconf_gid = INVALID_GID;
2136 status = HVctl_st_ok;
2137 }
2138
2139 spinlock_exit(&config.del_reconf_lock);
2140
2141 return (status);
2142}