aboutsummaryrefslogtreecommitdiffstats
path: root/xen/drivers/passthrough
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-02-14 09:42:57 +0100
committerJan Beulich <jbeulich@suse.com>2013-02-14 09:42:57 +0100
commitb5955458b3d1655f1b40cebd28d8735c146987af (patch)
tree09cb8ea207db55c80096ab376cded850e42e5850 /xen/drivers/passthrough
parent2101800f68b3e13064df34fa404dd012e2b598dd (diff)
downloadxen-b5955458b3d1655f1b40cebd28d8735c146987af.tar.gz
xen-b5955458b3d1655f1b40cebd28d8735c146987af.tar.bz2
xen-b5955458b3d1655f1b40cebd28d8735c146987af.zip
AMD IOMMU: handle MSI for phantom functions
With ordinary requests allowed to come from phantom functions, the remapping tables ought to be set up to also allow for MSI triggers to come from other than the "real" device too. It is not clear to me whether the alias-ID handling also needs adjustment for this to work properly, or whether firmware can be expected to properly express this through a device alias range descriptor (or multiple device alias ones). Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'xen/drivers/passthrough')
-rw-r--r--xen/drivers/passthrough/amd/iommu_intr.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/xen/drivers/passthrough/amd/iommu_intr.c b/xen/drivers/passthrough/amd/iommu_intr.c
index 5629cc7712..4ae5a54079 100644
--- a/xen/drivers/passthrough/amd/iommu_intr.c
+++ b/xen/drivers/passthrough/amd/iommu_intr.c
@@ -286,7 +286,7 @@ void amd_iommu_ioapic_update_ire(
static void update_intremap_entry_from_msi_msg(
struct amd_iommu *iommu, u16 bdf,
- struct msi_desc *msi_desc, struct msi_msg *msg)
+ int *remap_index, const struct msi_msg *msg)
{
unsigned long flags;
u32* entry;
@@ -302,7 +302,7 @@ static void update_intremap_entry_from_msi_msg(
{
lock = get_intremap_lock(iommu->seg, req_id);
spin_lock_irqsave(lock, flags);
- free_intremap_entry(iommu->seg, req_id, msi_desc->remap_index);
+ free_intremap_entry(iommu->seg, req_id, *remap_index);
spin_unlock_irqrestore(lock, flags);
if ( ( req_id != alias_id ) &&
@@ -310,7 +310,7 @@ static void update_intremap_entry_from_msi_msg(
{
lock = get_intremap_lock(iommu->seg, alias_id);
spin_lock_irqsave(lock, flags);
- free_intremap_entry(iommu->seg, alias_id, msi_desc->remap_index);
+ free_intremap_entry(iommu->seg, alias_id, *remap_index);
spin_unlock_irqrestore(lock, flags);
}
goto done;
@@ -324,7 +324,10 @@ static void update_intremap_entry_from_msi_msg(
vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK;
dest = (msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff;
offset = get_intremap_offset(vector, delivery_mode);
- msi_desc->remap_index = offset;
+ if ( *remap_index < 0)
+ *remap_index = offset;
+ else
+ BUG_ON(*remap_index != offset);
entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
@@ -379,12 +382,30 @@ void amd_iommu_msi_msg_update_ire(
}
if ( msi_desc->remap_index >= 0 )
- update_intremap_entry_from_msi_msg(iommu, bdf, msi_desc, NULL);
+ {
+ do {
+ update_intremap_entry_from_msi_msg(iommu, bdf,
+ &msi_desc->remap_index, NULL);
+ if ( !pdev || !pdev->phantom_stride )
+ break;
+ bdf += pdev->phantom_stride;
+ } while ( PCI_SLOT(bdf) == PCI_SLOT(pdev->devfn) );
+
+ msi_desc->remap_index = -1;
+ if ( pdev )
+ bdf = PCI_BDF2(pdev->bus, pdev->devfn);
+ }
if ( !msg )
return;
- update_intremap_entry_from_msi_msg(iommu, bdf, msi_desc, msg);
+ do {
+ update_intremap_entry_from_msi_msg(iommu, bdf, &msi_desc->remap_index,
+ msg);
+ if ( !pdev || !pdev->phantom_stride )
+ break;
+ bdf += pdev->phantom_stride;
+ } while ( PCI_SLOT(bdf) == PCI_SLOT(pdev->devfn) );
}
void amd_iommu_read_msi_from_ire(