aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/physdev.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-08-08 11:12:14 +0200
committerJan Beulich <jbeulich@suse.com>2013-08-08 11:12:14 +0200
commitd1b6d0a02489c2d0e237d03e1d8af8d11df53b05 (patch)
tree63f46916a9ffd60319ae7da560bee26bc00b456b /xen/arch/x86/physdev.c
parentfe6df5abc40ba9928b25e84a9e2aa7434ce76283 (diff)
downloadxen-d1b6d0a02489c2d0e237d03e1d8af8d11df53b05.tar.gz
xen-d1b6d0a02489c2d0e237d03e1d8af8d11df53b05.tar.bz2
xen-d1b6d0a02489c2d0e237d03e1d8af8d11df53b05.zip
x86: enable multi-vector MSI
This implies - extending the public interface to have a way to request a block of MSIs - allocating a block of contiguous pIRQ-s for the target domain (but note that the Xen IRQs allocated have no need of being contiguous) - repeating certain operations for all involved IRQs - fixing multi_msi_enable() - adjusting the mask bit accesses for maskable MSIs Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com> Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/physdev.c')
-rw-r--r--xen/arch/x86/physdev.c56
1 files changed, 50 insertions, 6 deletions
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index 3733c7a129..4835ed7796 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -140,8 +140,11 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p,
break;
case MAP_PIRQ_TYPE_MSI:
+ if ( !msi->table_base )
+ msi->entry_nr = 1;
irq = *index;
if ( irq == -1 )
+ case MAP_PIRQ_TYPE_MULTI_MSI:
irq = create_irq(NUMA_NO_NODE);
if ( irq < nr_irqs_gsi || irq >= nr_irqs )
@@ -179,6 +182,30 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p,
goto done;
}
}
+ else if ( type == MAP_PIRQ_TYPE_MULTI_MSI )
+ {
+ if ( msi->entry_nr <= 0 || msi->entry_nr > 32 )
+ ret = -EDOM;
+ else if ( msi->entry_nr != 1 && !iommu_intremap )
+ ret = -EOPNOTSUPP;
+ else
+ {
+ while ( msi->entry_nr & (msi->entry_nr - 1) )
+ msi->entry_nr += msi->entry_nr & -msi->entry_nr;
+ pirq = get_free_pirqs(d, msi->entry_nr);
+ if ( pirq < 0 )
+ {
+ while ( (msi->entry_nr >>= 1) > 1 )
+ if ( get_free_pirqs(d, msi->entry_nr) > 0 )
+ break;
+ dprintk(XENLOG_G_ERR, "dom%d: no block of %d free pirqs\n",
+ d->domain_id, msi->entry_nr << 1);
+ ret = pirq;
+ }
+ }
+ if ( ret < 0 )
+ goto done;
+ }
else
{
pirq = get_free_pirq(d, type);
@@ -210,8 +237,15 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p,
done:
spin_unlock(&d->event_lock);
spin_unlock(&pcidevs_lock);
- if ( (ret != 0) && (type == MAP_PIRQ_TYPE_MSI) && (*index == -1) )
- destroy_irq(irq);
+ if ( ret != 0 )
+ switch ( type )
+ {
+ case MAP_PIRQ_TYPE_MSI:
+ if ( *index == -1 )
+ case MAP_PIRQ_TYPE_MULTI_MSI:
+ destroy_irq(irq);
+ break;
+ }
free_domain:
rcu_unlock_domain(d);
return ret;
@@ -390,14 +424,22 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
if ( copy_from_guest(&map, arg, 1) != 0 )
break;
- if ( map.type == MAP_PIRQ_TYPE_MSI_SEG )
+ switch ( map.type )
{
+ case MAP_PIRQ_TYPE_MSI_SEG:
map.type = MAP_PIRQ_TYPE_MSI;
msi.seg = map.bus >> 16;
- }
- else
- {
+ break;
+
+ case MAP_PIRQ_TYPE_MULTI_MSI:
+ if ( map.table_base )
+ return -EINVAL;
+ msi.seg = map.bus >> 16;
+ break;
+
+ default:
msi.seg = 0;
+ break;
}
msi.bus = map.bus;
msi.devfn = map.devfn;
@@ -406,6 +448,8 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
ret = physdev_map_pirq(map.domid, map.type, &map.index, &map.pirq,
&msi);
+ if ( map.type == MAP_PIRQ_TYPE_MULTI_MSI )
+ map.entry_nr = msi.entry_nr;
if ( __copy_to_guest(arg, &map, 1) )
ret = -EFAULT;
break;