* ========== Copyright Header Begin ==========================================
* Hypervisor Software File: res_pcie.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* - Do no alter or remove copyright notices
* - Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or maintenance of
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)res_pcie.c 1.7 07/06/07 SMI"
* (re)-configuration code to handle HV PCI-E resources
* resource processing support
static void res_pcie_bus_commit_config(int i
);
static void res_pcie_bus_commit_unconfig(int i
);
static hvctl_status_t
res_pcie_bus_parse_1(bin_md_t
*mdp
,
md_element_t
*pcie_nodep
,
hvctl_res_error_t
*fail_codep
, int *fail_res_idp
);
void config_a_guest_pcie_bus(pcie_device_t
*pciep
);
void unconfig_a_guest_pcie_bus(pcie_device_t
*pciep
);
pciep
= (pcie_device_t
*)config
.pcie_busses
;
/* if the bus is configured mark it for unconfiguring */
for (i
= 0; i
< NUM_PCIE_BUSSES
; i
++) {
pciep
[i
].guestp
== NULL
? RESF_Noop
: RESF_Unconfig
;
res_pcie_bus_parse(bin_md_t
*mdp
, hvctl_res_error_t
*fail_codep
,
md_element_t
**failnodepp
, int *fail_res_idp
)
md_element_t
*mdep
, *pcie_nodep
, *rootnodep
;
mdp
= (bin_md_t
*)config
.parse_hvmd
;
rootnodep
= md_find_node(mdp
, NULL
, MDNAME(root
));
DBG(c_printf("Missing root node in HVMD\n"));
DBGPE(c_printf("PCI-E configuration:\n"));
arc_token
= MDARC(MDNAME(fwd
));
name_token
= MDNODE(MDNAME(devices
));
if (md_find_node_by_arc(mdp
, rootnodep
, arc_token
, name_token
,
DBG(c_printf("Missing devices node in HVMD\n"));
DBG(md_dump_node(mdp
, mdep
));
name_token
= MDNODE(MDNAME(pcie_bus
));
while (NULL
!= (mdep
= md_find_node_by_arc(mdp
, mdep
,
arc_token
, name_token
, &pcie_nodep
))) {
status
= res_pcie_bus_parse_1(mdp
, pcie_nodep
, fail_codep
,
if (status
!= HVctl_st_ok
) {
*failnodepp
= pcie_nodep
;
res_pcie_bus_parse_1(bin_md_t
*mdp
, md_element_t
*pcie_nodep
,
hvctl_res_error_t
*fail_codep
, int *fail_res_idp
)
md_element_t
*guestnodep
;
DBGPE(c_printf("Parse PCIE node\n"));
DBG(md_dump_node(mdp
, pcie_nodep
));
if (!md_node_get_val(mdp
, pcie_nodep
, MDNAME(resource_id
), &id
)) {
DBGPE(c_printf("Missing id in PCIE node\n"));
*fail_codep
= HVctl_e_pcie_missing_prop
;
if (!md_node_get_val(mdp
, pcie_nodep
, MDNAME(cfghandle
), &cfg_handle
)) {
DBGPE(c_printf("Missing cfg-handle in PCIE node\n"));
*fail_codep
= HVctl_e_pcie_missing_prop
;
if (id
>= NUM_PCIE_BUSSES
) {
DBGPE(c_printf("Invalid PCIE id 0x%x in PCIE node\n", id
));
*fail_codep
= HVctl_e_pcie_illegal_prop
;
DBGPE(c_printf("\tPCIE bus 0x%x :\n", id
));
if (md_node_get_val(mdp
, pcie_nodep
, MDNAME(allow_bypass
), &dummy
) &&
if (NULL
== md_find_node_by_arc(mdp
, pcie_nodep
, MDARC(MDNAME(back
)),
MDNODE(MDNAME(guest
)), &guestnodep
)) {
DBG(c_printf("Missing back arc to guest node in "
*fail_codep
= HVctl_e_pcie_missing_guest
;
if (!md_node_get_val(mdp
, guestnodep
, MDNAME(resource_id
), &guestid
)) {
DBG(c_printf("Missing resource_id in guest node\n"));
*fail_codep
= HVctl_e_guest_missing_id
;
if (guestid
>= NGUESTS
) {
DBG(c_printf("Invalid resource_id %d in guest node\n",
*fail_codep
= HVctl_e_guest_invalid_id
;
pciep
= config
.pcie_busses
;
pciep
->cfg_handle
= cfg_handle
;
/* Possible sanity checks on guest validity */
if (pciep
->guestp
== NULL
) {
pciep
->pip
.res
.flags
= RESF_Config
;
pciep
->pip
.guestid
= guestid
;
pciep
->pip
.allow_bypass
= allow_bypass
;
DBGPE(c_printf("\tElected to config PCIE bus\n"));
if (&(guestp
[guestid
]) != pciep
->guestp
||
pciep
->allow_bypass
!= allow_bypass
) {
DBGPE(c_printf("Cannot rebind/modify a PCIE device\n"));
*fail_codep
= HVctl_e_pcie_rebind_na
;
return (HVctl_st_eillegal
);
DBGPE(c_printf("Elected to ignore PCIE bus\n"));
pciep
->pip
.res
.flags
= RESF_Noop
;
res_pcie_bus_postparse(hvctl_res_error_t
*res_error
, int *fail_res_id
)
res_pcie_bus_commit(int flag
)
pcie_device_t
*pcie_busses
;
pcie_busses
= (pcie_device_t
*)config
.pcie_busses
;
for (i
= 0; i
< NUM_PCIE_BUSSES
; i
++) {
pciep
= &(pcie_busses
[i
]);
/* if not this ops turn move on */
if (pciep
->pip
.res
.flags
!= flag
) continue;
switch (pciep
->pip
.res
.flags
) {
DBG(c_printf("pcie 0x%x : noop\n", i
));
res_pcie_bus_commit_unconfig(i
);
res_pcie_bus_commit_config(i
);
DBG(c_printf("pcie 0x%x : rebind\n", i
));
ASSERT(0); /* not supported */
DBG(c_printf("pcie 0x%x : modify\n", i
));
ASSERT(0); /* not supported */
pciep
->pip
.res
.flags
= RESF_Noop
; /* cleanup */
res_pcie_bus_commit_config(int bus
)
pciep
= (pcie_device_t
*)config
.pcie_busses
;
guestp
= (guest_t
*)config
.guests
;
ASSERT(pciep
->guestp
== NULL
);
DBG(c_printf("\tpcie 0x%x configuring for guest 0x%x\n", bus
,
guestp
= &(guestp
[pciep
->pip
.guestid
]);
pciep
->allow_bypass
= pciep
->pip
.allow_bypass
;
config_a_guest_pcie_bus(pciep
);
res_pcie_bus_commit_unconfig(int bus
)
pciep
= (pcie_device_t
*)config
.pcie_busses
;
ASSERT(pciep
->guestp
!= NULL
);
* If the owning guest is still live we have a problem.
* We would like to reset the pcie bus as part of the
* unconfigure, but the reset delay will cause a mondo timeout
* on the hvctl channel vcpu.
* So we assume that since we can't DR PCI busses, that
* the guest must be stopped before this can be done.
if (pciep
->guestp
->state
!= GUEST_STATE_STOPPED
) {
DBG(c_printf("\tWARNING: pcie unconfigure should reset "
"pcie bus 0x%x\n", bus
));
DBG(c_printf("\tpcie 0x%x unconfigured\n", bus
));
unconfig_a_guest_pcie_bus(pciep
);