|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 1/2] xen/vpci: header: filter PCI capabilities
On 16.08.2023 20:50, Stewart Hildebrand wrote:
> If there are no capabilities to be exposed to the guest, a future status
> register handler likely would want to mask the PCI_STATUS_CAP_LIST bit. See
> [1]
> for a suggestion of how this might be tracked in struct vpci_header.
Can we actually get away without doing this right away? I'm not sure
consumers are required to range check what they read from PCI_CAPABILITY_LIST.
> --- a/xen/drivers/pci/pci.c
> +++ b/xen/drivers/pci/pci.c
> @@ -39,27 +39,27 @@ int pci_find_cap_offset(u16 seg, u8 bus, u8 dev, u8 func,
> u8 cap)
> return 0;
> }
>
> -int pci_find_next_cap(u16 seg, u8 bus, unsigned int devfn, u8 pos, int cap)
> +int pci_find_next_cap(pci_sbdf_t sbdf, uint8_t pos, bool
> (*is_match)(uint8_t),
> + int *ttl)
Why plain int? When values can't go negative, respective variables generally
want to be of unsigned types.
> {
> - u8 id;
> - int ttl = 48;
> + uint8_t id;
>
> - while ( ttl-- )
> + while ( (*ttl)-- > 0 )
I don't see why you add "> 0" here.
> {
> - pos = pci_conf_read8(PCI_SBDF(seg, bus, devfn), pos);
> + pos = pci_conf_read8(sbdf, pos);
> if ( pos < 0x40 )
> break;
>
> - pos &= ~3;
> - id = pci_conf_read8(PCI_SBDF(seg, bus, devfn), pos +
> PCI_CAP_LIST_ID);
> + id = pci_conf_read8(sbdf, (pos & ~3) + PCI_CAP_LIST_ID);
>
> if ( id == 0xff )
> break;
> - if ( id == cap )
> + if ( is_match(id) )
> return pos;
>
> - pos += PCI_CAP_LIST_NEXT;
> + pos = (pos & ~3) + PCI_CAP_LIST_NEXT;
> }
> +
> return 0;
> }
As said in context of v1, this function should remain usable for its
original purpose. That, to me, includes the caller not needing to care about
ttl. I could see you convert the original function the way you do, but under
a new name, and then implement the original one simply in terms of this more
general purpose function.
Also, while I appreciate the sbdf conversion, that wants to be a separate
patch, which would then want to take care of the sibling functions as well.
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -513,6 +513,18 @@ static void cf_check rom_write(
> rom->addr = val & PCI_ROM_ADDRESS_MASK;
> }
>
> +static bool cf_check vpci_cap_supported(uint8_t id)
> +{
> + switch ( id )
> + {
> + case PCI_CAP_ID_MSI:
> + case PCI_CAP_ID_MSIX:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> static int cf_check init_bars(struct pci_dev *pdev)
> {
> uint16_t cmd;
> @@ -544,6 +556,60 @@ static int cf_check init_bars(struct pci_dev *pdev)
> if ( rc )
> return rc;
>
> + if ( !is_hardware_domain(pdev->domain) )
> + {
> + if ( (pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST)
> + == 0 )
This fits on a single line when written this more commonly used way:
if ( !(pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST) )
Otherwise it needs wrapping differently - binary operators at a wrapping
point belong on the earlier line in our style.
> + {
> + /* RAZ/WI */
> + rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
> + PCI_CAPABILITY_LIST, 1, NULL);
This last NULL is likely misleading to readers: It does not obviously
represent the value 0 cast to void *. (Same then for the extended cap
handler at the end.)
> + if ( rc )
> + return rc;
> + }
> + else
> + {
> + /* Only expose capabilities to the guest that vPCI can handle. */
> + uint8_t next;
> + int ttl = 48;
> +
> + next = pci_find_next_cap(pdev->sbdf, PCI_CAPABILITY_LIST,
> + vpci_cap_supported, &ttl);
> +
> + rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
> + PCI_CAPABILITY_LIST, 1,
> + (void *)(uintptr_t)next);
> + if ( rc )
> + return rc;
> +
> + while ( next && (ttl > 0) )
Don't you need to mask off the low two bits first (rather than [only] ...
> + {
> + uint8_t pos = next;
> +
> + next = pci_find_next_cap(pdev->sbdf, pos + PCI_CAP_LIST_NEXT,
> + vpci_cap_supported, &ttl);
> +
> + rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL,
> + pos + PCI_CAP_LIST_ID, 1, NULL);
> + if ( rc )
> + return rc;
> +
> + rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
> + pos + PCI_CAP_LIST_NEXT, 1,
> + (void *)(uintptr_t)next);
> + if ( rc )
> + return rc;
> +
> + next &= ~3;
... here)?
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |