|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 04/11] vpci/header: Add and remove register handlers dynamically
On Thu, Sep 30, 2021 at 10:52:16AM +0300, Oleksandr Andrushchenko wrote:
> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
>
> Add relevant vpci register handlers when assigning PCI device to a domain
> and remove those when de-assigning. This allows having different
> handlers for different domains, e.g. hwdom and other guests.
>
> Use stubs for guest domains for now.
>
> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
>
> ---
> Since v2:
> - remove unneeded ifdefs for CONFIG_HAS_VPCI_GUEST_SUPPORT as more code
> has been eliminated from being built on x86
> Since v1:
> - constify struct pci_dev where possible
> - do not open code is_system_domain()
> - simplify some code3. simplify
> - use gdprintk + error code instead of gprintk
> - gate vpci_bar_{add|remove}_handlers with CONFIG_HAS_VPCI_GUEST_SUPPORT,
> so these do not get compiled for x86
> - removed unneeded is_system_domain check
> ---
> xen/drivers/vpci/header.c | 72 ++++++++++++++++++++++++++++++++++-----
> xen/drivers/vpci/vpci.c | 4 +--
> xen/include/xen/vpci.h | 8 +++++
> 3 files changed, 74 insertions(+), 10 deletions(-)
>
> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> index 3d571356397a..1ce98795fcca 100644
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -397,6 +397,17 @@ static void bar_write(const struct pci_dev *pdev,
> unsigned int reg,
> pci_conf_write32(pdev->sbdf, reg, val);
> }
>
> +static void guest_bar_write(const struct pci_dev *pdev, unsigned int reg,
> + uint32_t val, void *data)
> +{
> +}
> +
> +static uint32_t guest_bar_read(const struct pci_dev *pdev, unsigned int reg,
> + void *data)
> +{
> + return 0xffffffff;
> +}
> +
> static void rom_write(const struct pci_dev *pdev, unsigned int reg,
> uint32_t val, void *data)
> {
> @@ -445,14 +456,25 @@ static void rom_write(const struct pci_dev *pdev,
> unsigned int reg,
> rom->addr = val & PCI_ROM_ADDRESS_MASK;
> }
>
> -static int add_bar_handlers(const struct pci_dev *pdev)
> +static void guest_rom_write(const struct pci_dev *pdev, unsigned int reg,
> + uint32_t val, void *data)
> +{
> +}
> +
> +static uint32_t guest_rom_read(const struct pci_dev *pdev, unsigned int reg,
> + void *data)
> +{
> + return 0xffffffff;
> +}
FWIW, I would also be fine with introducing the code for those
handlers at the same time.
> +
> +static int add_bar_handlers(const struct pci_dev *pdev, bool is_hwdom)
I would rather use is_hardware_domain(pdev->domain) than passing a
boolean here, no need to duplicate data which is already available
from the pdev.
> {
> unsigned int i;
> struct vpci_header *header = &pdev->vpci->header;
> struct vpci_bar *bars = header->bars;
> int rc;
>
> - /* Setup a handler for the command register. */
> + /* Setup a handler for the command register: same for hwdom and guests.
> */
> rc = vpci_add_register(pdev->vpci, vpci_hw_read16, cmd_write,
> PCI_COMMAND,
> 2, header);
> if ( rc )
> @@ -475,8 +497,13 @@ static int add_bar_handlers(const struct pci_dev *pdev)
> rom_reg = PCI_ROM_ADDRESS;
> else
> rom_reg = PCI_ROM_ADDRESS1;
> - rc = vpci_add_register(pdev->vpci, vpci_hw_read32, rom_write,
> - rom_reg, 4, &bars[i]);
> + if ( is_hwdom )
> + rc = vpci_add_register(pdev->vpci, vpci_hw_read32, rom_write,
> + rom_reg, 4, &bars[i]);
> + else
> + rc = vpci_add_register(pdev->vpci,
> + guest_rom_read, guest_rom_write,
> + rom_reg, 4, &bars[i]);
I think you could use:
else if ( IS_ENABLED(CONFIG_HAS_VPCI_GUEST_SUPPORT) )
rc = vpci_add_register(...
else
ASSERT_UNREACHABLE();
And then guard the guest_ handlers with CONFIG_HAS_VPCI_GUEST_SUPPORT.
> if ( rc )
> return rc;
> }
> @@ -485,8 +512,13 @@ static int add_bar_handlers(const struct pci_dev *pdev)
> uint8_t reg = PCI_BASE_ADDRESS_0 + i * 4;
>
> /* This is either VPCI_BAR_MEM32 or VPCI_BAR_MEM64_{LO|HI}. */
> - rc = vpci_add_register(pdev->vpci, vpci_hw_read32, bar_write,
> reg,
> - 4, &bars[i]);
> + if ( is_hwdom )
> + rc = vpci_add_register(pdev->vpci, vpci_hw_read32, bar_write,
> + reg, 4, &bars[i]);
> + else
> + rc = vpci_add_register(pdev->vpci,
> + guest_bar_read, guest_bar_write,
> + reg, 4, &bars[i]);
> if ( rc )
> return rc;
> }
> @@ -520,7 +552,7 @@ static int init_bars(struct pci_dev *pdev)
> }
>
> if ( pdev->ignore_bars )
> - return add_bar_handlers(pdev);
> + return add_bar_handlers(pdev, true);
>
> /* Disable memory decoding before sizing. */
> cmd = pci_conf_read16(pdev->sbdf, PCI_COMMAND);
> @@ -582,7 +614,7 @@ static int init_bars(struct pci_dev *pdev)
> PCI_ROM_ADDRESS_ENABLE;
> }
>
> - rc = add_bar_handlers(pdev);
> + rc = add_bar_handlers(pdev, true);
> if ( rc )
> {
> pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
> @@ -593,6 +625,30 @@ static int init_bars(struct pci_dev *pdev)
> }
> REGISTER_VPCI_INIT(init_bars, VPCI_PRIORITY_MIDDLE);
>
> +#ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
> +int vpci_bar_add_handlers(const struct domain *d, const struct pci_dev *pdev)
> +{
> + int rc;
> +
> + /* Remove previously added registers. */
> + vpci_remove_device_registers(pdev);
Shouldn't this be done by vpci_assign_device as a preparation for
assigning the device?
> +
> + rc = add_bar_handlers(pdev, is_hardware_domain(d));
Also this model seems to assume that vPCI will require the hardware
domain to have owned the device before it being assigned to a guest,
but for example when using a PV dom0 that won't be the case, and hence
we would need the vPCI fields to be filled when assigning to a guest.
Hence I wonder whether we shouldn't do a full re-initialization when
assigning to a guest instead of this partial one.
> + if ( rc )
> + gdprintk(XENLOG_ERR,
> + "%pp: failed to add BAR handlers for dom%pd: %d\n",
> + &pdev->sbdf, d, rc);
> + return rc;
> +}
> +
> +int vpci_bar_remove_handlers(const struct domain *d, const struct pci_dev
> *pdev)
> +{
> + /* Remove previously added registers. */
> + vpci_remove_device_registers(pdev);
> + return 0;
> +}
> +#endif
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
> index 0fe86cb30d23..702f7b5d5dda 100644
> --- a/xen/drivers/vpci/vpci.c
> +++ b/xen/drivers/vpci/vpci.c
> @@ -95,7 +95,7 @@ int vpci_assign_device(struct domain *d, const struct
> pci_dev *dev)
> if ( is_system_domain(d) || !has_vpci(d) )
> return 0;
>
> - return 0;
> + return vpci_bar_add_handlers(d, dev);
> }
>
> /* Notify vPCI that device is de-assigned from guest. */
> @@ -105,7 +105,7 @@ int vpci_deassign_device(struct domain *d, const struct
> pci_dev *dev)
> if ( is_system_domain(d) || !has_vpci(d) )
> return 0;
>
> - return 0;
> + return vpci_bar_remove_handlers(d, dev);
I think it would be better to use something similar to
REGISTER_VPCI_INIT here, otherwise this will need to be modified every
time a new capability is handled by Xen.
Maybe we could reuse or expand REGISTER_VPCI_INIT adding another field
to be used for guest initialization?
> }
> #endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */
>
> diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
> index ecc08f2c0f65..fd822c903af5 100644
> --- a/xen/include/xen/vpci.h
> +++ b/xen/include/xen/vpci.h
> @@ -57,6 +57,14 @@ uint32_t vpci_hw_read32(const struct pci_dev *pdev,
> unsigned int reg,
> */
> bool __must_check vpci_process_pending(struct vcpu *v);
>
> +#ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
> +/* Add/remove BAR handlers for a domain. */
> +int vpci_bar_add_handlers(const struct domain *d,
> + const struct pci_dev *pdev);
> +int vpci_bar_remove_handlers(const struct domain *d,
> + const struct pci_dev *pdev);
> +#endif
This would then go away if we implement a mechanism similar to
REGISTER_VPCI_INIT.
Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |