ia64/xen-unstable
changeset 17742:5de1048b884e
vtd: Fix bugs of ioapic interrupt remapping.
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Wed May 28 09:28:42 2008 +0100 (2008-05-28) |
parents | c93a913c221f |
children | 1e66fa5931ee |
files | xen/drivers/passthrough/vtd/intremap.c |
line diff
1.1 --- a/xen/drivers/passthrough/vtd/intremap.c Tue May 27 13:03:05 2008 +0100 1.2 +++ b/xen/drivers/passthrough/vtd/intremap.c Wed May 28 09:28:42 2008 +0100 1.3 @@ -48,14 +48,14 @@ static void remap_entry_to_ioapic_rte( 1.4 { 1.5 struct iremap_entry *iremap_entry = NULL, *iremap_entries; 1.6 struct IO_APIC_route_remap_entry *remap_rte; 1.7 - unsigned int index; 1.8 + int index = 0; 1.9 unsigned long flags; 1.10 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); 1.11 1.12 - if ( ir_ctrl == NULL ) 1.13 + if ( ir_ctrl == NULL || ir_ctrl->iremap_index < 0 ) 1.14 { 1.15 dprintk(XENLOG_ERR VTDPREFIX, 1.16 - "remap_entry_to_ioapic_rte: ir_ctl == NULL"); 1.17 + "remap_entry_to_ioapic_rte: ir_ctl is not ready\n"); 1.18 return; 1.19 } 1.20 1.21 @@ -63,11 +63,8 @@ static void remap_entry_to_ioapic_rte( 1.22 index = (remap_rte->index_15 << 15) + remap_rte->index_0_14; 1.23 1.24 if ( index > ir_ctrl->iremap_index ) 1.25 - { 1.26 - dprintk(XENLOG_ERR VTDPREFIX, 1.27 - "Index is larger than remap table entry size. Error!\n"); 1.28 - return; 1.29 - } 1.30 + panic("%s: index (%d) is larger than remap table entry size (%d)!\n", 1.31 + __func__, index, ir_ctrl->iremap_index); 1.32 1.33 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); 1.34 1.35 @@ -81,79 +78,90 @@ static void remap_entry_to_ioapic_rte( 1.36 old_rte->trigger = iremap_entry->lo.tm; 1.37 old_rte->__reserved_2 = 0; 1.38 old_rte->dest.logical.__reserved_1 = 0; 1.39 - old_rte->dest.logical.logical_dest = iremap_entry->lo.dst; 1.40 + old_rte->dest.logical.logical_dest = iremap_entry->lo.dst >> 8; 1.41 1.42 unmap_vtd_domain_page(iremap_entries); 1.43 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); 1.44 } 1.45 1.46 static void ioapic_rte_to_remap_entry(struct iommu *iommu, 1.47 - int apic_id, struct IO_APIC_route_entry *old_rte) 1.48 + int apic_id, struct IO_APIC_route_entry *old_rte, 1.49 + unsigned int rte_upper, unsigned int value) 1.50 { 1.51 struct iremap_entry *iremap_entry = NULL, *iremap_entries; 1.52 + struct iremap_entry new_ire; 1.53 struct IO_APIC_route_remap_entry *remap_rte; 1.54 - unsigned int index; 1.55 + struct IO_APIC_route_entry new_rte; 1.56 + int index; 1.57 unsigned long flags; 1.58 - int ret = 0; 1.59 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); 1.60 1.61 remap_rte = (struct IO_APIC_route_remap_entry *) old_rte; 1.62 spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); 1.63 - index = ir_ctrl->iremap_index; 1.64 - if ( index > IREMAP_ENTRY_NR - 1 ) 1.65 + 1.66 + if ( remap_rte->format == 0 ) 1.67 { 1.68 - dprintk(XENLOG_ERR VTDPREFIX, 1.69 - "The interrupt number is more than 256!\n"); 1.70 - goto out; 1.71 + ir_ctrl->iremap_index++; 1.72 + index = ir_ctrl->iremap_index; 1.73 } 1.74 + else 1.75 + index = (remap_rte->index_15 << 15) | remap_rte->index_0_14; 1.76 + 1.77 + if ( index > IREMAP_ENTRY_NR - 1 ) 1.78 + panic("ioapic_rte_to_remap_entry: intremap index is more than 256!\n"); 1.79 1.80 iremap_entries = 1.81 (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); 1.82 iremap_entry = &iremap_entries[index]; 1.83 1.84 - if ( *(u64 *)iremap_entry != 0 ) 1.85 - dprintk(XENLOG_WARNING VTDPREFIX, 1.86 - "Interrupt remapping entry is in use already!\n"); 1.87 - iremap_entry->lo.fpd = 0; 1.88 - iremap_entry->lo.dm = old_rte->dest_mode; 1.89 - iremap_entry->lo.rh = 0; 1.90 - iremap_entry->lo.tm = old_rte->trigger; 1.91 - iremap_entry->lo.dlm = old_rte->delivery_mode; 1.92 - iremap_entry->lo.avail = 0; 1.93 - iremap_entry->lo.res_1 = 0; 1.94 - iremap_entry->lo.vector = old_rte->vector; 1.95 - iremap_entry->lo.res_2 = 0; 1.96 - iremap_entry->lo.dst = (old_rte->dest.logical.logical_dest << 8); 1.97 - iremap_entry->hi.sid = apicid_to_bdf(apic_id); 1.98 - iremap_entry->hi.sq = 0; /* comparing all 16-bit of SID */ 1.99 - iremap_entry->hi.svt = 1; /* turn on requestor ID verification SID/SQ */ 1.100 - iremap_entry->hi.res_1 = 0; 1.101 - iremap_entry->lo.p = 1; /* finally, set present bit */ 1.102 - ir_ctrl->iremap_index++; 1.103 + memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry)); 1.104 + 1.105 + if ( rte_upper ) 1.106 + new_ire.lo.dst = (value >> 24) << 8; 1.107 + else 1.108 + { 1.109 + *(((u32 *)&new_rte) + 0) = value; 1.110 + new_ire.lo.fpd = 0; 1.111 + new_ire.lo.dm = new_rte.dest_mode; 1.112 + new_ire.lo.rh = 0; 1.113 + new_ire.lo.tm = new_rte.trigger; 1.114 + new_ire.lo.dlm = new_rte.delivery_mode; 1.115 + new_ire.lo.avail = 0; 1.116 + new_ire.lo.res_1 = 0; 1.117 + new_ire.lo.vector = new_rte.vector; 1.118 + new_ire.lo.res_2 = 0; 1.119 + new_ire.hi.sid = apicid_to_bdf(apic_id); 1.120 + 1.121 + new_ire.hi.sq = 0; /* comparing all 16-bit of SID */ 1.122 + new_ire.hi.svt = 1; /* requestor ID verification SID/SQ */ 1.123 + new_ire.hi.res_1 = 0; 1.124 + new_ire.lo.p = 1; /* finally, set present bit */ 1.125 + 1.126 + /* now construct new ioapic rte entry */ 1.127 + remap_rte->vector = new_rte.vector; 1.128 + remap_rte->delivery_mode = 0; /* has to be 0 for remap format */ 1.129 + remap_rte->index_15 = index & 0x8000; 1.130 + remap_rte->index_0_14 = index & 0x7fff; 1.131 + 1.132 + remap_rte->delivery_status = new_rte.delivery_status; 1.133 + remap_rte->polarity = new_rte.polarity; 1.134 + remap_rte->irr = new_rte.irr; 1.135 + remap_rte->trigger = new_rte.trigger; 1.136 + remap_rte->mask = new_rte.mask; 1.137 + remap_rte->reserved = 0; 1.138 + remap_rte->format = 1; /* indicate remap format */ 1.139 + } 1.140 + 1.141 + memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry)); 1.142 + iommu_flush_iec_index(iommu, 0, index); 1.143 + invalidate_sync(iommu); 1.144 1.145 unmap_vtd_domain_page(iremap_entries); 1.146 - iommu_flush_iec_index(iommu, 0, index); 1.147 - ret = invalidate_sync(iommu); 1.148 - 1.149 - /* now construct new ioapic rte entry */ 1.150 - remap_rte->vector = old_rte->vector; 1.151 - remap_rte->delivery_mode = 0; /* has to be 0 for remap format */ 1.152 - remap_rte->index_15 = index & 0x8000; 1.153 - remap_rte->index_0_14 = index & 0x7fff; 1.154 - remap_rte->delivery_status = old_rte->delivery_status; 1.155 - remap_rte->polarity = old_rte->polarity; 1.156 - remap_rte->irr = old_rte->irr; 1.157 - remap_rte->trigger = old_rte->trigger; 1.158 - remap_rte->mask = 1; 1.159 - remap_rte->reserved = 0; 1.160 - remap_rte->format = 1; /* indicate remap format */ 1.161 -out: 1.162 spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); 1.163 return; 1.164 } 1.165 1.166 -unsigned int 1.167 -io_apic_read_remap_rte( 1.168 +unsigned int io_apic_read_remap_rte( 1.169 unsigned int apic, unsigned int reg) 1.170 { 1.171 struct IO_APIC_route_entry old_rte = { 0 }; 1.172 @@ -198,15 +206,15 @@ io_apic_read_remap_rte( 1.173 } 1.174 } 1.175 1.176 -void 1.177 -io_apic_write_remap_rte( 1.178 +void io_apic_write_remap_rte( 1.179 unsigned int apic, unsigned int reg, unsigned int value) 1.180 { 1.181 struct IO_APIC_route_entry old_rte = { 0 }; 1.182 struct IO_APIC_route_remap_entry *remap_rte; 1.183 - int rte_upper = (reg & 1) ? 1 : 0; 1.184 + unsigned int rte_upper = (reg & 1) ? 1 : 0; 1.185 struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); 1.186 struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); 1.187 + int saved_mask; 1.188 1.189 if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) 1.190 { 1.191 @@ -225,21 +233,22 @@ io_apic_write_remap_rte( 1.192 *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4); 1.193 1.194 remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte; 1.195 - if ( remap_rte->mask || (remap_rte->format == 0) ) 1.196 - { 1.197 - *IO_APIC_BASE(apic) = rte_upper ? ++reg : reg; 1.198 - *(IO_APIC_BASE(apic)+4) = value; 1.199 - return; 1.200 - } 1.201 1.202 - *(((u32 *)&old_rte) + rte_upper) = value; 1.203 - ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid, &old_rte); 1.204 + /* mask the interrupt while we change the intremap table */ 1.205 + saved_mask = remap_rte->mask; 1.206 + remap_rte->mask = 1; 1.207 + *IO_APIC_BASE(apic) = reg; 1.208 + *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0); 1.209 + remap_rte->mask = saved_mask; 1.210 + 1.211 + ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid, 1.212 + &old_rte, rte_upper, value); 1.213 1.214 /* write new entry to ioapic */ 1.215 *IO_APIC_BASE(apic) = reg; 1.216 - *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0); 1.217 + *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0); 1.218 *IO_APIC_BASE(apic) = reg + 1; 1.219 - *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+1); 1.220 + *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1); 1.221 } 1.222 1.223 int intremap_setup(struct iommu *iommu) 1.224 @@ -260,6 +269,7 @@ int intremap_setup(struct iommu *iommu) 1.225 "Cannot allocate memory for ir_ctrl->iremap_maddr\n"); 1.226 return -ENODEV; 1.227 } 1.228 + ir_ctrl->iremap_index = -1; 1.229 } 1.230 1.231 #if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT)