|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 7/8] vpci/msi: Free MSI resources when init_msi() fails
On 2025/4/15 21:29, Roger Pau Monné wrote:
> On Wed, Apr 09, 2025 at 02:45:27PM +0800, Jiqian Chen wrote:
>> When init_msi() fails, the previous new changes will hide MSI
>> capability, it can't rely on vpci_deassign_device() to remove
>> all MSI related resources anymore, those resources must be
>> cleaned up in failure path of init_msi.
>>
>> To do that, add a new function to free MSI resources.
>>
>> Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx>
>> ---
>> cc: "Roger Pau Monné" <roger.pau@xxxxxxxxxx>
>> ---
>> v1->v2 changes:
>> * Added a new function fini_msi to free all MSI resources instead of using
>> an array to record registered registers.
>> ---
>> xen/drivers/vpci/msi.c | 47 +++++++++++++++++++++++++++++++++---------
>> 1 file changed, 37 insertions(+), 10 deletions(-)
>>
>> diff --git a/xen/drivers/vpci/msi.c b/xen/drivers/vpci/msi.c
>> index ca89ae9b9c22..48a466dba0ef 100644
>> --- a/xen/drivers/vpci/msi.c
>> +++ b/xen/drivers/vpci/msi.c
>> @@ -193,6 +193,33 @@ static void cf_check mask_write(
>> msi->mask = val;
>> }
>>
>> +/* 12 is size of MSI structure for 32-bit Message Address without PVM */
>> +#define MSI_STRUCTURE_SIZE_32 12
>
> I'm confused by this. The minimum size of the capability is 4 bytes
> for the capability pointer, plus 4 bytes for the message address,
> plus 2 bytes for the message data. So that's 10 bytes in total.
The remain 2 bytes is Extended Message Data, PCIe spec has this register's
definition even though it is optional.
>
> I think it would be best if you calculate the size based on the
> existing msi_ macros.
>
> if ( masking )
> end = msi_pending_bits_reg(msi_pos, address64);
> else
> end = msi_mask_bits_reg(msi_pos, address64) - 2;
>
> size = end - msi_control_reg(msi_pos);
Thanks, I will change to this in next version.
>
>> +
>> +static void fini_msi(struct pci_dev *pdev)
>> +{
>> + unsigned int size = MSI_STRUCTURE_SIZE_32;
>> +
>> + if ( !pdev->vpci->msi )
>> + return;
>> +
>> + if ( pdev->vpci->msi->address64 )
>> + size += 4;
>> + if ( pdev->vpci->msi->masking )
>> + size += 4;
>> +
>> + /*
>> + * Remove all possible registered registers except capability ID
>> + * register and next capability pointer register, which will be
>> + * removed in mask function.
>> + *msi_mask_bits_reg/
>> + vpci_remove_registers(pdev->vpci,
>> + msi_control_reg(pdev->msi_pos),
>> + size - PCI_MSI_FLAGS);
>> + xfree(pdev->vpci->msi);
>> + pdev->vpci->msi = NULL;
>> +}
>> +
>> static int cf_check init_msi(struct pci_dev *pdev)
>> {
>> unsigned int pos = pdev->msi_pos;
>> @@ -209,12 +236,7 @@ static int cf_check init_msi(struct pci_dev *pdev)
>> ret = vpci_add_register(pdev->vpci, control_read, control_write,
>> msi_control_reg(pos), 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;
>>
>> /* Get the maximum number of vectors the device supports. */
>> control = pci_conf_read16(pdev->sbdf, msi_control_reg(pos));
>> @@ -237,20 +259,20 @@ static int cf_check init_msi(struct pci_dev *pdev)
>> ret = vpci_add_register(pdev->vpci, address_read, address_write,
>> msi_lower_address_reg(pos), 4, pdev->vpci->msi);
>> if ( ret )
>> - return ret;
>> + goto fail;
>>
>> ret = vpci_add_register(pdev->vpci, data_read, data_write,
>> msi_data_reg(pos, pdev->vpci->msi->address64),
>> 2,
>> pdev->vpci->msi);
>> if ( ret )
>> - return ret;
>> + goto fail;
>>
>> if ( pdev->vpci->msi->address64 )
>> {
>> ret = vpci_add_register(pdev->vpci, address_hi_read,
>> address_hi_write,
>> msi_upper_address_reg(pos), 4,
>> pdev->vpci->msi);
>> if ( ret )
>> - return ret;
>> + goto fail;
>> }
>>
>> if ( pdev->vpci->msi->masking )
>> @@ -260,7 +282,7 @@ static int cf_check init_msi(struct pci_dev *pdev)
>>
>> pdev->vpci->msi->address64),
>> 4, pdev->vpci->msi);
>> if ( ret )
>> - return ret;
>> + goto fail;
>> /*
>> * 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 +291,11 @@ static int cf_check init_msi(struct pci_dev *pdev)
>> }
>>
>> return 0;
>> +
>> + fail:
>> + fini_msi(pdev);
>> +
>> + return ret;
>> }
>> REGISTER_VPCI_LEGACY_CAP(PCI_CAP_ID_MSI, init_msi);
>
> I wonder if the fini_msi should be referenced in
> REGISTER_VPCI_{EXTENDED,LEGACY}_CAP(), so that the caller of
> init_msi() can call fini_msi() on failure and thus avoid all those
> fail hooks and labels, as the caller can take care of the cleanup.
Got it. I will add a hook for fini_x function.
>
> Thanks, Roger.
--
Best regards,
Jiqian Chen.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |