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>
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)