* [PATCH] AMD IOMMU: Fix a xen crash on amd iommu systems
@ 2009-12-16 15:54 Wei Wang2
0 siblings, 0 replies; 2+ messages in thread
From: Wei Wang2 @ 2009-12-16 15:54 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 527 bytes --]
(the correct attachment)
Changeset 20514 implemented deallocation for msi interrupt remapping entries.
Attached patch adds the same support for amd iommu to fix a xen crash on amd
iommu systems.
Thanks,
Wei
Signed-off-by: Wei Wang <wei.wang2@amd.com>
--
Legal Information:
Advanced Micro Devices GmbH
Karl-Hammerschmidt-Str. 34
85609 Dornach b. München
Geschäftsführer: Andrew Bowd, Thomas M. McCoy, Giuliano Meroni
Sitz: Dornach, Gemeinde Aschheim, Landkreis München
Registergericht München, HRB Nr. 43632
[-- Attachment #2: fix_msi.patch --]
[-- Type: text/x-diff, Size: 6214 bytes --]
diff -r 1e9441f4dcbd xen/drivers/passthrough/amd/iommu_intr.c
--- a/xen/drivers/passthrough/amd/iommu_intr.c Mon Dec 14 11:58:45 2009 +0000
+++ b/xen/drivers/passthrough/amd/iommu_intr.c Wed Dec 16 15:49:31 2009 +0100
@@ -23,6 +23,9 @@
#include <asm/hvm/svm/amd-iommu-proto.h>
#define INTREMAP_TABLE_ORDER 1
+#define INTREMAP_LENGTH 0xB
+#define INTREMAP_ENTRIES (1 << INTREMAP_LENGTH)
+
int ioapic_bdf[MAX_IO_APICS];
extern struct ivrs_mappings *ivrs_mappings;
extern unsigned short ivrs_bdf_entries;
@@ -42,19 +45,30 @@ static int get_intremap_requestor_id(int
return ivrs_mappings[bdf].dte_requestor_id;
}
-static u8 *get_intremap_entry(int bdf, u8 vector, u8 dm)
-{
- u8 *table;
+static int get_intremap_offset(u8 vector, u8 dm)
+{
int offset = 0;
-
- table = (u8*)ivrs_mappings[bdf].intremap_table;
- ASSERT( table != NULL );
-
offset = (dm << INT_REMAP_INDEX_DM_SHIFT) & INT_REMAP_INDEX_DM_MASK;
offset |= (vector << INT_REMAP_INDEX_VECTOR_SHIFT ) &
INT_REMAP_INDEX_VECTOR_MASK;
+ return offset;
+}
+
+static u8 *get_intremap_entry(int bdf, int offset)
+{
+ u8 *table;
+
+ table = (u8*)ivrs_mappings[bdf].intremap_table;
+ ASSERT( (table != NULL) && (offset < INTREMAP_ENTRIES) );
return (u8*) (table + offset);
+}
+
+static void free_intremap_entry(int bdf, int offset)
+{
+ u32* entry;
+ entry = (u32*)get_intremap_entry(bdf, offset);
+ memset(entry, 0, sizeof(u32));
}
static void update_intremap_entry(u32* entry, u8 vector, u8 int_type,
@@ -111,6 +125,7 @@ static void update_intremap_entry_from_i
struct IO_APIC_route_entry *rte = ioapic_rte;
int req_id;
spinlock_t *lock;
+ int offset;
req_id = get_intremap_requestor_id(bdf);
lock = get_intremap_lock(req_id);
@@ -123,11 +138,13 @@ static void update_intremap_entry_from_i
dest = rte->dest.logical.logical_dest;
spin_lock_irqsave(lock, flags);
- entry = (u32*)get_intremap_entry(req_id, vector, delivery_mode);
+ offset = get_intremap_offset(vector, delivery_mode);
+ entry = (u32*)get_intremap_entry(req_id, offset);
+
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
spin_unlock_irqrestore(lock, flags);
- if ( iommu->enabled )
+ if ( iommu->enabled )
{
spin_lock_irqsave(&iommu->lock, flags);
invalidate_interrupt_table(iommu, req_id);
@@ -147,6 +164,7 @@ int __init amd_iommu_setup_ioapic_remapp
u16 bdf, req_id;
struct amd_iommu *iommu;
spinlock_t *lock;
+ int offset;
/* Read ioapic entries and update interrupt remapping table accordingly */
for ( apic = 0; apic < nr_ioapics; apic++ )
@@ -178,7 +196,8 @@ int __init amd_iommu_setup_ioapic_remapp
dest = rte.dest.logical.logical_dest;
spin_lock_irqsave(lock, flags);
- entry = (u32*)get_intremap_entry(req_id, vector, delivery_mode);
+ offset = get_intremap_offset(vector, delivery_mode);
+ entry = (u32*)get_intremap_entry(req_id, offset);
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
spin_unlock_irqrestore(lock, flags);
@@ -242,16 +261,38 @@ void amd_iommu_ioapic_update_ire(
}
static void update_intremap_entry_from_msi_msg(
- struct amd_iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg)
+ struct amd_iommu *iommu, struct pci_dev *pdev,
+ struct msi_desc *msi_desc, struct msi_msg *msg)
{
unsigned long flags;
u32* entry;
u16 bdf, req_id, alias_id;
u8 delivery_mode, dest, vector, dest_mode;
spinlock_t *lock;
+ int offset;
bdf = (pdev->bus << 8) | pdev->devfn;
req_id = get_dma_requestor_id(bdf);
+ alias_id = get_intremap_requestor_id(bdf);
+
+ if ( msg == NULL )
+ {
+ lock = get_intremap_lock(req_id);
+ spin_lock_irqsave(lock, flags);
+ free_intremap_entry(req_id, msi_desc->remap_index);
+ spin_unlock_irqrestore(lock, flags);
+
+ if ( ( req_id != alias_id ) &&
+ ivrs_mappings[alias_id].intremap_table != NULL )
+ {
+ lock = get_intremap_lock(alias_id);
+ spin_lock_irqsave(lock, flags);
+ free_intremap_entry(alias_id, msi_desc->remap_index);
+ spin_unlock_irqrestore(lock, flags);
+ }
+ goto done;
+ }
+
lock = get_intremap_lock(req_id);
spin_lock_irqsave(lock, flags);
@@ -259,8 +300,10 @@ static void update_intremap_entry_from_m
delivery_mode = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;
vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK;
dest = (msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff;
-
- entry = (u32*)get_intremap_entry(req_id, vector, delivery_mode);
+ offset = get_intremap_offset(vector, delivery_mode);
+ msi_desc->remap_index = offset;
+
+ entry = (u32*)get_intremap_entry(req_id, offset);
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
spin_unlock_irqrestore(lock, flags);
@@ -270,18 +313,18 @@ static void update_intremap_entry_from_m
* We have to setup a secondary interrupt remapping entry to satisfy those
* devices.
*/
- alias_id = get_intremap_requestor_id(bdf);
+
lock = get_intremap_lock(alias_id);
- if ( ( bdf != alias_id ) &&
+ if ( ( req_id != alias_id ) &&
ivrs_mappings[alias_id].intremap_table != NULL )
{
spin_lock_irqsave(lock, flags);
- entry = (u32*)get_intremap_entry(alias_id, vector, delivery_mode);
+ entry = (u32*)get_intremap_entry(alias_id, offset);
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
- invalidate_interrupt_table(iommu, alias_id);
spin_unlock_irqrestore(lock, flags);
}
+done:
if ( iommu->enabled )
{
spin_lock_irqsave(&iommu->lock, flags);
@@ -312,7 +355,7 @@ void amd_iommu_msi_msg_update_ire(
return;
}
- update_intremap_entry_from_msi_msg(iommu, pdev, msg);
+ update_intremap_entry_from_msi_msg(iommu, pdev, msi_desc, msg);
}
unsigned int amd_iommu_read_ioapic_from_ire(
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH] AMD IOMMU: Fix a xen crash on amd iommu systems
@ 2009-12-16 15:50 Wei Wang2
0 siblings, 0 replies; 2+ messages in thread
From: Wei Wang2 @ 2009-12-16 15:50 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 499 bytes --]
Changeset 20514 implemented deallocation for msi interrupt remapping entries.
Attached patch adds the same support for amd iommu to fix a xen crash on amd
iommu systems.
Thanks,
Wei
Signed-off-by: Wei Wang <wei.wang2@amd.com>
--
Legal Information:
Advanced Micro Devices GmbH
Karl-Hammerschmidt-Str. 34
85609 Dornach b. München
Geschäftsführer: Andrew Bowd, Thomas M. McCoy, Giuliano Meroni
Sitz: Dornach, Gemeinde Aschheim, Landkreis München
Registergericht München, HRB Nr. 43632
[-- Attachment #2: reset.patch --]
[-- Type: text/x-diff, Size: 4774 bytes --]
diff -r 0f332e986bae xen/drivers/passthrough/amd/iommu_init.c
--- a/xen/drivers/passthrough/amd/iommu_init.c Wed Dec 16 15:50:35 2009 +0100
+++ b/xen/drivers/passthrough/amd/iommu_init.c Wed Dec 16 15:58:09 2009 +0100
@@ -270,26 +270,65 @@ static void set_iommu_event_log_control(
writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
}
-static int amd_iommu_read_event_log(struct amd_iommu *iommu, u32 event[])
+static void amd_iommu_reset_event_log(struct amd_iommu *iommu)
+{
+ u32 entry;
+ int log_run;
+ int loop_count = 1000;
+
+ /* wait until EventLogRun bit = 0 */
+ do {
+ entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+ log_run = get_field_from_reg_u32(entry,
+ IOMMU_STATUS_EVENT_LOG_RUN_MASK,
+ IOMMU_STATUS_EVENT_LOG_RUN_SHIFT);
+ loop_count--;
+ } while ( log_run && loop_count );
+
+ if ( log_run )
+ {
+ AMD_IOMMU_DEBUG("Warning: EventLogRun bit is not cleared"
+ "before reset!\n");
+ return;
+ }
+
+ set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
+
+ /*clear overflow bit */
+ set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
+ IOMMU_STATUS_EVENT_OVERFLOW_MASK,
+ IOMMU_STATUS_EVENT_OVERFLOW_SHIFT, &entry);
+ writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
+
+ /*reset event log base address */
+ iommu->event_log_head = 0;
+
+ set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
+}
+
+static void parse_event_log_entry(u32 entry[]);
+
+static int amd_iommu_read_event_log(struct amd_iommu *iommu)
{
u32 tail, head, *event_log;
- int i;
-
- BUG_ON( !iommu || !event );
+
+ BUG_ON( !iommu );
/* make sure there's an entry in the log */
- tail = get_field_from_reg_u32(
- readl(iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET),
- IOMMU_EVENT_LOG_TAIL_MASK,
- IOMMU_EVENT_LOG_TAIL_SHIFT);
- if ( tail != iommu->event_log_head )
+ tail = readl(iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET);
+ tail = get_field_from_reg_u32(tail,
+ IOMMU_EVENT_LOG_TAIL_MASK,
+ IOMMU_EVENT_LOG_TAIL_SHIFT);
+
+ while ( tail != iommu->event_log_head )
{
/* read event log entry */
event_log = (u32 *)(iommu->event_log.buffer +
- (iommu->event_log_head *
- IOMMU_EVENT_LOG_ENTRY_SIZE));
- for ( i = 0; i < IOMMU_EVENT_LOG_U32_PER_ENTRY; i++ )
- event[i] = event_log[i];
+ (iommu->event_log_head *
+ IOMMU_EVENT_LOG_ENTRY_SIZE));
+
+ parse_event_log_entry(event_log);
+
if ( ++iommu->event_log_head == iommu->event_log.entries )
iommu->event_log_head = 0;
@@ -298,10 +337,9 @@ static int amd_iommu_read_event_log(stru
IOMMU_EVENT_LOG_HEAD_MASK,
IOMMU_EVENT_LOG_HEAD_SHIFT, &head);
writel(head, iommu->mmio_base + IOMMU_EVENT_LOG_HEAD_OFFSET);
- return 0;
- }
-
- return -EFAULT;
+ }
+
+ return 0;
}
static void iommu_msi_set_affinity(unsigned int irq, cpumask_t mask)
@@ -459,14 +497,24 @@ static void amd_iommu_page_fault(int irq
static void amd_iommu_page_fault(int irq, void *dev_id,
struct cpu_user_regs *regs)
{
- u32 event[4];
u32 entry;
unsigned long flags;
- int ret = 0;
+ int of;
struct amd_iommu *iommu = dev_id;
spin_lock_irqsave(&iommu->lock, flags);
- ret = amd_iommu_read_event_log(iommu, event);
+ amd_iommu_read_event_log(iommu);
+
+ /*check event overflow */
+ entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+ of = get_field_from_reg_u32(entry,
+ IOMMU_STATUS_EVENT_OVERFLOW_MASK,
+ IOMMU_STATUS_EVENT_OVERFLOW_SHIFT);
+
+ /* reset event log if event overflow */
+ if ( of )
+ amd_iommu_reset_event_log(iommu);
+
/* reset interrupt status bit */
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
@@ -474,10 +522,6 @@ static void amd_iommu_page_fault(int irq
IOMMU_STATUS_EVENT_LOG_INT_SHIFT, &entry);
writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
spin_unlock_irqrestore(&iommu->lock, flags);
-
- if ( ret != 0 )
- return;
- parse_event_log_entry(event);
}
static int set_iommu_interrupt_handler(struct amd_iommu *iommu)
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2009-12-16 15:54 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-16 15:54 [PATCH] AMD IOMMU: Fix a xen crash on amd iommu systems Wei Wang2
-- strict thread matches above, loose matches on Subject: below --
2009-12-16 15:50 Wei Wang2
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.