|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V2 21/25] tools/libxc: Add a new interface to bind remapping format msi with pirq
On Wed, Aug 09, 2017 at 04:34:22PM -0400, Lan Tianyu wrote:
> From: Chao Gao <chao.gao@xxxxxxxxx>
>
> Introduce a new binding relationship and provide a new interface to
> manage the new relationship.
>
> Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
> Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>
> ---
> tools/libxc/include/xenctrl.h | 17 ++++++
> tools/libxc/xc_domain.c | 53 +++++++++++++++++
> xen/drivers/passthrough/io.c | 135
> +++++++++++++++++++++++++++++++++++-------
> xen/include/public/domctl.h | 7 +++
> xen/include/xen/hvm/irq.h | 7 +++
> 5 files changed, 198 insertions(+), 21 deletions(-)
>
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index dfaa9d5..b0a9437 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -1720,6 +1720,15 @@ int xc_domain_ioport_mapping(xc_interface *xch,
> uint32_t nr_ports,
> uint32_t add_mapping);
>
> +int xc_domain_update_msi_irq_remapping(
> + xc_interface *xch,
> + uint32_t domid,
> + uint32_t pirq,
> + uint32_t source_id,
> + uint32_t data,
> + uint64_t addr,
> + uint64_t gtable);
> +
> int xc_domain_update_msi_irq(
> xc_interface *xch,
> uint32_t domid,
> @@ -1734,6 +1743,14 @@ int xc_domain_unbind_msi_irq(xc_interface *xch,
> uint32_t pirq,
> uint32_t gflags);
>
> +int xc_domain_unbind_msi_irq_remapping(
> + xc_interface *xch,
> + uint32_t domid,
> + uint32_t pirq,
> + uint32_t source_id,
> + uint32_t data,
> + uint64_t addr);
I think this doesn't match the coding style, but it seems like the
surrounding functions also use it, so I will let the maintainers
decide whether this is fine or not.
> int xc_domain_bind_pt_irq(xc_interface *xch,
> uint32_t domid,
> uint8_t machine_irq,
> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> index 3bab4e8..4b6a510 100644
> --- a/tools/libxc/xc_domain.c
> +++ b/tools/libxc/xc_domain.c
> @@ -1702,8 +1702,34 @@ int xc_deassign_dt_device(
> return rc;
> }
>
> +int xc_domain_update_msi_irq_remapping(
> + xc_interface *xch,
> + uint32_t domid,
> + uint32_t pirq,
> + uint32_t source_id,
> + uint32_t data,
> + uint64_t addr,
> + uint64_t gtable)
> +{
> + int rc;
> + xen_domctl_bind_pt_irq_t *bind;
No newline.
> + DECLARE_DOMCTL;
>
> + domctl.cmd = XEN_DOMCTL_bind_pt_irq;
> + domctl.domain = (domid_t)domid;
>
> + bind = &(domctl.u.bind_pt_irq);
> + bind->irq_type = PT_IRQ_TYPE_MSI_IR;
> + bind->machine_irq = pirq;
> + bind->u.msi_ir.source_id = source_id;
> + bind->u.msi_ir.data = data;
> + bind->u.msi_ir.addr = addr;
> + bind->u.msi_ir.gtable = gtable;
> +
> + rc = do_domctl(xch, &domctl);
> + return rc;
> +}
>
> int xc_domain_update_msi_irq(
> xc_interface *xch,
> @@ -1732,6 +1758,33 @@ int xc_domain_update_msi_irq(
> return rc;
> }
>
> +int xc_domain_unbind_msi_irq_remapping(
> + xc_interface *xch,
> + uint32_t domid,
> + uint32_t pirq,
> + uint32_t source_id,
> + uint32_t data,
> + uint64_t addr)
> +{
> + int rc;
> + xen_domctl_bind_pt_irq_t *bind;
> +
> + DECLARE_DOMCTL;
> +
> + domctl.cmd = XEN_DOMCTL_unbind_pt_irq;
> + domctl.domain = (domid_t)domid;
> +
> + bind = &(domctl.u.bind_pt_irq);
> + bind->irq_type = PT_IRQ_TYPE_MSI_IR;
> + bind->machine_irq = pirq;
> + bind->u.msi_ir.source_id = source_id;
> + bind->u.msi_ir.data = data;
> + bind->u.msi_ir.addr = addr;
> +
> + rc = do_domctl(xch, &domctl);
> + return rc;
> +}
> +
> int xc_domain_unbind_msi_irq(
> xc_interface *xch,
> uint32_t domid,
> diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c
> index 4d457f6..0510887 100644
> --- a/xen/drivers/passthrough/io.c
> +++ b/xen/drivers/passthrough/io.c
> @@ -276,6 +276,92 @@ static struct vcpu *vector_hashing_dest(const struct
> domain *d,
> return dest;
> }
>
> +static inline void set_hvm_gmsi_info(struct hvm_gmsi_info *msi,
> + xen_domctl_bind_pt_irq_t *pt_irq_bind)
Inline? I would rather let the compiler decide IMHO.
> +{
> + if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
A switch seems like a better choice here.
> + {
> + msi->legacy.gvec = pt_irq_bind->u.msi.gvec;
> + msi->legacy.gflags = pt_irq_bind->u.msi.gflags;
> + }
> + else if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_IR )
> + {
> + msi->intremap.source_id = pt_irq_bind->u.msi_ir.source_id;
> + msi->intremap.data = pt_irq_bind->u.msi_ir.data;
> + msi->intremap.addr = pt_irq_bind->u.msi_ir.addr;
> + }
> + else
> + BUG();
ASSERT_UNREACHABLE();
> +}
> +
> +static inline void clear_hvm_gmsi_info(struct hvm_gmsi_info *msi, int
> irq_type)
No inline.
> +{
> + if ( irq_type == PT_IRQ_TYPE_MSI )
Same here (switch + ASSERT). Maybe a memset would be faster here?
> + {
> + msi->legacy.gvec = 0;
> + msi->legacy.gflags = 0;
> + }
> + else if ( irq_type == PT_IRQ_TYPE_MSI_IR )
> + {
> + msi->intremap.source_id = 0;
> + msi->intremap.data = 0;
> + msi->intremap.addr = 0;
> + }
> + else
> + BUG();
> +}
> +
> +static inline bool hvm_gmsi_info_need_update(struct hvm_gmsi_info *msi,
No inline.
> + xen_domctl_bind_pt_irq_t
> *pt_irq_bind)
> +{
> + if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
switch please.
> + return ((msi->legacy.gvec != pt_irq_bind->u.msi.gvec) ||
> + (msi->legacy.gflags != pt_irq_bind->u.msi.gflags));
> + else if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_IR )
Unneeded else.
> + return ((msi->intremap.source_id != pt_irq_bind->u.msi_ir.source_id)
> ||
> + (msi->intremap.data != pt_irq_bind->u.msi_ir.data) ||
> + (msi->intremap.addr != pt_irq_bind->u.msi_ir.addr));
> + BUG();
ASSERT_UNREACHABLE and newline.
> + return 0;
> +}
> +
> +static int pirq_dpci_2_msi_attr(struct domain *d,
> + struct hvm_pirq_dpci *pirq_dpci, uint8_t
> *gvec,
> + uint8_t *dest, uint8_t *dm, uint8_t *dlm)
> +{
> + int rc = 0;
> +
> + if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI )
> + {
> + *gvec = pirq_dpci->gmsi.legacy.gvec;
> + *dest = pirq_dpci->gmsi.legacy.gflags & VMSI_DEST_ID_MASK;
> + *dm = !!(pirq_dpci->gmsi.legacy.gflags & VMSI_DM_MASK);
> + *dlm = (pirq_dpci->gmsi.legacy.gflags & VMSI_DELIV_MASK) >>
> + GFLAGS_SHIFT_DELIV_MODE;
MASK_EXTR.
> + }
> + else if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI_IR )
> + {
> + struct irq_remapping_request request;
> + struct irq_remapping_info irq_info;
> +
> + irq_request_msi_fill(&request, pirq_dpci->gmsi.intremap.source_id,
> + pirq_dpci->gmsi.intremap.addr,
> + pirq_dpci->gmsi.intremap.data);
> + /* Currently, only viommu 0 is supported */
> + rc = viommu_get_irq_info(d, 0, &request, &irq_info);
> + if ( !rc )
I don't like the !rc construct, I would rather have:
if ( rc )
return rc;
*gvec = ...;
But that's my personal taste, you should wait for maintainers to
express their opinions.
> + {
> + *gvec = irq_info.vector;
> + *dest = irq_info.dest;
> + *dm = irq_info.dest_mode;
> + *dlm = irq_info.delivery_mode;
> + }
> + }
> + else
> + BUG();
ASSERT_UNREACHABLE();
> + return rc;
> +}
> +
> int pt_irq_create_bind(
> struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
> {
> @@ -339,17 +425,21 @@ int pt_irq_create_bind(
> switch ( pt_irq_bind->irq_type )
> {
> case PT_IRQ_TYPE_MSI:
> + case PT_IRQ_TYPE_MSI_IR:
> {
> - uint8_t dest, dest_mode, delivery_mode;
> + uint8_t dest = 0, dest_mode = 0, delivery_mode = 0, gvec;
Why do you need those initializations now? They where unneeded before
and I don't see you using those variables.
> int dest_vcpu_id;
> const struct vcpu *vcpu;
> + bool ir = (pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_IR);
> + uint64_t gtable = ir ? pt_irq_bind->u.msi_ir.gtable :
> + pt_irq_bind->u.msi.gtable;
>
> if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) )
> {
> pirq_dpci->flags = HVM_IRQ_DPCI_MAPPED | HVM_IRQ_DPCI_MACH_MSI |
> - HVM_IRQ_DPCI_GUEST_MSI;
> - pirq_dpci->gmsi.legacy.gvec = pt_irq_bind->u.msi.gvec;
> - pirq_dpci->gmsi.legacy.gflags = pt_irq_bind->u.msi.gflags;
> + (ir ? HVM_IRQ_DPCI_GUEST_MSI_IR :
> + HVM_IRQ_DPCI_GUEST_MSI);
> + set_hvm_gmsi_info(&pirq_dpci->gmsi, pt_irq_bind);
> /*
> * 'pt_irq_create_bind' can be called after
> 'pt_irq_destroy_bind'.
> * The 'pirq_cleanup_check' which would free the structure is
> only
> @@ -364,9 +454,9 @@ int pt_irq_create_bind(
> pirq_dpci->dom = d;
> /* bind after hvm_irq_dpci is setup to avoid race with irq
> handler*/
> rc = pirq_guest_bind(d->vcpu[0], info, 0);
> - if ( rc == 0 && pt_irq_bind->u.msi.gtable )
> + if ( rc == 0 && gtable )
> {
> - rc = msixtbl_pt_register(d, info, pt_irq_bind->u.msi.gtable);
> + rc = msixtbl_pt_register(d, info, gtable);
> if ( unlikely(rc) )
> {
> pirq_guest_unbind(d, info);
> @@ -381,8 +471,7 @@ int pt_irq_create_bind(
> }
> if ( unlikely(rc) )
> {
> - pirq_dpci->gmsi.legacy.gflags = 0;
> - pirq_dpci->gmsi.legacy.gvec = 0;
> + clear_hvm_gmsi_info(&pirq_dpci->gmsi, pt_irq_bind->irq_type);
> pirq_dpci->dom = NULL;
> pirq_dpci->flags = 0;
> pirq_cleanup_check(info, d);
> @@ -392,7 +481,8 @@ int pt_irq_create_bind(
> }
> else
> {
> - uint32_t mask = HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_MSI;
> + uint32_t mask = HVM_IRQ_DPCI_MACH_MSI |
> + (ir ? HVM_IRQ_DPCI_GUEST_MSI_IR :
> HVM_IRQ_DPCI_GUEST_MSI);
Maybe:
uint32_t mask = (ir ? HVM_IRQ_DPCI_GUEST_MSI_IR
: HVM_IRQ_DPCI_GUEST_MSI) |
HVM_IRQ_DPCI_MACH_MSI;
>
> if ( (pirq_dpci->flags & mask) != mask )
> {
> @@ -401,29 +491,31 @@ int pt_irq_create_bind(
> }
>
> /* If pirq is already mapped as vmsi, update guest data/addr. */
> - if ( pirq_dpci->gmsi.legacy.gvec != pt_irq_bind->u.msi.gvec ||
> - pirq_dpci->gmsi.legacy.gflags != pt_irq_bind->u.msi.gflags )
> + if ( hvm_gmsi_info_need_update(&pirq_dpci->gmsi, pt_irq_bind) )
> {
> /* Directly clear pending EOIs before enabling new MSI info.
> */
> pirq_guest_eoi(info);
>
> - pirq_dpci->gmsi.legacy.gvec = pt_irq_bind->u.msi.gvec;
> - pirq_dpci->gmsi.legacy.gflags = pt_irq_bind->u.msi.gflags;
> + set_hvm_gmsi_info(&pirq_dpci->gmsi, pt_irq_bind);
> }
> }
> /* Calculate dest_vcpu_id for MSI-type pirq migration. */
> - dest = pirq_dpci->gmsi.legacy.gflags & VMSI_DEST_ID_MASK;
> - dest_mode = !!(pirq_dpci->gmsi.legacy.gflags & VMSI_DM_MASK);
> - delivery_mode = (pirq_dpci->gmsi.legacy.gflags & VMSI_DELIV_MASK) >>
> - GFLAGS_SHIFT_DELIV_MODE;
> -
> - dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode);
> + rc = pirq_dpci_2_msi_attr(d, pirq_dpci, &gvec, &dest, &dest_mode,
> + &delivery_mode);
> + if ( unlikely(rc) )
> + {
> + spin_unlock(&d->event_lock);
> + return -EFAULT;
Return rc? Or else you are losing the return value for no apparent
reason.
> + }
> + else
Unneeded else branch.
> + dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode);
> pirq_dpci->gmsi.dest_vcpu_id = dest_vcpu_id;
> spin_unlock(&d->event_lock);
>
> pirq_dpci->gmsi.posted = false;
> vcpu = (dest_vcpu_id >= 0) ? d->vcpu[dest_vcpu_id] : NULL;
> - if ( iommu_intpost )
> + /* Currently, don't use interrupt posting for guest's remapping MSIs
> */
> + if ( iommu_intpost && !ir )
> {
> if ( delivery_mode == dest_LowestPrio )
> vcpu = vector_hashing_dest(d, dest, dest_mode,
> @@ -435,7 +527,7 @@ int pt_irq_create_bind(
> hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]);
>
> /* Use interrupt posting if it is supported. */
> - if ( iommu_intpost )
> + if ( iommu_intpost && !ir )
So with interrupt remapping posted interrupts are not available...
> pi_update_irte(vcpu ? &vcpu->arch.hvm_vmx.pi_desc : NULL,
> info, pirq_dpci->gmsi.legacy.gvec);
>
> @@ -627,6 +719,7 @@ int pt_irq_destroy_bind(
> }
> break;
> case PT_IRQ_TYPE_MSI:
> + case PT_IRQ_TYPE_MSI_IR:
> break;
> default:
> return -EOPNOTSUPP;
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 4b10f26..1adf032 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -555,6 +555,7 @@ typedef enum pt_irq_type_e {
> PT_IRQ_TYPE_MSI,
> PT_IRQ_TYPE_MSI_TRANSLATE,
> PT_IRQ_TYPE_SPI, /* ARM: valid range 32-1019 */
> + PT_IRQ_TYPE_MSI_IR,
> } pt_irq_type_t;
> struct xen_domctl_bind_pt_irq {
> uint32_t machine_irq;
> @@ -575,6 +576,12 @@ struct xen_domctl_bind_pt_irq {
> uint64_aligned_t gtable;
> } msi;
> struct {
> + uint32_t source_id;
> + uint32_t data;
> + uint64_t addr;
> + uint64_aligned_t gtable;
uint64_aligned_t? Please use uint64_t.
> + } msi_ir;
> + struct {
> uint16_t spi;
> } spi;
> } u;
> diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h
> index 5e736f8..884e092 100644
> --- a/xen/include/xen/hvm/irq.h
> +++ b/xen/include/xen/hvm/irq.h
> @@ -41,6 +41,7 @@ struct dev_intx_gsi_link {
> #define _HVM_IRQ_DPCI_GUEST_PCI_SHIFT 4
> #define _HVM_IRQ_DPCI_GUEST_MSI_SHIFT 5
> #define _HVM_IRQ_DPCI_IDENTITY_GSI_SHIFT 6
> +#define _HVM_IRQ_DPCI_GUEST_MSI_IR_SHIFT 7
Trailing space.
Roger.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |