Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / res_ldc.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: res_ldc.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_ldc.c 1.7 07/06/07 SMI"
50
51#include <stdarg.h>
52#include <sys/htypes.h>
53#include <traps.h>
54#include <mmu.h>
55#include <vdev_intr.h>
56#include <ncs.h>
57#include <cyclic.h>
58#include <support.h>
59#include <strand.h>
60#include <vcpu.h>
61#include <guest.h>
62#include <pcie.h>
63#include <vdev_ops.h>
64#include <fpga.h>
65#include <ldc.h>
66#include <config.h>
67#include <offsets.h>
68#include <hvctl.h>
69#include <md.h>
70#include <abort.h>
71#include <hypervisor.h>
72#include <proto.h>
73#include <debug.h>
74
75
76/*
77 * (re)-configuration code to handle HV LDC resources
78 */
79static void res_ldc_commit_config(guest_t *gp, ldc_endpoint_t *ldcp);
80static void res_ldc_commit_unconfig(guest_t *gp, ldc_endpoint_t *ldcp);
81
82static hvctl_status_t res_ldc_parse_1(bin_md_t *mdp, md_element_t *guest_nodep,
83 hvctl_res_error_t *fail_codep,
84 md_element_t **failnodepp, int *fail_res_idp);
85
86static hvctl_status_t res_ldc_parse_2(bin_md_t *mdp, int guest_id,
87 md_element_t *ldce_nodep,
88 hvctl_res_error_t *fail_codep, int *fail_res_idp);
89
90static void res_hv_ldc_commit_config(int ch_id);
91static void res_hv_ldc_commit_unconfig(int ch_id);
92
93static hvctl_status_t res_hv_ldc_parse_1(bin_md_t *mdp,
94 md_element_t *hvldc_nodep,
95 hvctl_res_error_t *fail_codep, int *fail_res_idp);
96
97
98
99/*
100 * LDC support functions
101 *
102 * FIXME: This changes when LDC endpoints have their own
103 * global IDs. This means for now the uniq ID for an endpoints
104 * is the tuple: (guest_id, channel_id)
105 *
106 * We'll fix this later...
107 */
108void
109res_ldc_prep()
110{
111 guest_t *gp;
112 int i;
113
114 gp = config.guests;
115
116 for (i = 0; i < NGUESTS; i++, gp++) {
117 int j;
118
119 /*
120 * If the guest is already unconfigured, then
121 * we've nothing to potentially unconfigure
122 * So we could optimise by skipping all the
123 * channels, but it's pointless because the
124 * per-guest endpoints are going away.
125 * So for now we brute force all endpoints.
126 */
127 for (j = 0; j < MAX_LDC_CHANNELS; j++) {
128 ldc_endpoint_t *ep;
129
130 ep = &(gp->ldc_endpoint[j]);
131
132 /* unconfigd guest cannot have live channel */
133 ASSERT(!(gp->state == GUEST_STATE_UNCONFIGURED &&
134 ep->is_live));
135
136 /* if live potentially unconfig it */
137 ep->pip.res.flags = ep->is_live ?
138 RESF_Unconfig : RESF_Noop;
139 }
140 }
141}
142
143
144hvctl_status_t
145res_ldc_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep,
146 md_element_t **failnodepp, int *fail_res_idp)
147{
148 md_element_t *mdep;
149 uint64_t arc_token;
150 uint64_t node_token;
151 md_element_t *guest_nodep;
152 hvctl_status_t status;
153
154 mdp = (bin_md_t *)config.parse_hvmd;
155
156 DBGL(c_printf("\nLDC configuration:\n"));
157
158 mdep = md_find_node(mdp, NULL, MDNAME(guests));
159 if (mdep == NULL) {
160 DBG(c_printf("Missing guests node in HVMD\n"));
161 *failnodepp = NULL;
162 *fail_res_idp = 0;
163 return (HVctl_st_badmd);
164 }
165
166 /*
167 * FIXME: this multistep process goes away once the top-level
168 * ldc-endpoints aggregator includes all endpoints.
169 */
170 arc_token = MDARC(MDNAME(fwd));
171 node_token = MDNODE(MDNAME(guest));
172
173 status = HVctl_st_ok;
174 while (status == HVctl_st_ok &&
175 NULL != (mdep = md_find_node_by_arc(mdp, mdep, arc_token,
176 node_token, &guest_nodep))) {
177 status = res_ldc_parse_1(mdp, guest_nodep, fail_codep,
178 failnodepp, fail_res_idp);
179 }
180 return (status);
181}
182
183
184hvctl_status_t
185res_ldc_parse_1(bin_md_t *mdp, md_element_t *guest_nodep,
186 hvctl_res_error_t *fail_codep,
187 md_element_t **failnodepp, int *fail_res_idp)
188{
189 md_element_t *elemp;
190 md_element_t *ldce_nodep;
191 int dummy;
192 uint64_t guest_id;
193 uint64_t arc_token;
194 uint64_t node_token;
195
196 /*
197 * by now we know its here because we passed the guest parse
198 * which is higher priority than this parse function.
199 */
200 dummy = md_node_get_val(mdp, guest_nodep, MDNAME(resource_id),
201 &guest_id);
202 ASSERT(dummy);
203
204#if defined(lint)
205 dummy = dummy;
206#endif
207
208 DBGL(c_printf("\tGuest 0x%x for ldcs:\n", guest_id));
209
210 arc_token = MDARC(MDNAME(fwd));
211 node_token = MDNODE(MDNAME(ldc_endpoint));
212
213 /*
214 * Spin through the "ldc_endpoint" arcs in the
215 * ldc_endpoints node and config each endpoint !
216 * FIXME; what if already configured !
217 */
218 elemp = guest_nodep;
219 while (NULL != (elemp = md_find_node_by_arc(mdp, elemp, arc_token,
220 node_token, &ldce_nodep))) {
221 hvctl_status_t status;
222
223 status = res_ldc_parse_2(mdp, guest_id, ldce_nodep,
224 fail_codep, fail_res_idp);
225 if (status != HVctl_st_ok) {
226 *failnodepp = ldce_nodep;
227 return (HVctl_st_badmd);
228 }
229 }
230 return (HVctl_st_ok);
231}
232
233
234hvctl_status_t
235res_ldc_parse_2(bin_md_t *mdp, int guest_id, md_element_t *ldce_nodep,
236 hvctl_res_error_t *fail_codep, int *fail_res_idp)
237{
238 uint64_t endpt_id;
239 ldc_endpoint_t *ldc_ep;
240 uint64_t target_type;
241 uint64_t target_channel;
242 uint64_t tx_ino;
243 uint64_t rx_ino;
244 guest_t *guestp;
245 bool_t check_guest;
246 guest_t *target_guestp;
247 uint64_t pvt_svc;
248
249 guestp = config.guests;
250 guestp = &(guestp[guest_id]);
251
252 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(channel),
253 &endpt_id)) {
254 DBGL(c_printf("Missing channel (endpoint number) in"
255 " ldc_endpoint node\n"));
256 *fail_res_idp = 0;
257miss_prop:
258 *fail_codep = HVctl_e_ldc_missing_prop;
259 return (HVctl_st_badmd);
260 }
261
262 if (endpt_id >= MAX_LDC_CHANNELS) {
263 DBGL(c_printf("Illegal channel (endpoint number) in"
264 " ldc_endpoint node\n"));
265 *fail_res_idp = 0;
266ill_prop:
267 *fail_codep = HVctl_e_ldc_illegal_prop;
268 return (HVctl_st_badmd);
269 }
270
271 DBGL(c_printf("\t\tGuest 0x%x endpoint 0x%x\n", guest_id, endpt_id));
272
273 ldc_ep = &(guestp->ldc_endpoint[endpt_id]);
274
275 ldc_ep->pip.channel = endpt_id;
276
277 *fail_res_idp = endpt_id;
278
279 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_type),
280 &target_type)) {
281 DBGL(c_printf("Missing target_type in ldc_endpoint node\n"));
282 goto miss_prop;
283 }
284 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_channel),
285 &target_channel)) {
286 DBGL(c_printf("Missing target_channel in "
287 "ldc_endpoint node\n"));
288 goto ill_prop;
289 }
290
291 ldc_ep->pip.target_type = target_type;
292 ldc_ep->pip.target_channel = target_channel;
293
294 check_guest = false; /* a flag for later change check */
295
296 switch (target_type) {
297 uint64_t target_guest_id;
298 case LDC_HV_ENDPOINT:
299 /* nothing more to do */
300 DBGL(c_printf("\t\tConnected to HV endpoint 0x%x\n",
301 target_channel));
302 break;
303
304 case LDC_GUEST_ENDPOINT:
305 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(target_guest),
306 &target_guest_id)) {
307 DBGL(c_printf("Missing target_guest in "
308 "ldc_endpoint node\n"));
309 goto miss_prop;
310 }
311
312 DBGL(c_printf("\t\t\tConnected to guest 0x%x endpoint 0x%x\n",
313 target_guest_id, target_channel));
314
315 /* This goes away with single target ID */
316 target_guestp = config.guests;
317 target_guestp = &(target_guestp[target_guest_id]);
318 ldc_ep->pip.target_guestp = target_guestp;
319 check_guest = true;
320 break;
321
322#ifdef CONFIG_FPGA /* { */
323 case LDC_SP_ENDPOINT:
324 DBGL(c_printf("\t\t\tConnected to SP endpoint 0x%x\n",
325 target_channel));
326 break;
327#endif /* } */
328
329 default:
330 DBGL(c_printf("Invalid target_type in ldc-endpoint node\n"));
331 goto ill_prop;
332 }
333
334
335 if (md_node_get_val(mdp, ldce_nodep, MDNAME(private_svc), &pvt_svc)) {
336
337 ldc_ep->pip.is_private = 1;
338 ldc_ep->pip.svc_id = pvt_svc;
339
340 switch (ldc_ep->pip.svc_id) {
341 case LDC_CONSOLE_SVC:
342
343 if (target_type == LDC_HV_ENDPOINT) {
344 DBG(c_printf("Console cannot use HV "
345 "endpoint\n"));
346 goto ill_prop;
347 }
348
349 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(rx_ino),
350 &rx_ino)) {
351 DBG(c_printf("Missing rx_ino in ldc_endpoint "
352 "node\n"));
353 goto miss_prop;
354 }
355
356 ldc_ep->pip.tx_ino = ldc_ep->pip.rx_ino = tx_ino =
357 rx_ino;
358
359 break;
360
361 default:
362 DBG(c_printf("Invalid private service type\n"));
363 goto ill_prop;
364 }
365 } else {
366 ldc_ep->pip.is_private = 0;
367
368 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(tx_ino),
369 &tx_ino)) {
370 DBGL(c_printf("Missing tx-ino in ldc_endpoint node\n"));
371 goto miss_prop;
372 }
373 if (!md_node_get_val(mdp, ldce_nodep, MDNAME(rx_ino),
374 &rx_ino)) {
375 DBGL(c_printf("Missing rx-ino in ldc_endpoint node\n"));
376 goto miss_prop;
377 }
378
379 DBGL(c_printf("\t\t\t\ttx-ino 0x%x rx-ino 0x%x\n", tx_ino,
380 rx_ino));
381
382 ldc_ep->pip.tx_ino = tx_ino;
383 ldc_ep->pip.rx_ino = rx_ino;
384 }
385
386 /*
387 * OK figure out if something changed, or if this is a
388 * noop or a config.
389 */
390 if (!ldc_ep->is_live) {
391 ldc_ep->pip.res.flags = RESF_Config;
392 DBGL(c_printf("\t\tElected to config LDC endpoint\n"));
393 } else
394 if (ldc_ep->target_type != target_type ||
395 ldc_ep->target_channel != target_channel ||
396 (!(ldc_ep->pip.is_private) && (ldc_ep->tx_mapreg.ino != tx_ino)) ||
397 (!(ldc_ep->pip.is_private) && (ldc_ep->rx_mapreg.ino != rx_ino)) ||
398 (check_guest && (ldc_ep->target_guest != target_guestp))) {
399
400#define E(_e) DBGL(if (_e) c_printf("\t\t\t%s\n", #_e));
401 E(ldc_ep->target_type != target_type);
402 E(ldc_ep->target_channel != target_channel);
403 E(ldc_ep->tx_mapreg.ino != tx_ino);
404 E(ldc_ep->rx_mapreg.ino != rx_ino);
405 E((check_guest && (ldc_ep->target_guest != target_guestp)));
406#undef E
407 DBGL(c_printf("\t\tModify not supported on LDC channels\n"));
408 *fail_codep = HVctl_e_ldc_rebind_na;
409 return (HVctl_st_badmd);
410 } else {
411 DBGL(c_printf("\t\tElected to ignore LDC endpoint\n"));
412 ldc_ep->pip.res.flags = RESF_Noop;
413 }
414
415 return (HVctl_st_ok);
416}
417
418
419hvctl_status_t
420res_ldc_postparse(hvctl_res_error_t *res_error, int *fail_res_id)
421{
422 return (HVctl_st_ok);
423}
424
425
426void
427res_ldc_commit(int flag)
428{
429 guest_t *gp;
430 int i;
431
432 gp = config.guests;
433
434 for (i = 0; i < NGUESTS; i++, gp++) {
435 int j;
436
437 /*
438 * FIXME:again can optimise around guest configdness
439 * and to skip the unsupported flags
440 */
441 for (j = 0; j < MAX_LDC_CHANNELS; j++) {
442 ldc_endpoint_t *ep;
443
444 ep = &(gp->ldc_endpoint[j]);
445
446 /* if not this ops turn move on */
447 if (ep->pip.res.flags != flag) continue;
448
449 switch (ep->pip.res.flags) {
450 case RESF_Noop:
451 DBG(c_printf("guest 0x%x ldc 0x%x : noop\n",
452 gp->guestid, j));
453 ASSERT(0); /* not supported */
454 break;
455 case RESF_Unconfig:
456 res_ldc_commit_unconfig(gp, ep);
457 break;
458 case RESF_Config:
459 res_ldc_commit_config(gp, ep);
460 break;
461 case RESF_Rebind:
462 DBG(c_printf("guest 0x%x ldc 0x%x : rebind\n",
463 gp->guestid, j));
464 ASSERT(0); /* not supported */
465 break;
466 case RESF_Modify:
467 DBG(c_printf("guest 0x%x ldc 0x%x : rebind\n",
468 gp->guestid, j));
469 ASSERT(0); /* not supported */
470 break;
471 default:
472 ASSERT(0);
473 }
474
475 ep->pip.res.flags = RESF_Noop; /* cleanup */
476 }
477 }
478}
479
480
481void
482reset_ldc_endpoint(ldc_endpoint_t *ldc_ep)
483{
484 ldc_ep->tx_qbase_ra = 0;
485 ldc_ep->tx_qhead = 0;
486 ldc_ep->tx_qtail = 0;
487
488 ldc_ep->rx_qbase_ra = 0;
489 ldc_ep->rx_qhead = 0;
490 ldc_ep->rx_qtail = 0;
491}
492
493
494void
495res_ldc_commit_config(guest_t *guestp, ldc_endpoint_t *ldc_ep)
496{
497 int tx_ino;
498 int rx_ino;
499
500 DBG(c_printf("res_ldc_commit_config guest 0x%x ldce 0x%x\n",
501 guestp->guestid, ldc_ep - guestp->ldc_endpoint));
502
503 ldc_ep->target_type = ldc_ep->pip.target_type;
504 ldc_ep->target_channel = ldc_ep->pip.target_channel;
505 ldc_ep->is_private = ldc_ep->pip.is_private;
506 ldc_ep->svc_id = ldc_ep->pip.svc_id;
507
508 switch (ldc_ep->target_type) {
509 case LDC_HV_ENDPOINT:
510 DBG(c_printf("\tHV"));
511 break;
512 case LDC_GUEST_ENDPOINT:
513 ldc_ep->target_guest = ldc_ep->pip.target_guestp;
514 DBG(c_printf("\tguest 0x%x", ldc_ep->target_guest->guestid));
515 break;
516 case LDC_SP_ENDPOINT:
517 DBG(c_printf("\tSP"));
518 break;
519 default:
520 ASSERT(0);
521 }
522
523 DBG(c_printf(" endpoint 0x%x\n", ldc_ep->target_channel));
524
525
526 if (!ldc_ep->is_private) {
527 tx_ino = ldc_ep->pip.tx_ino;
528
529 ldc_ep->tx_mapreg.ino = tx_ino;
530 guestp->ldc_ino2endpoint[tx_ino].endpointp = ldc_ep;
531 guestp->ldc_ino2endpoint[tx_ino].mapregp = &(ldc_ep->tx_mapreg);
532
533 ASSERT(guestp->cdev_cfghandle != 0);
534 config_a_guest_device_vino(guestp, tx_ino, DEVOPS_CDEV);
535 rx_ino = ldc_ep->pip.rx_ino;
536
537 ldc_ep->rx_mapreg.ino = rx_ino;
538 guestp->ldc_ino2endpoint[rx_ino].endpointp = ldc_ep;
539 guestp->ldc_ino2endpoint[rx_ino].mapregp = &(ldc_ep->rx_mapreg);
540
541 config_a_guest_device_vino(guestp, rx_ino, DEVOPS_CDEV);
542
543 ldc_ep->tx_qbase_pa = 0;
544 ldc_ep->tx_qsize = 0;
545
546 ldc_ep->rx_qbase_pa = 0;
547 ldc_ep->rx_qsize = 0;
548 ldc_ep->rx_updated = 1;
549 }
550
551 reset_ldc_endpoint(ldc_ep);
552
553 ldc_ep->is_live = true;
554}
555
556
557void
558res_ldc_commit_unconfig(guest_t *guestp, ldc_endpoint_t *ldc_ep)
559{
560 int tx_ino;
561 int rx_ino;
562
563 DBG(c_printf("res_ldc_commit_unconfig guest 0x%x ldce 0x%x\n",
564 guestp->guestid, ldc_ep - guestp->ldc_endpoint));
565
566 ASSERT(ldc_ep->is_live);
567
568 /*
569 * Undo the interrupt back maps
570 */
571 if (ldc_ep->is_private == 0) {
572 tx_ino = ldc_ep->tx_mapreg.ino;
573 guestp->ldc_ino2endpoint[tx_ino].endpointp = NULL;
574 guestp->ldc_ino2endpoint[tx_ino].mapregp = NULL;
575
576 unconfig_a_guest_device_vino(guestp, tx_ino, DEVOPS_CDEV);
577
578 rx_ino = ldc_ep->rx_mapreg.ino;
579 guestp->ldc_ino2endpoint[rx_ino].endpointp = NULL;
580 guestp->ldc_ino2endpoint[rx_ino].mapregp = NULL;
581
582 unconfig_a_guest_device_vino(guestp, rx_ino, DEVOPS_CDEV);
583 }
584
585 /* This is about it for an unconfigure */
586 ldc_ep->is_live = false;
587}
588
589
590/*
591 * Now the HV LDCs ... which should be vanishing into
592 * becomming regular LDCs sometime in the very newar future.
593 */
594void
595res_hv_ldc_prep()
596{
597 int i;
598
599 for (i = 0; i < MAX_HV_LDC_CHANNELS; i++) {
600 ldc_endpoint_t *hvep;
601
602 hvep = config.hv_ldcs;
603 hvep = &(hvep[i]);
604
605 hvep->pip.res.flags = (!hvep->is_live) ?
606 RESF_Noop : RESF_Unconfig;
607 }
608}
609
610
611hvctl_status_t
612res_hv_ldc_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep,
613 md_element_t **failnodepp, int *fail_res_idp)
614{
615 md_element_t *mdep, *hvldc_nodep, *rootnodep;
616 uint64_t arc_token;
617 uint64_t name_token;
618
619 mdp = (bin_md_t *)config.parse_hvmd;
620
621 DBGHL(c_printf("HV LDC configuration:\n"));
622
623 /*
624 * First find the root node
625 */
626 rootnodep = md_find_node(mdp, NULL, MDNAME(root));
627 if (rootnodep == NULL) {
628 DBGHL(c_printf("Missing root node in HVMD\n"));
629 *failnodepp = NULL;
630 *fail_res_idp = 0;
631 return (HVctl_st_badmd);
632 }
633
634 /* if no ldc_endpoints node under root nothing to parse */
635 if (md_find_node_by_arc(mdp, rootnodep, MDARC(MDNAME(fwd)),
636 MDNODE(MDNAME(ldc_endpoints)), &mdep) == NULL) {
637 return (HVctl_st_ok);
638 }
639
640 arc_token = MDARC(MDNAME(fwd));
641 name_token = MDNODE(MDNAME(ldc_endpoint));
642
643 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep, arc_token,
644 name_token, &hvldc_nodep))) {
645 hvctl_status_t status;
646
647 status = res_hv_ldc_parse_1(mdp, hvldc_nodep, fail_codep,
648 fail_res_idp);
649 if (status != HVctl_st_ok) {
650 *failnodepp = hvldc_nodep;
651 return (status);
652 }
653 }
654 return (HVctl_st_ok);
655}
656
657
658hvctl_status_t
659res_hv_ldc_parse_1(bin_md_t *mdp, md_element_t *hvldc_nodep,
660 hvctl_res_error_t *fail_codep, int *fail_res_idp)
661{
662 uint64_t chid;
663 uint64_t type;
664 uint64_t guestid;
665 uint64_t svc_id;
666 uint64_t tchan_id;
667 ldc_endpoint_t *hvep;
668
669 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(svc_id), &svc_id)) {
670 /* Not a HV endpoint - skip it */
671 return (HVctl_st_ok);
672 }
673
674 DBGHL(c_printf("Parse HV LDC endpoints\n"));
675
676 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(channel), &chid)) {
677 DBGHL(c_printf("Missing channel id in HV LDC node\n"));
678 *fail_res_idp = 0;
679miss_prop:
680 *fail_codep = HVctl_e_hv_ldc_missing_prop;
681 return (HVctl_st_badmd);
682 }
683 if (chid >= MAX_HV_LDC_CHANNELS) {
684 DBGHL(c_printf("Invalid channel id 0x%x in HV LDC node\n",
685 chid));
686 *fail_res_idp = 0;
687ill_prop:
688 *fail_codep = HVctl_e_hv_ldc_illegal_prop;
689 return (HVctl_st_badmd);
690 }
691
692 DBGHL(c_printf("\tHV endpoint 0x%x :", chid));
693
694 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_type), &type)) {
695 DBG(c_printf("Missing target_type in HV LDC node\n"));
696 goto miss_prop;
697 }
698
699 hvep = config.hv_ldcs;
700 hvep = &(hvep[chid]);
701
702 *fail_res_idp = chid;
703
704 hvep->pip.target_type = type;
705
706 switch (type) {
707 case LDC_GUEST_ENDPOINT: /* guest<->HV LDC */
708 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_guest),
709 &guestid)) {
710 DBGHL(c_printf("Missing target_guest in HV "
711 "LDC node\n"));
712 goto miss_prop;
713 }
714
715 /* point to target guest */
716 hvep->pip.target_guestp =
717 &(((guest_t *)config.guests)[guestid]);
718
719 DBGHL(c_printf("\tConnected to endpoint in guest 0x%x\n",
720 guestid));
721 break;
722
723 case LDC_SP_ENDPOINT: /* HV<->SP LDC */
724 DBGHL(c_printf("\tConnected to SP endpoint\n"));
725 break;
726
727 default:
728 DBGHL(c_printf("Illegal target_type 0x%x\n", type));
729 goto ill_prop;
730 }
731
732
733 if (!md_node_get_val(mdp, hvldc_nodep, MDNAME(target_channel),
734 &tchan_id)) {
735 DBGHL(c_printf("Missing target channel id in HV LDC node\n"));
736 goto miss_prop;
737 }
738 if (tchan_id >= MAX_LDC_CHANNELS) {
739 DBGHL(c_printf("Invalid target channel id 0x%x in HV "
740 "LDC node\n", tchan_id));
741 goto ill_prop;
742 }
743
744 DBGHL(c_printf("\t\tTarget channel = 0x%x ", tchan_id));
745
746 hvep->pip.target_channel = tchan_id;
747
748 hvep->pip.svc_id = svc_id;
749
750 switch (svc_id) {
751 case LDC_HVCTL_SVC:
752 /*
753 * We don't yet allow for HVCTL channel between the
754 * hypervisor and SP. Maybe one day we will have a
755 * Zeus or Zeus-lite running on the SP and at that
756 * point we can remove this check.
757 */
758 if (hvep->pip.target_type == LDC_SP_ENDPOINT) {
759 DBGHL(c_printf("No HVCTL LDC to the SP "
760 "allowed yet\n"));
761 goto ill_prop;
762 }
763
764 DBGHL(c_printf(" for HVCTL service\n"));
765
766 break;
767
768 default:
769 DBGHL(c_printf("Unknown service type 0x%x\n", svc_id));
770 goto miss_prop;
771 }
772
773 /*
774 * Now figure if this is a config or a modify
775 */
776 if (!hvep->is_live) {
777 hvep->pip.res.flags = RESF_Config;
778 DBGHL(c_printf("Elected to Configure"));
779 } else {
780 if (hvep->pip.target_type != hvep->target_type ||
781 (hvep->target_type == LDC_GUEST_ENDPOINT &&
782 hvep->pip.target_guestp != hvep->target_guest) ||
783 hvep->pip.target_channel != hvep->target_channel) {
784 DBGHL(c_printf("A HV LDC channel must be unconfiged "
785 "before it can be re-bound\n"));
786 *fail_codep = HVctl_e_hv_ldc_rebind_na;
787 return (HVctl_st_eillegal);
788 } else {
789 hvep->pip.res.flags = RESF_Noop;
790 DBGHL(c_printf("Elected to Ignore"));
791 }
792 }
793
794 return (HVctl_st_ok);
795}
796
797
798hvctl_status_t
799res_hv_ldc_postparse(hvctl_res_error_t *res_error, int *fail_res_id)
800{
801 return (HVctl_st_ok);
802}
803
804
805void
806res_hv_ldc_commit(int flag)
807{
808 int i;
809
810 for (i = 0; i < MAX_HV_LDC_CHANNELS; i++) {
811 ldc_endpoint_t *hvep;
812
813 hvep = config.hv_ldcs;
814 hvep = &(hvep[i]);
815
816 /* if not this ops turn move on */
817 if (hvep->pip.res.flags != flag) continue;
818
819 switch (hvep->pip.res.flags) {
820 case RESF_Noop:
821 DBG(c_printf("hv_ldc 0x%x : noop\n", i));
822 break;
823 case RESF_Unconfig:
824 res_hv_ldc_commit_unconfig(i);
825 break;
826 case RESF_Config:
827 res_hv_ldc_commit_config(i);
828 break;
829 case RESF_Rebind:
830 DBG(c_printf("hv_ldc 0x%x : rebind\n", i));
831 ASSERT(0); /* not supported */
832 break;
833 case RESF_Modify:
834 DBG(c_printf("hv_ldc 0x%x : modify\n", i));
835 ASSERT(0); /* not supported */
836 break;
837 default:
838 ASSERT(0);
839 }
840
841 hvep->pip.res.flags = RESF_Noop; /* cleanup */
842 }
843}
844
845
846void
847res_hv_ldc_commit_config(int ch_id)
848{
849 ldc_endpoint_t *hvep;
850 extern void hvctl_svc_callback(); /* FIXME: in a header */
851
852 hvep = config.hv_ldcs;
853 hvep = &(hvep[ch_id]);
854
855 DBGHL(c_printf("\t\tConfig endpoint\n"));
856 ASSERT(!hvep->is_live);
857
858 hvep->target_type = hvep->pip.target_type;
859
860 switch (hvep->target_type) {
861 case LDC_GUEST_ENDPOINT: /* guest<->HV LDC */
862 hvep->target_guest = hvep->pip.target_guestp;
863 break;
864
865 case LDC_SP_ENDPOINT: /* HV<->SP LDC */
866 break;
867 default:
868 ASSERT(0);
869 }
870
871 hvep->target_channel = hvep->pip.target_channel;
872
873 /* svc id determines the callback setup */
874 switch (hvep->pip.svc_id) {
875
876 case LDC_HVCTL_SVC:
877 /*
878 * FIXME: Why did we save the endpoint number
879 * instead of a pointer to the endpoint ?
880 */
881 config.hvctl_ldc = ch_id; /* save the HVCTL channel id */
882
883 hvep->rx_cb = (uint64_t)&hvctl_svc_callback;
884 hvep->rx_cbarg = (uint64_t)&config;
885 break;
886
887 default:
888 DBG(c_printf("Unknown service type 0x%x\n", hvep->pip.svc_id));
889 ASSERT(0);
890 }
891
892 /* Mark channel as live */
893 ASSERT(!hvep->is_live);
894 hvep->is_live = true;
895}
896
897
898void
899res_hv_ldc_commit_unconfig(int ch_id)
900{
901 ldc_endpoint_t *hvep;
902
903 hvep = config.hv_ldcs;
904 hvep = &(hvep[ch_id]);
905
906 DBGHL(c_printf("\t\tUnconfig endpoint %d\n", ch_id));
907 ASSERT(hvep->is_live);
908
909 hvep->is_live = false;
910}