|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 3/3] vpci/msi: Remove registers when init_msi() fails
When init_msi() fails, the new codes will try to hide MSI
capability, so it can't rely on vpci_deassign_device() to
remove all MSI related registers anymore, those registers
must be cleaned up in failure path of init_msi.
To do that, use a vpci_register array to record all MSI
registers and call vpci_remove_register() to remove registers.
Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx>
---
xen/drivers/vpci/msi.c | 57 +++++++++++++++++++++++++++++-------------
1 file changed, 39 insertions(+), 18 deletions(-)
diff --git a/xen/drivers/vpci/msi.c b/xen/drivers/vpci/msi.c
index 9d7a9fd8dba1..30ef97efb7b0 100644
--- a/xen/drivers/vpci/msi.c
+++ b/xen/drivers/vpci/msi.c
@@ -195,6 +195,9 @@ static void cf_check mask_write(
static int cf_check init_msi(struct pci_dev *pdev)
{
+ unsigned int offset;
+ unsigned int reg_index = 0;
+ struct vpci_register registers[VPCI_CAP_MAX_REGISTER];
unsigned int pos = pdev->msi_pos;
uint16_t control;
int ret;
@@ -206,15 +209,13 @@ static int cf_check init_msi(struct pci_dev *pdev)
if ( !pdev->vpci->msi )
return -ENOMEM;
+ offset = msi_control_reg(pos);
ret = vpci_add_register(pdev->vpci, control_read, control_write,
- msi_control_reg(pos), 2, pdev->vpci->msi);
+ offset, 2, pdev->vpci->msi);
if ( ret )
- /*
- * NB: there's no need to free the msi struct or remove the register
- * handlers form the config space, the caller will take care of the
- * cleanup.
- */
- return ret;
+ goto fail;
+ registers[reg_index].offset = offset;
+ registers[reg_index++].size = 2;
/* Get the maximum number of vectors the device supports. */
control = pci_conf_read16(pdev->sbdf, msi_control_reg(pos));
@@ -234,33 +235,42 @@ static int cf_check init_msi(struct pci_dev *pdev)
pdev->vpci->msi->address64 = is_64bit_address(control);
pdev->vpci->msi->masking = is_mask_bit_support(control);
+ offset = msi_lower_address_reg(pos);
ret = vpci_add_register(pdev->vpci, address_read, address_write,
- msi_lower_address_reg(pos), 4, pdev->vpci->msi);
+ offset, 4, pdev->vpci->msi);
if ( ret )
- return ret;
+ goto fail;
+ registers[reg_index].offset = offset;
+ registers[reg_index++].size = 4;
+ offset = msi_data_reg(pos, pdev->vpci->msi->address64);
ret = vpci_add_register(pdev->vpci, data_read, data_write,
- msi_data_reg(pos, pdev->vpci->msi->address64), 2,
- pdev->vpci->msi);
+ offset, 2, pdev->vpci->msi);
if ( ret )
- return ret;
+ goto fail;
+ registers[reg_index].offset = offset;
+ registers[reg_index++].size = 2;
if ( pdev->vpci->msi->address64 )
{
+ offset = msi_upper_address_reg(pos);
ret = vpci_add_register(pdev->vpci, address_hi_read, address_hi_write,
- msi_upper_address_reg(pos), 4,
pdev->vpci->msi);
+ offset, 4, pdev->vpci->msi);
if ( ret )
- return ret;
+ goto fail;
+ registers[reg_index].offset = offset;
+ registers[reg_index++].size = 4;
}
if ( pdev->vpci->msi->masking )
{
+ offset = msi_mask_bits_reg(pos, pdev->vpci->msi->address64);
ret = vpci_add_register(pdev->vpci, mask_read, mask_write,
- msi_mask_bits_reg(pos,
- pdev->vpci->msi->address64),
- 4, pdev->vpci->msi);
+ offset, 4, pdev->vpci->msi);
if ( ret )
- return ret;
+ goto fail;
+ registers[reg_index].offset = offset;
+ registers[reg_index++].size = 4;
/*
* FIXME: do not add any handler for the pending bits for the hardware
* domain, which means direct access. This will be revisited when
@@ -269,6 +279,17 @@ static int cf_check init_msi(struct pci_dev *pdev)
}
return 0;
+
+ fail:
+ for ( unsigned int i = 0; i < reg_index; i++ )
+ if ( vpci_remove_register(pdev->vpci,
+ registers[i].offset,
+ registers[i].size) )
+ continue;
+ xfree(pdev->vpci->msi);
+ pdev->vpci->msi = NULL;
+
+ return ret;
}
REGISTER_VPCI_LEGACY_CAP(PCI_CAP_ID_MSI, init_msi, VPCI_PRIORITY_LOW);
--
2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |