mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
vpci/rebar: Implement cleanup function for Rebar
When Rebar initialization fails, vPCI hides the capability, but removing handlers and datas won't be performed until the device is deassigned. So, implement Rebar cleanup hook that will be called to cleanup Rebar related handlers and free it's associated data when initialization fails. Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
1 parent
d0f94a0d40
commit
ee459aeac0
1 file changed
+54
-9
@@ -49,6 +49,58 @@ static void cf_check rebar_ctrl_write(const struct pci_dev *pdev,
|
||||
bar->guest_addr = bar->addr;
|
||||
}
|
||||
|
||||
static int cf_check cleanup_rebar(const struct pci_dev *pdev, bool hide)
|
||||
{
|
||||
int rc;
|
||||
uint32_t ctrl;
|
||||
unsigned int nbars;
|
||||
unsigned int rebar_offset = pci_find_ext_capability(pdev,
|
||||
PCI_EXT_CAP_ID_REBAR);
|
||||
|
||||
if ( !hide )
|
||||
return 0;
|
||||
|
||||
ctrl = pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CTRL(0));
|
||||
nbars = MASK_EXTR(ctrl, PCI_REBAR_CTRL_NBAR_MASK);
|
||||
|
||||
rc = vpci_remove_registers(pdev->vpci, rebar_offset + PCI_REBAR_CAP(0),
|
||||
PCI_REBAR_CTRL(nbars - 1));
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_ERR "%pd %pp: fail to remove Rebar handlers rc=%d\n",
|
||||
pdev->domain, &pdev->sbdf, rc);
|
||||
ASSERT_UNREACHABLE();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unprivileged domains have a deny by default register access policy, no
|
||||
* need to add any further handlers for them.
|
||||
*/
|
||||
if ( !is_hardware_domain(pdev->domain) )
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The driver may not traverse the capability list and think device
|
||||
* supports Rebar by default. So here let the control register of Rebar
|
||||
* be Read-Only is to ensure Rebar disabled.
|
||||
*/
|
||||
for ( unsigned int i = 0; i < nbars; i++ )
|
||||
{
|
||||
rc = vpci_add_register(pdev->vpci, vpci_hw_read32, NULL,
|
||||
rebar_offset + PCI_REBAR_CTRL(i), 4, NULL);
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_ERR
|
||||
"%pd %pp: fail to add Rebar ctrl handler rc=%d\n",
|
||||
pdev->domain, &pdev->sbdf, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cf_check init_rebar(struct pci_dev *pdev)
|
||||
{
|
||||
uint32_t ctrl;
|
||||
@@ -97,14 +149,7 @@ static int cf_check init_rebar(struct pci_dev *pdev)
|
||||
{
|
||||
printk(XENLOG_ERR "%pd %pp: BAR%u fail to add reg of REBAR_CTRL rc=%d\n",
|
||||
pdev->domain, &pdev->sbdf, index, rc);
|
||||
/*
|
||||
* Ideally we would hide the ReBar capability on error, but code
|
||||
* for doing so still needs to be written. Use continue instead
|
||||
* to keep any already setup register hooks, as returning an
|
||||
* error will cause the hardware domain to get unmediated access
|
||||
* to all device registers.
|
||||
*/
|
||||
continue;
|
||||
return rc;
|
||||
}
|
||||
|
||||
bar->resizable_sizes =
|
||||
@@ -118,7 +163,7 @@ static int cf_check init_rebar(struct pci_dev *pdev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
REGISTER_VPCI_EXTCAP(REBAR, init_rebar, NULL);
|
||||
REGISTER_VPCI_EXTCAP(REBAR, init_rebar, cleanup_rebar);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||