Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / res_console.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: res_console.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_console.c 1.6 07/06/07 SMI"
50
51#include <stdarg.h>
52
53#include <sys/htypes.h>
54#include <traps.h>
55#include <cache.h>
56#include <mmu.h>
57#include <sun4v/asi.h>
58#include <vdev_intr.h>
59#include <ncs.h>
60#include <cyclic.h>
61#include <support.h>
62#include <strand.h>
63#include <vcpu.h>
64#include <guest.h>
65#include <pcie.h>
66#include <vdev_ops.h>
67#include <fpga.h>
68#include <ldc.h>
69#include <config.h>
70#include <offsets.h>
71#include <hvctl.h>
72#include <md.h>
73#include <abort.h>
74#include <hypervisor.h>
75#include <proto.h>
76#include <debug.h>
77
78/*
79 * (re)-configuration code to handle HV guest consoles
80 */
81static hvctl_status_t res_console_parse_1(bin_md_t *mdp,
82 md_element_t *cons_nodep,
83 hvctl_res_error_t *fail_codep, int *fail_res_idp);
84
85static void res_console_commit_config(guest_t *guestp);
86static void res_console_commit_unconfig(guest_t *guestp);
87static void res_console_commit_modify(guest_t *guestp);
88
89
90void
91init_consoles()
92{
93 guest_t *gp;
94 int i;
95
96 gp = (guest_t *)config.guests;
97
98 for (i = 0; i < NGUESTS; i++, gp++) {
99 gp->console.type = CONS_TYPE_UNCONFIG;
100 }
101}
102
103/*
104 * Console MD support functions.
105 */
106void
107res_console_prep()
108{
109 guest_t *gp;
110 int i;
111
112 gp = config.guests;
113
114 for (i = 0; i < NGUESTS; i++, gp++) {
115 gp->console.pip.res.flags =
116 (gp->console.type == CONS_TYPE_UNCONFIG) ?
117 RESF_Noop : RESF_Unconfig;
118 }
119}
120
121
122hvctl_status_t
123res_console_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep,
124 md_element_t **failnodepp, int *fail_res_idp)
125{
126 md_element_t *mdep;
127 uint64_t arc_token;
128 uint64_t node_token;
129 md_element_t *cons_nodep;
130
131 mdp = (bin_md_t *)config.parse_hvmd;
132
133 DBG(c_printf("\nConsole configuration:\n"));
134
135 mdep = md_find_node(mdp, NULL, MDNAME(consoles));
136 if (mdep == NULL) {
137 DBG(c_printf("Missing consoles node in HVMD\n"));
138 *failnodepp = NULL;
139 *fail_res_idp = 0;
140 return (HVctl_st_badmd);
141 }
142
143 arc_token = MDARC(MDNAME(fwd));
144 node_token = MDNODE(MDNAME(console));
145
146 while (NULL != (mdep = md_find_node_by_arc(mdp, mdep, arc_token,
147 node_token, &cons_nodep))) {
148 hvctl_status_t status;
149 status = res_console_parse_1(mdp, cons_nodep, fail_codep,
150 fail_res_idp);
151 if (status != HVctl_st_ok) {
152 *failnodepp = cons_nodep;
153 return (status);
154 }
155 }
156 DBG(c_printf("\nConsole configuration: OK \n"));
157 return (HVctl_st_ok);
158}
159
160
161hvctl_status_t
162res_console_parse_1(bin_md_t *mdp, md_element_t *cons_nodep,
163 hvctl_res_error_t *fail_codep, int *fail_res_idp)
164{
165 uint64_t resource_id, guest_id, channel_id, ino;
166 guest_t *guestp;
167 md_element_t *guest_nodep, *ldc_nodep, *mdep;
168
169 DBG(md_dump_node(mdp, cons_nodep));
170
171 if (!md_node_get_val(mdp, cons_nodep, MDNAME(resource_id),
172 &resource_id)) {
173 DBG(c_printf("Missing resource_id in console node\n"));
174 *fail_codep = HVctl_e_cons_missing_id;
175 *fail_res_idp = 0;
176 return (HVctl_st_badmd);
177 }
178
179 *fail_res_idp = resource_id;
180
181 /*
182 * This console node needs to point back to the guest
183 * that owns it.
184 */
185
186 mdep = md_find_node_by_arc(mdp, cons_nodep, MDARC(MDNAME(back)),
187 MDNODE(MDNAME(guest)), &guest_nodep);
188 if (mdep == NULL) {
189 DBG(c_printf("Missing guest for console 0x%x", resource_id));
190 *fail_codep = HVctl_e_cons_missing_guest;
191 goto fail;
192 }
193
194 if (!md_node_get_val(mdp, guest_nodep, MDNAME(resource_id),
195 &guest_id)) {
196 DBG(c_printf("Missing resource_id in console's guest node\n"));
197 *fail_codep = HVctl_e_cons_missing_guest_id;
198 *fail_res_idp = 0;
199 return (HVctl_st_badmd);
200 }
201 if (guest_id >= NGUESTS) {
202 DBG(c_printf("Invalid resource_id in console's guest node\n"));
203 *fail_codep = HVctl_e_cons_invalid_guest_id;
204 *fail_res_idp = 0;
205 return (HVctl_st_badmd);
206 }
207
208 guestp = config.guests;
209 guestp = &(guestp[guest_id]);
210
211 DBG(c_printf("\tconsole 0x%x for guest 0x%x @ 0x%x\n",
212 resource_id, guest_id, (uint64_t)guestp));
213
214 /*
215 * This console node points fwd to the LDC node
216 * that it needs. Failing that there should be a
217 * UART address in the node for this specific
218 * console.
219 */
220
221 mdep = md_find_node_by_arc(mdp, cons_nodep, MDARC(MDNAME(fwd)),
222 MDNODE(MDNAME(ldc_endpoint)), &ldc_nodep);
223 if (mdep == NULL) {
224#ifdef CONFIG_CN_UART /* { */
225 uint64_t uartbase;
226 if (!md_node_get_val(mdp, cons_nodep, MDNAME(uartbase),
227 &uartbase)) {
228 DBG(c_printf("Missing ldc arc or uartbase in console"
229 " node\n"));
230 *fail_codep = HVctl_e_cons_missing_uartbase;
231 goto fail;
232 }
233 guestp->console.pip.type = CONS_TYPE_UART;
234 guestp->console.pip.uartbase = uartbase;
235 DBG(c_printf("UART specified for console\n"));
236#else /* } { */
237 DBG(c_printf("No ldc endpoint specified for console\n"));
238 *fail_codep = HVctl_e_cons_missing_ldc_id;
239 goto fail;
240#endif /* } */
241 } else {
242
243 /*
244 * FIXME: LDC errors shouldn't really be possible here
245 * we should have already parsed all the LDC endpoints
246 * so if properties were wrong or missing by this point
247 * we would already have found out.
248 * We leave the checks in here for sanity for now.
249 */
250
251 if (!md_node_get_val(mdp, ldc_nodep, MDNAME(channel),
252 &channel_id)) {
253 DBG(c_printf("Missing channel_id in console's"
254 " ldc node\n"));
255 *fail_codep = HVctl_e_cons_missing_ldc_id;
256 *fail_res_idp = 0;
257 goto fail;
258 }
259 if (channel_id >= MAX_LDC_CHANNELS) {
260 DBG(c_printf("Invalid channel id in console's ldc"
261 " node\n"));
262 *fail_codep = HVctl_e_cons_invalid_ldc_id;
263 *fail_res_idp = 0;
264 goto fail;
265 }
266
267 DBG(c_printf("\tconsole 0x%x for guest 0x%x [@ 0x%x]"
268 " uses LDC channel 0x%x\n",
269 resource_id, guest_id, (uint64_t)guestp, channel_id));
270
271 guestp->console.pip.type = CONS_TYPE_LDC;
272 guestp->console.pip.ldc_channel = channel_id;
273 }
274
275
276 /* Determine the interrupt the console is bound to */
277 if (!md_node_get_val(mdp, cons_nodep, MDNAME(ino), &ino)) {
278 DBG(c_printf("Missing ino in console node\n"));
279 *fail_codep = HVctl_e_cons_missing_ino;
280 goto fail;
281 }
282 if (ino >= NINOSPERDEV) {
283 DBG(c_printf("Invalid ino in console node\n"));
284 *fail_codep = HVctl_e_cons_invalid_ino;
285 goto fail;
286 }
287 guestp->console.pip.ino = ino;
288
289 /*
290 * Now we go and figureout what we need to do to the
291 * guest console to update or configure its state.
292 */
293 if (guestp->console.type == CONS_TYPE_UNCONFIG) {
294 DBG(c_printf("\t\tElected to config console of "
295 "guest 0x%x\n", guest_id));
296 guestp->console.pip.res.flags = RESF_Config;
297 } else {
298/* BEGIN CSTYLED */
299 if (guestp->console.type != guestp->console.pip.type ||
300 (guestp->console.type == CONS_TYPE_LDC &&
301 guestp->console.endpt !=
302 guestp->console.pip.ldc_channel) ||
303 (guestp->console.vintr_mapreg->ino !=
304 guestp->console.pip.ino)
305#ifdef CONFIG_CN_UART /* { */
306 || ((guestp->console.type == CONS_TYPE_UART) &&
307 (guestp->console.uartbase !=
308 guestp->console.pip.uartbase))
309#endif /* } */
310 ) {
311
312 DBG(c_printf("\t\tElected to modify console of "
313 "guest 0x%x\n", guest_id));
314 guestp->console.pip.res.flags = RESF_Modify;
315 } else {
316 DBG(c_printf("\t\tElected to ignore console of "
317 "guest 0x%x\n", guest_id));
318 guestp->console.pip.res.flags = RESF_Noop;
319 }
320/* END CSTYLED */
321 }
322
323 return (HVctl_st_ok);
324
325fail:;
326 return (HVctl_st_badmd);
327}
328
329
330hvctl_status_t
331res_console_postparse(hvctl_res_error_t *res_error, int *fail_res_id)
332{
333 return (HVctl_st_ok);
334}
335
336
337void
338res_console_commit(int flag)
339{
340 guest_t *gp;
341 int i;
342
343 gp = config.guests;
344
345 for (i = 0; i < NGUESTS; i++, gp++) {
346 /* if not this ops turn move on */
347 if (gp->console.pip.res.flags != flag) continue;
348
349 switch (gp->console.pip.res.flags) {
350 case RESF_Noop:
351 DBG(c_printf("console for guest 0x%x : noop\n", i));
352 break;
353 case RESF_Unconfig:
354 res_console_commit_unconfig(gp);
355 break;
356 case RESF_Config:
357 DBG(c_printf("console for guest 0x%x : config\n", i));
358 res_console_commit_config(gp);
359 break;
360 case RESF_Rebind:
361 DBG(c_printf("console for guest 0x%x : rebind\n", i));
362 ASSERT(0); /* not supported */
363 break;
364 case RESF_Modify:
365 res_console_commit_modify(gp);
366 break;
367 default:
368 ASSERT(0);
369 }
370
371 gp->console.pip.res.flags = RESF_Noop; /* cleanup */
372 }
373}
374
375
376void
377res_console_commit_modify(guest_t *guestp)
378{
379 DBG(c_printf("commit modify for guest 0x%x console\n",
380 guestp->guestid));
381 ASSERT(guestp->console.type != CONS_TYPE_UNCONFIG);
382 res_console_commit_unconfig(guestp);
383 res_console_commit_config(guestp);
384}
385
386
387void
388res_console_commit_config(guest_t *guestp)
389{
390 int channelid;
391 int ino;
392 ldc_endpoint_t *ldc_ep;
393 vdev_mapreg_t *mapregp;
394
395 DBG(c_printf("commit config for guest 0x%x console\n",
396 guestp->guestid));
397 ASSERT(guestp->console.type == CONS_TYPE_UNCONFIG);
398
399 guestp->console.type = guestp->console.pip.type;
400
401#ifdef CONFIG_CN_UART /* { */
402 if (guestp->console.type == CONS_TYPE_UART) {
403 guestp->console.uartbase = guestp->console.pip.uartbase;
404 return;
405 }
406#endif /* } */
407
408 ASSERT(guestp->console.type == CONS_TYPE_LDC);
409
410 channelid = guestp->console.pip.ldc_channel;
411
412 guestp->console.endpt = channelid;
413
414 guestp->console.in_head = 0;
415 guestp->console.in_tail = 0;
416 guestp->console.status = LDC_CONS_READY;
417
418 ldc_ep = &(guestp->ldc_endpoint[channelid]);
419
420 /* Quick check that the LDC endpoint was configured */
421 ASSERT(ldc_ep->is_live);
422 ASSERT(ldc_ep->is_private);
423 ASSERT(ldc_ep->svc_id == LDC_CONSOLE_SVC);
424
425 ino = guestp->console.pip.ino;
426 DBG(c_printf("\tconsole - ino 0x%x\n", ino));
427
428 mapregp = &(guestp->vdev_state.mapreg[(ino & DEVINOMASK)]);
429
430 guestp->console.vintr_mapreg = mapregp;
431 ldc_ep->rx_vintr_cookie = mapregp;
432 mapregp->ino = ino;
433
434 config_a_guest_device_vino(guestp, ino, DEVOPS_VDEV);
435
436 ldc_ep->tx_qbase_pa =
437 (uint64_t)&cons_queues[guestp->guestid].cons_txq;
438
439 ldc_ep->rx_qbase_pa =
440 (uint64_t)&cons_queues[guestp->guestid].cons_rxq;
441
442 ldc_ep->tx_qsize = Q_EL_SIZE * LDC_CONS_QSIZE;
443 ldc_ep->rx_qsize = Q_EL_SIZE * LDC_CONS_QSIZE;
444
445#if defined(CONFIG_FPGA) /* { */
446 if (ldc_ep->target_type == LDC_SP_ENDPOINT) {
447 sp_ldc_endpoint_t *sp_ept;
448 sram_ldc_qd_t *sram_qd_pa;
449
450 sp_ept = config.sp_ldcs;
451 sp_ept = &(sp_ept[ldc_ep->target_channel]);
452 sram_qd_pa = sp_ept->rx_qd_pa;
453
454 sram_qd_pa->state_updated = 1;
455 sram_qd_pa->state = 1;
456 sram_qd_pa->state_notify = 1;
457 c_ldc_send_sp_intr(sp_ept, SP_LDC_STATE_CHG);
458 }
459#endif /* } CONFIG_FPGA */
460
461 DBG(c_printf("\tguest has LDC based console.\n"));
462}
463
464
465void
466res_console_commit_unconfig(guest_t *guestp)
467{
468 ldc_endpoint_t *ldc_ep;
469 int ino;
470
471 DBG(c_printf("commit unconfig for guest 0x%x console\n",
472 guestp->guestid));
473 ASSERT(guestp->console.type != CONS_TYPE_UNCONFIG);
474
475#ifdef CONFIG_CN_UART /* { */
476 if (guestp->console.type == CONS_TYPE_UART) {
477 guestp->console.type = CONS_TYPE_UNCONFIG;
478 return;
479 }
480#endif /* } */
481
482 ldc_ep = &(guestp->ldc_endpoint[guestp->console.endpt]);
483
484 /* Quick check that the LDC endpoint was configured */
485 ASSERT(ldc_ep->is_live);
486 ASSERT(ldc_ep->is_private);
487 ASSERT(ldc_ep->svc_id == LDC_CONSOLE_SVC);
488
489 ino = guestp->console.vintr_mapreg->ino;
490 unconfig_a_guest_device_vino(guestp, ino, DEVOPS_VDEV);
491
492 guestp->console.vintr_mapreg = NULL;
493 ldc_ep->rx_vintr_cookie = NULL;
494 ldc_ep->rx_qsize = 0;
495 ldc_ep->tx_qsize = 0;
496 /* Leave the Q bases incase packets are in flight */
497 guestp->console.type = CONS_TYPE_UNCONFIG;
498}