ia64/xen-unstable

changeset 17496:da261c25f160

vt-d: Fix a bug in addr_to_dma_page_maddr(), and add timeout in infinite loop

In addr_to_dma_page_maddr(), pte should not be used after
unmap_vtd_domain_page(parent). In addition, timeout is added in some
infinite loops.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 22 10:20:05 2008 +0100 (2008-04-22)
parents 65802c51edb5
children d9a74b8e9b1a
files xen/drivers/passthrough/vtd/iommu.c
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Tue Apr 22 10:18:13 2008 +0100
     1.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Tue Apr 22 10:20:05 2008 +0100
     1.3 @@ -229,11 +229,7 @@ static u64 addr_to_dma_page_maddr(struct
     1.4              dma_set_pte_addr(*pte, maddr);
     1.5              vaddr = map_vtd_domain_page(maddr);
     1.6              if ( !vaddr )
     1.7 -            {
     1.8 -                unmap_vtd_domain_page(parent);
     1.9 -                spin_unlock_irqrestore(&hd->mapping_lock, flags);
    1.10 -                return 0;
    1.11 -            }
    1.12 +                break;
    1.13  
    1.14              /*
    1.15               * high level table always sets r/w, last level
    1.16 @@ -247,14 +243,9 @@ static u64 addr_to_dma_page_maddr(struct
    1.17          {
    1.18              vaddr = map_vtd_domain_page(pte->val);
    1.19              if ( !vaddr )
    1.20 -            {
    1.21 -                unmap_vtd_domain_page(parent);
    1.22 -                spin_unlock_irqrestore(&hd->mapping_lock, flags);
    1.23 -                return 0;
    1.24 -            }
    1.25 +                break;
    1.26          }
    1.27  
    1.28 -        unmap_vtd_domain_page(parent);
    1.29          if ( level == 2 )
    1.30          {
    1.31              pte_maddr = pte->val & PAGE_MASK_4K;
    1.32 @@ -262,11 +253,13 @@ static u64 addr_to_dma_page_maddr(struct
    1.33              break;
    1.34          }
    1.35  
    1.36 +        unmap_vtd_domain_page(parent);
    1.37          parent = (struct dma_pte *)vaddr;
    1.38          vaddr = NULL;
    1.39          level--;
    1.40      }
    1.41  
    1.42 +    unmap_vtd_domain_page(parent);
    1.43      spin_unlock_irqrestore(&hd->mapping_lock, flags);
    1.44      return pte_maddr;
    1.45  }
    1.46 @@ -641,7 +634,7 @@ void dma_pte_free_pagetable(struct domai
    1.47      struct dma_pte *page, *pte;
    1.48      int total = agaw_to_level(hd->agaw);
    1.49      int level;
    1.50 -    u32 tmp;
    1.51 +    u64 tmp;
    1.52      u64 pg_maddr;
    1.53  
    1.54      drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
    1.55 @@ -662,7 +655,10 @@ void dma_pte_free_pagetable(struct domai
    1.56          {
    1.57              pg_maddr = dma_addr_level_page_maddr(domain, tmp, level);
    1.58              if ( pg_maddr == 0 )
    1.59 -                return;
    1.60 +            {
    1.61 +                tmp += level_size(level);
    1.62 +                continue;
    1.63 +            }
    1.64              page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
    1.65              pte = page + address_level_offset(tmp, level);
    1.66              dma_clear_pte(*pte);
    1.67 @@ -688,6 +684,7 @@ static int iommu_set_root_entry(struct i
    1.68  {
    1.69      u32 cmd, sts;
    1.70      unsigned long flags;
    1.71 +    s_time_t start_time;
    1.72  
    1.73      if ( iommu == NULL )
    1.74      {
    1.75 @@ -713,11 +710,14 @@ static int iommu_set_root_entry(struct i
    1.76      dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd);
    1.77  
    1.78      /* Make sure hardware complete it */
    1.79 +    start_time = NOW();
    1.80      for ( ; ; )
    1.81      {
    1.82          sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    1.83          if ( sts & DMA_GSTS_RTPS )
    1.84              break;
    1.85 +        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
    1.86 +            panic("DMAR hardware is malfunctional, please disable IOMMU\n");
    1.87          cpu_relax();
    1.88      }
    1.89  
    1.90 @@ -730,6 +730,7 @@ static int iommu_enable_translation(stru
    1.91  {
    1.92      u32 sts;
    1.93      unsigned long flags;
    1.94 +    s_time_t start_time;
    1.95  
    1.96      dprintk(XENLOG_INFO VTDPREFIX,
    1.97              "iommu_enable_translation: iommu->reg = %p\n", iommu->reg);
    1.98 @@ -737,11 +738,14 @@ static int iommu_enable_translation(stru
    1.99      iommu->gcmd |= DMA_GCMD_TE;
   1.100      dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
   1.101      /* Make sure hardware complete it */
   1.102 +    start_time = NOW();
   1.103      for ( ; ; )
   1.104      {
   1.105          sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
   1.106          if ( sts & DMA_GSTS_TES )
   1.107              break;
   1.108 +        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
   1.109 +            panic("DMAR hardware is malfunctional, please disable IOMMU\n");
   1.110          cpu_relax();
   1.111      }
   1.112  
   1.113 @@ -755,17 +759,21 @@ int iommu_disable_translation(struct iom
   1.114  {
   1.115      u32 sts;
   1.116      unsigned long flags;
   1.117 +    s_time_t start_time;
   1.118  
   1.119      spin_lock_irqsave(&iommu->register_lock, flags);
   1.120      iommu->gcmd &= ~ DMA_GCMD_TE;
   1.121      dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
   1.122  
   1.123      /* Make sure hardware complete it */
   1.124 +    start_time = NOW();
   1.125      for ( ; ; )
   1.126      {
   1.127          sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
   1.128          if ( !(sts & DMA_GSTS_TES) )
   1.129              break;
   1.130 +        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
   1.131 +            panic("DMAR hardware is malfunctional, please disable IOMMU\n");
   1.132          cpu_relax();
   1.133      }
   1.134      spin_unlock_irqrestore(&iommu->register_lock, flags);