[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v20 2/2] vpci: translate virtual PCI bus topology for guests
On 5/6/25 07:16, Roger Pau Monné wrote: > Hello, > > Sorry I haven't looked at this before, I was confused with the cover > letter having ARM in the subject and somehow assumed all the code was > ARM related. No worries, thanks for taking a look. > On Fri, Apr 18, 2025 at 02:58:37PM -0400, Stewart Hildebrand wrote: >> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx> >> >> There are two originators for the PCI configuration space access: >> 1. The domain that owns physical host bridge: MMIO handlers are >> there so we can update vPCI register handlers with the values >> written by the hardware domain, e.g. physical view of the registers >> vs guest's view on the configuration space. >> 2. Guest access to the passed through PCI devices: we need to properly >> map virtual bus topology to the physical one, e.g. pass the configuration >> space access to the corresponding physical devices. >> >> In vpci_read(), use the access size to create a mask so as to not set >> any bits above the access size when returning an error. > > I see this here, and the code below, yet I'm not following why this is > a requirement for the code added here. It seems like an unrelated > change? See below >> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx> >> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx> >> Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx> >> --- >> In v20: >> * call translate_virtual_device() from within locked context of >> vpci_{read,write} >> * update commit message >> In v19: >> * move locking to pre-patch >> In v18: >> * address warning in vpci test suite >> In v17: >> * move lock to inside vpci_translate_virtual_device() >> * acks were previously given for Arm [0] and vPCI [1], but since it was >> two releases ago and the patch has changed, I didn't pick them up >> >> [0] >> https://lore.kernel.org/xen-devel/4afe33f2-72e6-4755-98ce-d7f9da374e90@xxxxxxx/ >> [1] https://lore.kernel.org/xen-devel/Zk70udmiriruMt0r@macbook/ >> >> In v15: >> - base on top of ("arm/vpci: honor access size when returning an error") >> In v11: >> - Fixed format issues >> - Added ASSERT_UNREACHABLE() to the dummy implementation of >> vpci_translate_virtual_device() >> - Moved variable in vpci_sbdf_from_gpa(), now it is easier to follow >> the logic in the function >> Since v9: >> - Commend about required lock replaced with ASSERT() >> - Style fixes >> - call to vpci_translate_virtual_device folded into vpci_sbdf_from_gpa >> Since v8: >> - locks moved out of vpci_translate_virtual_device() >> Since v6: >> - add pcidevs locking to vpci_translate_virtual_device >> - update wrt to the new locking scheme >> Since v5: >> - add vpci_translate_virtual_device for #ifndef CONFIG_HAS_VPCI_GUEST_SUPPORT >> case to simplify ifdefery >> - add ASSERT(!is_hardware_domain(d)); to vpci_translate_virtual_device >> - reset output register on failed virtual SBDF translation >> Since v4: >> - indentation fixes >> - constify struct domain >> - updated commit message >> - updates to the new locking scheme (pdev->vpci_lock) >> Since v3: >> - revisit locking >> - move code to vpci.c >> Since v2: >> - pass struct domain instead of struct vcpu >> - constify arguments where possible >> - gate relevant code with CONFIG_HAS_VPCI_GUEST_SUPPORT >> New in v2 >> --- >> tools/tests/vpci/emul.h | 2 +- >> xen/arch/arm/vpci.c | 4 +++ >> xen/drivers/vpci/vpci.c | 73 +++++++++++++++++++++++++++++++++++++---- >> 3 files changed, 71 insertions(+), 8 deletions(-) >> >> diff --git a/tools/tests/vpci/emul.h b/tools/tests/vpci/emul.h >> index da446bba86b4..dd048cffbf9d 100644 >> --- a/tools/tests/vpci/emul.h >> +++ b/tools/tests/vpci/emul.h >> @@ -89,7 +89,7 @@ typedef union { >> >> #define __hwdom_init >> >> -#define is_hardware_domain(d) ((void)(d), false) >> +#define is_hardware_domain(d) ((void)(d), true) >> >> #define has_vpci(d) true >> >> diff --git a/xen/arch/arm/vpci.c b/xen/arch/arm/vpci.c >> index b63a356bb4a8..618ddb7f6547 100644 >> --- a/xen/arch/arm/vpci.c >> +++ b/xen/arch/arm/vpci.c >> @@ -34,6 +34,8 @@ static int vpci_mmio_read(struct vcpu *v, mmio_info_t >> *info, >> /* data is needed to prevent a pointer cast on 32bit */ >> unsigned long data; >> >> + ASSERT(!bridge == !is_hardware_domain(v->domain)); >> + >> if ( vpci_ecam_read(sbdf, ECAM_REG_OFFSET(info->gpa), >> 1U << info->dabt.size, &data) ) >> { >> @@ -52,6 +54,8 @@ static int vpci_mmio_write(struct vcpu *v, mmio_info_t >> *info, >> struct pci_host_bridge *bridge = p; >> pci_sbdf_t sbdf = vpci_sbdf_from_gpa(bridge, info->gpa); >> >> + ASSERT(!bridge == !is_hardware_domain(v->domain)); >> + >> return vpci_ecam_write(sbdf, ECAM_REG_OFFSET(info->gpa), >> 1U << info->dabt.size, r); >> } >> diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c >> index 1e6aa5d799b9..fc409f3fc346 100644 >> --- a/xen/drivers/vpci/vpci.c >> +++ b/xen/drivers/vpci/vpci.c >> @@ -174,6 +174,41 @@ int vpci_assign_device(struct pci_dev *pdev) >> } >> #endif /* __XEN__ */ >> >> +#ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT >> +/* >> + * Find the physical device which is mapped to the virtual device >> + * and translate virtual SBDF to the physical one. >> + */ >> +static const struct pci_dev *translate_virtual_device(const struct domain >> *d, >> + pci_sbdf_t *sbdf) >> +{ >> + const struct pci_dev *pdev; >> + >> + ASSERT(!is_hardware_domain(d)); >> + ASSERT(rw_is_locked(&d->pci_lock)); >> + >> + for_each_pdev ( d, pdev ) >> + { >> + if ( pdev->vpci && (pdev->vpci->guest_sbdf.sbdf == sbdf->sbdf) ) >> + { >> + /* Replace guest SBDF with the physical one. */ >> + *sbdf = pdev->sbdf; >> + return pdev; >> + } >> + } >> + >> + return NULL; >> +} >> +#else >> +static const struct pci_dev *translate_virtual_device(const struct domain >> *d, >> + pci_sbdf_t *sbdf) >> +{ >> + ASSERT_UNREACHABLE(); >> + >> + return NULL; >> +} >> +#endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */ > > Jan's suggestion avoids having duplicate headers, and results in less > code overall: > > static const struct pci_dev *translate_virtual_device(const struct domain *d, > pci_sbdf_t *sbdf) > { > #ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT > const struct pci_dev *pdev; > ... > #else /* !CONFIG_HAS_VPCI_GUEST_SUPPORT */ > ASSERT_UNREACHABLE() > #endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */ > > return NULL; > } > > I've not overly fuzzed either way, but if changes are required you > might as well change to this form. Will do >> static int vpci_register_cmp(const struct vpci_register *r1, >> const struct vpci_register *r2) >> { >> @@ -438,7 +473,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, >> unsigned int size) >> const struct pci_dev *pdev; >> const struct vpci_register *r; >> unsigned int data_offset = 0; >> - uint32_t data = ~(uint32_t)0; >> + uint32_t data = 0xffffffffU >> (32 - 8 * size); > > This seems kind of unrelated to the rest of the code in the patch, > why is this needed? Isn't it always fine to return all ones, and let > the caller truncate to the required size? > > Otherwise the code in vpci_read_hw() also needs to be adjusted. On Arm, since 9a5e22b64266 ("xen/arm: check read handler behavior") we assert that the read handlers don't set any bits above the access size. I had adjusted data here due to returning it directly from vpci_read() in the current form of the patch. With your suggestion below we would only need to adjust vpci_read_hw() (and then data here would not strictly need adjusting). > And > you can likely use GENMASK(size * 8, 0) as it's easier to read. OK. I'll then also provide a definition for GENMASK in tools/tests/vpci/emul.h. >> >> if ( !size ) >> { >> @@ -453,9 +488,21 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, >> unsigned int size) >> * pci_lock is sufficient. >> */ >> read_lock(&d->pci_lock); >> - pdev = pci_get_pdev(d, sbdf); >> - if ( !pdev && is_hardware_domain(d) ) >> - pdev = pci_get_pdev(dom_xen, sbdf); >> + if ( is_hardware_domain(d) ) >> + { >> + pdev = pci_get_pdev(d, sbdf); >> + if ( !pdev ) >> + pdev = pci_get_pdev(dom_xen, sbdf); >> + } >> + else >> + { >> + pdev = translate_virtual_device(d, &sbdf); >> + if ( !pdev ) >> + { >> + read_unlock(&d->pci_lock); >> + return data; >> + } > > You don't need this checking here, as the check below will already be > enough AFAICT, iow: > > if ( is_hardware_domain(d) ) > { > pdev = pci_get_pdev(d, sbdf); > if ( !pdev ) > pdev = pci_get_pdev(dom_xen, sbdf); > } > else > pdev = translate_virtual_device(d, &sbdf); > > if ( !pdev || !pdev->vpci ) > { > read_unlock(&d->pci_lock); > return vpci_read_hw(sbdf, reg, size); > } > > Achieves the same and is more compact by having a single return for > all the possible cases? Same for the write case below. Seeing as there is a is_hardware_domain check inside vpci_read_hw(), that is okay. I'll make the adjustment here and in vpci_write.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |