amd iommu: support ATS device passthru on IOMMUv2 systems
PATCH v2 1/1 amd iommu: support ATS device passthru on IOMMUv2 systems
ATS devices with PRI and PASID capabilities can communicate with iommuv2 to perform two level (nested) address translation and demand paging for DMA. To passthru such devices, iommu driver has to been enabled in guest OS. This patch set adds initial iommu emulation for hvm guests to support ATS device passthru.
Changes in v2:
* Do not use linked list to access guest iommu tables.
* Do not parse iommu parameter in libxl_device_model_info again.
* Fix incorrect logical calculation in patch 11.
* Fix hypercall definition for non-x86 systems.
Please review.
Thanks,
Wei
PATCH 1/1 amd iommu: Refactoring iommu ring buffer definition
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569370 -3600
# Node ID 4c986253976d7efd19640500aa3bb69a5a534637
# Parent 492914c658383e071bef2f907cb62ede69ba48a4
amd iommu: Refactoring iommu ring buffer definition.
Introduce struct ring_buffer to represent iommu cmd buffer, event log and ppr log
xen/drivers/passthrough/amd/iommu_cmd.c +4 -4
@@ -29,7 +29,7 @@ static int queue_iommu_command(struct amu32 tail, head, *cmd_buffer;int i; - tail = iommu->cmd_buffer_tail; + tail = iommu->cmd_buffer.tail;if ( ++tail == iommu->cmd_buffer.entries ) tail =0 ;
@@ -40,13 +40,13 @@ static int queue_iommu_command(struct amif ( head != tail ) { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer + - (iommu->cmd_buffer_tail * + (iommu->cmd_buffer.tail *IOMMU_CMD_BUFFER_ENTRY_SIZE ));for ( i =0 ; i <IOMMU_CMD_BUFFER_U32_PER_ENTRY ; i++ ) cmd_buffer[i] = cmd[i]; - iommu->cmd_buffer_tail = tail; + iommu->cmd_buffer.tail = tail;return 1 ; }
@@ -57,7 +57,7 @@ static void commit_iommu_command_buffer( {u32 tail; -set_field_in_reg_u32 (iommu->cmd_buffer_tail,0 , +set_field_in_reg_u32 (iommu->cmd_buffer.tail,0 ,IOMMU_CMD_BUFFER_TAIL_MASK ,IOMMU_CMD_BUFFER_TAIL_SHIFT , &tail);writel (tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET );
xen/drivers/passthrough/amd/iommu_init.c +70 -56
191 lines not on this page · raw message
xen/include/asm-x86/amd-iommu.h +33 -4
@@ -30,12 +30,43 @@extern struct list_head amd_iommu_head; +#pragma pack(1) +typedef struct event_entry +{ +uint32_t data[4 ]; +}event_entry_t ; + +typedef struct ppr_entry +{ +uint32_t data[4 ]; +}ppr_entry_t ; + +typedef struct cmd_entry +{ +uint32_t data[4 ]; +}cmd_entry_t ; + +typedef struct dev_entry +{ +uint32_t data[8 ]; +}dev_entry_t ; +#pragma pack() +struct table_struct {void *buffer;unsigned long entries;unsigned long alloc_size; }; +struct ring_buffer { +void *buffer; +unsigned long entries; +unsigned long alloc_size; +unsigned long entry_size; +uint32_t tail; +uint32_t head; +}; + typedef struct iommu_cap { uint32_t header; /* offset 00h */ uint32_t base_low; /* offset 04h */
@@ -60,10 +91,8 @@ struct amd_iommu {unsigned long mmio_base_phys;struct table_struct dev_table; -struct table_struct cmd_buffer; -u32 cmd_buffer_tail; -struct table_struct event_log; -u32 event_log_head; +struct ring_buffer cmd_buffer; +struct ring_buffer event_log;int exclusion_enable;int exclusion_allow_all;
Re: [PATCH 01 of 16] amd iommu: Refactoring iommu ring buffer definition
xen/include/asm-x86/amd-iommu.h line 65
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/include/asm-x86/amd-iommu.h +5
-0+struct ring_buffer { +void *buffer; +unsigned long entries; +unsigned long alloc_size; +unsigned long entry_size;
I haven't been able to spot a real use of this field (throughout the patch series).
Jan
Quoted 7 lines
xen/include/asm-x86/amd-iommu.h +4
-0+uint32_t tail; +uint32_t head; +}; + typedef struct iommu_cap { uint32_t header; /* offset 00h */ uint32_t base_low; /* offset 04h */
PATCH 1/1 amd iommu: Introduces new helper functions to simplify iommu bitwise operations
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569374 -3600
# Node ID e15194f68f99a64b65046ba3d29a3f06ccdca950
# Parent 4c986253976d7efd19640500aa3bb69a5a534637
amd iommu: Introduces new helper functions to simplify iommu bitwise operations
xen/drivers/passthrough/amd/iommu_cmd.c +4 -8
@@ -33,10 +33,8 @@ static int queue_iommu_command(struct amif ( ++tail == iommu->cmd_buffer.entries ) tail =0 ; - head =get_field_from_reg_u32 (readl (iommu->mmio_base + -IOMMU_CMD_BUFFER_HEAD_OFFSET ), -IOMMU_CMD_BUFFER_HEAD_MASK , -IOMMU_CMD_BUFFER_HEAD_SHIFT ); + head =iommu_get_rb_pointer (readl (iommu->mmio_base + +IOMMU_CMD_BUFFER_HEAD_OFFSET ));if ( head != tail ) { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
@@ -55,11 +53,9 @@ static int queue_iommu_command(struct amstatic void commit_iommu_command_buffer (struct amd_iommu *iommu) { -u32 tail; +u32 tail =0 ; -set_field_in_reg_u32 (iommu->cmd_buffer.tail,0 , -IOMMU_CMD_BUFFER_TAIL_MASK , -IOMMU_CMD_BUFFER_TAIL_SHIFT , &tail); +iommu_set_rb_pointer (&tail, iommu->cmd_buffer.tail);writel (tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET ); }
xen/drivers/passthrough/amd/iommu_init.c +23 -27
109 lines not on this page · raw message
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +80 -0
85 lines not on this page · raw message
Re: [PATCH 02 of 16] amd iommu: Introduces new helper functions to simplify iommu bitwise operations
Quoted 20 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/drivers/passthrough/amd/iommu_cmd.c +2
-4@@ -33,10 +33,8 @@ static int queue_iommu_command(struct amif ( ++tail == iommu->cmd_buffer.entries ) tail =0 ; - head =get_field_from_reg_u32 (readl (iommu->mmio_base + -IOMMU_CMD_BUFFER_HEAD_OFFSET ), -IOMMU_CMD_BUFFER_HEAD_MASK , -IOMMU_CMD_BUFFER_HEAD_SHIFT ); + head =iommu_get_rb_pointer (readl (iommu->mmio_base + +IOMMU_CMD_BUFFER_HEAD_OFFSET ));if ( head != tail ) { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +@@ -55,11 +53,9 @@ static int queue_iommu_command(struct amstatic void commit_iommu_command_buffer (struct amd_iommu *iommu) {
xen/drivers/passthrough/amd/iommu_cmd.c static int queue_iommu_command(struct am · line 61
Quoted 10 lines
xen/drivers/passthrough/amd/iommu_cmd.c +2
-4-u32 tail; +u32 tail =0 ; -set_field_in_reg_u32 (iommu->cmd_buffer.tail,0 , -IOMMU_CMD_BUFFER_TAIL_MASK , -IOMMU_CMD_BUFFER_TAIL_SHIFT , &tail); +iommu_set_rb_pointer (&tail, iommu->cmd_buffer.tail);writel (tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET ); }
Afaict with these two changes IOMMU_CMD_BUFFER_{HEAD,TAIL}_{MASK,SHIFT} are unused, so please remove them.
Quoted 7 lines
xen/drivers/passthrough/amd/iommu_init.c +1
-0@@ -106,21 +106,21 @@ static void register_iommu_dev_table_in_u64 addr_64, addr_lo, addr_hi;u32 entry; +ASSERT ( iommu->dev_table.buffer );
xen/drivers/passthrough/amd/iommu_init.c static void register_iommu_dev_table_in_ · line 116
Quoted 10 lines
xen/drivers/passthrough/amd/iommu_init.c +3
-3+ addr_64 = (u64 )virt_to_maddr (iommu->dev_table.buffer); addr_lo = addr_64 &DMA_32BIT_MASK ; addr_hi = addr_64 >>32 ; -set_field_in_reg_u32 ((u32 )addr_lo >>PAGE_SHIFT ,0 , -IOMMU_DEV_TABLE_BASE_LOW_MASK , -IOMMU_DEV_TABLE_BASE_LOW_SHIFT , &entry); + entry =0 ; +iommu_set_addr_lo_to_reg (&entry, addr_lo >>PAGE_SHIFT );
While I didn't check, I suspect the same applies to the old definitions here and further down in this same file.
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h static inline int iommu_has_feature(stru · line 196
Quoted 10 lines
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +4
-0+0100 @@ -191,5 +191,85 @@ static inline int iommu_has_feature(strureturn 0 ;return !!(iommu->features & (1U << bit)); } +/* access tail or head pointer of ring buffer */ +#define IOMMU_RING_BUFFER_PTR_MASK 0x0007FFF0 +#define IOMMU_RING_BUFFER_PTR_SHIFT 4
I suppose these (and the others below) really belong into amd-iommu-defs.h?
Jan
Quoted 79 lines
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +77
-0+static inline uint32_t iommu_get_rb_pointer (uint32_t reg) +{ +return get_field_from_reg_u32 (reg,IOMMU_RING_BUFFER_PTR_MASK , +IOMMU_RING_BUFFER_PTR_SHIFT ); +} + +static inline void iommu_set_rb_pointer (uint32_t *reg,uint32_t val) +{ +set_field_in_reg_u32 (val, *reg,IOMMU_RING_BUFFER_PTR_MASK , +IOMMU_RING_BUFFER_PTR_SHIFT , reg); +} + +/* access device field from iommu cmd */ +#define IOMMU_CMD_DEVICE_ID_MASK 0x0000FFFF +#define IOMMU_CMD_DEVICE_ID_SHIFT 0 + +static inline uint16_t iommu_get_devid_from_cmd (uint32_t cmd) +{ +return get_field_from_reg_u32 (cmd,IOMMU_CMD_DEVICE_ID_MASK , +IOMMU_CMD_DEVICE_ID_SHIFT ); +} + +static inline void iommu_set_devid_to_cmd (uint32_t *cmd,uint16_t id) +{ +set_field_in_reg_u32 (id, *cmd,IOMMU_CMD_DEVICE_ID_MASK , +IOMMU_CMD_DEVICE_ID_SHIFT , cmd); +} + +/* access address field from iommu cmd */ +#define IOMMU_CMD_ADDR_LOW_MASK 0xFFFFF000 +#define IOMMU_CMD_ADDR_LOW_SHIFT 12 +#define IOMMU_CMD_ADDR_HIGH_MASK 0xFFFFFFFF +#define IOMMU_CMD_ADDR_HIGH_SHIFT 0 + +static inline uint32_t iommu_get_addr_lo_from_cmd (uint32_t cmd) +{ +return get_field_from_reg_u32 (cmd,IOMMU_CMD_ADDR_LOW_MASK , +IOMMU_CMD_ADDR_LOW_SHIFT ); +} + +static inline uint32_t iommu_get_addr_hi_from_cmd (uint32_t cmd) +{ +return get_field_from_reg_u32 (cmd,IOMMU_CMD_ADDR_LOW_MASK , +IOMMU_CMD_ADDR_HIGH_SHIFT ); +} + +#define iommu_get_devid_from_event iommu_get_devid_from_cmd + +/* access iommu base addresses from mmio regs */ +#define IOMMU_REG_BASE_ADDR_BASE_LOW_MASK 0xFFFFF000 +#define IOMMU_REG_BASE_ADDR_LOW_SHIFT 12 +#define IOMMU_REG_BASE_ADDR_HIGH_MASK 0x000FFFFF +#define IOMMU_REG_BASE_ADDR_HIGH_SHIFT 0 + +static inline void iommu_set_addr_lo_to_reg (uint32_t *reg,uint32_t addr) +{ +set_field_in_reg_u32 (addr, *reg,IOMMU_REG_BASE_ADDR_BASE_LOW_MASK , +IOMMU_REG_BASE_ADDR_LOW_SHIFT , reg); +} + +static inline void iommu_set_addr_hi_to_reg (uint32_t *reg,uint32_t addr) +{ +set_field_in_reg_u32 (addr, *reg,IOMMU_REG_BASE_ADDR_HIGH_MASK , +IOMMU_REG_BASE_ADDR_HIGH_SHIFT , reg); +} + +static inline uint32_t iommu_get_addr_lo_from_reg (uint32_t reg) +{ +return get_field_from_reg_u32 (reg,IOMMU_REG_BASE_ADDR_BASE_LOW_MASK , +IOMMU_REG_BASE_ADDR_LOW_SHIFT ); +} + +static inline uint32_t iommu_get_addr_hi_from_reg (uint32_t reg) +{ +return get_field_from_reg_u32 (reg,IOMMU_REG_BASE_ADDR_HIGH_MASK , +IOMMU_REG_BASE_ADDR_HIGH_SHIFT ); +}#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
PATCH 1/1 amd iommu: Add iommu emulation for hvm guest
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569377 -3600
# Node ID 07f338ae663242ba9080f1ab84298894783da3e2
# Parent e15194f68f99a64b65046ba3d29a3f06ccdca950
amd iommu: Add iommu emulation for hvm guest
ATS device driver that support PASID [1] and PRI [2] capabilites needs to work with iommu driver in OS. If we want passthru ATS device to hvm guests using unmodified OS, we have to expose iommu functionality to HVM guest.
[1] http://www.pcisig.com/specifications/pciexpress/specifications/ECN-PASID-ATS-2011-03-31.pdf
[2] http://www.pcisig.com/members/downloads/specifications/iov/ats_r1.1_26Jan09.pdf
xen/drivers/passthrough/amd/Makefile +1 -0
@@ -5,3 +5,4 @@ obj-y += pci_amd_iommu.o obj-bin-y += iommu_acpi.init.o obj-y += iommu_intr.o obj-y += iommu_cmd.o +obj-y += iommu_guest.o
xen/drivers/passthrough/amd/iommu_cmd.c +12 -0
@@ -398,3 +398,15 @@ void amd_iommu_flush_all_caches(struct ainvalidate_iommu_all (iommu);flush_command_buffer (iommu); } + +void amd_iommu_send_guest_cmd (struct amd_iommu *iommu,u32 cmd[]) +{ +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + +send_iommu_command (iommu, cmd); +flush_command_buffer (iommu); + +spin_unlock_irqrestore (&iommu->lock, flags); +}
xen/drivers/passthrough/amd/iommu_guest.c new file +915 -0
915 lines not on this page · raw message
xen/drivers/passthrough/amd/iommu_map.c +47 -0
53 lines not on this page · raw message
xen/drivers/passthrough/amd/pci_amd_iommu.c +3 -0
@@ -260,6 +260,8 @@ static int amd_iommu_domain_init(struct hd->domain_id = d->domain_id; +guest_iommu_init (d); +return 0 ; }
@@ -443,6 +445,7 @@ static void deallocate_iommu_page_tablesstatic void amd_iommu_domain_destroy (struct domain *d) { +guest_iommu_destroy (d);deallocate_iommu_page_tables (d);amd_iommu_flush_all_pages (d); }
xen/include/asm-x86/amd-iommu.h +52 -0
62 lines not on this page · raw message
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +44 -2
100 lines not on this page · raw message
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +10 -0
@@ -71,6 +71,8 @@ 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 iommu_dte_set_guest_cr3 (u32 *dte,u16 dom_id,u64 gcr3, +int gv,unsigned int glx);/* send cmd to iommu */ void amd_iommu_flush_all_pages (struct domain *d);
@@ -106,6 +108,14 @@ void amd_iommu_resume(void);void amd_iommu_suspend (void );void amd_iommu_crash_shutdown (void ); +/* guest iommu support */ +void amd_iommu_send_guest_cmd (struct amd_iommu *iommu,u32 cmd[]); +void guest_iommu_add_ppr_log (struct domain *d,u32 entry[]); +void guest_iommu_add_event_log (struct domain *d,u32 entry[]); +int guest_iommu_init (struct domain * d); +void guest_iommu_destroy (struct domain *d); +int guest_iommu_set_base (struct domain *d,uint64_t base); +static inline u32 get_field_from_reg_u32 (u32 reg_value,u32 mask,u32 shift) {u32 field;
xen/include/xen/hvm/iommu.h +1 -0
@@ -47,6 +47,7 @@ struct hvm_iommu {int domain_id;int paging_mode;struct page_info *root_table; +struct guest_iommu *g_iommu;/* iommu_ops */ const struct iommu_ops *platform_ops;
PATCH 1/1 amd iommu: Enable ppr log
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569381 -3600
# Node ID 33f88c76776c318eea74b8fc1ba467389407ad57
# Parent 07f338ae663242ba9080f1ab84298894783da3e2
amd iommu: Enable ppr log.
IOMMUv2 writes peripheral page service request (PPR) records into ppr log to report DMA page request from ATS devices to OS.
xen/drivers/passthrough/amd/iommu_init.c +84 -4
@@ -178,6 +178,34 @@ static void register_iommu_event_log_in_writel (entry, iommu->mmio_base+IOMMU_EVENT_LOG_BASE_HIGH_OFFSET ); } +static void register_iommu_ppr_log_in_mmio_space (struct amd_iommu *iommu) +{ +u64 addr_64, addr_lo, addr_hi; +u32 power_of2_entries; +u32 entry; + +ASSERT ( iommu->ppr_log.buffer ); + + addr_64 = (u64 )virt_to_maddr (iommu->ppr_log.buffer); + addr_lo = addr_64 &DMA_32BIT_MASK ; + addr_hi = addr_64 >>32 ; + + entry =0 ; +iommu_set_addr_lo_to_reg (&entry, addr_lo >>PAGE_SHIFT ); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_LOW_OFFSET ); + + power_of2_entries =get_order_from_bytes (iommu->ppr_log.alloc_size) + +IOMMU_PPR_LOG_POWER_OF2_ENTRIES_PER_PAGE ; + + entry =0 ; +iommu_set_addr_hi_to_reg (&entry, addr_hi); +set_field_in_reg_u32 (power_of2_entries, entry, +IOMMU_PPR_LOG_LENGTH_MASK , +IOMMU_PPR_LOG_LENGTH_SHIFT , &entry); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_HIGH_OFFSET ); +} + +static void set_iommu_translation_control (struct amd_iommu *iommu,int enable) {
@@ -278,6 +306,35 @@ static void set_iommu_event_log_control(writel (entry, iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); } +static void set_iommu_ppr_log_control (struct amd_iommu *iommu, +int enable) +{ +u32 entry; + + entry =readl (iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); + +/*reset head and tail pointer manually before enablement */ +if ( enable ) + { +writel (0x0 , iommu->mmio_base +IOMMU_PPR_LOG_HEAD_OFFSET ); +writel (0x0 , iommu->mmio_base +IOMMU_PPR_LOG_TAIL_OFFSET ); + +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_ENABLE_SHIFT ); +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_INT_SHIFT ); +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT ); + } +else + { +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_ENABLE_SHIFT ); +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_INT_SHIFT ); +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT ); + } + +writel (entry, iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); +if ( enable ) +AMD_IOMMU_DEBUG ("PPR Log Enabled.\n" ); +} +static void parse_event_log_entry (struct amd_iommu *,u32 entry[]);static int amd_iommu_read_event_log (struct amd_iommu *iommu)
@@ -585,12 +642,19 @@ static void enable_iommu(struct amd_iommregister_iommu_event_log_in_mmio_space (iommu);register_iommu_exclusion_range (iommu); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +register_iommu_ppr_log_in_mmio_space (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 ); + +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_ENABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_ENABLED );if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) )
@@ -672,16 +736,29 @@ static void * __init allocate_event_log( IOMMU_EVENT_LOG_DEFAULT_ENTRIES, "Event Log"); } +static void *__init allocate_ppr_log (struct amd_iommu *iommu) +{ +/* allocate 'ppr log' in power of 2 increments of 4K */ +return allocate_ring_buffer (&iommu->ppr_log,sizeof (ppr_entry_t), +IOMMU_PPR_LOG_DEFAULT_ENTRIES ,"PPR Log" ); +} +static int __init amd_iommu_init_one (struct amd_iommu *iommu) { +if (map_iommu_mmio_region (iommu) !=0 ) + goto error_out; + +get_iommu_features (iommu); +if (allocate_cmd_buffer (iommu) ==NULL ) goto error_out;if (allocate_event_log (iommu) ==NULL ) goto error_out; -if (map_iommu_mmio_region (iommu) !=0 ) - goto error_out; +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +if (allocate_ppr_log (iommu) ==NULL ) + goto error_out;if (set_iommu_interrupt_handler (iommu) ==0 ) goto error_out;
@@ -694,8 +771,6 @@ 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++;
@@ -718,6 +793,7 @@ static void __init amd_iommu_init_cleanu {deallocate_ring_buffer (&iommu->cmd_buffer);deallocate_ring_buffer (&iommu->event_log); +deallocate_ring_buffer (&iommu->ppr_log);unmap_iommu_mmio_region (iommu); }xfree (iommu);
@@ -916,6 +992,10 @@ static void disable_iommu(struct amd_iomamd_iommu_msi_enable (iommu,IOMMU_CONTROL_DISABLED );set_iommu_command_buffer_control (iommu,IOMMU_CONTROL_DISABLED );set_iommu_event_log_control (iommu,IOMMU_CONTROL_DISABLED ); + +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_DISABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_DISABLED ); iommu->enabled =0 ;
xen/include/asm-x86/amd-iommu.h +1 -0
@@ -94,6 +94,7 @@ struct amd_iommu {struct table_struct dev_table;struct ring_buffer cmd_buffer;struct ring_buffer event_log; +struct ring_buffer ppr_log;int exclusion_enable;int exclusion_allow_all;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +3 -0
@@ -27,6 +27,9 @@/* IOMMU Event Log entries: in power of 2 increments, minimum of 256 */ #define IOMMU_EVENT_LOG_DEFAULT_ENTRIES 512 +/* IOMMU PPR Log entries: in power of 2 increments, minimum of 256 */ +#define IOMMU_PPR_LOG_DEFAULT_ENTRIES 512 +#define PTE_PER_TABLE_SHIFT 9#define PTE_PER_TABLE_SIZE (1 << PTE_PER_TABLE_SHIFT)#define PTE_PER_TABLE_MASK (~(PTE_PER_TABLE_SIZE - 1))
Re: [PATCH 04 of 16] amd iommu: Enable ppr log
Quoted 16 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569381 -3600
# Node ID33f88c76776c318eea74b8fc1ba467389407ad57
# Parent07f338ae663242ba9080f1ab84298894783da3e2
amd iommu: Enable ppr log.
IOMMUv2 writes peripheral page service request (PPR) records into ppr log to report DMA page request from ATS devices to OS.Signed-off-by Wei Wang <[email protected]>diff -r
07f338ae6632-r33f88c76776cxen/drivers/passthrough/amd/iommu_init.c
xen/drivers/passthrough/amd/iommu_init.c static void register_iommu_event_log_in_ · line 183
Quoted 6 lines
xen/drivers/passthrough/amd/iommu_init.c +3
-0@@ -178,6 +178,34 @@ static void register_iommu_event_log_in_writel (entry, iommu->mmio_base+IOMMU_EVENT_LOG_BASE_HIGH_OFFSET ); } +static void register_iommu_ppr_log_in_mmio_space (struct amd_iommu *iommu) +{ +u64 addr_64, addr_lo, addr_hi;
The latter two should be u32.
xen/drivers/passthrough/amd/iommu_init.c static void register_iommu_event_log_in_ · line 189
Quoted 6 lines
xen/drivers/passthrough/amd/iommu_init.c +6
-0+u32 power_of2_entries; +u32 entry; + +ASSERT ( iommu->ppr_log.buffer ); + + addr_64 = (u64 )virt_to_maddr (iommu->ppr_log.buffer);
Pointless cast?
xen/drivers/passthrough/amd/iommu_init.c static void register_iommu_event_log_in_ · line 190
Quoted 1 line
xen/drivers/passthrough/amd/iommu_init.c +1
-0+ addr_lo = addr_64 &DMA_32BIT_MASK ;
DMA_32BIT_MASK is clearly not meant to be used here (and if addr_lo was of type u32, a plain assignment would be all that's needed here).
Jan
Quoted 21 lines
xen/drivers/passthrough/amd/iommu_init.c +18
-0+ addr_hi = addr_64 >>32 ; + + entry =0 ; +iommu_set_addr_lo_to_reg (&entry, addr_lo >>PAGE_SHIFT ); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_LOW_OFFSET ); + + power_of2_entries =get_order_from_bytes (iommu->ppr_log.alloc_size) + +IOMMU_PPR_LOG_POWER_OF2_ENTRIES_PER_PAGE ; + + entry =0 ; +iommu_set_addr_hi_to_reg (&entry, addr_hi); +set_field_in_reg_u32 (power_of2_entries, entry, +IOMMU_PPR_LOG_LENGTH_MASK , +IOMMU_PPR_LOG_LENGTH_SHIFT , &entry); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_HIGH_OFFSET ); +} + +static void set_iommu_translation_control (struct amd_iommu *iommu,int enable) {
PATCH 1/1 amd iommu: Enable guest level translation
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569385 -3600
# Node ID 120144c1fac2dd26926b3b2a6362d30a4029620f
# Parent 33f88c76776c318eea74b8fc1ba467389407ad57
amd iommu: Enable guest level translation.
Similar to nested paging for SVM, IOMMUv2 supports two level translations for DMA. This patch enables this feature.
xen/drivers/passthrough/amd/iommu_init.c +23 -0
@@ -220,6 +220,23 @@ static void set_iommu_translation_controwritel (entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET ); } +static void set_iommu_guest_translation_control (struct amd_iommu *iommu, +int enable) +{ +u32 entry; + + entry =readl (iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); + + enable ? +iommu_set_bit (&entry,IOMMU_CONTROL_GT_ENABLE_SHIFT ): +iommu_clear_bit (&entry,IOMMU_CONTROL_GT_ENABLE_SHIFT ); + +writel (entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET ); + +if ( enable ) +AMD_IOMMU_DEBUG ("Guest Translation Enabled.\n" ); +} +static void set_iommu_command_buffer_control (struct amd_iommu *iommu,int enable) {
@@ -655,6 +672,9 @@ static void enable_iommu(struct amd_iommif (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) )set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_ENABLED ); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_GTSUP_SHIFT ) ) +set_iommu_guest_translation_control (iommu,IOMMU_CONTROL_ENABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_ENABLED );if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) )
@@ -996,6 +1016,9 @@ static void disable_iommu(struct amd_iomif (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) )set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_DISABLED ); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_GTSUP_SHIFT ) ) +set_iommu_guest_translation_control (iommu,IOMMU_CONTROL_DISABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_DISABLED ); iommu->enabled =0 ;
PATCH 1/1 amd iommu: add ppr log processing into iommu interrupt handling
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569388 -3600
# Node ID bf9f21ad9a0ec245b409f3862a5a36c0e070f333
# Parent 120144c1fac2dd26926b3b2a6362d30a4029620f
amd iommu: add ppr log processing into iommu interrupt handling PPR log and event log share the same interrupt source. Interrupt handler should check both of them.
xen/drivers/passthrough/amd/iommu_init.c +121 -43
@@ -352,75 +352,91 @@ static void set_iommu_ppr_log_control(stAMD_IOMMU_DEBUG ("PPR Log Enabled.\n" ); } -static void parse_event_log_entry (struct amd_iommu *,u32 entry[]); +/* read event log or ppr log from iommu ring buffer */ +static int iommu_read_log (struct amd_iommu *iommu, +struct ring_buffer *log, +void (*parse_func)(struct amd_iommu *,u32 *)) +{ +u32 tail, head, *entry, tail_offest, head_offset; -static int amd_iommu_read_event_log (struct amd_iommu *iommu) -{ -u32 tail, head, *event_log; - -BUG_ON ( !iommu ); +BUG_ON ( !iommu || ((log != &iommu->event_log) && + (log != &iommu->ppr_log)) );/* make sure there's an entry in the log */ - 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 ); + tail_offest = ( log == &iommu->event_log ) ? +IOMMU_EVENT_LOG_TAIL_OFFSET : +IOMMU_PPR_LOG_TAIL_OFFSET ; -while ( tail != iommu->event_log.head ) + head_offset = ( log == &iommu->event_log ) ? +IOMMU_EVENT_LOG_HEAD_OFFSET : +IOMMU_PPR_LOG_HEAD_OFFSET ; + + tail =readl (iommu->mmio_base + tail_offest); + tail =iommu_get_rb_pointer (tail); + +while ( tail != log->head ) {/* read event log entry */ - event_log = (u32 *)(iommu->event_log.buffer + - (iommu->event_log.head * -IOMMU_EVENT_LOG_ENTRY_SIZE )); + entry = (u32 *)(log->buffer + log->head * log->entry_size); -parse_event_log_entry (iommu, event_log); - -if ( ++iommu->event_log.head == iommu->event_log.entries ) - iommu->event_log.head =0 ; +parse_func (iommu, entry); +if ( ++log->head == log->entries ) + log->head =0 ;/* update head pointer */ -set_field_in_reg_u32 (iommu->event_log.head,0 , -IOMMU_EVENT_LOG_HEAD_MASK , -IOMMU_EVENT_LOG_HEAD_SHIFT , &head); -writel (head, iommu->mmio_base +IOMMU_EVENT_LOG_HEAD_OFFSET ); + head =0 ; +iommu_set_rb_pointer (&head, log->head); + +writel (head, iommu->mmio_base + head_offset); }return 0 ; } -static void amd_iommu_reset_event_log (struct amd_iommu *iommu) +/* reset event log or ppr log when overflow */ +static void iommu_reset_log (struct amd_iommu *iommu, +struct ring_buffer *log, +void (*ctrl_func)(struct amd_iommu *iommu,int )) {u32 entry; -int log_run; +int log_run, run_bit, of_bit;int loop_count =1000 ; +BUG_ON ( !iommu || ((log != &iommu->event_log) && + (log != &iommu->ppr_log)) ); + + run_bit = ( log == &iommu->event_log ) ? +IOMMU_STATUS_EVENT_LOG_RUN_SHIFT : +IOMMU_STATUS_PPR_LOG_RUN_SHIFT ; + + of_bit = ( log == &iommu->event_log ) ? +IOMMU_STATUS_EVENT_OVERFLOW_SHIFT : +IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT ; +/* wait until EventLogRun bit = 0 */ do { entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); - log_run =iommu_get_bit (entry,IOMMU_STATUS_EVENT_LOG_RUN_SHIFT ); + log_run =iommu_get_bit (entry, run_bit); loop_count--; }while ( log_run && loop_count );if ( log_run ) { -AMD_IOMMU_DEBUG ("Warning: EventLogRun bit is not cleared" -"before reset!\n" ); +AMD_IOMMU_DEBUG ("Warning: Log Run bit %d is not cleared" +"before reset! \n" , run_bit);return ; } -set_iommu_event_log_control (iommu,IOMMU_CONTROL_DISABLED ); +ctrl_func (iommu,IOMMU_CONTROL_DISABLED ); -/* read event log for debugging */ -amd_iommu_read_event_log (iommu);/*clear overflow bit */ -iommu_clear_bit (&entry,IOMMU_STATUS_EVENT_OVERFLOW_SHIFT ); - -writel (entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET ); +iommu_clear_bit (&entry, of_bit); +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );/*reset event log base address */ - iommu->event_log.head =0 ; + log->head =0 ; -set_iommu_event_log_control (iommu,IOMMU_CONTROL_ENABLED ); +ctrl_func (iommu,IOMMU_CONTROL_ENABLED ); }static void iommu_msi_set_affinity (struct irq_desc *desc,const cpumask_t *mask)
@@ -592,30 +608,93 @@ static void parse_event_log_entry(struct } } -static void amd_iommu_page_fault (int irq,void *dev_id, -struct cpu_user_regs *regs) +static void iommu_check_event_log (struct amd_iommu *iommu) {u32 entry;unsigned long flags; -struct amd_iommu *iommu = dev_id;spin_lock_irqsave (&iommu->lock, flags); -amd_iommu_read_event_log (iommu); + +iommu_read_log (iommu, &iommu->event_log, parse_event_log_entry);/*check event overflow */ entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );if (iommu_get_bit (entry,IOMMU_STATUS_EVENT_OVERFLOW_SHIFT ) ) -amd_iommu_reset_event_log (iommu); +iommu_reset_log (iommu, &iommu->event_log, set_iommu_event_log_control);/* reset interrupt status bit */ entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );iommu_set_bit (&entry,IOMMU_STATUS_EVENT_LOG_INT_SHIFT ); -writel (entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET ); +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); +spin_unlock_irqrestore (&iommu->lock, flags); } +void parse_ppr_log_entry (struct amd_iommu *iommu,u32 entry[]) +{ + +u16 device_id; +u8 bus, devfn; +struct pci_dev *pdev; +struct domain *d; + +/* here device_id is physical value */ + device_id =iommu_get_devid_from_cmd (entry[0 ]); + bus = device_id >>8 ; + devfn = device_id &0xFF ; + +local_irq_enable (); + +spin_lock (&pcidevs_lock); + pdev =pci_get_pdev (0 , bus, devfn); +spin_unlock (&pcidevs_lock); + +local_irq_disable (); + +if ( pdev ==NULL ) +return ; + + d = pdev->domain; + +guest_iommu_add_ppr_log (d, entry); +} + +static void iommu_check_ppr_log (struct amd_iommu *iommu) +{ +u32 entry; +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + +iommu_read_log (iommu, &iommu->ppr_log, parse_ppr_log_entry); + +/*check event overflow */ + entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); + +if (iommu_get_bit (entry,IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT ) ) +iommu_reset_log (iommu, &iommu->ppr_log, set_iommu_ppr_log_control); + +/* reset interrupt status bit */ + entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); +iommu_set_bit (&entry,IOMMU_STATUS_PPR_LOG_INT_SHIFT ); + +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); + +spin_unlock_irqrestore (&iommu->lock, flags); +} + +static void iommu_interrupt_handler (int irq,void *dev_id, +struct cpu_user_regs *regs) +{ +struct amd_iommu *iommu = dev_id; +iommu_check_event_log (iommu); + +if ( iommu->ppr_log.buffer !=NULL ) +iommu_check_ppr_log (iommu); +} +static int __init set_iommu_interrupt_handler (struct amd_iommu *iommu) {int irq, ret;
@@ -628,8 +707,7 @@ static int __init set_iommu_interrupt_ha } irq_desc[irq].handler = &iommu_msi_type; - ret =request_irq (irq, amd_iommu_page_fault,0 , -"amd_iommu" , iommu); + ret =request_irq (irq, iommu_interrupt_handler,0 ,"amd_iommu" , iommu);if ( ret ) { irq_desc[irq].handler = &no_irq_type;
Re: [PATCH 06 of 16] amd iommu: add ppr log processing into iommu interrupt handling
xen/drivers/passthrough/amd/iommu_init.c static void parse_event_log_entry(struct · line 635
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/drivers/passthrough/amd/iommu_init.c +1
-0spin_unlock_irqrestore (&iommu->lock, flags); } +void parse_ppr_log_entry (struct amd_iommu *iommu,u32 entry[])
static?
xen/drivers/passthrough/amd/iommu_init.c static void parse_event_log_entry(struct · line 638
Quoted 4 lines
xen/drivers/passthrough/amd/iommu_init.c +3
-0+{ + +u16 device_id;
Jan
Re: [PATCH 06 of 16] amd iommu: add ppr log processing into iommu interrupt handling
Hi Jan,
Thanks for the review. I will fix all of them in the next try. Wei
Quoted 18 lines · On Monday 02 January 2012 14:13:00 Jan Beulich wrote:
Quoted 9 lines
Quoted 1 line
Quoted 1 line · Wei Wang
---
a/xen/drivers/passthrough/amd/iommu_init.cThu Dec 22 16:56:25 2011
+0100 +++b/xen/drivers/passthrough/amd/iommu_init.cThu Dec 22 16:56:28
2011 +0100 ...spin_unlock_irqrestore(&iommu->lock, flags);}
+void
parse_ppr_log_entry(struct amd_iommu *iommu, u32 entry[])static?
xen/drivers/passthrough/amd/iommu_init.c static void parse_event_log_entry(struct · line 638
Quoted 4 lines
xen/drivers/passthrough/amd/iommu_init.c +3
-0+{ + +u16 device_id;Jan
PATCH 1/1 amd iommu: Add 2 hypercalls for libxc
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569392 -3600
# Node ID 40d61d0390ec930cf53ce5cbf91faada8c7192bd # Parent bf9f21ad9a0ec245b409f3862a5a36c0e070f333 amd iommu: Add 2 hypercalls for libxc
iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest space. Hypervisor needs this vector to inject msi into guest when PPR logging happens.
iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards them to host iommu. But virtual device id from guest should be converted into physical before sending to real hardware.
Signed -off-by: Wei Wang <[email protected]>
xen/drivers/passthrough/amd/iommu_guest.c +57 -2
@@ -50,12 +50,27 @@static unsigned int machine_bdf (struct domain *d,uint16_t guest_bdf) { -return guest_bdf; +struct pci_dev *pdev; +uint16_t mbdf =0 ; + +for_each_pdev ( d, pdev ) + { +if ( pdev->gbdf == guest_bdf ) + { + mbdf =PCI_BDF2 (pdev->bus, pdev->devfn); +break ; + } + } +return mbdf; }static uint16_t guest_bdf (struct domain *d,uint16_t machine_bdf) { -return machine_bdf; +struct pci_dev *pdev; + + pdev =pci_get_pdev_by_domain (d,0 ,PCI_BUS (machine_bdf), +PCI_DEVFN2 (machine_bdf)); +return pdev->gbdf; }static inline struct guest_iommu *domain_iommu (struct domain *d)
@@ -913,3 +928,43 @@ const struct hvm_mmio_handler iommu_mmio .read_handler = guest_iommu_mmio_read, .write_handler = guest_iommu_mmio_write }; + +/* iommu hypercall handler */ +int iommu_bind_bdf (struct domain * d,uint16_t gbdf,uint16_t mbdf) +{ +struct pci_dev *pdev; +int ret = -ENODEV ; + +if ( !iommu_found () ) +return 0 ; + +spin_lock (&pcidevs_lock); + +for_each_pdev ( d, pdev ) + { +if ( (pdev->bus !=PCI_BUS (mbdf) ) || + (pdev->devfn !=PCI_DEVFN2 (mbdf)) ) +continue ; + + pdev->gbdf = gbdf; + ret =0 ; + } + +spin_unlock (&pcidevs_lock); +return ret; +} + +void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode) +{ +struct guest_iommu *iommu =domain_iommu (d); + +if ( !iommu_found () ) +return ; + + iommu->msi.vector = vector; + iommu->msi.dest = dest; + iommu->msi.dest_mode = dest_mode; + iommu->msi.trig_mode = trig_mode; +}
xen/drivers/passthrough/iommu.c +34 -0
@@ -648,6 +648,40 @@ int iommu_do_domctl(put_domain (d);break ; +#ifndef __ia64__ +case XEN_DOMCTL_guest_iommu_op: + { +xen_domctl_guest_iommu_op_t * guest_op; + +if (unlikely ((d =get_domain_by_id (domctl->domain)) ==NULL ) ) + { +gdprintk (XENLOG_ERR , +"XEN_DOMCTL_guest_iommu_op: get_domain_by_id() failed\n" ); + ret = -EINVAL ; +break ; + } + + guest_op = &(domctl->u.guest_iommu_op); +switch ( guest_op->op ) + { +case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI : +iommu_set_msi (d, guest_op->u.msi.vector, + guest_op->u.msi.dest, + guest_op->u.msi.dest_mode, + guest_op->u.msi.delivery_mode, + guest_op->u.msi.trig_mode); + ret =0 ; +break ; +case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF : + ret =iommu_bind_bdf (d, guest_op->u.bdf_bind.g_bdf, + guest_op->u.bdf_bind.m_bdf); +break ; + } +put_domain (d); +break ; + } +#endif +default : ret = -ENOSYS ;break ;
xen/include/public/domctl.h +25 -0
@@ -848,6 +848,29 @@ struct xen_domctl_set_access_required {typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t ;DEFINE_XEN_GUEST_HANDLE (xen_domctl_set_access_required_t); +/* Support for guest iommu emulation */ +struct xen_domctl_guest_iommu_op { +/* XEN_DOMCTL_GUEST_IOMMU_OP_* */ +#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI 0 +#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF 1 +uint8_t op; +union { +struct iommu_msi { +uint8_t vector; +uint8_t dest; +uint8_t dest_mode; +uint8_t delivery_mode; +uint8_t trig_mode; + } msi; +struct bdf_bind { +uint32_t g_bdf; +uint32_t m_bdf; + } bdf_bind; + } u; +}; +typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t ; +DEFINE_XEN_GUEST_HANDLE (xen_domctl_guest_iommu_op_t); +struct xen_domctl {uint32_t cmd;#define XEN_DOMCTL_createdomain 1
@@ -912,6 +935,7 @@ struct xen_domctl {#define XEN_DOMCTL_getvcpuextstate 63#define XEN_DOMCTL_set_access_required 64#define XEN_DOMCTL_audit_p2m 65 +#define XEN_DOMCTL_guest_iommu_op 66#define XEN_DOMCTL_gdbsx_guestmemio 1000#define XEN_DOMCTL_gdbsx_pausevcpu 1001#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
@@ -960,6 +984,7 @@ struct xen_domctl {struct xen_domctl_debug_op debug_op;struct xen_domctl_mem_event_op mem_event_op;struct xen_domctl_mem_sharing_op mem_sharing_op; +struct xen_domctl_guest_iommu_op guest_iommu_op;#if defined(__i386__) || defined(__x86_64__)struct xen_domctl_cpuid cpuid;struct xen_domctl_vcpuextstate vcpuextstate;
xen/include/xen/iommu.h +8 -0
@@ -164,6 +164,14 @@ int iommu_do_domctl(struct xen_domctl *,void iommu_iotlb_flush (struct domain *d,unsigned long gfn,unsigned int page_count);void iommu_iotlb_flush_all (struct domain *d); +#ifndef __ia64_ +/* Only used by AMD IOMMU */ +void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode); +int iommu_bind_bdf (struct domain * d,uint16_t gbdf,uint16_t mbdf); +#endif +/* * The purpose of the iommu_dont_flush_iotlb optional cpu flag is to * avoid unecessary iotlb_flush in the low level IOMMU code.
xen/include/xen/pci.h +3 -0
@@ -63,6 +63,9 @@ struct pci_dev {const u8 devfn;struct pci_dev_info info;u64 vf_rlen[6 ]; + +/* used by amd iomm to represent bdf value in guest space */ +u16 gbdf; };#define for_each_pdev (domain, pdev) \
Re: [PATCH 07 of 16] amd iommu: Add 2 hypercalls for libxc
Quoted 105 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569392 -3600
# Node ID40d61d0390ec930cf53ce5cbf91faada8c7192bd# Parentbf9f21ad9a0ec245b409f3862a5a36c0e070f333amd iommu: Add 2 hypercalls for libxc
iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest
space. Hypervisor needs this vector to inject msi into guest when PPR logging
happens.
iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards
them to host iommu. But virtual device id from guest should be converted into
physical before sending to real hardware.Signed -off-by: Wei Wang <[email protected]>
diff -r
bf9f21ad9a0e-r40d61d0390ecxen/drivers/passthrough/amd/iommu_guest.cxen/drivers/passthrough/amd/iommu_guest.c +58
-2+0100 @@ -50,12 +50,27 @@static unsigned int machine_bdf (struct domain *d,uint16_t guest_bdf) { -return guest_bdf; +struct pci_dev *pdev; +uint16_t mbdf =0 ; + +for_each_pdev ( d, pdev ) + { +if ( pdev->gbdf == guest_bdf ) + { + mbdf =PCI_BDF2 (pdev->bus, pdev->devfn); +break ; + } + } +return mbdf; }static uint16_t guest_bdf (struct domain *d,uint16_t machine_bdf) { -return machine_bdf; +struct pci_dev *pdev; + + pdev =pci_get_pdev_by_domain (d,0 ,PCI_BUS (machine_bdf), +PCI_DEVFN2 (machine_bdf)); +return pdev->gbdf; }static inline struct guest_iommu *domain_iommu (struct domain *d)@@ -913,3 +928,43 @@ const struct hvm_mmio_handler iommu_mmio .read_handler = guest_iommu_mmio_read, .write_handler = guest_iommu_mmio_write }; + +/* iommu hypercall handler */ +int iommu_bind_bdf (struct domain * d,uint16_t gbdf,uint16_t mbdf) +{ +struct pci_dev *pdev; +int ret = -ENODEV ; + +if ( !iommu_found () ) +return 0 ; + +spin_lock (&pcidevs_lock); + +for_each_pdev ( d, pdev ) + { +if ( (pdev->bus !=PCI_BUS (mbdf) ) || + (pdev->devfn !=PCI_DEVFN2 (mbdf)) ) +continue ; + + pdev->gbdf = gbdf; + ret =0 ; + } + +spin_unlock (&pcidevs_lock); +return ret; +} + +void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode) +{ +struct guest_iommu *iommu =domain_iommu (d); + +if ( !iommu_found () ) +return ; + + iommu->msi.vector = vector; + iommu->msi.dest = dest; + iommu->msi.dest_mode = dest_mode; + iommu->msi.trig_mode = trig_mode; +}diff -r
bf9f21ad9a0e-r40d61d0390ecxen/drivers/passthrough/iommu.c
xen/drivers/passthrough/iommu.c int iommu_do_domctl( · line 651
Quoted 4 lines
xen/drivers/passthrough/iommu.c +1
-0@@ -648,6 +648,40 @@ int iommu_do_domctl(put_domain (d);break ; +#ifndef __ia64__
While I understand your reasons for putting the #ifdef here, I would like to see it removed in favor of a proper abstraction through vectors in struct iommu_ops.
Quoted 91 lines
xen/drivers/passthrough/iommu.c +33
-0+case XEN_DOMCTL_guest_iommu_op: + { +xen_domctl_guest_iommu_op_t * guest_op; + +if (unlikely ((d =get_domain_by_id (domctl->domain)) ==NULL ) ) + { +gdprintk (XENLOG_ERR , +"XEN_DOMCTL_guest_iommu_op: get_domain_by_id() failed\n"); + ret = -EINVAL ; +break ; + } + + guest_op = &(domctl->u.guest_iommu_op); +switch ( guest_op->op ) + { +case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI : +iommu_set_msi (d, guest_op->u.msi.vector, + guest_op->u.msi.dest, + guest_op->u.msi.dest_mode, + guest_op->u.msi.delivery_mode, + guest_op->u.msi.trig_mode); + ret =0 ; +break ; +case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF : + ret =iommu_bind_bdf (d, guest_op->u.bdf_bind.g_bdf, + guest_op->u.bdf_bind.m_bdf); +break ; + } +put_domain (d); +break ; + } +#endif +default : ret = -ENOSYS ;break;diff -r
bf9f21ad9a0e-r40d61d0390ecxen/include/public/domctl.hxen/include/public/domctl.h +23
-0@@ -848,6 +848,29 @@ struct xen_domctl_set_access_required {typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t ;DEFINE_XEN_GUEST_HANDLE (xen_domctl_set_access_required_t); +/* Support for guest iommu emulation */ +struct xen_domctl_guest_iommu_op { +/* XEN_DOMCTL_GUEST_IOMMU_OP_* */ +#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI 0 +#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF 1 +uint8_t op; +union { +struct iommu_msi { +uint8_t vector; +uint8_t dest; +uint8_t dest_mode; +uint8_t delivery_mode; +uint8_t trig_mode; + } msi; +struct bdf_bind { +uint32_t g_bdf; +uint32_t m_bdf; + } bdf_bind; + } u; +}; +typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t ; +DEFINE_XEN_GUEST_HANDLE (xen_domctl_guest_iommu_op_t); +struct xen_domctl {uint32_t cmd;#define
XEN_DOMCTL_createdomain1xen/include/public/domctl.h +2
-0@@ -912,6 +935,7 @@ struct xen_domctl {#define XEN_DOMCTL_getvcpuextstate 63#define XEN_DOMCTL_set_access_required 64#define XEN_DOMCTL_audit_p2m 65 +#define XEN_DOMCTL_guest_iommu_op 66#define XEN_DOMCTL_gdbsx_guestmemio 1000#define XEN_DOMCTL_gdbsx_pausevcpu 1001#define XEN_DOMCTL_gdbsx_unpausevcpu 1002@@ -960,6 +984,7 @@ struct xen_domctl {struct xen_domctl_debug_op debug_op;struct xen_domctl_mem_event_op mem_event_op;struct xen_domctl_mem_sharing_op mem_sharing_op; +struct xen_domctl_guest_iommu_op guest_iommu_op;#if defined(__i386__) || defined(__x86_64__)struct xen_domctl_cpuid cpuid;struct xen_domctl_vcpuextstate vcpuextstate;diff -r
bf9f21ad9a0e-r40d61d0390ecxen/include/xen/iommu.h
xen/include/xen/iommu.h int iommu_do_domctl(struct xen_domctl *, · line 169
Quoted 6 lines
xen/include/xen/iommu.h +2
-0@@ -164,6 +164,14 @@ int iommu_do_domctl(struct xen_domctl *,void iommu_iotlb_flush (struct domain *d,unsigned long gfn,unsigned int page_count);void iommu_iotlb_flush_all (struct domain *d); +#ifndef __ia64_ +/* Only used by AMD IOMMU */
Even without said abstraction, the conditional is pointless here, and the comment would seem unnecessary to me.
Quoted 13 lines
xen/include/xen/iommu.h +6
-0+void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode); +int iommu_bind_bdf (struct domain * d,uint16_t gbdf,uint16_t mbdf); +#endif +/* * The purpose of the iommu_dont_flush_iotlb optional cpu flag is to * avoid unecessary
iotlb_flushin the low level IOMMU code.
diff -rbf9f21ad9a0e-r40d61d0390ecxen/include/xen/pci.h
xen/include/xen/pci.h struct pci_dev { · line 68
Quoted 6 lines
xen/include/xen/pci.h +3
-0@@ -63,6 +63,9 @@ struct pci_dev {const u8 devfn;struct pci_dev_info info;u64 vf_rlen[6 ]; + +/* used by amd iomm to represent bdf value in guest space */ +u16 gbdf;
For one, this would better be placed immediately after devfn (on 64-bit there's a 32-bit hole there).
Second, what about the segment number - is that one always going to be the physical one? Or always zero?
Finally, please correct the typo ("iommu") and remove "amd" as once again the concept ought to be generic.
Jan
Quoted 3 lines
xen/include/xen/pci.h +0
-0};#define for_each_pdev (domain, pdev) \
PATCH 1/1 amd iommu: Add a hypercall for hvmloader
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569395 -3600
# Node ID 2329dad2786f6f20ea69c9609ab60208cad6fca9 # Parent 40d61d0390ec930cf53ce5cbf91faada8c7192bd amd iommu: Add a hypercall for hvmloader.
IOMMU MMIO base address is dynamically allocated by firmware. This patch allows hvmloader to notify hypervisor where the iommu mmio pages are.
xen/arch/x86/hvm/hvm.c +4 -0
@@ -65,6 +65,7 @@#include <public/memory.h> #include <asm/mem_event.h> #include <public/mem_event.h> +#include <asm/hvm/svm/amd-iommu-proto.h> bool_t __read_mostly hvm_enabled;
@@ -3677,6 +3678,9 @@ long do_hvm_op(unsigned long op, XEN_GUEcase HVM_PARAM_BUFIOREQ_EVTCHN : rc = -EINVAL ;break ; +case HVM_PARAM_IOMMU_BASE : + rc =guest_iommu_set_base (d, a.value); +break ; }if ( rc ==0 )
xen/include/public/hvm/params.h +5 -1
@@ -142,6 +142,10 @@/* Boolean: Enable nestedhvm (hvm only) */ #define HVM_PARAM_NESTEDHVM 24 -#define HVM_NR_PARAMS 27 +#ifndef __ia64__ +#define HVM_PARAM_IOMMU_BASE 27 +#endif + +#define HVM_NR_PARAMS 28#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
Re: [PATCH 08 of 16] amd iommu: Add a hypercall for hvmloader
Quoted 38 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569395 -3600
# Node ID2329dad2786f6f20ea69c9609ab60208cad6fca9# Parent40d61d0390ec930cf53ce5cbf91faada8c7192bdamd iommu: Add a hypercall for hvmloader.
IOMMU MMIO base address is dynamically allocated by firmware. This patch allows hvmloader to notify hypervisor where the iommu mmio pages are.Signed-off-by Wei Wang <[email protected]>diff -r
40d61d0390ec-r2329dad2786fxen/arch/x86/hvm/hvm.cxen/arch/x86/hvm/hvm.c +4
-0@@ -65,6 +65,7 @@#include <public/memory.h> #include <asm/mem_event.h> #include <public/mem_event.h> +#include <asm/hvm/svm/amd-iommu-proto.h> bool_t __read_mostly hvm_enabled;@@ -3677,6 +3678,9 @@ long do_hvm_op(unsigned long op, XEN_GUEcase HVM_PARAM_BUFIOREQ_EVTCHN : rc = -EINVAL ;break ; +case HVM_PARAM_IOMMU_BASE : + rc =guest_iommu_set_base (d, a.value); +break ; }if ( rc ==0 )diff -r
40d61d0390ec-r2329dad2786fxen/include/public/hvm/params.h
xen/include/public/hvm/params.h line 145
Quoted 5 lines
xen/include/public/hvm/params.h +1
-1@@ -142,6 +142,10 @@/* Boolean: Enable nestedhvm (hvm only) */ #define HVM_PARAM_NESTEDHVM 24 -#define HVM_NR_PARAMS 27 +#ifndef __ia64__
As with the domctl definitions, I fail to see why this should be excluded for IA64 - the general concept, even if not currently implemented, is valid for any architecture that could potentially have IOMMUs.
Jan
Quoted 6 lines
xen/include/public/hvm/params.h +4
-0+#define HVM_PARAM_IOMMU_BASE 27 +#endif + +#define HVM_NR_PARAMS 28#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
PATCH 1/1 amd iommu: add iommu mmio handler
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569398 -3600
# Node ID dd808bdd61c581b041d5b7e816b18674de51da6f # Parent 2329dad2786f6f20ea69c9609ab60208cad6fca9 amd iommu: add iommu mmio handler.
xen/arch/x86/hvm/intercept.c +2 -1
@@ -38,7 +38,8 @@ hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] = &hpet_mmio_handler, &vlapic_mmio_handler, &vioapic_mmio_handler, - &msixtbl_mmio_handler + &msixtbl_mmio_handler, + &iommu_mmio_handler }; static int hvm_mmio_access(struct vcpu *v,
xen/include/asm-x86/hvm/io.h +2 -1
@@ -69,8 +69,9 @@ extern const struct hvm_mmio_handler hpeextern const struct hvm_mmio_handler vlapic_mmio_handler;extern const struct hvm_mmio_handler vioapic_mmio_handler;extern const struct hvm_mmio_handler msixtbl_mmio_handler; +extern const struct hvm_mmio_handler iommu_mmio_handler; -#define HVM_MMIO_HANDLER_NR 4 +#define HVM_MMIO_HANDLER_NR 5int hvm_io_intercept (ioreq_t *p,int type); void register_io_handler(
Re: [PATCH 09 of 16] amd iommu: add iommu mmio handler
Quoted 7 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569398 -3600
# Node IDdd808bdd61c581b041d5b7e816b18674de51da6f# Parent2329dad2786f6f20ea69c9609ab60208cad6fca9amd iommu: add iommu mmio handler.
This could be part of patch 3, or (perhaps better) the respective bits should get moved here instead of adding them as dead code there.
Jan
Quoted 29 lines
Signed-off-by Wei Wang <[email protected]>diff -r
2329dad2786f-rdd808bdd61c5xen/arch/x86/hvm/intercept.cxen/arch/x86/hvm/intercept.c +2
-1@@ -38,7 +38,8 @@ hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] = &hpet_mmio_handler, &vlapic_mmio_handler, &vioapic_mmio_handler, - &msixtbl_mmio_handler + &msixtbl_mmio_handler, + &iommu_mmio_handler }; static int hvm_mmio_access(struct vcpu *v,diff -r
2329dad2786f-rdd808bdd61c5xen/include/asm-x86/hvm/io.hxen/include/asm-x86/hvm/io.h +2
-1@@ -69,8 +69,9 @@ extern const struct hvm_mmio_handler hpeextern const struct hvm_mmio_handler vlapic_mmio_handler;extern const struct hvm_mmio_handler vioapic_mmio_handler;extern const struct hvm_mmio_handler msixtbl_mmio_handler; +extern const struct hvm_mmio_handler iommu_mmio_handler; -#define HVM_MMIO_HANDLER_NR 4 +#define HVM_MMIO_HANDLER_NR 5int hvm_io_intercept (ioreq_t *p,int type); void register_io_handler(
PATCH 1/1 amd iommu: Enable FC bit in iommu host level PTE
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569401 -3600
# Node ID 30b1f434160d989be5e0bb6c6956bb7e3985db59 # Parent dd808bdd61c581b041d5b7e816b18674de51da6f amd iommu: Enable FC bit in iommu host level PTE
xen/drivers/passthrough/amd/iommu_map.c +5 -0
@@ -83,6 +83,11 @@ static bool_t set_iommu_pde_present(u32set_field_in_reg_u32 (ir, entry,IOMMU_PDE_IO_READ_PERMISSION_MASK ,IOMMU_PDE_IO_READ_PERMISSION_SHIFT , &entry); + +/* IOMMUv2 needs FC bit enabled */ +if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) +set_field_in_reg_u32 (IOMMU_CONTROL_ENABLED , entry, +IOMMU_PTE_FC_MASK ,IOMMU_PTE_FC_SHIFT , &entry); pde[1 ] = entry;/* mark next level as 'present' */
Re: [PATCH 10 of 16] amd iommu: Enable FC bit in iommu host level PTE
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569401 -3600
# Node ID30b1f434160d989be5e0bb6c6956bb7e3985db59# Parentdd808bdd61c581b041d5b7e816b18674de51da6famd iommu: Enable FC bit in iommu host level PTESigned-off-by Wei Wang <[email protected]>diff -r
dd808bdd61c5-r30b1f434160dxen/drivers/passthrough/amd/iommu_map.c
xen/drivers/passthrough/amd/iommu_map.c static bool_t set_iommu_pde_present(u32 · line 87
Quoted 5 lines
xen/drivers/passthrough/amd/iommu_map.c +2
-0@@ -83,6 +83,11 @@ static bool_t set_iommu_pde_present(u32set_field_in_reg_u32 (ir, entry,IOMMU_PDE_IO_READ_PERMISSION_MASK ,IOMMU_PDE_IO_READ_PERMISSION_SHIFT , &entry); + +/* IOMMUv2 needs FC bit enabled */
This comment suggests that the patches prior to that aren't consistent. Is this really a proper standalone patch, or is the word "needs" too strict, or should it really be moved ahead in the series?
xen/drivers/passthrough/amd/iommu_map.c static bool_t set_iommu_pde_present(u32 · line 90
Quoted 3 lines
xen/drivers/passthrough/amd/iommu_map.c +3
-0+if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) +set_field_in_reg_u32 (IOMMU_CONTROL_ENABLED , entry, +IOMMU_PTE_FC_MASK ,IOMMU_PTE_FC_SHIFT , &entry);
This is being done no matter whether it actually is a v2 IOMMU that you deal with here - if that's correct, the comment above should be adjusted accordingly.
Jan
Quoted 3 lines
xen/drivers/passthrough/amd/iommu_map.c +0
-0pde[1 ] = entry;/* mark next level as 'present' */
Re: [PATCH 10 of 16] amd iommu: Enable FC bit in iommu host level PTE
Quoted 26 lines · On Monday 02 January 2012 12:36:08 Jan Beulich wrote:
Quoted 19 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569401 -3600
# Node ID30b1f434160d989be5e0bb6c6956bb7e3985db59# Parentdd808bdd61c581b041d5b7e816b18674de51da6famd iommu: Enable FC bit in iommu host level PTESigned-off-by Wei Wang <[email protected]>diff -r
dd808bdd61c5-r30b1f434160dxen/drivers/passthrough/amd/iommu_map.c---a/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22 16:56:38 2011 +0100
+++b/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22 16:56:41 2011
+0100 @@ -83,6 +83,11 @@ staticbool_tset_iommu_pde_present(u32set_field_in_reg_u32(ir, entry, IOMMU_PDE_IO_READ_PERMISSION_MASK, IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);xen/drivers/passthrough/amd/iommu_map.c static bool_t set_iommu_pde_present(u32 · line 87
Quoted 2 lines
xen/drivers/passthrough/amd/iommu_map.c +2
-0+ +/* IOMMUv2 needs FC bit enabled */ This comment suggests that the patches prior to that aren't consistent. Is this really a proper standalone patch, or is the word "needs" too strict, or should it really be moved ahead in the series?
Quoted 8 lines
Quoted 4 lines
xen/drivers/passthrough/amd/iommu_map.c +3
-0+if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) + set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, + IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT,&entry);
This is being done no matter whether it actually is a v2 IOMMU that you deal with here - if that's correct, the comment above should be adjusted accordingly.
This bit forces pci-defined no snoop bit to be cleared. This helps to solve potential issues in ATS devices with early drivers. I did not see any breaks on legacy devices and iommuv1 with FC = 1. But if you like I could make this only for v2 or change the comment a bit.
Thanks,
Wei
Quoted 5 lines
Jan
Quoted 3 lines
pde[1] = entry; /* mark next level as 'present' */
Re: [PATCH 10 of 16] amd iommu: Enable FC bit in iommu host level PTE
Quoted 37 lines
Quoted 1 line
Quoted 1 line · On 03.01.12 at 11:05, Wei Wang2 <[email protected]> wrote:
Quoted 26 lines · On Monday 02 January 2012 12:36:08 Jan Beulich wrote:
Quoted 19 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569401 -3600
# Node ID30b1f434160d989be5e0bb6c6956bb7e3985db59# Parentdd808bdd61c581b041d5b7e816b18674de51da6famd iommu: Enable FC bit in iommu host level PTESigned-off-by Wei Wang <[email protected]>diff -r
dd808bdd61c5-r30b1f434160dxen/drivers/passthrough/amd/iommu_map.c---a/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22 16:56:38 2011 +0100
+++b/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22 16:56:41 2011
+0100 @@ -83,6 +83,11 @@ staticbool_tset_iommu_pde_present(u32set_field_in_reg_u32(ir, entry, IOMMU_PDE_IO_READ_PERMISSION_MASK, IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);xen/drivers/passthrough/amd/iommu_map.c static bool_t set_iommu_pde_present(u32 · line 87
Quoted 2 lines
xen/drivers/passthrough/amd/iommu_map.c +2
-0+ +/* IOMMUv2 needs FC bit enabled */ This comment suggests that the patches prior to that aren't consistent. Is this really a proper standalone patch, or is the word "needs" too strict, or should it really be moved ahead in the series?
Quoted 8 lines
Quoted 4 lines
xen/drivers/passthrough/amd/iommu_map.c +3
-0+if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) + set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, + IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT,&entry);
This is being done no matter whether it actually is a v2 IOMMU that you deal with here - if that's correct, the comment above should be adjusted accordingly.
Quoted 6 lines
This bit forces pci-defined no snoop bit to be cleared. This helps to solve potential issues in ATS devices with early drivers. I did not see any breaks
on legacy devices and iommuv1 with FC = 1. But if you like I could make this
only for v2 or change the comment a bit.
Whatever is the most appropriate thing to do here (you definitely know better than I do).
Jan
Re: [PATCH 10 of 16] amd iommu: Enable FC bit in iommu host level PTE
Quoted 42 lines · On Tuesday 03 January 2012 11:12:35 Jan Beulich wrote:
Quoted 42 lines
Quoted 1 line
Quoted 1 line · On 03.01.12 at 11:05, Wei Wang2 <[email protected]> wrote:
Quoted 26 lines · On Monday 02 January 2012 12:36:08 Jan Beulich wrote:
Quoted 19 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569401 -3600
# Node ID30b1f434160d989be5e0bb6c6956bb7e3985db59# Parentdd808bdd61c581b041d5b7e816b18674de51da6famd iommu: Enable FC bit in iommu host level PTESigned-off-by Wei Wang <[email protected]>diff -r
dd808bdd61c5-r30b1f434160dxen/drivers/passthrough/amd/iommu_map.c---a/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22 16:56:38 2011
+0100 +++b/xen/drivers/passthrough/amd/iommu_map.cThu Dec 22
16:56:41 2011 +0100 @@ -83,6 +83,11 @@ staticbool_tset_iommu_pde_present(u32 set_field_in_reg_u32(ir, entry,IOMMU_PDE_IO_READ_PERMISSION_MASK, IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);xen/drivers/passthrough/amd/iommu_map.c static bool_t set_iommu_pde_present(u32 · line 87
Quoted 2 lines
xen/drivers/passthrough/amd/iommu_map.c +2
-0+ +/* IOMMUv2 needs FC bit enabled */ This comment suggests that the patches prior to that aren't consistent. Is this really a proper standalone patch, or is the word "needs" too strict, or should it really be moved ahead in the series?
Quoted 8 lines
Quoted 4 lines
xen/drivers/passthrough/amd/iommu_map.c +3
-0+if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) + set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, + IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT,&entry);
This is being done no matter whether it actually is a v2 IOMMU that you deal with here - if that's correct, the comment above should be adjusted accordingly.
This bit forces pci-defined no snoop bit to be cleared. This helps to solve potential issues in ATS devices with early drivers. I did not see any breaks
Quoted 7 lines
Quoted 4 lines
on legacy devices and iommuv1 with FC = 1. But if you like I could make this
only for v2 or change the comment a bit.
Whatever is the most appropriate thing to do here (you definitely know better than I do)
I intend to keep fc =1 for both v1 and v2. This setup also aligns with Linux iommu driver. I will change the comment.
Thanks,
wei
Quoted 1 line
Jan
PATCH 1/1 amd iommu: Add a new flag to indication iommuv2 feature enabled or not
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569405 -3600
# Node ID b70cf1dcb110f79546f3efac3201a08d70c8b96e
# Parent 30b1f434160d989be5e0bb6c6956bb7e3985db59
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.
xen/drivers/passthrough/amd/iommu_guest.c +13 -7
@@ -48,6 +48,8 @@ (reg)->hi = (val >>32 ) &0xFFFFFFFF ; \ }while (0 ) +extern bool_t iommuv2_enabled; +static unsigned int machine_bdf (struct domain *d,uint16_t guest_bdf) {struct pci_dev *pdev;
@@ -819,6 +821,9 @@ int guest_iommu_set_base(struct domain *p2m_type_t t;struct guest_iommu *iommu =domain_iommu (d); +if ( !is_hvm_domain (d) || !iommuv2_enabled ) +return 1 ; + iommu->mmio_base = base; base >>=PAGE_SHIFT ;
@@ -878,7 +883,7 @@ int guest_iommu_init(struct domain* d)struct guest_iommu *iommu;struct hvm_iommu *hd =domain_hvm_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return 0 ; iommu = xzalloc(struct guest_iommu);
@@ -902,13 +907,11 @@ int guest_iommu_init(struct domain* d)void guest_iommu_destroy (struct domain *d) { -struct guest_iommu *iommu; +struct guest_iommu *iommu =domain_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return ; - iommu =domain_iommu (d); -tasklet_kill (&iommu->cmd_buffer_tasklet);xfree (iommu);
@@ -919,6 +922,9 @@ static int guest_iommu_mmio_range(struct {struct guest_iommu *iommu =vcpu_iommu (v); +if ( !iommu_found () || !iommuv2_enabled ) +return 0 ; +return ( addr >= iommu->mmio_base && addr < (iommu->mmio_base +IOMMU_MMIO_SIZE ) ); }
@@ -935,7 +941,7 @@ int iommu_bind_bdf(struct domain* d, uinstruct pci_dev *pdev;int ret = -ENODEV ; -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return 0 ;spin_lock (&pcidevs_lock);
@@ -960,7 +966,7 @@ void iommu_set_msi(struct domain* d, uin {struct guest_iommu *iommu =domain_iommu (d); -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return ; iommu->msi.vector = vector;
xen/drivers/passthrough/amd/iommu_init.c +5 -0
@@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;static struct radix_tree_root ivrs_maps;struct list_head amd_iommu_head;struct table_struct device_table; +bool_t iommuv2_enabled;static int iommu_has_ht_flag (struct amd_iommu *iommu,u8 mask) {
@@ -759,6 +760,10 @@ static void enable_iommu(struct amd_iommamd_iommu_flush_all_caches (iommu); iommu->enabled =1 ; + +if ( iommu->features ) + iommuv2_enabled =1 ; +spin_unlock_irqrestore (&iommu->lock, flags); }
Re: [PATCH 11 of 16] amd iommu: Add a new flag to indication iommuv2 feature enabled or not
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569405 -3600
# Node IDb70cf1dcb110f79546f3efac3201a08d70c8b96e
# Parent30b1f434160d989be5e0bb6c6956bb7e3985db59
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.
Shouldn't this be done right away when those functions/hypercalls get introduced?
xen/drivers/passthrough/amd/iommu_guest.c line 51
Quoted 11 lines
Signed-off-by Wei Wang <[email protected]>diff -r
30b1f434160d-rb70cf1dcb110xen/drivers/passthrough/amd/iommu_guest.cxen/drivers/passthrough/amd/iommu_guest.c +2
-0+0100 @@ -48,6 +48,8 @@ (reg)->hi = (val >>32 ) &0xFFFFFFFF ; \ }while (0 ) +extern bool_t iommuv2_enabled;
No new extern declarations in .c files, please.
Jan
Quoted 89 lines
xen/drivers/passthrough/amd/iommu_guest.c +12
-7+static unsigned int machine_bdf (struct domain *d,uint16_t guest_bdf) {struct pci_dev *pdev;@@ -819,6 +821,9 @@ int guest_iommu_set_base(struct domain *p2m_type_t t;struct guest_iommu *iommu =domain_iommu (d); +if ( !is_hvm_domain (d) || !iommuv2_enabled ) +return 1 ; + iommu->mmio_base = base; base >>=PAGE_SHIFT ;@@ -878,7 +883,7 @@ int guest_iommu_init(struct domain* d)struct guest_iommu *iommu;struct hvm_iommu *hd =domain_hvm_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return 0 ; iommu = xzalloc(struct guest_iommu);@@ -902,13 +907,11 @@ int guest_iommu_init(struct domain* d)void guest_iommu_destroy (struct domain *d) { -struct guest_iommu *iommu; +struct guest_iommu *iommu =domain_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return ; - iommu =domain_iommu (d); -tasklet_kill (&iommu->cmd_buffer_tasklet);xfree (iommu);@@ -919,6 +922,9 @@ static int guest_iommu_mmio_range(struct {struct guest_iommu *iommu =vcpu_iommu (v); +if ( !iommu_found () || !iommuv2_enabled ) +return 0 ; +return ( addr >= iommu->mmio_base && addr < (iommu->mmio_base +IOMMU_MMIO_SIZE ) ); }@@ -935,7 +941,7 @@ int iommu_bind_bdf(struct domain* d, uinstruct pci_dev *pdev;int ret = -ENODEV ; -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return 0 ;spin_lock (&pcidevs_lock);@@ -960,7 +966,7 @@ void iommu_set_msi(struct domain* d, uin {struct guest_iommu *iommu =domain_iommu (d); -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return ; iommu->msi.vector = vector;diff -r
30b1f434160d-rb70cf1dcb110xen/drivers/passthrough/amd/iommu_init.cxen/drivers/passthrough/amd/iommu_init.c +5
-0@@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;static struct radix_tree_root ivrs_maps;struct list_head amd_iommu_head;struct table_struct device_table; +bool_t iommuv2_enabled;static int iommu_has_ht_flag (struct amd_iommu *iommu,u8 mask) {@@ -759,6 +760,10 @@ static void enable_iommu(struct amd_iommamd_iommu_flush_all_caches (iommu); iommu->enabled =1 ; + +if ( iommu->features ) + iommuv2_enabled =1 ; +spin_unlock_irqrestore (&iommu->lock, flags); }
PATCH 1/1 hvmloader: Build IVRS table
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569408 -3600
# Node ID bb76ba2457e629d668c08e57f2168b13bdfb7930 # Parent b70cf1dcb110f79546f3efac3201a08d70c8b96e
hvmloader: Build IVRS table.
tools/firmware/hvmloader/acpi/acpi2_0.h +54 -0
@@ -389,6 +389,60 @@ struct acpi_20_madt_intsrcovr {#define ACPI_2_0_WAET_REVISION 0x01#define ACPI_1_0_FADT_REVISION 0x01 +#define IVRS_SIGNATURE ASCII32('I','V','R','S') +#define IVRS_REVISION 1 +#define IVRS_VASIZE 64 +#define IVRS_PASIZE 52 +#define IVRS_GVASIZE 64 + +#define IVHD_BLOCK_TYPE 0x10 +#define IVHD_FLAG_HTTUNEN (1 << 0) +#define IVHD_FLAG_PASSPW (1 << 1) +#define IVHD_FLAG_RESPASSPW (1 << 2) +#define IVHD_FLAG_ISOC (1 << 3) +#define IVHD_FLAG_IOTLBSUP (1 << 4) +#define IVHD_FLAG_COHERENT (1 << 5) +#define IVHD_FLAG_PREFSUP (1 << 6) +#define IVHD_FLAG_PPRSUP (1 << 7) + +#define IVHD_EFR_GTSUP (1 << 2) +#define IVHD_EFR_IASUP (1 << 5) + +#define IVHD_SELECT_4_BYTE 0x2 + +struct ivrs_ivhd_block +{ +uint8_t type; +uint8_t flags; +uint16_t length; +uint16_t devid; +uint16_t cap_offset; +uint64_t iommu_base_addr; +uint16_t pci_segment; +uint16_t iommu_info; +uint32_t reserved; +}; + +/* IVHD 4-byte device entries */ +struct ivrs_ivhd_device +{ +uint8_t type; +uint16_t dev_id; +uint8_t flags; +}; + +#define PT_DEV_MAX_NR 32 +#define IOMMU_CAP_OFFSET 0x40 +struct acpi_40_ivrs +{ +struct acpi_header header; +uint32_t iv_info; +uint32_t reserved[2 ]; +struct ivrs_ivhd_block ivhd_block; +struct ivrs_ivhd_device ivhd_device[PT_DEV_MAX_NR ]; +}; + +#pragma pack ()struct acpi_config {
tools/firmware/hvmloader/acpi/build.c +81 -0
105 lines not on this page · raw message
tools/firmware/hvmloader/pci.c +29 -1
@@ -34,11 +34,17 @@ unsigned long pci_mem_end = PCI_MEM_END;enum virtual_vga virtual_vga = VGA_none;unsigned long igd_opregion_pgbase =0 ; +/* support up to 32 passthrough devices */ +#define PT_DEV_MAX_NR 32 +uint32_t ptdev_bdf[PT_DEV_MAX_NR ]; +uint32_t ptdev_nr; +uint32_t iommu_bdf; +void pci_setup (void ) {uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd, mmio_total =0 ;uint32_t vga_devfn =256 ; -uint16_t class, vendor_id, device_id; +uint16_t class, vendor_id, device_id, sub_vendor_id;unsigned int bar, pin, link, isa_irq;/* Resources assignable to PCI devices via BARs. */
@@ -72,12 +78,34 @@ void pci_setup(void) class =pci_readw (devfn,PCI_CLASS_DEVICE ); vendor_id =pci_readw (devfn,PCI_VENDOR_ID ); device_id =pci_readw (devfn,PCI_DEVICE_ID ); + sub_vendor_id =pci_readw (devfn,PCI_SUBSYSTEM_VENDOR_ID ); +if ( (vendor_id ==0xffff ) && (device_id ==0xffff ) )continue ;ASSERT ((devfn !=PCI_ISA_DEVFN ) || ((vendor_id ==0x8086 ) && (device_id ==0x7000 ))); +/* Found amd iommu device. */ +if ( class ==0x0806 && vendor_id ==0x1022 ) + { + iommu_bdf = devfn; +continue ; + } +/* IVRS: Detecting passthrough devices. +* sub_vendor_id != citrix && sub_vendor_id != qemu */ +if ( sub_vendor_id !=0x5853 && sub_vendor_id !=0x1af4 ) + { +/* found amd iommu device */ +if ( ptdev_nr <PT_DEV_MAX_NR ) + { + ptdev_bdf[ptdev_nr] = devfn; + ptdev_nr ++; + } +else +printf ("Number of passthru devices > PT_DEV_MAX_NR \n" ); + } +switch ( class ) {case 0x0300 :
xen/include/public/hvm/hvm_info_table.h +3 -0
@@ -67,6 +67,9 @@ struct hvm_info_table {/* Bitmap of which CPUs are online at boot time. */ uint8_t vcpu_online[(HVM_MAX_VCPUS +7 )/8 ]; + +/* guest iommu enabled */ + uint8_t iommu_enabled; };#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */
Re: [PATCH 12 of 16] hvmloader: Build IVRS table
Quoted 7 lines · Wei Wang
diff -r
b70cf1dcb110-rbb76ba2457e6xen/include/public/hvm/hvm_info_table.h
---a/xen/include/public/hvm/hvm_info_table.hThu Dec 22 16:56:45
2011 +0100
+++b/xen/include/public/hvm/hvm_info_table.hThu Dec 22 16:56:48
2011 +0100
xen/include/public/hvm/hvm_info_table.h struct hvm_info_table { · line 75
Quoted 9 lines
xen/include/public/hvm/hvm_info_table.h +3
-0@@ -67,6 +67,9 @@ struct hvm_info_table {/* Bitmap of which CPUs are online at boot time. */ uint8_t vcpu_online[(HVM_MAX_VCPUS +7 )/8 ]; + +/* guest iommu enabled */ + uint8_t iommu_enabled; };#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */
Please can we avoid adding new things to this struct and use xenstore to pass new configuration items instead. See Paul Durrant's recent patches to make s3 optional via the platform/acpi_s3 node.
Ian.
Re: [PATCH 12 of 16] hvmloader: Build IVRS table
Quoted 16 lines · On Friday 23 December 2011 12:36:32 Ian Campbell wrote:
Quoted 15 lines · Wei Wang
diff -r
b70cf1dcb110-rbb76ba2457e6xen/include/public/hvm/hvm_info_table.h
---a/xen/include/public/hvm/hvm_info_table.hThu Dec 22 16:56:45
2011 +0100
+++b/xen/include/public/hvm/hvm_info_table.hThu Dec 22 16:56:48
2011 +0100xen/include/public/hvm/hvm_info_table.h +3
-0@@ -67,6 +67,9 @@ struct hvm_info_table {/* Bitmap of which CPUs are online at boot time. */ uint8_t vcpu_online[(HVM_MAX_VCPUS +7 )/8 ]; + +/* guest iommu enabled */ +uint8_t iommu_enabled; };
Quoted 6 lines
xen/include/public/hvm/hvm_info_table.h struct hvm_info_table { · line 75
Quoted 1 line
xen/include/public/hvm/hvm_info_table.h +0
-0#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */ Please can we avoid adding new things to this struct and use xenstore to pass new configuration items instead. See Paul Durrant's recent patches to make s3 optional via the platform/acpi_s3 node.
Ian.
Good point, Will use xenstore_read in next try.
Thanks,
Wei
PATCH 1/1 libxc: add wrappers for new hypercalls
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569412 -3600
# Node ID 00bdad5dfb7f5efd0b1cc54622b3ccb1b1b1b16f # Parent bb76ba2457e629d668c08e57f2168b13bdfb7930
libxc: add wrappers for new hypercalls
tools/libxc/xc_domain.c +49 -0
@@ -1352,6 +1352,55 @@ int xc_domain_bind_pt_isa_irq( PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq)); } +int xc_domain_update_iommu_msi ( +xc_interface *xch, +uint32_t domid, +uint8_t vector, +uint8_t dest, +uint8_t dest_mode, +uint8_t delivery_mode, +uint8_t trig_mode) +{ +int rc; +DECLARE_DOMCTL ; +xen_domctl_guest_iommu_op_t * iommu_op; + + domctl.cmd = XEN_DOMCTL_guest_iommu_op; + domctl.domain = (domid_t )domid; + + iommu_op = &(domctl.u.guest_iommu_op); + iommu_op->op =XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI ; + iommu_op->u.msi.vector = vector; + iommu_op->u.msi.dest = dest; + iommu_op->u.msi.dest_mode = dest_mode; + iommu_op->u.msi.delivery_mode = delivery_mode; + iommu_op->u.msi.trig_mode = trig_mode; + + rc =do_domctl (xch, &domctl); +return rc; +} + +int xc_domain_bind_pt_bdf (xc_interface *xch, +uint32_t domid, +uint32_t gbdf, +uint32_t mbdf) +{ +int rc; +DECLARE_DOMCTL ; +xen_domctl_guest_iommu_op_t * guest_op; + + domctl.cmd = XEN_DOMCTL_guest_iommu_op; + domctl.domain = (domid_t )domid; + + guest_op = &(domctl.u.guest_iommu_op); + guest_op->op =XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF ; + guest_op->u.bdf_bind.g_bdf = gbdf; + guest_op->u.bdf_bind.m_bdf = mbdf; + + rc =do_domctl (xch, &domctl); +return rc; +} + int xc_domain_memory_mapping( xc_interface *xch, uint32_t domid,
tools/libxc/xenctrl.h +13 -0
@@ -1697,6 +1697,19 @@ int xc_domain_bind_pt_isa_irq(xc_interfauint32_t domid, uint8_t machine_irq); +int xc_domain_bind_pt_bdf (xc_interface *xch, +uint32_t domid, +uint32_t gbdf, +uint32_t mbdf); + +int xc_domain_update_iommu_msi (xc_interface *xch, +uint32_t domid, +uint8_t vector, +uint8_t dest, +uint8_t dest_mode, +uint8_t delivery_mode, +uint8_t trig_mode); +int xc_domain_set_machine_address_size (xc_interface *xch,uint32_t domid,unsigned int width);
PATCH 1/1 libxl: bind virtual bdf to physical bdf after device assignment
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569415 -3600
# Node ID 7ac92c11a11a4dbdf85ef503445128be861cb400
# Parent 00bdad5dfb7f5efd0b1cc54622b3ccb1b1b1b16f
libxl: bind virtual bdf to physical bdf after device assignment
tools/libxl/libxl_pci.c +7 -0
@@ -735,6 +735,13 @@ out:LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_assign_device failed" );return ERROR_FAIL ; } +if (LIBXL__DOMAIN_IS_TYPE (gc, domid,HVM )) { + rc =xc_domain_bind_pt_bdf (ctx->xch, domid, pcidev->vdevfn,pcidev_encode_bdf (pcidev)); +if ( rc ) { +LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_domain_bind_pt_bdf failed" ); +return ERROR_FAIL ; + } + } }if (!starting)
Re: [PATCH 14 of 16] libxl: bind virtual bdf to physical bdf after device assignment
Quoted 13 lines · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569415 -3600
# Node ID7ac92c11a11a4dbdf85ef503445128be861cb400
# Parent00bdad5dfb7f5efd0b1cc54622b3ccb1b1b1b16f
libxl: bind virtual bdf to physical bdf after device assignmentSigned-off-by Wei Wang <[email protected]>diff -r
00bdad5dfb7f-r7ac92c11a11atools/libxl/libxl_pci.c
tools/libxl/libxl_pci.c out: · line 744
Quoted 10 lines
tools/libxl/libxl_pci.c +7
-0@@ -735,6 +735,13 @@ out:LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_assign_device failed" );return ERROR_FAIL ; } +if (LIBXL__DOMAIN_IS_TYPE (gc, domid,HVM )) { + rc =xc_domain_bind_pt_bdf (ctx->xch, domid, pcidev->vdevfn,pcidev_encode_bdf (pcidev)); +if ( rc ) { +LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_domain_bind_pt_bdf failed" ); +return ERROR_FAIL ; + } + }
Indentation is wrong here, or you've used hard tabs where you need 4 spaces.
Ian.
Re: [PATCH 14 of 16] libxl: bind virtual bdf to physical bdf after device assignment
Quoted 19 lines · On Friday 23 December 2011 12:37:17 Ian Campbell wrote:
Quoted 18 lines · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569415 -3600
# Node ID7ac92c11a11a4dbdf85ef503445128be861cb400
# Parent00bdad5dfb7f5efd0b1cc54622b3ccb1b1b1b16f
libxl: bind virtual bdf to physical bdf after device assignmentSigned-off-by Wei Wang <[email protected]>diff -r
00bdad5dfb7f-r7ac92c11a11atools/libxl/libxl_pci.ctools/libxl/libxl_pci.c +2
-0@@ -735,6 +735,13 @@ out:LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_assign_device failed" );return ERROR_FAIL ; } +if (LIBXL__DOMAIN_IS_TYPE (gc, domid,HVM )) { + rc = xc_domain_bind_pt_bdf(ctx->xch, domid, pcidev->vdevfn,
Quoted 8 lines
tools/libxl/libxl_pci.c out: · line 744
Quoted 5 lines
tools/libxl/libxl_pci.c +3
-0pcidev_encode_bdf(pcidev)); + if ( rc ) { +LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc, "xc_domain_bind_pt_bdf failed"); + return ERROR_FAIL; + } + }Indentation is wrong here, or you've used hard tabs where you need 4 spaces.
Yes, indeed. I will fix it.
Thanks,
Wei
Quoted 1 line
Ian.
Re: [PATCH 14 of 16] libxl: bind virtual bdf to physical bdf after device assignment
In reply to Wei WangWei Wang writes ("[PATCH 14 of 16] libxl: bind virtual bdf to physical bdf after device assignment"):
Quoted 1 line
+ rc =
xc_domain_bind_pt_bdf(ctx->xch, domid, pcidev->vdevfn, pcidev_encode_bdf(pcidev));
This and many of your other patches to libxl need rewrapping to fit within 75-80 columns, correct indentation, and correct the coding style to fit with the rest of the code.
Ian.
PATCH 1/1 libxl: Introduce a new guest config file parameter
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569419 -3600
# Node ID 8ea73cd1a367b318f72026a02629c774d24f999f # Parent 7ac92c11a11a4dbdf85ef503445128be861cb400
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
tools/libxl/libxl_create.c +1 -0
@@ -99,6 +99,7 @@ int libxl_init_build_info(libxl_ctx *ctx b_info->u.hvm.vpt_align =1 ; b_info->u.hvm.timer_mode =1 ; b_info->u.hvm.nested_hvm =0 ; + b_info->u.hvm.iommu =0 ;break ;case LIBXL_DOMAIN_TYPE_PV : b_info->u.pv.slack_memkb =8 *1024 ;
tools/libxl/libxl_dom.c +4 -0
@@ -266,6 +266,10 @@ static int hvm_build_set_params(xc_inter va_hvm = (struct hvm_info_table *)(va_map +HVM_INFO_OFFSET ); va_hvm->apic_mode = info->u.hvm.apic; va_hvm->nr_vcpus = info->max_vcpus; + +if ( info->u.hvm.iommu ) + va_hvm->iommu_enabled =1 ; +memcpy (va_hvm->vcpu_online, &info->cur_vcpus,sizeof (info->cur_vcpus));for (i =0 , sum =0 ; i < va_hvm->length; i++) sum += ((uint8_t *) va_hvm)[i];
tools/libxl/libxl_types.idl +1 -0
@@ -184,6 +184,7 @@ libxl_domain_build_info = Struct("domain ("vpt_align", bool), ("timer_mode", integer), ("nested_hvm", bool), + ("iommu", bool), ])), ("pv", Struct(None, [("kernel", libxl_file_reference), ("slack_memkb", uint32),
tools/libxl/xl_cmdimpl.c +3 -0
@@ -360,6 +360,7 @@ static void printf_info(int domid,printf ("\t\t\t(vpt_align %d)\n" , b_info->u.hvm.vpt_align);printf ("\t\t\t(timer_mode %d)\n" , b_info->u.hvm.timer_mode);printf ("\t\t\t(nestedhvm %d)\n" , b_info->u.hvm.nested_hvm); +printf ("\t\t\t(iommu %d)\n" , b_info->u.hvm.iommu);printf ("\t\t\t(device_model %s)\n" , dm_info->device_model ? :"default" );printf ("\t\t\t(videoram %d)\n" , dm_info->videoram);
@@ -764,6 +765,8 @@ static void parse_config_data(const char b_info->u.hvm.timer_mode = l;if (!xlu_cfg_get_long (config,"nestedhvm" , &l,0 )) b_info->u.hvm.nested_hvm = l; +if (!xlu_cfg_get_long (config,"iommu" , &l,0 )) + b_info->u.hvm.iommu = l;break ;case LIBXL_DOMAIN_TYPE_PV : {
Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter
Wei Wang writes ("[PATCH 15 of 16] libxl: Introduce a new guest config file parameter"):
Quoted 3 lines
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
I'm not sure I like this name. It's confusing because it's not at first glance clear whether it refers to the host's putative iommu, or some kind of provision to the guest.
And it needs documentation, which I hope will answer my other question which is "what is this good for?" :-).
Ian.
Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter [and 1 more messages]
Wei Wang writes ("[PATCH 14 of 14 V3] libxl: Introduce a new guest config file parameter"):
Quoted 8 lines
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213623 -3600
# Node ID39eb093ea89eeaa4dbff29439499f2a289291ff0# Parent9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
Ian Jackson writes ("Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter"):
Quoted 11 lines
Wei Wang writes ("[PATCH 15 of 16] libxl: Introduce a new guest config file parameter"):
Quoted 3 lines
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
I'm not sure I like this name. It's confusing because it's not at first glance clear whether it refers to the host's putative iommu, or some kind of provision to the guest.
And it needs documentation, which I hope will answer my other question which is "what is this good for?" :-).
Ian.
Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter [and 1 more messages]
Quoted 1 line · On Tuesday 10 January 2012 18:12:05 Ian Jackson wrote:
Wei Wang writes ("[PATCH 14 of 14 V3] libxl: Introduce a new guest config
file parameter"):
Quoted 10 lines
Quoted 8 lines
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213623 -3600
# Node ID39eb093ea89eeaa4dbff29439499f2a289291ff0# Parent9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.Ian Jackson writes ("Re: [PATCH 15 of 16] libxl: Introduce a new guest
config file parameter"):
Quoted 1 line
Quoted 1 line
Wei Wang writes ("[PATCH 15 of 16] libxl: Introduce a new guest config
file parameter"):
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
I'm not sure I like this name. It's confusing because it's not at first glance clear whether it refers to the host's putative iommu, or some kind of provision to the guest.
How about guest_iommu = {1, 0} or ats_passthru = {1, 0}? Actually the idea of the whole patch queue is to enable passthru for sophisticated ats devices (e.g. Tahiti the latest AMD gfx/gpgpu), so that we utilize the device to do general-purpose computations in guest.
Quoted 2 lines
Quoted 2 lines
And it needs documentation, which I hope will answer my other question which is "what is this good for?" :-).
Sure, I am working on the docs now. It will be sent together with the next try after I had collected enough comments of this version.
Thanks,
Wei
Quoted 1 line
Ian.
Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter [and 1 more messages]
Wei Wang2 writes ("Re: [PATCH 15 of 16] libxl: Introduce a new guest config file parameter [and 1 more messages]"):
Quoted 1 line
How about
guest_iommu= {1, 0} orats_passthru= {1, 0}?
I think "guest_iommu" is more likely to be something people have heard of. Personally I'm afraid I have no idea what (an) "ATS" is ...
Quoted 4 lines
Actually the idea of> the whole patch queue is to enable passthru
for sophisticated ats devices (e.g. Tahiti the latest AMD gfx/gpgpu), so that we utilize the device to do general-purpose computations in guest.
Right.
Ian.
PATCH 1/1 libxl: pass iommu parameter to qemu-dm
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1324569422 -3600
# Node ID 1aad019305172c4abca8c2c9d7e632fe3291fead # Parent 8ea73cd1a367b318f72026a02629c774d24f999f
libxl: pass iommu parameter to qemu-dm.
When iomm = 0, virtual iommu device will be disabled.
tools/libxl/libxl_create.c +1 -1
@@ -559,7 +559,7 @@ static int do_domain_create(libxl__gc *glibxl_device_vkb_dispose (&vkb); dm_info->domid = domid; - ret =libxl__create_device_model (gc, dm_info, + ret =libxl__create_device_model (gc, dm_info, &d_config->b_info, d_config->disks, d_config->num_disks, d_config->vifs, d_config->num_vifs, &dm_starting);
tools/libxl/libxl_dm.c +15 -5
@@ -84,6 +84,7 @@ static const char *libxl__domain_bios(listatic char **libxl__build_device_model_args_old (libxl__gc *gc,const char *dm,libxl_device_model_info *info, +libxl_domain_build_info *b_info,libxl_device_disk *disks,int num_disks,libxl_device_nic *vifs,int num_vifs) {
@@ -199,6 +200,9 @@ static char ** libxl__build_device_modelif (info->gfx_passthru) {flexarray_append (dm_args,"-gfx_passthru" ); } +if (b_info && b_info->u.hvm.iommu) { +flexarray_append (dm_args,"-iommu" ); + } }if (info->saved_state) {flexarray_vappend (dm_args,"-loadvm" , info->saved_state,NULL );
@@ -237,6 +241,7 @@ static const char *qemu_disk_format_stristatic char **libxl__build_device_model_args_new (libxl__gc *gc,const char *dm,libxl_device_model_info *info, +libxl_domain_build_info *b_info,libxl_device_disk *disks,int num_disks,libxl_device_nic *vifs,int num_vifs) {
@@ -409,6 +414,9 @@ static char ** libxl__build_device_modelif (info->gfx_passthru) {flexarray_append (dm_args,"-gfx_passthru" ); } +if (b_info && b_info->u.hvm.iommu) { +flexarray_append (dm_args,"-iommu" ); + } }if (info->saved_state) {/* This file descriptor is meant to be used by QEMU */
@@ -500,6 +508,7 @@ static char ** libxl__build_device_modelstatic char **libxl__build_device_model_args (libxl__gc *gc,const char *dm,libxl_device_model_info *info, +libxl_domain_build_info *b_info,libxl_device_disk *disks,int num_disks,libxl_device_nic *vifs,int num_vifs) {
@@ -507,11 +516,11 @@ static char ** libxl__build_device_modelswitch (info->device_model_version) {case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL : -return libxl__build_device_model_args_old (gc, dm, info, +return libxl__build_device_model_args_old (gc, dm, info, b_info, disks, num_disks, vifs, num_vifs);case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN : -return libxl__build_device_model_args_new (gc, dm, info, +return libxl__build_device_model_args_new (gc, dm, info, b_info, disks, num_disks, vifs, num_vifs);default :
@@ -619,7 +628,7 @@ static int libxl__create_stubdom(libxl__ goto out; } - args =libxl__build_device_model_args (gc,"stubdom-dm" , info, + args =libxl__build_device_model_args (gc,"stubdom-dm" , info,NULL , disks, num_disks, vifs, num_vifs);if (!args) {
@@ -782,6 +791,7 @@ out:int libxl__create_device_model (libxl__gc *gc,libxl_device_model_info *info, +libxl_domain_build_info *b_info,libxl_device_disk *disks,int num_disks,libxl_device_nic *vifs,int num_vifs,libxl__spawner_starting **starting_r)
@@ -820,7 +830,7 @@ int libxl__create_device_model(libxl__gc rc =ERROR_FAIL ; goto out; } - args =libxl__build_device_model_args (gc, dm, info, disks, num_disks, + args =libxl__build_device_model_args (gc, dm, info, b_info, disks, num_disks, vifs, num_vifs);if (!args) { rc =ERROR_FAIL ;
@@ -1046,7 +1056,7 @@ int libxl__create_xenpv_qemu(libxl__gc * libxl__spawner_starting **starting_r) {libxl__build_xenpv_qemu_args (gc, domid, vfb, info); -libxl__create_device_model (gc, info,NULL ,0 ,NULL ,0 , starting_r); +libxl__create_device_model (gc, info,NULL ,NULL ,0 ,NULL ,0 , starting_r);return 0 ; }
tools/libxl/libxl_internal.h +1 -0
@@ -466,6 +466,7 @@ _hidden const char *libxl__domain_device libxl_device_model_info *info); _hidden int libxl__create_device_model(libxl__gc *gc,libxl_device_model_info *info, +libxl_domain_build_info *b_info,libxl_device_disk *disk,int num_disks,libxl_device_nic *vifs,int num_vifs,libxl__spawner_starting **starting_r);
PATCH v3 1/1 amd iommu: support ATS device passthru on IOMMUv2 systems
Hi all, this is patch v3.
ATS devices with PRI and PASID capabilities can communicate with iommuv2 to perform two level (nested) address translation and demand paging for DMA. To passthru such devices, iommu driver has to been enabled in guest OS. This patch set adds initial iommu emulation for hvm guests to support ATS device passthru.
changes in v3:
* Use xenstore to receive guest iommu configuration instead of adding in a new field in hvm_info_table.
* Support pci segment in vbdf to mbdf bind.
* Make hypercalls visible for non-x86 platforms.
* A few code cleanups according to comments from Jan and Ian.
Changes in v2:
* Do not use linked list to access guest iommu tables.
* Do not parse iommu parameter in libxl_device_model_info again.
* Fix incorrect logical calculation in patch 11.
* Fix hypercall definition for non-x86 systems.
Thanks,
Wei
PATCH v3 1/1 amd iommu: Refactoring iommu ring buffer definition
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213576 -3600
# Node ID 9c9ddf2dd700119fdaf8a420fb051c22279853cc
# Parent 5b2676ac13218951698c49fa0350f2ac48220f3d
amd iommu: Refactoring iommu ring buffer definition.
Introduce struct ring_buffer to represent iommu cmd buffer, event log and ppr log
xen/drivers/passthrough/amd/iommu_cmd.c +4 -4
@@ -29,7 +29,7 @@ static int queue_iommu_command(struct amu32 tail, head, *cmd_buffer;int i; - tail = iommu->cmd_buffer_tail; + tail = iommu->cmd_buffer.tail;if ( ++tail == iommu->cmd_buffer.entries ) tail =0 ;
@@ -40,13 +40,13 @@ static int queue_iommu_command(struct amif ( head != tail ) { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer + - (iommu->cmd_buffer_tail * + (iommu->cmd_buffer.tail *IOMMU_CMD_BUFFER_ENTRY_SIZE ));for ( i =0 ; i <IOMMU_CMD_BUFFER_U32_PER_ENTRY ; i++ ) cmd_buffer[i] = cmd[i]; - iommu->cmd_buffer_tail = tail; + iommu->cmd_buffer.tail = tail;return 1 ; }
@@ -57,7 +57,7 @@ static void commit_iommu_command_buffer( {u32 tail; -set_field_in_reg_u32 (iommu->cmd_buffer_tail,0 , +set_field_in_reg_u32 (iommu->cmd_buffer.tail,0 ,IOMMU_CMD_BUFFER_TAIL_MASK ,IOMMU_CMD_BUFFER_TAIL_SHIFT , &tail);writel (tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET );
xen/drivers/passthrough/amd/iommu_init.c +69 -56
190 lines not on this page · raw message
xen/include/asm-x86/amd-iommu.h +32 -4
@@ -30,12 +30,42 @@extern struct list_head amd_iommu_head; +#pragma pack(1) +typedef struct event_entry +{ +uint32_t data[4 ]; +}event_entry_t ; + +typedef struct ppr_entry +{ +uint32_t data[4 ]; +}ppr_entry_t ; + +typedef struct cmd_entry +{ +uint32_t data[4 ]; +}cmd_entry_t ; + +typedef struct dev_entry +{ +uint32_t data[8 ]; +}dev_entry_t ; +#pragma pack() +struct table_struct {void *buffer;unsigned long entries;unsigned long alloc_size; }; +struct ring_buffer { +void *buffer; +unsigned long entries; +unsigned long alloc_size; +uint32_t tail; +uint32_t head; +}; + typedef struct iommu_cap { uint32_t header; /* offset 00h */ uint32_t base_low; /* offset 04h */
@@ -60,10 +90,8 @@ struct amd_iommu {unsigned long mmio_base_phys;struct table_struct dev_table; -struct table_struct cmd_buffer; -u32 cmd_buffer_tail; -struct table_struct event_log; -u32 event_log_head; +struct ring_buffer cmd_buffer; +struct ring_buffer event_log;int exclusion_enable;int exclusion_allow_all;
PATCH v3 1/1 amd iommu: Introduces new helper functions to simplify bitwise operations
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213581 -3600
# Node ID dfdc0df7d68fa4551271b29671a2d333b185a48c
# Parent 9c9ddf2dd700119fdaf8a420fb051c22279853cc
amd iommu: Introduces new helper functions to simplify bitwise operations
xen/drivers/passthrough/amd/iommu_cmd.c +4 -8
@@ -33,10 +33,8 @@ static int queue_iommu_command(struct amif ( ++tail == iommu->cmd_buffer.entries ) tail =0 ; - head =get_field_from_reg_u32 (readl (iommu->mmio_base + -IOMMU_CMD_BUFFER_HEAD_OFFSET ), -IOMMU_CMD_BUFFER_HEAD_MASK , -IOMMU_CMD_BUFFER_HEAD_SHIFT ); + head =iommu_get_rb_pointer (readl (iommu->mmio_base + +IOMMU_CMD_BUFFER_HEAD_OFFSET ));if ( head != tail ) { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer +
@@ -55,11 +53,9 @@ static int queue_iommu_command(struct amstatic void commit_iommu_command_buffer (struct amd_iommu *iommu) { -u32 tail; +u32 tail =0 ; -set_field_in_reg_u32 (iommu->cmd_buffer.tail,0 , -IOMMU_CMD_BUFFER_TAIL_MASK , -IOMMU_CMD_BUFFER_TAIL_SHIFT , &tail); +iommu_set_rb_pointer (&tail, iommu->cmd_buffer.tail);writel (tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET ); }
xen/drivers/passthrough/amd/iommu_init.c +23 -27
109 lines not on this page · raw message
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +16 -17
@@ -82,10 +82,6 @@/* Device Table */ #define IOMMU_DEV_TABLE_BASE_LOW_OFFSET 0x00#define IOMMU_DEV_TABLE_BASE_HIGH_OFFSET 0x04 -#define IOMMU_DEV_TABLE_BASE_LOW_MASK 0xFFFFF000 -#define IOMMU_DEV_TABLE_BASE_LOW_SHIFT 12 -#define IOMMU_DEV_TABLE_BASE_HIGH_MASK 0x000FFFFF -#define IOMMU_DEV_TABLE_BASE_HIGH_SHIFT 0#define IOMMU_DEV_TABLE_SIZE_MASK 0x000001FF#define IOMMU_DEV_TABLE_SIZE_SHIFT 0
@@ -164,22 +160,13 @@#define IOMMU_DEV_TABLE_INT_CONTROL_MASK 0x30000000#define IOMMU_DEV_TABLE_INT_CONTROL_SHIFT 28 -/* Command Buffer */ #define IOMMU_CMD_BUFFER_BASE_LOW_OFFSET 0x08#define IOMMU_CMD_BUFFER_BASE_HIGH_OFFSET 0x0C#define IOMMU_CMD_BUFFER_HEAD_OFFSET 0x2000#define IOMMU_CMD_BUFFER_TAIL_OFFSET 0x2008 -#define IOMMU_CMD_BUFFER_BASE_LOW_MASK 0xFFFFF000 -#define IOMMU_CMD_BUFFER_BASE_LOW_SHIFT 12 -#define IOMMU_CMD_BUFFER_BASE_HIGH_MASK 0x000FFFFF -#define IOMMU_CMD_BUFFER_BASE_HIGH_SHIFT 0#define IOMMU_CMD_BUFFER_LENGTH_MASK 0x0F000000#define IOMMU_CMD_BUFFER_LENGTH_SHIFT 24 -#define IOMMU_CMD_BUFFER_HEAD_MASK 0x0007FFF0 -#define IOMMU_CMD_BUFFER_HEAD_SHIFT 4 -#define IOMMU_CMD_BUFFER_TAIL_MASK 0x0007FFF0 -#define IOMMU_CMD_BUFFER_TAIL_SHIFT 4#define IOMMU_CMD_BUFFER_ENTRY_SIZE 16#define IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE 8
@@ -251,10 +238,6 @@#define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET 0x14#define IOMMU_EVENT_LOG_HEAD_OFFSET 0x2010#define IOMMU_EVENT_LOG_TAIL_OFFSET 0x2018 -#define IOMMU_EVENT_LOG_BASE_LOW_MASK 0xFFFFF000 -#define IOMMU_EVENT_LOG_BASE_LOW_SHIFT 12 -#define IOMMU_EVENT_LOG_BASE_HIGH_MASK 0x000FFFFF -#define IOMMU_EVENT_LOG_BASE_HIGH_SHIFT 0#define IOMMU_EVENT_LOG_LENGTH_MASK 0x0F000000#define IOMMU_EVENT_LOG_LENGTH_SHIFT 24#define IOMMU_EVENT_LOG_HEAD_MASK 0x0007FFF0
@@ -440,4 +423,20 @@#define INV_IOMMU_ALL_PAGES_ADDRESS ((1ULL << 63) - 1) +#define IOMMU_RING_BUFFER_PTR_MASK 0x0007FFF0 +#define IOMMU_RING_BUFFER_PTR_SHIFT 4 + +#define IOMMU_CMD_DEVICE_ID_MASK 0x0000FFFF +#define IOMMU_CMD_DEVICE_ID_SHIFT 0 + +#define IOMMU_CMD_ADDR_LOW_MASK 0xFFFFF000 +#define IOMMU_CMD_ADDR_LOW_SHIFT 12 +#define IOMMU_CMD_ADDR_HIGH_MASK 0xFFFFFFFF +#define IOMMU_CMD_ADDR_HIGH_SHIFT 0 + +#define IOMMU_REG_BASE_ADDR_LOW_MASK 0xFFFFF000 +#define IOMMU_REG_BASE_ADDR_LOW_SHIFT 12 +#define IOMMU_REG_BASE_ADDR_HIGH_MASK 0x000FFFFF +#define IOMMU_REG_BASE_ADDR_HIGH_SHIFT 0 +#endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +67 -0
71 lines not on this page · raw message
PATCH v3 1/1 amd iommu: Add iommu emulation for hvm guest
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213585 -3600
# Node ID 6789e0d335e67e700f97942dd094c548fbbd80f3
# Parent dfdc0df7d68fa4551271b29671a2d333b185a48c
amd iommu: Add iommu emulation for hvm guest
ATS device driver that support PASID [1] and PRI [2] capabilites needs to work with iommu driver in guest OS. We have to expose iommu functionality to HVM guest, if we want assign ATS device to it. A new hypervisor mmio handler is added to intercept iommu mmio accesses from guest.
[1] http://www.pcisig.com/specifications/pciexpress/specifications/ECN-PASID-ATS-2011-03-31.pdf
[2] http://www.pcisig.com/members/downloads/specifications/iov/ats_r1.1_26Jan09.pdf
xen/arch/x86/hvm/intercept.c +2 -1
@@ -38,7 +38,8 @@ hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] = &hpet_mmio_handler, &vlapic_mmio_handler, &vioapic_mmio_handler, - &msixtbl_mmio_handler + &msixtbl_mmio_handler, + &iommu_mmio_handler }; static int hvm_mmio_access(struct vcpu *v,
xen/drivers/passthrough/amd/Makefile +1 -0
@@ -5,3 +5,4 @@ obj-y += pci_amd_iommu.o obj-bin-y += iommu_acpi.init.o obj-y += iommu_intr.o obj-y += iommu_cmd.o +obj-y += iommu_guest.o
xen/drivers/passthrough/amd/iommu_cmd.c +12 -0
@@ -398,3 +398,15 @@ void amd_iommu_flush_all_caches(struct ainvalidate_iommu_all (iommu);flush_command_buffer (iommu); } + +void amd_iommu_send_guest_cmd (struct amd_iommu *iommu,u32 cmd[]) +{ +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + +send_iommu_command (iommu, cmd); +flush_command_buffer (iommu); + +spin_unlock_irqrestore (&iommu->lock, flags); +}
xen/drivers/passthrough/amd/iommu_guest.c new file +915 -0
915 lines not on this page · raw message
xen/drivers/passthrough/amd/iommu_map.c +47 -0
53 lines not on this page · raw message
xen/drivers/passthrough/amd/pci_amd_iommu.c +3 -0
@@ -260,6 +260,8 @@ static int amd_iommu_domain_init(struct hd->domain_id = d->domain_id; +guest_iommu_init (d); +return 0 ; }
@@ -443,6 +445,7 @@ static void deallocate_iommu_page_tablesstatic void amd_iommu_domain_destroy (struct domain *d) { +guest_iommu_destroy (d);deallocate_iommu_page_tables (d);amd_iommu_flush_all_pages (d); }
xen/include/asm-x86/amd-iommu.h +52 -0
62 lines not on this page · raw message
xen/include/asm-x86/hvm/io.h +2 -1
@@ -69,8 +69,9 @@ extern const struct hvm_mmio_handler hpeextern const struct hvm_mmio_handler vlapic_mmio_handler;extern const struct hvm_mmio_handler vioapic_mmio_handler;extern const struct hvm_mmio_handler msixtbl_mmio_handler; +extern const struct hvm_mmio_handler iommu_mmio_handler; -#define HVM_MMIO_HANDLER_NR 4 +#define HVM_MMIO_HANDLER_NR 5int hvm_io_intercept (ioreq_t *p,int type); void register_io_handler(
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +44 -1
93 lines not on this page · raw message
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +10 -0
@@ -71,6 +71,8 @@ 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 iommu_dte_set_guest_cr3 (u32 *dte,u16 dom_id,u64 gcr3, +int gv,unsigned int glx);/* send cmd to iommu */ void amd_iommu_flush_all_pages (struct domain *d);
@@ -106,6 +108,14 @@ void amd_iommu_resume(void);void amd_iommu_suspend (void );void amd_iommu_crash_shutdown (void ); +/* guest iommu support */ +void amd_iommu_send_guest_cmd (struct amd_iommu *iommu,u32 cmd[]); +void guest_iommu_add_ppr_log (struct domain *d,u32 entry[]); +void guest_iommu_add_event_log (struct domain *d,u32 entry[]); +int guest_iommu_init (struct domain * d); +void guest_iommu_destroy (struct domain *d); +int guest_iommu_set_base (struct domain *d,uint64_t base); +static inline u32 get_field_from_reg_u32 (u32 reg_value,u32 mask,u32 shift) {u32 field;
xen/include/xen/hvm/iommu.h +1 -0
@@ -47,6 +47,7 @@ struct hvm_iommu {int domain_id;int paging_mode;struct page_info *root_table; +struct guest_iommu *g_iommu;/* iommu_ops */ const struct iommu_ops *platform_ops;
Re: [PATCH 03 of 14 V3] amd iommu: Add iommu emulation for hvm guest
xen/drivers/passthrough/amd/iommu_guest.c line 128
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c new file +7
-0+static unsigned long get_gfn_from_base_reg (uint64_t base_raw) +{ +uint64_t addr_lo, addr_hi, addr64; + + addr_lo =iommu_get_addr_lo_from_reg (base_raw &DMA_32BIT_MASK ); + addr_hi =iommu_get_addr_hi_from_reg (base_raw >>32 ); + addr64 = (addr_hi <<32 ) | (addr_lo <<PAGE_SHIFT );
I suppose that this isn't really correct - addr_lo shouldn't really need any shifting, or else base_raw would be a pretty odd entity. I'll convert the function to use reg_to_u64() instead. While I won't do this, I then also wonder whether the first two operations could be converted to u64_to_reg(), and if so, what the purpose of the whole function is (it would then merely shift the input value to obtain a frame number).
Jan
Quoted 5 lines
xen/drivers/passthrough/amd/iommu_guest.c new file +5
-0+ +ASSERT ( addr64 !=0 ); + +return addr64 >>PAGE_SHIFT ; +}
Re: [PATCH 03 of 14 V3] amd iommu: Add iommu emulation for hvm guest
Quoted 15 lines · Jan Beulich
Review
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang
(quoted diff) +7
-0+static unsigned long get_gfn_from_base_reg(uint64_t base_raw) +{ + uint64_t addr_lo, addr_hi, addr64; + + addr_lo = iommu_get_addr_lo_from_reg(base_raw& DMA_32BIT_MASK); + addr_hi = iommu_get_addr_hi_from_reg(base_raw>> 32); + addr64 = (addr_hi<< 32) | (addr_lo<< PAGE_SHIFT);I suppose that this isn't really correct -
addr_loshouldn't really need any shifting, or elsebase_rawwould be a pretty odd entity. I'll convert the function to usereg_to_u64()instead. While I won't do this, I then also wonder whether the first two operations could be converted tou64_to_reg(), and if so, what the purpose of the whole function is (it would then merely shift the input value to obtain a frame number)
The names might be confusing but actually iommu mmio regs do not cache lower 12 bit of the base addresses, so that addr_lo only contains bit 12 - bit 31 of the lower 32 bit part. That is why 12 bit left shift is needed to form a fully 64 bit address. But anyway this function seems redundant, I attached a patch to simplify it. Thanks,
Wei
Quoted 14 lines
Jan
Review
Quoted 5 lines
(quoted diff) +5
-0+ + ASSERT ( addr64 != 0 ); + + return addr64>> PAGE_SHIFT; +}_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
# HG changeset patch
# Parent 0d4a60bf37b95b58bbae7019e0c263c556999131
# User Wei Wang <[email protected]>
cleanup get_gfn_from_base_reg() function.
xen/drivers/passthrough/amd/iommu_guest.c +3 -10
@@ -121,16 +121,9 @@ static unsigned int host_domid(struct dostatic unsigned long get_gfn_from_base_reg (uint64_t base_raw) { -struct mmio_reg reg; -uint64_t addr64; - - reg.lo =iommu_get_addr_lo_from_reg (base_raw &DMA_32BIT_MASK ); - reg.hi =iommu_get_addr_hi_from_reg (base_raw >>32 ); - addr64 =reg_to_u64 (reg); - -ASSERT ( addr64 !=0 ); - -return addr64 >>PAGE_SHIFT ; + base_raw &= ~(0xFFFULL <<52 ); +ASSERT ( base_raw !=0 ); +return base_raw >>PAGE_SHIFT ; }static void guest_iommu_deliver_msi (struct domain *d)
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +0 -12
@@ -257,16 +257,4 @@ static inline void iommu_set_addr_hi_to_ IOMMU_REG_BASE_ADDR_HIGH_SHIFT, reg); } -static inline uint32_t iommu_get_addr_lo_from_reg (uint32_t reg) -{ -return get_field_from_reg_u32 (reg,IOMMU_REG_BASE_ADDR_LOW_MASK , -IOMMU_REG_BASE_ADDR_LOW_SHIFT ); -} - -static inline uint32_t iommu_get_addr_hi_from_reg (uint32_t reg) -{ -return get_field_from_reg_u32 (reg,IOMMU_REG_BASE_ADDR_HIGH_MASK , -IOMMU_REG_BASE_ADDR_HIGH_SHIFT ); -} -#endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
PATCH v3 1/1 amd iommu: Enable ppr log
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213589 -3600
# Node ID 6cb08a39044171124b9b9176b50d2ea9196420bb
# Parent 6789e0d335e67e700f97942dd094c548fbbd80f3
amd iommu: Enable ppr log.
IOMMUv2 writes peripheral page service request (PPR) records into ppr log to report guest OS pending DMA page requests from ATS devices.
xen/drivers/passthrough/amd/iommu_init.c +95 -12
@@ -126,14 +126,15 @@ static void register_iommu_dev_table_in_static void register_iommu_cmd_buffer_in_mmio_space (struct amd_iommu *iommu) { -u64 addr_64, addr_lo, addr_hi; +u64 addr_64; +u32 addr_lo, addr_hi;u32 power_of2_entries;u32 entry;ASSERT ( iommu->cmd_buffer.buffer ); - addr_64 = (u64 )virt_to_maddr (iommu->cmd_buffer.buffer); - addr_lo = addr_64 &DMA_32BIT_MASK ; + addr_64 =virt_to_maddr (iommu->cmd_buffer.buffer); + addr_lo = addr_64; addr_hi = addr_64 >>32 ; entry =0 ;
@@ -153,14 +154,15 @@ static void register_iommu_cmd_buffer_instatic void register_iommu_event_log_in_mmio_space (struct amd_iommu *iommu) { -u64 addr_64, addr_lo, addr_hi; +u64 addr_64; +u32 addr_lo, addr_hi;u32 power_of2_entries;u32 entry;ASSERT ( iommu->event_log.buffer ); - addr_64 = (u64 )virt_to_maddr (iommu->event_log.buffer); - addr_lo = addr_64 &DMA_32BIT_MASK ; + addr_64 =virt_to_maddr (iommu->event_log.buffer); + addr_lo = addr_64; addr_hi = addr_64 >>32 ; entry =0 ;
@@ -178,6 +180,35 @@ static void register_iommu_event_log_in_writel (entry, iommu->mmio_base+IOMMU_EVENT_LOG_BASE_HIGH_OFFSET ); } +static void register_iommu_ppr_log_in_mmio_space (struct amd_iommu *iommu) +{ +u64 addr_64; +u32 addr_lo, addr_hi; +u32 power_of2_entries; +u32 entry; + +ASSERT ( iommu->ppr_log.buffer ); + + addr_64 =virt_to_maddr (iommu->ppr_log.buffer); + addr_lo = addr_64; + addr_hi = addr_64 >>32 ; + + entry =0 ; +iommu_set_addr_lo_to_reg (&entry, addr_lo >>PAGE_SHIFT ); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_LOW_OFFSET ); + + power_of2_entries =get_order_from_bytes (iommu->ppr_log.alloc_size) + +IOMMU_PPR_LOG_POWER_OF2_ENTRIES_PER_PAGE ; + + entry =0 ; +iommu_set_addr_hi_to_reg (&entry, addr_hi); +set_field_in_reg_u32 (power_of2_entries, entry, +IOMMU_PPR_LOG_LENGTH_MASK , +IOMMU_PPR_LOG_LENGTH_SHIFT , &entry); +writel (entry, iommu->mmio_base +IOMMU_PPR_LOG_BASE_HIGH_OFFSET ); +} + +static void set_iommu_translation_control (struct amd_iommu *iommu,int enable) {
@@ -215,10 +246,10 @@ static void set_iommu_command_buffer_constatic void register_iommu_exclusion_range (struct amd_iommu *iommu) { -u64 addr_lo, addr_hi; +u32 addr_lo, addr_hi;u32 entry; - addr_lo = iommu->exclusion_limit &DMA_32BIT_MASK ; + addr_lo = iommu->exclusion_limit; addr_hi = iommu->exclusion_limit >>32 ; set_field_in_reg_u32((u32)addr_hi, 0,
@@ -278,6 +309,35 @@ static void set_iommu_event_log_control(writel (entry, iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); } +static void set_iommu_ppr_log_control (struct amd_iommu *iommu, +int enable) +{ +u32 entry; + + entry =readl (iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); + +/*reset head and tail pointer manually before enablement */ +if ( enable ) + { +writel (0x0 , iommu->mmio_base +IOMMU_PPR_LOG_HEAD_OFFSET ); +writel (0x0 , iommu->mmio_base +IOMMU_PPR_LOG_TAIL_OFFSET ); + +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_ENABLE_SHIFT ); +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_INT_SHIFT ); +iommu_set_bit (&entry,IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT ); + } +else + { +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_ENABLE_SHIFT ); +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_INT_SHIFT ); +iommu_clear_bit (&entry,IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT ); + } + +writel (entry, iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); +if ( enable ) +AMD_IOMMU_DEBUG ("PPR Log Enabled.\n" ); +} +static void parse_event_log_entry (struct amd_iommu *,u32 entry[]);static int amd_iommu_read_event_log (struct amd_iommu *iommu)
@@ -585,12 +645,19 @@ static void enable_iommu(struct amd_iommregister_iommu_event_log_in_mmio_space (iommu);register_iommu_exclusion_range (iommu); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +register_iommu_ppr_log_in_mmio_space (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 ); + +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_ENABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_ENABLED );if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) )
@@ -671,16 +738,29 @@ static void * __init allocate_event_log( IOMMU_EVENT_LOG_DEFAULT_ENTRIES, "Event Log"); } +static void *__init allocate_ppr_log (struct amd_iommu *iommu) +{ +/* allocate 'ppr log' in power of 2 increments of 4K */ +return allocate_ring_buffer (&iommu->ppr_log,sizeof (ppr_entry_t), +IOMMU_PPR_LOG_DEFAULT_ENTRIES ,"PPR Log" ); +} +static int __init amd_iommu_init_one (struct amd_iommu *iommu) { +if (map_iommu_mmio_region (iommu) !=0 ) + goto error_out; + +get_iommu_features (iommu); +if (allocate_cmd_buffer (iommu) ==NULL ) goto error_out;if (allocate_event_log (iommu) ==NULL ) goto error_out; -if (map_iommu_mmio_region (iommu) !=0 ) - goto error_out; +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +if (allocate_ppr_log (iommu) ==NULL ) + goto error_out;if (set_iommu_interrupt_handler (iommu) ==0 ) goto error_out;
@@ -693,8 +773,6 @@ 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++;
@@ -717,6 +795,7 @@ static void __init amd_iommu_init_cleanu {deallocate_ring_buffer (&iommu->cmd_buffer);deallocate_ring_buffer (&iommu->event_log); +deallocate_ring_buffer (&iommu->ppr_log);unmap_iommu_mmio_region (iommu); }xfree (iommu);
@@ -915,6 +994,10 @@ static void disable_iommu(struct amd_iomamd_iommu_msi_enable (iommu,IOMMU_CONTROL_DISABLED );set_iommu_command_buffer_control (iommu,IOMMU_CONTROL_DISABLED );set_iommu_event_log_control (iommu,IOMMU_CONTROL_DISABLED ); + +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) ) +set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_DISABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_DISABLED ); iommu->enabled =0 ;
xen/include/asm-x86/amd-iommu.h +1 -0
@@ -93,6 +93,7 @@ struct amd_iommu {struct table_struct dev_table;struct ring_buffer cmd_buffer;struct ring_buffer event_log; +struct ring_buffer ppr_log;int exclusion_enable;int exclusion_allow_all;
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +3 -0
@@ -27,6 +27,9 @@/* IOMMU Event Log entries: in power of 2 increments, minimum of 256 */ #define IOMMU_EVENT_LOG_DEFAULT_ENTRIES 512 +/* IOMMU PPR Log entries: in power of 2 increments, minimum of 256 */ +#define IOMMU_PPR_LOG_DEFAULT_ENTRIES 512 +#define PTE_PER_TABLE_SHIFT 9#define PTE_PER_TABLE_SIZE (1 << PTE_PER_TABLE_SHIFT)#define PTE_PER_TABLE_MASK (~(PTE_PER_TABLE_SIZE - 1))
PATCH v3 1/1 amd iommu: Enable guest level translation
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213593 -3600
# Node ID e698b7b63a9dc75c5cad4dbe02d38d90bdaf1512
# Parent 6cb08a39044171124b9b9176b50d2ea9196420bb
amd iommu: Enable guest level translation.
Similar to nested paging for SVM, IOMMUv2 supports two level translations for DMA. This patch enables this feature.
xen/drivers/passthrough/amd/iommu_init.c +23 -0
@@ -223,6 +223,23 @@ static void set_iommu_translation_controwritel (entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET ); } +static void set_iommu_guest_translation_control (struct amd_iommu *iommu, +int enable) +{ +u32 entry; + + entry =readl (iommu->mmio_base +IOMMU_CONTROL_MMIO_OFFSET ); + + enable ? +iommu_set_bit (&entry,IOMMU_CONTROL_GT_ENABLE_SHIFT ): +iommu_clear_bit (&entry,IOMMU_CONTROL_GT_ENABLE_SHIFT ); + +writel (entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET ); + +if ( enable ) +AMD_IOMMU_DEBUG ("Guest Translation Enabled.\n" ); +} +static void set_iommu_command_buffer_control (struct amd_iommu *iommu,int enable) {
@@ -658,6 +675,9 @@ static void enable_iommu(struct amd_iommif (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) )set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_ENABLED ); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_GTSUP_SHIFT ) ) +set_iommu_guest_translation_control (iommu,IOMMU_CONTROL_ENABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_ENABLED );if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_IASUP_SHIFT ) )
@@ -998,6 +1018,9 @@ static void disable_iommu(struct amd_iomif (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_PPRSUP_SHIFT ) )set_iommu_ppr_log_control (iommu,IOMMU_CONTROL_DISABLED ); +if (iommu_has_feature (iommu,IOMMU_EXT_FEATURE_GTSUP_SHIFT ) ) +set_iommu_guest_translation_control (iommu,IOMMU_CONTROL_DISABLED ); +set_iommu_translation_control (iommu,IOMMU_CONTROL_DISABLED ); iommu->enabled =0 ;
PATCH v3 1/1 amd iommu: add ppr log processing into iommu interrupt handling
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213597 -3600
# Node ID 3d252e3969bae12e85e5a1f2f339dad169d0d892
# Parent e698b7b63a9dc75c5cad4dbe02d38d90bdaf1512
amd iommu: add ppr log processing into iommu interrupt handling PPR log and event log share the same interrupt source. Interrupt handler should check both of them.
xen/drivers/passthrough/amd/iommu_init.c +124 -43
@@ -355,75 +355,92 @@ static void set_iommu_ppr_log_control(stAMD_IOMMU_DEBUG ("PPR Log Enabled.\n" ); } -static void parse_event_log_entry (struct amd_iommu *,u32 entry[]); +/* read event log or ppr log from iommu ring buffer */ +static int iommu_read_log (struct amd_iommu *iommu, +struct ring_buffer *log, +unsigned int entry_size, +void (*parse_func)(struct amd_iommu *,u32 *)) +{ +u32 tail, head, *entry, tail_offest, head_offset; -static int amd_iommu_read_event_log (struct amd_iommu *iommu) -{ -u32 tail, head, *event_log; - -BUG_ON ( !iommu ); +BUG_ON ( !iommu || ((log != &iommu->event_log) && + (log != &iommu->ppr_log)) );/* make sure there's an entry in the log */ - 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 ); + tail_offest = ( log == &iommu->event_log ) ? +IOMMU_EVENT_LOG_TAIL_OFFSET : +IOMMU_PPR_LOG_TAIL_OFFSET ; -while ( tail != iommu->event_log.head ) + head_offset = ( log == &iommu->event_log ) ? +IOMMU_EVENT_LOG_HEAD_OFFSET : +IOMMU_PPR_LOG_HEAD_OFFSET ; + + tail =readl (iommu->mmio_base + tail_offest); + tail =iommu_get_rb_pointer (tail); + +while ( tail != log->head ) {/* read event log entry */ - event_log = (u32 *)(iommu->event_log.buffer + - (iommu->event_log.head * -IOMMU_EVENT_LOG_ENTRY_SIZE )); + entry = (u32 *)(log->buffer + log->head * entry_size); -parse_event_log_entry (iommu, event_log); - -if ( ++iommu->event_log.head == iommu->event_log.entries ) - iommu->event_log.head =0 ; +parse_func (iommu, entry); +if ( ++log->head == log->entries ) + log->head =0 ;/* update head pointer */ -set_field_in_reg_u32 (iommu->event_log.head,0 , -IOMMU_EVENT_LOG_HEAD_MASK , -IOMMU_EVENT_LOG_HEAD_SHIFT , &head); -writel (head, iommu->mmio_base +IOMMU_EVENT_LOG_HEAD_OFFSET ); + head =0 ; +iommu_set_rb_pointer (&head, log->head); + +writel (head, iommu->mmio_base + head_offset); }return 0 ; } -static void amd_iommu_reset_event_log (struct amd_iommu *iommu) +/* reset event log or ppr log when overflow */ +static void iommu_reset_log (struct amd_iommu *iommu, +struct ring_buffer *log, +void (*ctrl_func)(struct amd_iommu *iommu,int )) {u32 entry; -int log_run; +int log_run, run_bit, of_bit;int loop_count =1000 ; +BUG_ON ( !iommu || ((log != &iommu->event_log) && + (log != &iommu->ppr_log)) ); + + run_bit = ( log == &iommu->event_log ) ? +IOMMU_STATUS_EVENT_LOG_RUN_SHIFT : +IOMMU_STATUS_PPR_LOG_RUN_SHIFT ; + + of_bit = ( log == &iommu->event_log ) ? +IOMMU_STATUS_EVENT_OVERFLOW_SHIFT : +IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT ; +/* wait until EventLogRun bit = 0 */ do { entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); - log_run =iommu_get_bit (entry,IOMMU_STATUS_EVENT_LOG_RUN_SHIFT ); + log_run =iommu_get_bit (entry, run_bit); loop_count--; }while ( log_run && loop_count );if ( log_run ) { -AMD_IOMMU_DEBUG ("Warning: EventLogRun bit is not cleared" -"before reset!\n" ); +AMD_IOMMU_DEBUG ("Warning: Log Run bit %d is not cleared" +"before reset! \n" , run_bit);return ; } -set_iommu_event_log_control (iommu,IOMMU_CONTROL_DISABLED ); +ctrl_func (iommu,IOMMU_CONTROL_DISABLED ); -/* read event log for debugging */ -amd_iommu_read_event_log (iommu);/*clear overflow bit */ -iommu_clear_bit (&entry,IOMMU_STATUS_EVENT_OVERFLOW_SHIFT ); - -writel (entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET ); +iommu_clear_bit (&entry, of_bit); +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );/*reset event log base address */ - iommu->event_log.head =0 ; + log->head =0 ; -set_iommu_event_log_control (iommu,IOMMU_CONTROL_ENABLED ); +ctrl_func (iommu,IOMMU_CONTROL_ENABLED ); }static void iommu_msi_set_affinity (struct irq_desc *desc,const cpumask_t *mask)
@@ -595,30 +612,95 @@ static void parse_event_log_entry(struct } } -static void amd_iommu_page_fault (int irq,void *dev_id, -struct cpu_user_regs *regs) +static void iommu_check_event_log (struct amd_iommu *iommu) {u32 entry;unsigned long flags; -struct amd_iommu *iommu = dev_id;spin_lock_irqsave (&iommu->lock, flags); -amd_iommu_read_event_log (iommu); + +iommu_read_log (iommu, &iommu->event_log, +sizeof (event_entry_t), parse_event_log_entry);/*check event overflow */ entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );if (iommu_get_bit (entry,IOMMU_STATUS_EVENT_OVERFLOW_SHIFT ) ) -amd_iommu_reset_event_log (iommu); +iommu_reset_log (iommu, &iommu->event_log, set_iommu_event_log_control);/* reset interrupt status bit */ entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET );iommu_set_bit (&entry,IOMMU_STATUS_EVENT_LOG_INT_SHIFT ); -writel (entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET ); +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); +spin_unlock_irqrestore (&iommu->lock, flags); } +void parse_ppr_log_entry (struct amd_iommu *iommu,u32 entry[]) +{ + +u16 device_id; +u8 bus, devfn; +struct pci_dev *pdev; +struct domain *d; + +/* here device_id is physical value */ + device_id =iommu_get_devid_from_cmd (entry[0 ]); + bus = device_id >>8 ; + devfn = device_id &0xFF ; + +local_irq_enable (); + +spin_lock (&pcidevs_lock); + pdev =pci_get_pdev (0 , bus, devfn); +spin_unlock (&pcidevs_lock); + +local_irq_disable (); + +if ( pdev ==NULL ) +return ; + + d = pdev->domain; + +guest_iommu_add_ppr_log (d, entry); +} + +static void iommu_check_ppr_log (struct amd_iommu *iommu) +{ +u32 entry; +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + +iommu_read_log (iommu, &iommu->ppr_log, +sizeof (ppr_entry_t), parse_ppr_log_entry); + +/*check event overflow */ + entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); + +if (iommu_get_bit (entry,IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT ) ) +iommu_reset_log (iommu, &iommu->ppr_log, set_iommu_ppr_log_control); + +/* reset interrupt status bit */ + entry =readl (iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); +iommu_set_bit (&entry,IOMMU_STATUS_PPR_LOG_INT_SHIFT ); + +writel (entry, iommu->mmio_base +IOMMU_STATUS_MMIO_OFFSET ); + +spin_unlock_irqrestore (&iommu->lock, flags); +} + +static void iommu_interrupt_handler (int irq,void *dev_id, +struct cpu_user_regs *regs) +{ +struct amd_iommu *iommu = dev_id; +iommu_check_event_log (iommu); + +if ( iommu->ppr_log.buffer !=NULL ) +iommu_check_ppr_log (iommu); +} +static int __init set_iommu_interrupt_handler (struct amd_iommu *iommu) {int irq, ret;
@@ -631,8 +713,7 @@ static int __init set_iommu_interrupt_ha } irq_desc[irq].handler = &iommu_msi_type; - ret =request_irq (irq, amd_iommu_page_fault,0 , -"amd_iommu" , iommu); + ret =request_irq (irq, iommu_interrupt_handler,0 ,"amd_iommu" , iommu);if ( ret ) { irq_desc[irq].handler = &no_irq_type;
PATCH v3 1/1 amd iommu: Add 2 hypercalls for libxc
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213601 -3600
# Node ID 31e61ed495ae1429e3317f8b0359ff37fdcbb6cd # Parent 3d252e3969bae12e85e5a1f2f339dad169d0d892 amd iommu: Add 2 hypercalls for libxc
iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest space. Hypervisor needs this vector to inject msi into guest when PPR logging happens.
iommu_bind_bdf: used by xl to bind guest bdf number to machine bdf number. IOMMU emulations codes receives commands from guest iommu driver and forwards them to host iommu. But virtual device id from guest should be converted into physical before sending to real hardware.
Signed -off-by: Wei Wang <[email protected]>
xen/drivers/passthrough/amd/iommu_guest.c +68 -9
@@ -48,14 +48,31 @@ (reg)->hi = (val >>32 ) &0xFFFFFFFF ; \ }while (0 ) -static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf) +static unsigned int machine_bdf(struct domain *d, uint16_t guest_seg, +uint16_t guest_bdf) { -return guest_bdf; +struct pci_dev *pdev; +uint16_t mbdf =0 ; + +for_each_pdev ( d, pdev ) + { +if ( (pdev->gbdf == guest_bdf) && (pdev->gseg == guest_seg) ) + { + mbdf =PCI_BDF2 (pdev->bus, pdev->devfn); +break ; + } + } +return mbdf; } -static uint16_t guest_bdf (struct domain *d,uint16_t machine_bdf) +static uint16_t guest_bdf (struct domain *d,uint16_t machine_seg, +uint16_t machine_bdf) { -return machine_bdf; +struct pci_dev *pdev; + + pdev =pci_get_pdev_by_domain (d, machine_seg,PCI_BUS (machine_bdf), +PCI_DEVFN2 (machine_bdf)); +return pdev->gbdf; }static inline struct guest_iommu *domain_iommu (struct domain *d)
@@ -207,7 +224,7 @@ void guest_iommu_add_ppr_log(struct doma log = log_base + tail % (PAGE_SIZE /sizeof (ppr_entry_t));/* Convert physical device id back into virtual device id */ - gdev_id =guest_bdf (d,iommu_get_devid_from_cmd (entry[0 ])); + gdev_id =guest_bdf (d,0 ,iommu_get_devid_from_cmd (entry[0 ]));iommu_set_devid_to_cmd (&entry[0 ], gdev_id);memcpy (log, entry,sizeof (ppr_entry_t));
@@ -250,7 +267,7 @@ void guest_iommu_add_event_log(struct do log = log_base + tail % (PAGE_SIZE /sizeof (event_entry_t));/* re-write physical device id into virtual device id */ - dev_id =guest_bdf (d,iommu_get_devid_from_cmd (entry[0 ])); + dev_id =guest_bdf (d,0 ,iommu_get_devid_from_cmd (entry[0 ]));iommu_set_devid_to_cmd (&entry[0 ], dev_id);memcpy (log, entry,sizeof (event_entry_t));
@@ -272,7 +289,7 @@ static int do_complete_ppr_request(strucuint16_t dev_id;struct amd_iommu *iommu; - dev_id =machine_bdf (d,iommu_get_devid_from_cmd (cmd->data[0 ])); + dev_id =machine_bdf (d,0 ,iommu_get_devid_from_cmd (cmd->data[0 ])); iommu =find_iommu_for_device (0 , dev_id);if ( !iommu )
@@ -324,7 +341,7 @@ static int do_invalidate_iotlb_pages(strstruct amd_iommu *iommu;uint16_t dev_id; - dev_id =machine_bdf (d,iommu_get_devid_from_cmd (cmd->data[0 ])); + dev_id =machine_bdf (d,0 ,iommu_get_devid_from_cmd (cmd->data[0 ])); iommu =find_iommu_for_device (0 , dev_id);if ( !iommu )
@@ -402,7 +419,7 @@ static int do_invalidate_dte(struct doma g_iommu =domain_iommu (d); gbdf =iommu_get_devid_from_cmd (cmd->data[0 ]); - mbdf =machine_bdf (d, gbdf); + mbdf =machine_bdf (d,0 , gbdf);/* Guest can only update DTEs for its passthru devices */ if ( mbdf ==0 || gbdf ==0 )
@@ -913,3 +930,45 @@ const struct hvm_mmio_handler iommu_mmio .read_handler = guest_iommu_mmio_read, .write_handler = guest_iommu_mmio_write }; + +/* iommu hypercall handler */ +int iommu_bind_bdf (struct domain * d,uint16_t gseg,uint16_t gbdf, +uint16_t mseg,uint16_t mbdf) +{ +struct pci_dev *pdev; +int ret = -ENODEV ; + +if ( !iommu_found () ) +return 0 ; + +spin_lock (&pcidevs_lock); + +for_each_pdev ( d, pdev ) + { +if ( (pdev->seg != mseg) || (pdev->bus !=PCI_BUS (mbdf) ) || + (pdev->devfn !=PCI_DEVFN2 (mbdf)) ) +continue ; + + pdev->gseg = gseg; + pdev->gbdf = gbdf; + ret =0 ; + } + +spin_unlock (&pcidevs_lock); +return ret; +} + +void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode) +{ +struct guest_iommu *iommu =domain_iommu (d); + +if ( !iommu_found () ) +return ; + + iommu->msi.vector = vector; + iommu->msi.dest = dest; + iommu->msi.dest_mode = dest_mode; + iommu->msi.trig_mode = trig_mode; +}
xen/drivers/passthrough/iommu.c +34 -0
@@ -648,6 +648,40 @@ int iommu_do_domctl(put_domain (d);break ; +case XEN_DOMCTL_guest_iommu_op: + { +xen_domctl_guest_iommu_op_t * guest_op; + +if (unlikely ((d =get_domain_by_id (domctl->domain)) ==NULL ) ) + { +gdprintk (XENLOG_ERR , +"XEN_DOMCTL_guest_iommu_op: get_domain_by_id() failed\n" ); + ret = -EINVAL ; +break ; + } + + guest_op = &(domctl->u.guest_iommu_op); +switch ( guest_op->op ) + { +case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI : +iommu_set_msi (d, guest_op->u.msi.vector, + guest_op->u.msi.dest, + guest_op->u.msi.dest_mode, + guest_op->u.msi.delivery_mode, + guest_op->u.msi.trig_mode); + ret =0 ; +break ; +case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF : + ret =iommu_bind_bdf (d, guest_op->u.bdf_bind.g_seg, + guest_op->u.bdf_bind.g_bdf, + guest_op->u.bdf_bind.m_seg, + guest_op->u.bdf_bind.m_bdf); +break ; + } +put_domain (d); +break ; + } +default : ret = -ENOSYS ;break ;
xen/include/public/domctl.h +27 -0
@@ -848,6 +848,31 @@ struct xen_domctl_set_access_required {typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t ;DEFINE_XEN_GUEST_HANDLE (xen_domctl_set_access_required_t); +/* Support for guest iommu emulation */ +struct xen_domctl_guest_iommu_op { +/* XEN_DOMCTL_GUEST_IOMMU_OP_* */ +#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI 0 +#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF 1 +uint8_t op; +union { +struct iommu_msi { +uint8_t vector; +uint8_t dest; +uint8_t dest_mode; +uint8_t delivery_mode; +uint8_t trig_mode; + } msi; +struct bdf_bind { +uint16_t g_seg; +uint16_t g_bdf; +uint16_t m_seg; +uint16_t m_bdf; + } bdf_bind; + } u; +}; +typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t ; +DEFINE_XEN_GUEST_HANDLE (xen_domctl_guest_iommu_op_t); +struct xen_domctl {uint32_t cmd;#define XEN_DOMCTL_createdomain 1
@@ -912,6 +937,7 @@ struct xen_domctl {#define XEN_DOMCTL_getvcpuextstate 63#define XEN_DOMCTL_set_access_required 64#define XEN_DOMCTL_audit_p2m 65 +#define XEN_DOMCTL_guest_iommu_op 66#define XEN_DOMCTL_gdbsx_guestmemio 1000#define XEN_DOMCTL_gdbsx_pausevcpu 1001#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
@@ -960,6 +986,7 @@ struct xen_domctl {struct xen_domctl_debug_op debug_op;struct xen_domctl_mem_event_op mem_event_op;struct xen_domctl_mem_sharing_op mem_sharing_op; +struct xen_domctl_guest_iommu_op guest_iommu_op;#if defined(__i386__) || defined(__x86_64__)struct xen_domctl_cpuid cpuid;struct xen_domctl_vcpuextstate vcpuextstate;
xen/include/xen/iommu.h +6 -0
@@ -164,6 +164,12 @@ int iommu_do_domctl(struct xen_domctl *,void iommu_iotlb_flush (struct domain *d,unsigned long gfn,unsigned int page_count);void iommu_iotlb_flush_all (struct domain *d); +/* Only used by AMD IOMMU so far */ +void iommu_set_msi (struct domain * d,uint16_t vector,uint16_t dest, +uint16_t dest_mode,uint16_t delivery_mode, +uint16_t trig_mode); +int iommu_bind_bdf (struct domain * d,uint16_t gseg,uint16_t gbdf, +uint16_t mseg,uint16_t mbdf);/* * The purpose of the iommu_dont_flush_iotlb optional cpu flag is to * avoid unecessary iotlb_flush in the low level IOMMU code.
xen/include/xen/pci.h +5 -0
@@ -59,6 +59,11 @@ struct pci_dev {const u16 seg;const u8 bus;const u8 devfn; + +/* Used by iommu to represent virtual seg and bdf value in guest space */ +u16 gseg; +u16 gbdf; +struct pci_dev_info info;struct arch_pci_dev arch;u64 vf_rlen[6 ];
PATCH v3 1/1 amd iommu: Add a new flag to indication iommuv2 feature enabled or not
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213604 -3600
# Node ID 82f5e77e13c43f0e4e34dfefdd218aec092f9542
# Parent 31e61ed495ae1429e3317f8b0359ff37fdcbb6cd
amd iommu: Add a new flag to indication iommuv2 feature enabled or not. Hypercalls should return early on non-iommuv2 systems.
xen/drivers/passthrough/amd/iommu_guest.c +11 -7
@@ -821,6 +821,9 @@ int guest_iommu_set_base(struct domain *p2m_type_t t;struct guest_iommu *iommu =domain_iommu (d); +if ( !is_hvm_domain (d) || !iommuv2_enabled ) +return 1 ; + iommu->mmio_base = base; base >>=PAGE_SHIFT ;
@@ -880,7 +883,7 @@ int guest_iommu_init(struct domain* d)struct guest_iommu *iommu;struct hvm_iommu *hd =domain_hvm_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return 0 ; iommu = xzalloc(struct guest_iommu);
@@ -904,13 +907,11 @@ int guest_iommu_init(struct domain* d)void guest_iommu_destroy (struct domain *d) { -struct guest_iommu *iommu; +struct guest_iommu *iommu =domain_iommu (d); -if ( !is_hvm_domain (d) ) +if ( !is_hvm_domain (d) || !iommuv2_enabled )return ; - iommu =domain_iommu (d); -tasklet_kill (&iommu->cmd_buffer_tasklet);xfree (iommu);
@@ -921,6 +922,9 @@ static int guest_iommu_mmio_range(struct {struct guest_iommu *iommu =vcpu_iommu (v); +if ( !iommu_found () || !iommuv2_enabled ) +return 0 ; +return ( addr >= iommu->mmio_base && addr < (iommu->mmio_base +IOMMU_MMIO_SIZE ) ); }
@@ -938,7 +942,7 @@ int iommu_bind_bdf(struct domain* d, uinstruct pci_dev *pdev;int ret = -ENODEV ; -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return 0 ;spin_lock (&pcidevs_lock);
@@ -964,7 +968,7 @@ void iommu_set_msi(struct domain* d, uin {struct guest_iommu *iommu =domain_iommu (d); -if ( !iommu_found () ) +if ( !iommu_found () || !iommuv2_enabled )return ; iommu->msi.vector = vector;
xen/drivers/passthrough/amd/iommu_init.c +5 -0
@@ -36,6 +36,7 @@ unsigned short ivrs_bdf_entries;static struct radix_tree_root ivrs_maps;struct list_head amd_iommu_head;struct table_struct device_table; +bool_t iommuv2_enabled;static int iommu_has_ht_flag (struct amd_iommu *iommu,u8 mask) {
@@ -765,6 +766,10 @@ static void enable_iommu(struct amd_iommamd_iommu_flush_all_caches (iommu); iommu->enabled =1 ; + +if ( iommu->features ) + iommuv2_enabled =1 ; +spin_unlock_irqrestore (&iommu->lock, flags); }
xen/include/asm-x86/amd-iommu.h +2 -0
@@ -182,4 +182,6 @@ struct guest_iommu { struct guest_iommu_msi msi; }; +extern bool_t iommuv2_enabled; +#endif /* _ASM_X86_64_AMD_IOMMU_H */
PATCH v3 1/1 amd iommu: Add a hypercall for hvmloader
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213608 -3600
# Node ID 2f9c68c3b521efccebebffe76d17ace7dbae5e25 # Parent 82f5e77e13c43f0e4e34dfefdd218aec092f9542 amd iommu: Add a hypercall for hvmloader.
IOMMU MMIO base address is dynamically allocated by firmware. This patch allows hvmloader to notify hypervisor where the iommu mmio pages are.
xen/arch/x86/hvm/hvm.c +4 -0
@@ -65,6 +65,7 @@#include <public/memory.h> #include <asm/mem_event.h> #include <public/mem_event.h> +#include <asm/hvm/svm/amd-iommu-proto.h> bool_t __read_mostly hvm_enabled;
@@ -3677,6 +3678,9 @@ long do_hvm_op(unsigned long op, XEN_GUEcase HVM_PARAM_BUFIOREQ_EVTCHN : rc = -EINVAL ;break ; +case HVM_PARAM_IOMMU_BASE : + rc =guest_iommu_set_base (d, a.value); +break ; }if ( rc ==0 )
xen/include/public/hvm/params.h +2 -1
@@ -141,7 +141,8 @@/* Boolean: Enable nestedhvm (hvm only) */ #define HVM_PARAM_NESTEDHVM 24 +#define HVM_PARAM_IOMMU_BASE 27 -#define HVM_NR_PARAMS 27 +#define HVM_NR_PARAMS 28#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
PATCH v3 1/1 amd iommu: Enable FC bit in iommu host level PTE
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213611 -3600
# Node ID f1bf84f5fbb94f8702c8e96462e715ad5066dca2 # Parent 2f9c68c3b521efccebebffe76d17ace7dbae5e25 amd iommu: Enable FC bit in iommu host level PTE
xen/drivers/passthrough/amd/iommu_map.c +7 -0
@@ -83,6 +83,13 @@ static bool_t set_iommu_pde_present(u32set_field_in_reg_u32 (ir, entry,IOMMU_PDE_IO_READ_PERMISSION_MASK ,IOMMU_PDE_IO_READ_PERMISSION_SHIFT , &entry); + +/* FC bit should be enabled in PTE, this helps to solve potential +* issues with ATS devices +*/ +if ( next_level ==IOMMU_PAGING_MODE_LEVEL_0 ) +set_field_in_reg_u32 (IOMMU_CONTROL_ENABLED , entry, +IOMMU_PTE_FC_MASK ,IOMMU_PTE_FC_SHIFT , &entry); pde[1 ] = entry;/* mark next level as 'present' */
PATCH v3 1/1 hvmloader: Build IVRS table
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213614 -3600
# Node ID 01d2c1d4e3b992997f170d95dccc2195b9206b04 # Parent f1bf84f5fbb94f8702c8e96462e715ad5066dca2
hvmloader: Build IVRS table.
tools/firmware/hvmloader/acpi/acpi2_0.h +54 -0
@@ -389,6 +389,60 @@ struct acpi_20_madt_intsrcovr {#define ACPI_2_0_WAET_REVISION 0x01#define ACPI_1_0_FADT_REVISION 0x01 +#define IVRS_SIGNATURE ASCII32('I','V','R','S') +#define IVRS_REVISION 1 +#define IVRS_VASIZE 64 +#define IVRS_PASIZE 52 +#define IVRS_GVASIZE 64 + +#define IVHD_BLOCK_TYPE 0x10 +#define IVHD_FLAG_HTTUNEN (1 << 0) +#define IVHD_FLAG_PASSPW (1 << 1) +#define IVHD_FLAG_RESPASSPW (1 << 2) +#define IVHD_FLAG_ISOC (1 << 3) +#define IVHD_FLAG_IOTLBSUP (1 << 4) +#define IVHD_FLAG_COHERENT (1 << 5) +#define IVHD_FLAG_PREFSUP (1 << 6) +#define IVHD_FLAG_PPRSUP (1 << 7) + +#define IVHD_EFR_GTSUP (1 << 2) +#define IVHD_EFR_IASUP (1 << 5) + +#define IVHD_SELECT_4_BYTE 0x2 + +struct ivrs_ivhd_block +{ +uint8_t type; +uint8_t flags; +uint16_t length; +uint16_t devid; +uint16_t cap_offset; +uint64_t iommu_base_addr; +uint16_t pci_segment; +uint16_t iommu_info; +uint32_t reserved; +}; + +/* IVHD 4-byte device entries */ +struct ivrs_ivhd_device +{ +uint8_t type; +uint16_t dev_id; +uint8_t flags; +}; + +#define PT_DEV_MAX_NR 32 +#define IOMMU_CAP_OFFSET 0x40 +struct acpi_40_ivrs +{ +struct acpi_header header; +uint32_t iv_info; +uint32_t reserved[2 ]; +struct ivrs_ivhd_block ivhd_block; +struct ivrs_ivhd_device ivhd_device[PT_DEV_MAX_NR ]; +}; + +#pragma pack ()struct acpi_config {
tools/firmware/hvmloader/acpi/build.c +81 -0
105 lines not on this page · raw message
tools/firmware/hvmloader/pci.c +29 -1
@@ -34,11 +34,17 @@ unsigned long pci_mem_end = PCI_MEM_END;enum virtual_vga virtual_vga = VGA_none;unsigned long igd_opregion_pgbase =0 ; +/* support up to 32 passthrough devices */ +#define PT_DEV_MAX_NR 32 +uint32_t ptdev_bdf[PT_DEV_MAX_NR ]; +uint32_t ptdev_nr; +uint32_t iommu_bdf; +void pci_setup (void ) {uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd, mmio_total =0 ;uint32_t vga_devfn =256 ; -uint16_t class, vendor_id, device_id; +uint16_t class, vendor_id, device_id, sub_vendor_id;unsigned int bar, pin, link, isa_irq;/* Resources assignable to PCI devices via BARs. */
@@ -72,12 +78,34 @@ void pci_setup(void) class =pci_readw (devfn,PCI_CLASS_DEVICE ); vendor_id =pci_readw (devfn,PCI_VENDOR_ID ); device_id =pci_readw (devfn,PCI_DEVICE_ID ); + sub_vendor_id =pci_readw (devfn,PCI_SUBSYSTEM_VENDOR_ID ); +if ( (vendor_id ==0xffff ) && (device_id ==0xffff ) )continue ;ASSERT ((devfn !=PCI_ISA_DEVFN ) || ((vendor_id ==0x8086 ) && (device_id ==0x7000 ))); +/* Found amd iommu device. */ +if ( class ==0x0806 && vendor_id ==0x1022 ) + { + iommu_bdf = devfn; +continue ; + } +/* IVRS: Detecting passthrough devices. +* sub_vendor_id != citrix && sub_vendor_id != qemu */ +if ( sub_vendor_id !=0x5853 && sub_vendor_id !=0x1af4 ) + { +/* found amd iommu device */ +if ( ptdev_nr <PT_DEV_MAX_NR ) + { + ptdev_bdf[ptdev_nr] = devfn; + ptdev_nr++; + } +else +printf ("Number of passthru devices > PT_DEV_MAX_NR \n" ); + } +switch ( class ) {case 0x0300 :
PATCH v3 1/1 libxc: add wrappers for new hypercalls
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213617 -3600
# Node ID 2dc60e3398dd602a34ebdf92103a3957b97c02c5 # Parent 01d2c1d4e3b992997f170d95dccc2195b9206b04
libxc: add wrappers for new hypercalls
tools/libxc/xc_domain.c +53 -0
@@ -1352,6 +1352,59 @@ int xc_domain_bind_pt_isa_irq( PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq)); } +int xc_domain_update_iommu_msi ( +xc_interface *xch, +uint32_t domid, +uint8_t vector, +uint8_t dest, +uint8_t dest_mode, +uint8_t delivery_mode, +uint8_t trig_mode) +{ +int rc; +DECLARE_DOMCTL ; +xen_domctl_guest_iommu_op_t * iommu_op; + + domctl.cmd = XEN_DOMCTL_guest_iommu_op; + domctl.domain = (domid_t )domid; + + iommu_op = &(domctl.u.guest_iommu_op); + iommu_op->op =XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI ; + iommu_op->u.msi.vector = vector; + iommu_op->u.msi.dest = dest; + iommu_op->u.msi.dest_mode = dest_mode; + iommu_op->u.msi.delivery_mode = delivery_mode; + iommu_op->u.msi.trig_mode = trig_mode; + + rc =do_domctl (xch, &domctl); +return rc; +} + +int xc_domain_bind_pt_bdf (xc_interface *xch, +uint32_t domid, +uint16_t gseg, +uint16_t gbdf, +uint16_t mseg, +uint16_t mbdf) +{ +int rc; +DECLARE_DOMCTL ; +xen_domctl_guest_iommu_op_t * guest_op; + + domctl.cmd = XEN_DOMCTL_guest_iommu_op; + domctl.domain = (domid_t )domid; + + guest_op = &(domctl.u.guest_iommu_op); + guest_op->op =XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF ; + guest_op->u.bdf_bind.g_seg = gseg; + guest_op->u.bdf_bind.g_bdf = gbdf; + guest_op->u.bdf_bind.m_seg = mseg; + guest_op->u.bdf_bind.m_bdf = mbdf; + + rc =do_domctl (xch, &domctl); +return rc; +} + int xc_domain_memory_mapping( xc_interface *xch, uint32_t domid,
tools/libxc/xenctrl.h +15 -0
@@ -1697,6 +1697,21 @@ int xc_domain_bind_pt_isa_irq(xc_interfauint32_t domid, uint8_t machine_irq); +int xc_domain_bind_pt_bdf (xc_interface *xch, +uint32_t domid, +uint16_t gseg, +uint16_t gbdf, +uint16_t mseg, +uint16_t mbdf); + +int xc_domain_update_iommu_msi (xc_interface *xch, +uint32_t domid, +uint8_t vector, +uint8_t dest, +uint8_t dest_mode, +uint8_t delivery_mode, +uint8_t trig_mode); +int xc_domain_set_machine_address_size (xc_interface *xch,uint32_t domid,unsigned int width);
PATCH v3 1/1 libxl: bind virtual bdf to physical bdf after device assignment
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213620 -3600
# Node ID 9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
# Parent 2dc60e3398dd602a34ebdf92103a3957b97c02c5
libxl: bind virtual bdf to physical bdf after device assignment
tools/libxl/libxl_pci.c +7 -0
@@ -735,6 +735,13 @@ out:LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_assign_device failed" );return ERROR_FAIL ; } +if (LIBXL__DOMAIN_IS_TYPE (gc, domid,HVM )) { + rc =xc_domain_bind_pt_bdf (ctx->xch, domid,0 , pcidev->vdevfn, pcidev->domain,pcidev_encode_bdf (pcidev)); +if ( rc ) { +LIBXL__LOG_ERRNOVAL (ctx,LIBXL__LOG_ERROR , rc,"xc_domain_bind_pt_bdf failed" ); +return ERROR_FAIL ; + } + } }if (!starting)
Re: [PATCH 13 of 14 V3] libxl: bind virtual bdf to physical bdf after device assignment
Wei Wang writes ("[PATCH 13 of 14 V3] libxl: bind virtual bdf to physical bdf after device assignment"):
Quoted 1 line
libxl: bind virtual bdf to physical bdf after device assignment
I confess I don't understand at all why this is needed.
Ian.
Re: [PATCH 13 of 14 V3] libxl: bind virtual bdf to physical bdf after device assignment
Quoted 1 line · On Tuesday 10 January 2012 18:13:35 Ian Jackson wrote:
Wei Wang writes ("[PATCH 13 of 14 V3] libxl: bind virtual bdf to physical
bdf after device assignment"):
Quoted 5 lines
Quoted 1 line
libxl: bind virtual bdf to physical bdf after device assignment
I confess I don't understand at all why this is needed.
Ian.
Oh, the idea of this hypercall is used to allow hypervisor to trace the virtual bdf of a physical bdf. IOMMU emulator reads iommu ppr log from host buffer and dispatch them into guest log buffer. In the host log entry, physical bdf is written by iommu and needs to be changed to virtual bdf when write back to a guest. It might also be done if we could extend the interface of xc_assign_device?
Thanks,
Wei
PATCH v3 1/1 libxl: Introduce a new guest config file parameter
In reply to Wei Wang# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213623 -3600
# Node ID 39eb093ea89eeaa4dbff29439499f2a289291ff0 # Parent 9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
tools/libxl/libxl_create.c +4 -1
@@ -99,6 +99,7 @@ int libxl_init_build_info(libxl_ctx *ctx b_info->u.hvm.vpt_align =1 ; b_info->u.hvm.timer_mode =1 ; b_info->u.hvm.nested_hvm =0 ; + b_info->u.hvm.iommu =0 ;break ;case LIBXL_DOMAIN_TYPE_PV : b_info->u.pv.slack_memkb =8 *1024 ;
@@ -189,13 +190,15 @@ int libxl__domain_build(libxl__gc *gc, vments[4 ] ="start_time" ; vments[5 ] =libxl__sprintf (gc,"%lu.%02d" , start_time.tv_sec,(int )start_time.tv_usec/10000 ); - localents =libxl__calloc (gc,7 ,sizeof (char *)); + localents =libxl__calloc (gc,9 ,sizeof (char *)); localents[0 ] ="platform/acpi" ; localents[1 ] = (info->u.hvm.acpi) ?"1" :"0" ; localents[2 ] ="platform/acpi_s3" ; localents[3 ] = (info->u.hvm.acpi_s3) ?"1" :"0" ; localents[4 ] ="platform/acpi_s4" ; localents[5 ] = (info->u.hvm.acpi_s4) ?"1" :"0" ; + localents[6 ] ="iommu" ; + localents[7 ] = (info->u.hvm.iommu) ?"1" :"0" ;break ;case LIBXL_DOMAIN_TYPE_PV :
tools/libxl/libxl_types.idl +1 -0
@@ -184,6 +184,7 @@ libxl_domain_build_info = Struct("domain ("vpt_align", bool), ("timer_mode", integer), ("nested_hvm", bool), + ("iommu", bool), ])), ("pv", Struct(None, [("kernel", libxl_file_reference), ("slack_memkb", uint32),
tools/libxl/xl_cmdimpl.c +3 -0
@@ -360,6 +360,7 @@ static void printf_info(int domid,printf ("\t\t\t(vpt_align %d)\n" , b_info->u.hvm.vpt_align);printf ("\t\t\t(timer_mode %d)\n" , b_info->u.hvm.timer_mode);printf ("\t\t\t(nestedhvm %d)\n" , b_info->u.hvm.nested_hvm); +printf ("\t\t\t(iommu %d)\n" , b_info->u.hvm.iommu);printf ("\t\t\t(device_model %s)\n" , dm_info->device_model ? :"default" );printf ("\t\t\t(videoram %d)\n" , dm_info->videoram);
@@ -766,6 +767,8 @@ static void parse_config_data(const char b_info->u.hvm.timer_mode = l;if (!xlu_cfg_get_long (config,"nestedhvm" , &l,0 )) b_info->u.hvm.nested_hvm = l; +if (!xlu_cfg_get_long (config,"iommu" , &l,0 )) + b_info->u.hvm.iommu = l;break ;case LIBXL_DOMAIN_TYPE_PV : {
Re: [PATCH 14 of 14 V3] libxl: Introduce a new guest config file parameter
Quoted 8 lines · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213623 -3600
# Node ID39eb093ea89eeaa4dbff29439499f2a289291ff0# Parent9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
Please patch docs/man/xl.cfg.pod.5 to explain this new option to the users, when/why they would enable it etc.
A description of the hardware requirements might be useful, although perhaps not in that document. Likewise the guest OS requirements. Is there a passthru page on the wiki which could be amended?
Quoted 1 line
Signed-off-by Wei Wang <[email protected]>
[...]
tools/libxl/xl_cmdimpl.c static void printf_info(int domid, · line 363
Quoted 8 lines
diff -r
9e89b6485b6c-r39eb093ea89etools/libxl/xl_cmdimpl.ctools/libxl/xl_cmdimpl.c +1
-0@@ -360,6 +360,7 @@ static void printf_info(int domid,printf ("\t\t\t(vpt_align %d)\n" , b_info->u.hvm.vpt_align);printf ("\t\t\t(timer_mode %d)\n" , b_info->u.hvm.timer_mode);printf ("\t\t\t(nestedhvm %d)\n" , b_info->u.hvm.nested_hvm); +printf ("\t\t\t(iommu %d)\n" , b_info->u.hvm.iommu);
I wonder if we should stop adding new stuff to this output, it's for legacy users anyway.
Ian.
Re: [PATCH 14 of 14 V3] libxl: Introduce a new guest config file parameter
Quoted 10 lines · On Wednesday 11 January 2012 09:43:44 Ian Campbell wrote:
Quoted 8 lines · Wei Wang
# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1326213623 -3600
# Node ID39eb093ea89eeaa4dbff29439499f2a289291ff0# Parent9e89b6485b6c91a8d563c46c47a8d768eee7d1f2
libxl: Introduce a new guest config file parameter Use iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0.
Quoted 2 lines
Please patch docs/man/xl.cfg.pod.5 to explain this new option to the users, when/why they would enable it etc.
Sure, will do that
Quoted 3 lines
A description of the hardware requirements might be useful, although perhaps not in that document. Likewise the guest OS requirements. Is there a passthru page on the wiki which could be amended?
I could add new section in http://wiki.xen.org/wiki/VTdHowTo
describing how to use iommu emulation for ats/gpgpu passthru and the hw/sw requirement.
Quoted 4 lines
Quoted 1 line
Signed-off-by Wei Wang <[email protected]>[...]
Quoted 11 lines
tools/libxl/xl_cmdimpl.c static void printf_info(int domid, · line 363
Quoted 8 lines
diff -r
9e89b6485b6c-r39eb093ea89etools/libxl/xl_cmdimpl.ctools/libxl/xl_cmdimpl.c +1
-0@@ -360,6 +360,7 @@ static void printf_info(int domid,printf ("\t\t\t(vpt_align %d)\n" , b_info->u.hvm.vpt_align);printf ("\t\t\t(timer_mode %d)\n" , b_info->u.hvm.timer_mode);printf ("\t\t\t(nestedhvm %d)\n" , b_info->u.hvm.nested_hvm); +printf ("\t\t\t(iommu %d)\n" , b_info->u.hvm.iommu);I wonder if we should stop adding new stuff to this output, it's for legacy users anyway.
Sounds like I could remove it..
Thanks
Wei
Quoted 1 line
Ian.
Quoted 7 lines
Quoted 1 line
Quoted 1 line · Wei Wang
Hi all, this is patch v3.
ATS devices with PRI and PASID capabilities can communicate with iommuv2 to perform two level (nested) address translation and demand paging for DMA. To passthru such devices, iommu driver has to been enabled in guest OS. This patch set adds initial iommu emulation for hvm guests to support ATS device passthru.
I would look into committing 1-6 and 10 (if that one is independent of 7-9), if you can confirm that those on their own provide meaningful benefit (enabling the ppr log probably is what I'm after, but I'd still like your confirmation - patch 3 in particular doesn't look very useful without the later ones). So ideally the ones leading up to the ppr log enabling would all be first (or even a separate series), and the guest iommu ones would follow (as those make only sense when the tools maintainers are okay with the changes too).
Jan
Quoted 15 lines
changes in v3:
* Use xenstore to receive guest iommu configuration instead of adding in a new field inhvm_info_table.
* Support pci segment in vbdf to mbdf bind.
* Make hypercalls visible for non-x86 platforms.
* A few code cleanups according to comments from Jan and Ian.Changes in v2:
* Do not use linked list to access guest iommu tables.
* Do not parse iommu parameter inlibxl_device_model_infoagain.
* Fix incorrect logical calculation in patch 11.
* Fix hypercall definition for non-x86 systems.Thanks,
Wei
Am 11.01.2012 16:04, schrieb Jan Beulich:
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line · Wei Wang
Hi all, this is patch v3.
ATS devices with PRI and PASID capabilities can communicate with iommuv2 to perform two level (nested) address translation and demand paging for DMA. To passthru such devices, iommu driver has to been enabled in guest OS. This patch set adds initial iommu emulation for hvm guests to support ATS device passthru.
Quoted 8 lines
I would look into committing 1-6 and 10 (if that one is independent of 7-9), if you can confirm that those on their own provide meaningful benefit (enabling the ppr log probably is what I'm after, but I'd still like your confirmation - patch 3 in particular doesn't look very useful without the later ones). So ideally the ones leading up to the ppr log enabling would all be first (or even a separate series), and the guest iommu ones would follow (as those make only sense when the tools maintainers are okay with the changes too)
Hi Jan,
Thanks for doing this. It sounds great! Even without guest iommu being enabled, patch 1-6 and 10 would still be useful for turn on ppr and GT features. Patch 6 will call some functions from patch 3. If you want to leave patch 3 behind, I could send a new version to move patch 6 ahead. Thanks,
Wei
Quoted 20 lines
Jan
Quoted 15 lines
changes in v3:
* Use xenstore to receive guest iommu configuration instead of adding in a new field inhvm_info_table.
* Support pci segment in vbdf to mbdf bind.
* Make hypercalls visible for non-x86 platforms.
* A few code cleanups according to comments from Jan and Ian.Changes in v2:
* Do not use linked list to access guest iommu tables.
* Do not parse iommu parameter inlibxl_device_model_infoagain.
* Fix incorrect logical calculation in patch 11.
* Fix hypercall definition for non-x86 systems.Thanks,
Wei