ia64/xen-unstable
changeset 17743:1e66fa5931ee
vtd: interrupt remapping for MSI/MSI-x.
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Weidong Han <weidong.han@intel.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Wed May 28 09:29:05 2008 +0100 (2008-05-28) |
parents | 5de1048b884e |
children | 460f72ca97b6 |
files | xen/arch/x86/msi.c xen/drivers/passthrough/vtd/intremap.c xen/drivers/passthrough/vtd/vtd.h xen/include/xen/iommu.h |
line diff
1.1 --- a/xen/arch/x86/msi.c Wed May 28 09:28:42 2008 +0100 1.2 +++ b/xen/arch/x86/msi.c Wed May 28 09:29:05 2008 +0100 1.3 @@ -25,6 +25,7 @@ 1.4 #include <mach_apic.h> 1.5 #include <io_ports.h> 1.6 #include <public/physdev.h> 1.7 +#include <xen/iommu.h> 1.8 1.9 extern int msi_irq_enable; 1.10 1.11 @@ -156,6 +157,9 @@ void read_msi_msg(unsigned int irq, stru 1.12 default: 1.13 BUG(); 1.14 } 1.15 + 1.16 + if ( vtd_enabled ) 1.17 + msi_msg_read_remap_rte(entry, msg); 1.18 } 1.19 1.20 static int set_vector_msi(struct msi_desc *entry) 1.21 @@ -202,6 +206,9 @@ void write_msi_msg(unsigned int irq, str 1.22 { 1.23 struct msi_desc *entry = irq_desc[irq].msi_desc; 1.24 1.25 + if ( vtd_enabled ) 1.26 + msi_msg_write_remap_rte(entry, msg); 1.27 + 1.28 switch ( entry->msi_attrib.type ) 1.29 { 1.30 case PCI_CAP_ID_MSI:
2.1 --- a/xen/drivers/passthrough/vtd/intremap.c Wed May 28 09:28:42 2008 +0100 2.2 +++ b/xen/drivers/passthrough/vtd/intremap.c Wed May 28 09:29:05 2008 +0100 2.3 @@ -251,6 +251,176 @@ void io_apic_write_remap_rte( 2.4 *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1); 2.5 } 2.6 2.7 +static void remap_entry_to_msi_msg( 2.8 + struct iommu *iommu, struct msi_msg *msg) 2.9 +{ 2.10 + struct iremap_entry *iremap_entry = NULL, *iremap_entries; 2.11 + struct msi_msg_remap_entry *remap_rte; 2.12 + int index; 2.13 + unsigned long flags; 2.14 + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); 2.15 + 2.16 + if ( ir_ctrl == NULL ) 2.17 + { 2.18 + dprintk(XENLOG_ERR VTDPREFIX, 2.19 + "remap_entry_to_msi_msg: ir_ctl == NULL"); 2.20 + return; 2.21 + } 2.22 + 2.23 + remap_rte = (struct msi_msg_remap_entry *) msg; 2.24 + index = (remap_rte->address_lo.index_15 << 15) | 2.25 + remap_rte->address_lo.index_0_14; 2.26 + 2.27 + if ( index > ir_ctrl->iremap_index ) 2.28 + panic("%s: index (%d) is larger than remap table entry size (%d)\n", 2.29 + __func__, index, ir_ctrl->iremap_index); 2.30 + 2.31 + spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); 2.32 + 2.33 + iremap_entries = 2.34 + (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); 2.35 + iremap_entry = &iremap_entries[index]; 2.36 + 2.37 + msg->address_hi = MSI_ADDR_BASE_HI; 2.38 + msg->address_lo = 2.39 + MSI_ADDR_BASE_LO | 2.40 + ((iremap_entry->lo.dm == 0) ? 2.41 + MSI_ADDR_DESTMODE_PHYS: 2.42 + MSI_ADDR_DESTMODE_LOGIC) | 2.43 + ((iremap_entry->lo.dlm != dest_LowestPrio) ? 2.44 + MSI_ADDR_REDIRECTION_CPU: 2.45 + MSI_ADDR_REDIRECTION_LOWPRI) | 2.46 + iremap_entry->lo.dst >> 8; 2.47 + 2.48 + msg->data = 2.49 + MSI_DATA_TRIGGER_EDGE | 2.50 + MSI_DATA_LEVEL_ASSERT | 2.51 + ((iremap_entry->lo.dlm != dest_LowestPrio) ? 2.52 + MSI_DATA_DELIVERY_FIXED: 2.53 + MSI_DATA_DELIVERY_LOWPRI) | 2.54 + iremap_entry->lo.vector; 2.55 + 2.56 + unmap_vtd_domain_page(iremap_entries); 2.57 + spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); 2.58 +} 2.59 + 2.60 +static void msi_msg_to_remap_entry( 2.61 + struct iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg) 2.62 +{ 2.63 + struct iremap_entry *iremap_entry = NULL, *iremap_entries; 2.64 + struct iremap_entry new_ire; 2.65 + struct msi_msg_remap_entry *remap_rte; 2.66 + unsigned int index; 2.67 + unsigned long flags; 2.68 + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); 2.69 + int i = 0; 2.70 + 2.71 + remap_rte = (struct msi_msg_remap_entry *) msg; 2.72 + spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); 2.73 + 2.74 + iremap_entries = 2.75 + (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); 2.76 + 2.77 + /* If the entry for a PCI device has been there, use the old entry, 2.78 + * Or, assign a new entry for it. 2.79 + */ 2.80 + for ( i = 0; i <= ir_ctrl->iremap_index; i++ ) 2.81 + { 2.82 + iremap_entry = &iremap_entries[i]; 2.83 + if ( iremap_entry->hi.sid == 2.84 + ((pdev->bus << 8) | pdev->devfn) ) 2.85 + break; 2.86 + } 2.87 + 2.88 + if ( i > ir_ctrl->iremap_index ) 2.89 + { 2.90 + ir_ctrl->iremap_index++; 2.91 + index = ir_ctrl->iremap_index; 2.92 + } 2.93 + else 2.94 + index = i; 2.95 + 2.96 + if ( index > IREMAP_ENTRY_NR - 1 ) 2.97 + panic("msi_msg_to_remap_entry: intremap index is more than 256!\n"); 2.98 + 2.99 + iremap_entry = &iremap_entries[index]; 2.100 + memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry)); 2.101 + 2.102 + /* Set interrupt remapping table entry */ 2.103 + new_ire.lo.fpd = 0; 2.104 + new_ire.lo.dm = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1; 2.105 + new_ire.lo.rh = 0; 2.106 + new_ire.lo.tm = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; 2.107 + new_ire.lo.dlm = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1; 2.108 + new_ire.lo.avail = 0; 2.109 + new_ire.lo.res_1 = 0; 2.110 + new_ire.lo.vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & 2.111 + MSI_DATA_VECTOR_MASK; 2.112 + new_ire.lo.res_2 = 0; 2.113 + new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) 2.114 + & 0xff) << 8; 2.115 + 2.116 + new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn; 2.117 + new_ire.hi.sq = 0; 2.118 + new_ire.hi.svt = 1; 2.119 + new_ire.hi.res_1 = 0; 2.120 + new_ire.lo.p = 1; /* finally, set present bit */ 2.121 + 2.122 + /* now construct new MSI/MSI-X rte entry */ 2.123 + remap_rte->address_lo.dontcare = 0; 2.124 + remap_rte->address_lo.index_15 = index & 0x8000; 2.125 + remap_rte->address_lo.index_0_14 = index & 0x7fff; 2.126 + remap_rte->address_lo.SHV = 1; 2.127 + remap_rte->address_lo.format = 1; 2.128 + 2.129 + remap_rte->address_hi = 0; 2.130 + remap_rte->data = 0; 2.131 + 2.132 + memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry)); 2.133 + iommu_flush_iec_index(iommu, 0, index); 2.134 + invalidate_sync(iommu); 2.135 + 2.136 + unmap_vtd_domain_page(iremap_entries); 2.137 + spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); 2.138 + return; 2.139 +} 2.140 + 2.141 +void msi_msg_read_remap_rte( 2.142 + struct msi_desc *msi_desc, struct msi_msg *msg) 2.143 +{ 2.144 + struct pci_dev *pdev = msi_desc->dev; 2.145 + struct acpi_drhd_unit *drhd = NULL; 2.146 + struct iommu *iommu = NULL; 2.147 + struct ir_ctrl *ir_ctrl; 2.148 + 2.149 + drhd = acpi_find_matched_drhd_unit(pdev); 2.150 + iommu = drhd->iommu; 2.151 + 2.152 + ir_ctrl = iommu_ir_ctrl(iommu); 2.153 + if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) 2.154 + return; 2.155 + 2.156 + remap_entry_to_msi_msg(iommu, msg); 2.157 +} 2.158 + 2.159 +void msi_msg_write_remap_rte( 2.160 + struct msi_desc *msi_desc, struct msi_msg *msg) 2.161 +{ 2.162 + struct pci_dev *pdev = msi_desc->dev; 2.163 + struct acpi_drhd_unit *drhd = NULL; 2.164 + struct iommu *iommu = NULL; 2.165 + struct ir_ctrl *ir_ctrl; 2.166 + 2.167 + drhd = acpi_find_matched_drhd_unit(msi_desc->dev); 2.168 + iommu = drhd->iommu; 2.169 + 2.170 + ir_ctrl = iommu_ir_ctrl(iommu); 2.171 + if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) 2.172 + return; 2.173 + 2.174 + msi_msg_to_remap_entry(iommu, pdev, msg); 2.175 +} 2.176 + 2.177 int intremap_setup(struct iommu *iommu) 2.178 { 2.179 struct ir_ctrl *ir_ctrl;
3.1 --- a/xen/drivers/passthrough/vtd/vtd.h Wed May 28 09:28:42 2008 +0100 3.2 +++ b/xen/drivers/passthrough/vtd/vtd.h Wed May 28 09:29:05 2008 +0100 3.3 @@ -42,6 +42,24 @@ struct IO_APIC_route_remap_entry { 3.4 }; 3.5 }; 3.6 3.7 +struct msi_msg_remap_entry { 3.8 + union { 3.9 + u32 val; 3.10 + struct { 3.11 + u32 dontcare:2, 3.12 + index_15:1, 3.13 + SHV:1, 3.14 + format:1, 3.15 + index_0_14:15, 3.16 + addr_id_val:12; /* Interrupt address identifier value, 3.17 + must be 0FEEh */ 3.18 + }; 3.19 + } address_lo; /* low 32 bits of msi message address */ 3.20 + 3.21 + u32 address_hi; /* high 32 bits of msi message address */ 3.22 + u32 data; /* msi message data */ 3.23 +}; 3.24 + 3.25 unsigned int get_clflush_size(void); 3.26 u64 alloc_pgtable_maddr(void); 3.27 void free_pgtable_maddr(u64 maddr);
4.1 --- a/xen/include/xen/iommu.h Wed May 28 09:28:42 2008 +0100 4.2 +++ b/xen/include/xen/iommu.h Wed May 28 09:29:05 2008 +0100 4.3 @@ -26,6 +26,7 @@ 4.4 #include <xen/pci.h> 4.5 #include <public/hvm/ioreq.h> 4.6 #include <public/domctl.h> 4.7 +#include <asm/msi.h> 4.8 4.9 extern int vtd_enabled; 4.10 extern int iommu_enabled; 4.11 @@ -78,6 +79,8 @@ int pt_irq_destroy_bind_vtd(struct domai 4.12 unsigned int io_apic_read_remap_rte(unsigned int apic, unsigned int reg); 4.13 void io_apic_write_remap_rte(unsigned int apic, 4.14 unsigned int reg, unsigned int value); 4.15 +void msi_msg_read_remap_rte(struct msi_desc *msi_desc, struct msi_msg *msg); 4.16 +void msi_msg_write_remap_rte(struct msi_desc *msi_desc, struct msi_msg *msg); 4.17 struct qi_ctrl *iommu_qi_ctrl(struct iommu *iommu); 4.18 struct ir_ctrl *iommu_ir_ctrl(struct iommu *iommu); 4.19 struct iommu_flush *iommu_get_flush(struct iommu *iommu);