|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v1 3/3] vpci/msi: Remove registers when init_msi() fails
On 2025/3/27 20:44, Roger Pau Monné wrote:
> On Thu, Mar 27, 2025 at 03:32:14PM +0800, Jiqian Chen wrote:
>> 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.
>
> As I'm just seeing 3 patches on the series, isn't there one missing
> for MSI-X at least?
No, because init_msix only call vpci_add_register once, there is no need to
remove registers when it fails.
>
>> 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;
>
> As commented on the previous patch, I don't like much the usage of
> this registers array to store which handlers have been added. It
> would be best if you just removed every possible handler that could be
> added, without keeping track of them.
Make sense, it will indeed be simpler if it is fine to remove all possible
registers.
>
> Thinking about it, do we maybe need a helper vcpi function that wipes
> all handlers from a specific range? I think it could be helpful here,
> as the size of the capabilities is well-known, so on error it would be
> easier to just call such a generic handler to wipe all hooks added to
> the region covered by the failing capability.
But I am not sure if that helper function is suitable for all capabilities.
Like Rebar, its structure can range from 12 bytes long(for a single BAR) to 52
bytes long(for all six BARs).
If a device supports Rebar and only has a single resizable BAR, does hardware
still reserved the range from 13 bytes to 52 bytes for that device?
I mean if I remove the registers(with range 13 to 52), is it possible that I
deleted registers belonging to other abilities?
>
> Let me know what you think of it.
>
> Thanks, Roger.
--
Best regards,
Jiqian Chen.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |