[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.