aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Wang <wei.wang2@amd.com>2011-11-11 12:05:14 +0100
committerWei Wang <wei.wang2@amd.com>2011-11-11 12:05:14 +0100
commit05498eaf28ff183dce5b7bad9f8643ba5032a0d2 (patch)
tree500bf2e25713360beab271ba3c2f20b544cd6324
parentc909d6094903ece47036cb79e13ed618e5738a11 (diff)
downloadxen-05498eaf28ff183dce5b7bad9f8643ba5032a0d2.tar.gz
xen-05498eaf28ff183dce5b7bad9f8643ba5032a0d2.tar.bz2
xen-05498eaf28ff183dce5b7bad9f8643ba5032a0d2.zip
amd iommu: Compress hyper-transport flags into a single byte
These flags are single bit, no need to be saved as integers. Add 3 inline helpers to make single bit access easier. Introduce iommu_has_ht_flag and set_iommu_ht_flags Signed-off-by: Wei Wang <wei.wang2@amd.com> Committed-by: Jan Beulich <jbeulich@suse.com>
-rw-r--r--xen/drivers/passthrough/amd/iommu_detect.c21
-rw-r--r--xen/drivers/passthrough/amd/iommu_init.c123
-rw-r--r--xen/include/asm-x86/amd-iommu.h6
-rw-r--r--xen/include/asm-x86/hvm/svm/amd-iommu-proto.h15
4 files changed, 81 insertions, 84 deletions
diff --git a/xen/drivers/passthrough/amd/iommu_detect.c b/xen/drivers/passthrough/amd/iommu_detect.c
index 9ead31d4e6..e0bce2d390 100644
--- a/xen/drivers/passthrough/amd/iommu_detect.c
+++ b/xen/drivers/passthrough/amd/iommu_detect.c
@@ -98,25 +98,8 @@ int __init amd_iommu_detect_one_acpi(void *ivhd)
iommu->cap_offset = ivhd_block->cap_offset;
iommu->mmio_base_phys = ivhd_block->mmio_base;
- /* override IOMMU support flags */
- iommu->coherent = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_COHERENT_MASK,
- AMD_IOMMU_ACPI_COHERENT_SHIFT);
- iommu->iotlb_support = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_IOTLB_SUP_MASK,
- AMD_IOMMU_ACPI_IOTLB_SUP_SHIFT);
- iommu->isochronous = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_ISOC_MASK,
- AMD_IOMMU_ACPI_ISOC_SHIFT);
- iommu->res_pass_pw = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_RES_PASS_PW_MASK,
- AMD_IOMMU_ACPI_RES_PASS_PW_SHIFT);
- iommu->pass_pw = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_PASS_PW_MASK,
- AMD_IOMMU_ACPI_PASS_PW_SHIFT);
- iommu->ht_tunnel_enable = get_field_from_byte(ivhd_block->header.flags,
- AMD_IOMMU_ACPI_HT_TUN_ENB_MASK,
- AMD_IOMMU_ACPI_HT_TUN_ENB_SHIFT);
+ /* override IOMMU HT flags */
+ iommu->ht_flags = ivhd_block->header.flags;
bus = PCI_BUS(iommu->bdf);
dev = PCI_SLOT(iommu->bdf);
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index b7f94328f6..ca71bf53bf 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -28,6 +28,7 @@
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <asm-x86/fixmap.h>
#include <mach_apic.h>
+#include <asm/hvm/svm/amd-iommu-acpi.h>
static int __initdata nr_amd_iommus;
@@ -36,6 +37,12 @@ static struct radix_tree_root ivrs_maps;
struct list_head amd_iommu_head;
struct table_struct device_table;
+static int iommu_has_ht_flag(struct amd_iommu *iommu, uint8_t bit)
+{
+ u8 mask = 1U << bit;
+ return iommu->ht_flags & mask;
+}
+
static int __init map_iommu_mmio_region(struct amd_iommu *iommu)
{
unsigned long mfn;
@@ -66,6 +73,34 @@ static void __init unmap_iommu_mmio_region(struct amd_iommu *iommu)
}
}
+static void set_iommu_ht_flags(struct amd_iommu *iommu)
+{
+ u32 entry;
+ entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
+
+ /* Setup HT flags */
+ iommu_has_ht_flag(iommu, AMD_IOMMU_ACPI_HT_TUN_ENB_SHIFT) ?
+ iommu_set_bit(&entry, IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT):
+ iommu_clear_bit(&entry, IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT);
+
+ iommu_has_ht_flag(iommu, AMD_IOMMU_ACPI_RES_PASS_PW_SHIFT) ?
+ iommu_set_bit(&entry, IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_SHIFT):
+ iommu_clear_bit(&entry, IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_SHIFT);
+
+ iommu_has_ht_flag(iommu, AMD_IOMMU_ACPI_ISOC_SHIFT) ?
+ iommu_set_bit(&entry, IOMMU_CONTROL_ISOCHRONOUS_SHIFT):
+ iommu_clear_bit(&entry, IOMMU_CONTROL_ISOCHRONOUS_SHIFT);
+
+ iommu_has_ht_flag(iommu, AMD_IOMMU_ACPI_PASS_PW_SHIFT) ?
+ iommu_set_bit(&entry, IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT):
+ iommu_clear_bit(&entry, IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT);
+
+ /* Force coherent */
+ iommu_set_bit(&entry, IOMMU_CONTROL_COHERENT_SHIFT);
+
+ writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
+}
+
static void register_iommu_dev_table_in_mmio_space(struct amd_iommu *iommu)
{
u64 addr_64, addr_lo, addr_hi;
@@ -150,33 +185,10 @@ static void set_iommu_translation_control(struct amd_iommu *iommu,
entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
- if ( enable )
- {
- set_field_in_reg_u32(iommu->ht_tunnel_support ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_MASK,
- IOMMU_CONTROL_HT_TUNNEL_TRANSLATION_SHIFT, &entry);
- set_field_in_reg_u32(iommu->isochronous ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_ISOCHRONOUS_MASK,
- IOMMU_CONTROL_ISOCHRONOUS_SHIFT, &entry);
- set_field_in_reg_u32(iommu->coherent ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_COHERENT_MASK,
- IOMMU_CONTROL_COHERENT_SHIFT, &entry);
- set_field_in_reg_u32(iommu->res_pass_pw ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_MASK,
- IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_SHIFT, &entry);
- /* do not set PassPW bit */
- set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_PASS_POSTED_WRITE_MASK,
- IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT, &entry);
- }
- set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_TRANSLATION_ENABLE_MASK,
- IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT, &entry);
+ enable ?
+ iommu_set_bit(&entry, IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT):
+ iommu_clear_bit(&entry, IOMMU_CONTROL_TRANSLATION_ENABLE_SHIFT);
+
writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
}
@@ -186,17 +198,17 @@ static void set_iommu_command_buffer_control(struct amd_iommu *iommu,
u32 entry;
entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
- set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK,
- IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT, &entry);
/*reset head and tail pointer manually before enablement */
- if ( enable == IOMMU_CONTROL_ENABLED )
+ if ( enable )
{
writel(0x0, iommu->mmio_base + IOMMU_CMD_BUFFER_HEAD_OFFSET);
writel(0x0, iommu->mmio_base + IOMMU_CMD_BUFFER_TAIL_OFFSET);
+
+ iommu_set_bit(&entry, IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT);
}
+ else
+ iommu_clear_bit(&entry, IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT);
writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
}
@@ -247,24 +259,24 @@ static void set_iommu_event_log_control(struct amd_iommu *iommu,
u32 entry;
entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
- set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_EVENT_LOG_ENABLE_MASK,
- IOMMU_CONTROL_EVENT_LOG_ENABLE_SHIFT, &entry);
- set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
- IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_EVENT_LOG_INT_MASK,
- IOMMU_CONTROL_EVENT_LOG_INT_SHIFT, &entry);
- set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
- IOMMU_CONTROL_COMP_WAIT_INT_MASK,
- IOMMU_CONTROL_COMP_WAIT_INT_SHIFT, &entry);
/*reset head and tail pointer manually before enablement */
- if ( enable == IOMMU_CONTROL_ENABLED )
+ if ( enable )
{
writel(0x0, iommu->mmio_base + IOMMU_EVENT_LOG_HEAD_OFFSET);
writel(0x0, iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET);
+
+ iommu_set_bit(&entry, IOMMU_CONTROL_EVENT_LOG_INT_SHIFT);
+ iommu_set_bit(&entry, IOMMU_CONTROL_EVENT_LOG_ENABLE_SHIFT);
}
+ else
+ {
+ iommu_clear_bit(&entry, IOMMU_CONTROL_EVENT_LOG_INT_SHIFT);
+ iommu_clear_bit(&entry, IOMMU_CONTROL_EVENT_LOG_ENABLE_SHIFT);
+ }
+
+ iommu_clear_bit(&entry, IOMMU_CONTROL_COMP_WAIT_INT_SHIFT);
+
writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
}
@@ -313,9 +325,7 @@ static void amd_iommu_reset_event_log(struct amd_iommu *iommu)
/* 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);
+ log_run = iommu_get_bit(entry, IOMMU_STATUS_EVENT_LOG_RUN_SHIFT);
loop_count--;
} while ( log_run && loop_count );
@@ -330,11 +340,9 @@ static void amd_iommu_reset_event_log(struct amd_iommu *iommu)
/* read event log for debugging */
amd_iommu_read_event_log(iommu);
-
/*clear overflow bit */
- set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
- IOMMU_STATUS_EVENT_OVERFLOW_MASK,
- IOMMU_STATUS_EVENT_OVERFLOW_SHIFT, &entry);
+ iommu_clear_bit(&entry, IOMMU_STATUS_EVENT_OVERFLOW_SHIFT);
+
writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
/*reset event log base address */
@@ -519,7 +527,6 @@ static void amd_iommu_page_fault(int irq, void *dev_id,
{
u32 entry;
unsigned long flags;
- int of;
struct amd_iommu *iommu = dev_id;
spin_lock_irqsave(&iommu->lock, flags);
@@ -527,19 +534,14 @@ static void amd_iommu_page_fault(int irq, void *dev_id,
/*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 )
+ if ( iommu_get_bit(entry, IOMMU_STATUS_EVENT_OVERFLOW_SHIFT) )
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,
- IOMMU_STATUS_EVENT_LOG_INT_MASK,
- IOMMU_STATUS_EVENT_LOG_INT_SHIFT, &entry);
+ iommu_set_bit(&entry, IOMMU_STATUS_EVENT_LOG_INT_SHIFT);
+
writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -590,6 +592,7 @@ static void enable_iommu(struct amd_iommu *iommu)
iommu_msi_set_affinity(irq_to_desc(iommu->irq), &cpu_online_map);
amd_iommu_msi_enable(iommu, IOMMU_CONTROL_ENABLED);
+ set_iommu_ht_flags(iommu);
set_iommu_command_buffer_control(iommu, IOMMU_CONTROL_ENABLED);
set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
set_iommu_translation_control(iommu, IOMMU_CONTROL_ENABLED);
diff --git a/xen/include/asm-x86/amd-iommu.h b/xen/include/asm-x86/amd-iommu.h
index 2719e3a72d..f2e0eb6ce2 100644
--- a/xen/include/asm-x86/amd-iommu.h
+++ b/xen/include/asm-x86/amd-iommu.h
@@ -57,11 +57,7 @@ struct amd_iommu {
u8 ht_tunnel_support;
u8 iotlb_support;
- u8 isochronous;
- u8 coherent;
- u8 res_pass_pw;
- u8 pass_pw;
- u8 ht_tunnel_enable;
+ u8 ht_flags;
void *mmio_base;
unsigned long mmio_base_phys;
diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
index 1268a287f8..a1b87da714 100644
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -166,4 +166,19 @@ static inline void __free_amd_iommu_tables(void *table, int order)
free_xenheap_pages(table, order);
}
+static inline void iommu_set_bit(uint32_t *reg, uint32_t bit)
+{
+ set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, *reg, 1U << bit, bit, reg);
+}
+
+static inline void iommu_clear_bit(uint32_t *reg, uint32_t bit)
+{
+ set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, *reg, 1U << bit, bit, reg);
+}
+
+static inline uint32_t iommu_get_bit(uint32_t reg, uint32_t bit)
+{
+ return get_field_from_reg_u32(reg, 1U << bit, bit);
+}
+
#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */