ia64/xen-unstable

changeset 18372:62b904dcf88c

vtd: Fix ioapic interrupt remapping

Besides io_apic_write(), io_apic_modify() also writes to io apic RTE.
This patch adds an intercept to remap interrupt in io_apic_modify().

In io_apic_read_remap_rte(), 'mask' value of RTE should not affect the
return value, so remove its checking.

Finally, remove panic() when index overflows. Instead, print error
messages and report back the failure to upper level.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Aug 26 13:00:43 2008 +0100 (2008-08-26)
parents 21294d41c26e
children 493a0a87919e
files xen/drivers/passthrough/vtd/intremap.c xen/include/asm-x86/io_apic.h
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/intremap.c	Tue Aug 26 10:14:32 2008 +0100
     1.2 +++ b/xen/drivers/passthrough/vtd/intremap.c	Tue Aug 26 13:00:43 2008 +0100
     1.3 @@ -43,7 +43,7 @@ u16 apicid_to_bdf(int apic_id)
     1.4      return 0;
     1.5  }
     1.6  
     1.7 -static void remap_entry_to_ioapic_rte(
     1.8 +static int remap_entry_to_ioapic_rte(
     1.9      struct iommu *iommu, struct IO_APIC_route_entry *old_rte)
    1.10  {
    1.11      struct iremap_entry *iremap_entry = NULL, *iremap_entries;
    1.12 @@ -56,15 +56,19 @@ static void remap_entry_to_ioapic_rte(
    1.13      {
    1.14          dprintk(XENLOG_ERR VTDPREFIX,
    1.15                  "remap_entry_to_ioapic_rte: ir_ctl is not ready\n");
    1.16 -        return;
    1.17 +        return -EFAULT;
    1.18      }
    1.19  
    1.20      remap_rte = (struct IO_APIC_route_remap_entry *) old_rte;
    1.21      index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
    1.22  
    1.23      if ( index > ir_ctrl->iremap_index )
    1.24 -        panic("%s: index (%d) is larger than remap table entry size (%d)!\n",
    1.25 -              __func__, index, ir_ctrl->iremap_index);
    1.26 +    {
    1.27 +        dprintk(XENLOG_ERR VTDPREFIX,
    1.28 +                "%s: index (%d) is larger than remap table entry size (%d)!\n",
    1.29 +                __func__, index, ir_ctrl->iremap_index);
    1.30 +        return -EFAULT;
    1.31 +    }
    1.32  
    1.33      spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
    1.34  
    1.35 @@ -82,9 +86,10 @@ static void remap_entry_to_ioapic_rte(
    1.36  
    1.37      unmap_vtd_domain_page(iremap_entries);
    1.38      spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
    1.39 +    return 0;
    1.40  }
    1.41  
    1.42 -static void ioapic_rte_to_remap_entry(struct iommu *iommu,
    1.43 +static int ioapic_rte_to_remap_entry(struct iommu *iommu,
    1.44      int apic_id, struct IO_APIC_route_entry *old_rte,
    1.45      unsigned int rte_upper, unsigned int value)
    1.46  {
    1.47 @@ -108,7 +113,14 @@ static void ioapic_rte_to_remap_entry(st
    1.48          index = (remap_rte->index_15 << 15) | remap_rte->index_0_14;
    1.49  
    1.50      if ( index > IREMAP_ENTRY_NR - 1 )
    1.51 -        panic("ioapic_rte_to_remap_entry: intremap index is more than 256!\n");
    1.52 +    {
    1.53 +        dprintk(XENLOG_ERR VTDPREFIX,
    1.54 +                "%s: intremap index (%d) is larger than"
    1.55 +                " the maximum index (%ld)!\n",
    1.56 +                __func__, index, IREMAP_ENTRY_NR - 1);
    1.57 +        spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
    1.58 +        return -EFAULT;
    1.59 +    }
    1.60  
    1.61      iremap_entries =
    1.62          (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr);
    1.63 @@ -159,7 +171,7 @@ static void ioapic_rte_to_remap_entry(st
    1.64  
    1.65      unmap_vtd_domain_page(iremap_entries);
    1.66      spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
    1.67 -    return;
    1.68 +    return 0;
    1.69  }
    1.70  
    1.71  unsigned int io_apic_read_remap_rte(
    1.72 @@ -189,23 +201,22 @@ unsigned int io_apic_read_remap_rte(
    1.73  
    1.74      remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
    1.75  
    1.76 -    if ( remap_rte->mask || (remap_rte->format == 0) )
    1.77 +    if ( remap_rte->format == 0 )
    1.78      {
    1.79 -        *IO_APIC_BASE(apic) = reg;
    1.80 +        *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
    1.81          return *(IO_APIC_BASE(apic)+4);
    1.82      }
    1.83  
    1.84 -    remap_entry_to_ioapic_rte(iommu, &old_rte);
    1.85 +    if ( remap_entry_to_ioapic_rte(iommu, &old_rte) )
    1.86 +    {
    1.87 +        *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
    1.88 +        return *(IO_APIC_BASE(apic)+4);
    1.89 +    }
    1.90 +
    1.91      if ( rte_upper )
    1.92 -    {
    1.93 -        *IO_APIC_BASE(apic) = reg + 1;
    1.94          return (*(((u32 *)&old_rte) + 1));
    1.95 -    }
    1.96      else
    1.97 -    {
    1.98 -        *IO_APIC_BASE(apic) = reg;
    1.99          return (*(((u32 *)&old_rte) + 0));
   1.100 -    }
   1.101  }
   1.102  
   1.103  void io_apic_write_remap_rte(
   1.104 @@ -243,8 +254,13 @@ void io_apic_write_remap_rte(
   1.105      *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0);
   1.106      remap_rte->mask = saved_mask;
   1.107  
   1.108 -    ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid,
   1.109 -                              &old_rte, rte_upper, value);
   1.110 +    if ( ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid,
   1.111 +                                   &old_rte, rte_upper, value) )
   1.112 +    {
   1.113 +        *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
   1.114 +        *(IO_APIC_BASE(apic)+4) = value;
   1.115 +        return;
   1.116 +    }
   1.117  
   1.118      /* write new entry to ioapic */
   1.119      *IO_APIC_BASE(apic) = reg;
   1.120 @@ -253,7 +269,7 @@ void io_apic_write_remap_rte(
   1.121      *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
   1.122  }
   1.123  
   1.124 -static void remap_entry_to_msi_msg(
   1.125 +static int remap_entry_to_msi_msg(
   1.126      struct iommu *iommu, struct msi_msg *msg)
   1.127  {
   1.128      struct iremap_entry *iremap_entry = NULL, *iremap_entries;
   1.129 @@ -266,7 +282,7 @@ static void remap_entry_to_msi_msg(
   1.130      {
   1.131          dprintk(XENLOG_ERR VTDPREFIX,
   1.132                  "remap_entry_to_msi_msg: ir_ctl == NULL");
   1.133 -        return;
   1.134 +        return -EFAULT;
   1.135      }
   1.136  
   1.137      remap_rte = (struct msi_msg_remap_entry *) msg;
   1.138 @@ -274,8 +290,12 @@ static void remap_entry_to_msi_msg(
   1.139               remap_rte->address_lo.index_0_14;
   1.140  
   1.141      if ( index > ir_ctrl->iremap_index )
   1.142 -        panic("%s: index (%d) is larger than remap table entry size (%d)\n",
   1.143 -              __func__, index, ir_ctrl->iremap_index);
   1.144 +    {
   1.145 +        dprintk(XENLOG_ERR VTDPREFIX,
   1.146 +                "%s: index (%d) is larger than remap table entry size (%d)\n",
   1.147 +                __func__, index, ir_ctrl->iremap_index);
   1.148 +        return -EFAULT;
   1.149 +    }
   1.150  
   1.151      spin_lock_irqsave(&ir_ctrl->iremap_lock, flags);
   1.152  
   1.153 @@ -304,9 +324,10 @@ static void remap_entry_to_msi_msg(
   1.154  
   1.155      unmap_vtd_domain_page(iremap_entries);
   1.156      spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
   1.157 +    return 0;
   1.158  }
   1.159  
   1.160 -static void msi_msg_to_remap_entry(
   1.161 +static int msi_msg_to_remap_entry(
   1.162      struct iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg)
   1.163  {
   1.164      struct iremap_entry *iremap_entry = NULL, *iremap_entries;
   1.165 @@ -343,7 +364,15 @@ static void msi_msg_to_remap_entry(
   1.166          index = i;
   1.167  
   1.168      if ( index > IREMAP_ENTRY_NR - 1 )
   1.169 -        panic("msi_msg_to_remap_entry: intremap index is more than 256!\n");
   1.170 +    {
   1.171 +        dprintk(XENLOG_ERR VTDPREFIX,
   1.172 +                "%s: intremap index (%d) is larger than"
   1.173 +                " the maximum index (%ld)!\n",
   1.174 +                __func__, index, IREMAP_ENTRY_NR - 1);
   1.175 +        unmap_vtd_domain_page(iremap_entries);
   1.176 +        spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
   1.177 +        return -EFAULT;
   1.178 +    }
   1.179  
   1.180      iremap_entry = &iremap_entries[index];
   1.181      memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry));
   1.182 @@ -385,7 +414,7 @@ static void msi_msg_to_remap_entry(
   1.183  
   1.184      unmap_vtd_domain_page(iremap_entries);
   1.185      spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);
   1.186 -    return;
   1.187 +    return 0;
   1.188  }
   1.189  
   1.190  void msi_msg_read_remap_rte(
     2.1 --- a/xen/include/asm-x86/io_apic.h	Tue Aug 26 10:14:32 2008 +0100
     2.2 +++ b/xen/include/asm-x86/io_apic.h	Tue Aug 26 13:00:43 2008 +0100
     2.3 @@ -125,7 +125,7 @@ extern int mpc_default_type;
     2.4  
     2.5  static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
     2.6  {
     2.7 -	if (vtd_enabled)
     2.8 +	if (iommu_enabled)
     2.9  		return io_apic_read_remap_rte(apic, reg);
    2.10  	*IO_APIC_BASE(apic) = reg;
    2.11  	return *(IO_APIC_BASE(apic)+4);
    2.12 @@ -152,6 +152,8 @@ extern int sis_apic_bug;
    2.13  #endif
    2.14  static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
    2.15  {
    2.16 +	if (iommu_enabled)
    2.17 +		return iommu_update_ire_from_apic(apic, reg, value);
    2.18  	if (sis_apic_bug)
    2.19  		*IO_APIC_BASE(apic) = reg;
    2.20  	*(IO_APIC_BASE(apic)+4) = value;