amd iommu: IOMMUv2 support
PATCH 1/1 amd iommu: IOMMUv2 support
This patch set adds basic supports for amd next generation iommu (IOMMUv2) hardware. IOMMUv2 supports various new features advertised by iommu extended feature register. It introduces guest level IO translation and supports state-of-the-art ATS/ATC devices with demand paging capability. Please refer to AMD IOMMU Architectural Specification [1] for more details.
Thanks,
Wei
PATCH 1/1 amd iommu: Advertise iommu extended feature bits to xen
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321541520 -3600
# Node ID ac472579595524317ab2f7e5ef545e67f4c9c6f0 # Parent dbdc840f8f62db58321b5009e5e0f7833066386f amd iommu: Advertise iommu extended feature bits to xen.
xen/drivers/passthrough/amd/iommu_detect.c +41 -0
@@ -62,6 +62,47 @@ static int __init get_iommu_capabilitiesreturn 0 ; } +void __init get_iommu_features (struct amd_iommu *iommu) +{ +u32 low, high; +int i =0 ; +char * feature_str[] = { +"- Prefetch Pages Command" , +"- Peripheral Page Service Request" , +"- X2APIC Supported" , +"- NX bit Supported" , +"- Guest Translation" , +"- Reserved bit [5]" , +"- Invalidate All Command" , +"- Guest APIC supported" , +"- Hardware Error Registers" , +"- Performance Counters" , +NULL + }; + +ASSERT ( iommu->mmio_base ); + +if ( !iommu_has_cap (iommu,PCI_CAP_EFRSUP_SHIFT ) ) + { + iommu->features =0 ; +return ; + } + + low =readl (iommu->mmio_base +IOMMU_EXT_FEATURE_MMIO_OFFSET ); + high =readl (iommu->mmio_base +IOMMU_EXT_FEATURE_MMIO_OFFSET +4 ); + + iommu->features = ((u64 )high <<32 ) | low; + +printk ("AMD-Vi: IOMMU Extended Features:\n" ); + +while ( feature_str[i] ) + { +if (iommu_has_feature (iommu, i) ) +printk (" %s\n" , feature_str[i]); + i++; + } +} +int __init amd_iommu_detect_one_acpi (void *ivhd) {struct amd_iommu *iommu;
xen/drivers/passthrough/amd/iommu_init.c +2 -0
@@ -684,6 +684,8 @@ static int __init amd_iommu_init_one(str iommu->dev_table.entries = device_table.entries; iommu->dev_table.buffer = device_table.buffer; +get_iommu_features (iommu); +enable_iommu (iommu);printk ("AMD-Vi: IOMMU %d Enabled.\n" , nr_amd_iommus ); nr_amd_iommus++;
xen/include/asm-x86/amd-iommu.h +1 -0
@@ -54,6 +54,7 @@ struct amd_iommu {iommu_cap_t cap;u8 ht_flags; +u64 features;void *mmio_base;unsigned long mmio_base_phys;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +21 -0
@@ -54,6 +54,7 @@#define PCI_CAP_HT_TUNNEL_SHIFT 25#define PCI_CAP_NP_CACHE_MASK 0x04000000#define PCI_CAP_NP_CACHE_SHIFT 26 +#define PCI_CAP_EFRSUP_SHIFT 27#define PCI_CAP_RESET_MASK 0x80000000#define PCI_CAP_RESET_SHIFT 31
@@ -327,6 +328,26 @@#define IOMMU_EXCLUSION_LIMIT_HIGH_MASK 0xFFFFFFFF#define IOMMU_EXCLUSION_LIMIT_HIGH_SHIFT 0 +/* Extended Feature Register*/ +#define IOMMU_EXT_FEATURE_MMIO_OFFSET 0x30 +#define IOMMU_EXT_FEATURE_PREFSUP_SHIFT 0x0 +#define IOMMU_EXT_FEATURE_PPRSUP_SHIFT 0x1 +#define IOMMU_EXT_FEATURE_XTSUP_SHIFT 0x2 +#define IOMMU_EXT_FEATURE_NXSUP_SHIFT 0x3 +#define IOMMU_EXT_FEATURE_GTSUP_SHIFT 0x4 +#define IOMMU_EXT_FEATURE_IASUP_SHIFT 0x6 +#define IOMMU_EXT_FEATURE_GASUP_SHIFT 0x7 +#define IOMMU_EXT_FEATURE_HESUP_SHIFT 0x8 +#define IOMMU_EXT_FEATURE_PCSUP_SHIFT 0x9 +#define IOMMU_EXT_FEATURE_HATS_SHIFT 0x10 +#define IOMMU_EXT_FEATURE_HATS_MASK 0x00000C00 +#define IOMMU_EXT_FEATURE_GATS_SHIFT 0x12 +#define IOMMU_EXT_FEATURE_GATS_MASK 0x00003000 +#define IOMMU_EXT_FEATURE_GLXSUP 0x14 + +#define IOMMU_EXT_FEATURE_PASMAX_SHIFT 0x0 +#define IOMMU_EXT_FEATURE_PASMAX_MASK 0x0000001F +/* Status Register*/ #define IOMMU_STATUS_MMIO_OFFSET 0x2020#define IOMMU_STATUS_EVENT_OVERFLOW_MASK 0x00000001
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +9 -0
@@ -43,6 +43,7 @@int amd_iommu_get_ivrs_dev_entries (void );int amd_iommu_detect_one_acpi (void *ivhd);int amd_iommu_detect_acpi (void ); +void get_iommu_features (struct amd_iommu *iommu);/* amd-iommu-init functions */ int amd_iommu_init (void );
@@ -187,4 +188,12 @@ static inline int iommu_has_cap(struct a return iommu->cap.header & mask; } +static inline int iommu_has_feature (struct amd_iommu *iommu,uint32_t bit) +{ +if (iommu_has_cap (iommu,PCI_CAP_EFRSUP_SHIFT ) ) +return iommu->features & (1U << bit); + +return 0 ; +} +#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
PATCH 1/1 amd iommu: Fix incorrect definitions
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321541523 -3600
# Node ID 135678ae1bbc02171294c21e2a5469d898d2a353 # Parent ac472579595524317ab2f7e5ef545e67f4c9c6f0 amd iommu: Fix incorrect definitions.
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +2 -4
@@ -293,10 +293,8 @@#define IOMMU_CONTROL_EVENT_LOG_INT_SHIFT 3#define IOMMU_CONTROL_COMP_WAIT_INT_MASK 0x00000010#define IOMMU_CONTROL_COMP_WAIT_INT_SHIFT 4 -#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_MASK 0x00000020 -#define IOMMU_CONTROL_TRANSLATION_CHECK_DISABLE_SHIFT 5 -#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK 0x000000C0 -#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT 6 +#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_MASK 0x000000E0 +#define IOMMU_CONTROL_INVALIDATION_TIMEOUT_SHIFT 5#define IOMMU_CONTROL_PASS_POSTED_WRITE_MASK 0x00000100#define IOMMU_CONTROL_PASS_POSTED_WRITE_SHIFT 8#define IOMMU_CONTROL_RESP_PASS_POSTED_WRITE_MASK 0x00000200
PATCH 1/1 amd iommu: Factor out iommu command handling functions,
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321610860 -3600
# Node ID 6ef12cc262fb3ac11f9ea58707afb4f7778017ac # Parent 135678ae1bbc02171294c21e2a5469d898d2a353 amd iommu: Factor out iommu command handling functions, and move them into a new file.
xen/drivers/passthrough/amd/Makefile +1 -0
@@ -4,3 +4,4 @@ obj-y += iommu_map.o obj-y += pci_amd_iommu.o obj-bin-y += iommu_acpi.init.o obj-y += iommu_intr.o +obj-y += iommu_cmd.o
xen/drivers/passthrough/amd/iommu_cmd.c new file +382 -0
382 lines not on this page · raw message
xen/drivers/passthrough/amd/iommu_init.c +2 -3
@@ -933,9 +933,8 @@ static int _invalidate_all_devices(if ( iommu ) {spin_lock_irqsave (&iommu->lock, flags); -invalidate_dev_table_entry (iommu, req_id); -invalidate_interrupt_table (iommu, req_id); -flush_command_buffer (iommu); +amd_iommu_flush_device (iommu, req_id); +amd_iommu_flush_intremap (iommu, req_id);spin_unlock_irqrestore (&iommu->lock, flags); } }
xen/drivers/passthrough/amd/iommu_intr.c +4 -23
@@ -96,22 +96,6 @@ static void update_intremap_entry(u32* e INT_REMAP_ENTRY_VECTOR_SHIFT, entry); } -void invalidate_interrupt_table (struct amd_iommu *iommu,u16 device_id) -{ -u32 cmd[4 ], entry; - - cmd[3 ] = cmd[2 ] =0 ; -set_field_in_reg_u32 (device_id,0 , -IOMMU_INV_INT_TABLE_DEVICE_ID_MASK , -IOMMU_INV_INT_TABLE_DEVICE_ID_SHIFT , &entry); - cmd[0 ] = entry; -set_field_in_reg_u32 (IOMMU_CMD_INVALIDATE_INT_TABLE ,0 , -IOMMU_CMD_OPCODE_MASK ,IOMMU_CMD_OPCODE_SHIFT , - &entry); - cmd[1 ] = entry; -send_iommu_command (iommu, cmd); -} - static void update_intremap_entry_from_ioapic( int bdf, struct amd_iommu *iommu,
@@ -144,8 +128,7 @@ static void update_intremap_entry_from_iif ( iommu->enabled ) {spin_lock_irqsave (&iommu->lock, flags); -invalidate_interrupt_table (iommu, req_id); -flush_command_buffer (iommu); +amd_iommu_flush_intremap (iommu, req_id);spin_unlock_irqrestore (&iommu->lock, flags); } }
@@ -202,8 +185,7 @@ int __init amd_iommu_setup_ioapic_remappif ( iommu->enabled ) {spin_lock_irqsave (&iommu->lock, flags); -invalidate_interrupt_table (iommu, req_id); -flush_command_buffer (iommu); +amd_iommu_flush_intremap (iommu, req_id);spin_unlock_irqrestore (&iommu->lock, flags); } }
@@ -347,10 +329,9 @@ done:if ( iommu->enabled ) {spin_lock_irqsave (&iommu->lock, flags); -invalidate_interrupt_table (iommu, req_id); +amd_iommu_flush_intremap (iommu, req_id);if ( alias_id != req_id ) -invalidate_interrupt_table (iommu, alias_id); -flush_command_buffer (iommu); +amd_iommu_flush_intremap (iommu, alias_id);spin_unlock_irqrestore (&iommu->lock, flags); } }
xen/drivers/passthrough/amd/iommu_map.c +1 -323
348 lines not on this page · raw message
xen/drivers/passthrough/amd/pci_amd_iommu.c +3 -4
@@ -118,8 +118,7 @@ static void amd_iommu_setup_domain_devic iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )iommu_dte_set_iotlb ((u32 *)dte, dte_i); -invalidate_dev_table_entry (iommu, req_id); -flush_command_buffer (iommu); +amd_iommu_flush_device (iommu, req_id);AMD_IOMMU_DEBUG ("Setup I/O page table: device id = 0x%04x, " "root table = 0x%"PRIx64", "
@@ -310,8 +309,8 @@ void amd_iommu_disable_domain_device(str iommu_has_cap(iommu, PCI_CAP_IOTLB_SHIFT) )iommu_dte_set_iotlb ((u32 *)dte,0 ); -invalidate_dev_table_entry (iommu, req_id); -flush_command_buffer (iommu); +amd_iommu_flush_device (iommu, req_id); + AMD_IOMMU_DEBUG("Disable: device id = 0x%04x, " "domain = %d, paging mode = %d\n", req_id, domain_hvm_iommu(domain)->domain_id,
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +7 -10
@@ -53,12 +53,6 @@ int amd_iommu_update_ivrs_mapping_acpi(vint amd_iommu_map_page (struct domain *d,unsigned long gfn,unsigned long mfn,unsigned int flags);int amd_iommu_unmap_page (struct domain *d,unsigned long gfn); -void amd_iommu_flush_pages (struct domain *d,unsigned long gfn, -unsigned int order); -void amd_iommu_flush_all_pages (struct domain *d); -void amd_iommu_flush_iotlb (struct pci_dev *pdev,uint64_t gaddr, -unsigned int order); -u64 amd_iommu_get_next_table_from_pte (u32 *entry); int amd_iommu_reserve_domain_unity_map(struct domain *domain, u64 phys_addr, unsigned long size,
@@ -75,11 +69,15 @@ void amd_iommu_set_root_page_table( u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid);void iommu_dte_set_iotlb (u32 *dte,u8 i);void iommu_dte_add_device_entry (u32 *dte,struct ivrs_mappings *ivrs_dev); -void invalidate_dev_table_entry (struct amd_iommu *iommu,u16 devic_id);/* send cmd to iommu */ -int send_iommu_command (struct amd_iommu *iommu,u32 cmd[]); -void flush_command_buffer (struct amd_iommu *iommu); +void amd_iommu_flush_all_pages (struct domain *d); +void amd_iommu_flush_pages (struct domain *d,unsigned long gfn, +unsigned int order); +void amd_iommu_flush_iotlb (struct pci_dev *pdev,uint64_t gaddr, +unsigned int order); +void amd_iommu_flush_device (struct amd_iommu *iommu,uint16_t bdf); +void amd_iommu_flush_intremap (struct amd_iommu *iommu,uint16_t bdf);/* find iommu for bdf */ struct amd_iommu *find_iommu_for_device (int seg,int bdf);
@@ -88,7 +86,6 @@ struct amd_iommu *find_iommu_for_device(int amd_iommu_setup_ioapic_remapping (void );void *amd_iommu_alloc_intremap_table (void );int amd_iommu_free_intremap_table (u16 seg,struct ivrs_mappings *); -void invalidate_interrupt_table (struct amd_iommu *iommu,u16 device_id);void amd_iommu_ioapic_update_ire (unsigned int apic,unsigned int reg,unsigned int value); void amd_iommu_msi_msg_update_ire(
PATCH 1/1 amd iommu: Support INVALIDATE_IOMMU_ALL command
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1321612881 -3600
# Node ID 9d4fecddb805b0780e2eeab9f1f69cc585eac7b8
# Parent 6ef12cc262fb3ac11f9ea58707afb4f7778017ac
amd iommu: Support INVALIDATE_IOMMU_ALL command.
It is one of the new architectural commands supported by iommu v2.It instructs iommu to clear all address translation and interrupt remapping caches for all devices and all domains.
xen/drivers/passthrough/amd/iommu_cmd.c +22 -0
@@ -277,6 +277,20 @@ static void invalidate_interrupt_table(ssend_iommu_command (iommu, cmd); } +void invalidate_iommu_all (struct amd_iommu *iommu) +{ +u32 cmd[4 ], entry; + + cmd[3 ] = cmd[2 ] = cmd[0 ] =0 ; + +set_field_in_reg_u32 (IOMMU_CMD_INVALIDATE_IOMMU_ALL ,0 , +IOMMU_CMD_OPCODE_MASK ,IOMMU_CMD_OPCODE_SHIFT , + &entry); + cmd[1 ] = entry; + +send_iommu_command (iommu, cmd); +} +void amd_iommu_flush_iotlb (struct pci_dev *pdev,uint64_t gaddr,unsigned int order) {
@@ -380,3 +394,11 @@ void amd_iommu_flush_intremap(struct amdinvalidate_interrupt_table (iommu, bdf);flush_command_buffer (iommu); } + +void amd_iommu_flush_all_caches (struct amd_iommu *iommu) +{ +ASSERT (spin_is_locked (&iommu->lock) ); + +invalidate_iommu_all (iommu); +flush_command_buffer (iommu); +}
xen/drivers/passthrough/amd/iommu_init.c +8 -2
@@ -598,6 +598,9 @@ static void enable_iommu(struct amd_iommset_iommu_event_log_control (iommu,IOMMU_CONTROL_ENABLED );set_iommu_translation_control (iommu,IOMMU_CONTROL_ENABLED ); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) ) +amd_iommu_flush_all_caches (iommu); + iommu->enabled =1 ;spin_unlock_irqrestore (&iommu->lock, flags);
@@ -970,6 +973,9 @@ void amd_iommu_resume(void) }/* flush all cache entries after iommu re-enabled */ -invalidate_all_devices (); -invalidate_all_domain_pages (); +if ( !iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) ) + { +invalidate_all_devices (); +invalidate_all_domain_pages (); + } }
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +1 -0
@@ -192,6 +192,7 @@#define IOMMU_CMD_INVALIDATE_IOMMU_PAGES 0x3#define IOMMU_CMD_INVALIDATE_IOTLB_PAGES 0x4#define IOMMU_CMD_INVALIDATE_INT_TABLE 0x5 +#define IOMMU_CMD_INVALIDATE_IOMMU_ALL 0x8/* COMPLETION_WAIT command */ #define IOMMU_COMP_WAIT_DATA_BUFFER_SIZE 8
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +1 -0
@@ -78,6 +78,7 @@ void amd_iommu_flush_iotlb(struct pci_de unsigned int order);void amd_iommu_flush_device (struct amd_iommu *iommu,uint16_t bdf);void amd_iommu_flush_intremap (struct amd_iommu *iommu,uint16_t bdf); +void amd_iommu_flush_all_caches (struct amd_iommu *iommu);/* find iommu for bdf */ struct amd_iommu *find_iommu_for_device (int seg,int bdf);
Quoted 5 lines · Wei Wang
This patch set adds basic supports for amd next generation iommu (IOMMUv2) hardware. IOMMUv2 supports various new features advertised by iommu extended feature register. It introduces guest level IO translation and supports state-of-the-art ATS/ATC devices with demand paging capability. Please refer to AMD IOMMU Architectural Specification [1] for more details.
Wei,
When is this hardware likely to be in the hands of customers?
-George