diff options
author | Wei Wang <wei.wang2@amd.com> | 2011-11-11 12:05:14 +0100 |
---|---|---|
committer | Wei Wang <wei.wang2@amd.com> | 2011-11-11 12:05:14 +0100 |
commit | 05498eaf28ff183dce5b7bad9f8643ba5032a0d2 (patch) | |
tree | 500bf2e25713360beab271ba3c2f20b544cd6324 | |
parent | c909d6094903ece47036cb79e13ed618e5738a11 (diff) | |
download | xen-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.c | 21 | ||||
-rw-r--r-- | xen/drivers/passthrough/amd/iommu_init.c | 123 | ||||
-rw-r--r-- | xen/include/asm-x86/amd-iommu.h | 6 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/svm/amd-iommu-proto.h | 15 |
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 */ |