debuggers.hg

changeset 22795:93e7bf0e1845

vt-d: quirks for Sandybridge errata workaround, WLAN, VT-d fault escalation

Adding errata workaround for newly released Sandybridge processor
graphics, additional WLAN device ID's for WLAN quirk, a quirk for
masking VT-d fault escalation to IOH HW that can cause system hangs on
some OEM hardware where the BIOS erroneously escalates VT-d faults to
the platform.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author Allen Kay <allen.m.kay@intel.com>
date Fri Jan 14 08:11:46 2011 +0000 (2011-01-14)
parents 47713825a3f9
children 4b7cb21caf0e
files xen/drivers/passthrough/vtd/extern.h xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/quirks.c
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/extern.h	Fri Jan 14 08:08:37 2011 +0000
     1.2 +++ b/xen/drivers/passthrough/vtd/extern.h	Fri Jan 14 08:11:46 2011 +0000
     1.3 @@ -86,5 +86,6 @@ void __init platform_quirks_init(void);
     1.4  void vtd_ops_preamble_quirk(struct iommu* iommu);
     1.5  void vtd_ops_postamble_quirk(struct iommu* iommu);
     1.6  void me_wifi_quirk(struct domain *domain, u8 bus, u8 devfn, int map);
     1.7 +void pci_vtd_quirk(struct pci_dev *pdev);
     1.8  
     1.9  #endif // _VTD_EXTERN_H_
     2.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Fri Jan 14 08:08:37 2011 +0000
     2.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Fri Jan 14 08:11:46 2011 +0000
     2.3 @@ -1914,6 +1914,7 @@ static void __init setup_dom0_devices(st
     2.4              list_add(&pdev->domain_list, &d->arch.pdev_list);
     2.5              domain_context_mapping(d, pdev->bus, pdev->devfn);
     2.6              pci_enable_acs(pdev);
     2.7 +            pci_vtd_quirk(pdev);
     2.8          }
     2.9      }
    2.10      spin_unlock(&pcidevs_lock);
     3.1 --- a/xen/drivers/passthrough/vtd/quirks.c	Fri Jan 14 08:08:37 2011 +0000
     3.2 +++ b/xen/drivers/passthrough/vtd/quirks.c	Fri Jan 14 08:11:46 2011 +0000
     3.3 @@ -47,11 +47,13 @@
     3.4  #define IS_CTG(id)    (id == 0x2a408086)
     3.5  #define IS_ILK(id)    (id == 0x00408086 || id == 0x00448086 || id== 0x00628086 || id == 0x006A8086)
     3.6  #define IS_CPT(id)    (id == 0x01008086 || id == 0x01048086)
     3.7 +#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 || id == 0x01268086 || id == 0x01028086 || id == 0x01128086 || id == 0x01228086 || id == 0x010A8086)
     3.8  
     3.9  u32 ioh_id;
    3.10  u32 igd_id;
    3.11  bool_t rwbf_quirk;
    3.12  static int is_cantiga_b3;
    3.13 +static int is_snb_gfx;
    3.14  static u8 *igd_reg_va;
    3.15  
    3.16  /*
    3.17 @@ -92,6 +94,12 @@ static void cantiga_b3_errata_init(void)
    3.18          is_cantiga_b3 = 1;
    3.19  }
    3.20  
    3.21 +/* check for Sandybridge IGD device ID's */
    3.22 +static void snb_errata_init(void)
    3.23 +{
    3.24 +    is_snb_gfx = IS_SNB_GFX(igd_id);
    3.25 +}
    3.26 +
    3.27  /*
    3.28   * QUIRK to workaround Cantiga IGD VT-d low power errata.
    3.29   * This errata impacts IGD assignment on Cantiga systems
    3.30 @@ -104,12 +112,15 @@ static void cantiga_b3_errata_init(void)
    3.31  /*
    3.32   * map IGD MMIO+0x2000 page to allow Xen access to IGD 3D register.
    3.33   */
    3.34 -static void map_igd_reg(void)
    3.35 +static void *map_igd_reg(void)
    3.36  {
    3.37      u64 igd_mmio, igd_reg;
    3.38  
    3.39 -    if ( !is_cantiga_b3 || igd_reg_va != NULL )
    3.40 -        return;
    3.41 +    if ( !is_cantiga_b3 && !is_snb_gfx )
    3.42 +        return NULL;
    3.43 +
    3.44 +    if ( igd_reg_va )
    3.45 +        return igd_reg_va;
    3.46  
    3.47      /* get IGD mmio address in PCI BAR */
    3.48      igd_mmio = ((u64)pci_conf_read32(0, IGD_DEV, 0, 0x14) << 32) +
    3.49 @@ -125,6 +136,7 @@ static void map_igd_reg(void)
    3.50  #else
    3.51      igd_reg_va = ioremap_nocache(igd_reg, 0x100);
    3.52  #endif
    3.53 +    return igd_reg_va;
    3.54  }
    3.55  
    3.56  /*
    3.57 @@ -138,6 +150,9 @@ static int cantiga_vtd_ops_preamble(stru
    3.58      if ( !is_igd_drhd(drhd) || !is_cantiga_b3 )
    3.59          return 0;
    3.60  
    3.61 +    if ( !map_igd_reg() )
    3.62 +        return 0;
    3.63 +
    3.64      /*
    3.65       * read IGD register at IGD MMIO + 0x20A4 to force IGD
    3.66       * to exit low power state.  Since map_igd_reg()
    3.67 @@ -148,11 +163,64 @@ static int cantiga_vtd_ops_preamble(stru
    3.68  }
    3.69  
    3.70  /*
    3.71 + * Sandybridge RC6 power management inhibit state erratum.
    3.72 + * This can cause power high power consumption.
    3.73 + * Workaround is to prevent graphics get into RC6
    3.74 + * state when doing VT-d IOTLB operations, do the VT-d
    3.75 + * IOTLB operation, and then re-enable RC6 state.
    3.76 + */
    3.77 +static void snb_vtd_ops_preamble(struct iommu* iommu)
    3.78 +{
    3.79 +    struct intel_iommu *intel = iommu->intel;
    3.80 +    struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
    3.81 +    s_time_t start_time;
    3.82 +
    3.83 +    if ( !is_igd_drhd(drhd) || !is_snb_gfx )
    3.84 +        return;
    3.85 +
    3.86 +    if ( !map_igd_reg() )
    3.87 +        return;
    3.88 +
    3.89 +    *((volatile u32 *)(igd_reg_va + 0x54)) = 0x000FFFFF;
    3.90 +    *((volatile u32 *)(igd_reg_va + 0x700)) = 0;
    3.91 +
    3.92 +    start_time = NOW();
    3.93 +    while ( (*((volatile u32 *)(igd_reg_va + 0x2AC)) & 0xF) != 0 )
    3.94 +    {
    3.95 +        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
    3.96 +        {
    3.97 +            dprintk(XENLOG_INFO VTDPREFIX,
    3.98 +                    "snb_vtd_ops_preamble: failed to disable idle handshake\n");
    3.99 +            break;
   3.100 +        }
   3.101 +        cpu_relax();
   3.102 +    }
   3.103 +
   3.104 +    *((volatile u32*)(igd_reg_va + 0x50)) = 0x10001;
   3.105 +}
   3.106 +
   3.107 +static void snb_vtd_ops_postamble(struct iommu* iommu)
   3.108 +{
   3.109 +    struct intel_iommu *intel = iommu->intel;
   3.110 +    struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL;
   3.111 +
   3.112 +    if ( !is_igd_drhd(drhd) || !is_snb_gfx )
   3.113 +        return;
   3.114 +
   3.115 +    if ( !map_igd_reg() )
   3.116 +        return;
   3.117 +
   3.118 +    *((volatile u32 *)(igd_reg_va + 0x54)) = 0xA;
   3.119 +    *((volatile u32 *)(igd_reg_va + 0x50)) = 0x10000;
   3.120 +}
   3.121 +
   3.122 +/*
   3.123   * call before VT-d translation enable and IOTLB flush operations.
   3.124   */
   3.125  void vtd_ops_preamble_quirk(struct iommu* iommu)
   3.126  {
   3.127      cantiga_vtd_ops_preamble(iommu);
   3.128 +    snb_vtd_ops_preamble(iommu);
   3.129  }
   3.130  
   3.131  /*
   3.132 @@ -160,7 +228,7 @@ void vtd_ops_preamble_quirk(struct iommu
   3.133   */
   3.134  void vtd_ops_postamble_quirk(struct iommu* iommu)
   3.135  {
   3.136 -    return;
   3.137 +    snb_vtd_ops_postamble(iommu);
   3.138  }
   3.139  
   3.140  /* initialize platform identification flags */
   3.141 @@ -179,6 +247,8 @@ void __init platform_quirks_init(void)
   3.142      /* initialize cantiga B3 identification */
   3.143      cantiga_b3_errata_init();
   3.144  
   3.145 +    snb_errata_init();
   3.146 +
   3.147      /* ioremap IGD MMIO+0x2000 page */
   3.148      map_igd_reg();
   3.149  }
   3.150 @@ -250,11 +320,14 @@ void me_wifi_quirk(struct domain *domain
   3.151          id = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
   3.152          switch (id)
   3.153          {
   3.154 -            case 0x00878086:
   3.155 +            case 0x00878086:        /* Kilmer Peak */
   3.156              case 0x00898086:
   3.157 -            case 0x00828086:
   3.158 +            case 0x00828086:        /* Taylor Peak */
   3.159              case 0x00858086:
   3.160 -            case 0x42388086:
   3.161 +            case 0x008F8086:        /* Rainbow Peak */
   3.162 +            case 0x00908086:
   3.163 +            case 0x00918086:
   3.164 +            case 0x42388086:        /* Puma Peak */
   3.165              case 0x422b8086:
   3.166              case 0x422c8086:
   3.167                  map_me_phantom_function(domain, 22, map);
   3.168 @@ -262,6 +335,26 @@ void me_wifi_quirk(struct domain *domain
   3.169              default:
   3.170                  break;
   3.171          }
   3.172 -
   3.173      }
   3.174  }
   3.175 +
   3.176 +/*
   3.177 + * Mask reporting Intel VT-d faults to IOH core logic:
   3.178 + *   - Some platform escalates VT-d faults to platform errors 
   3.179 + *   - This can cause system failure upon non-fatal VT-d faults
   3.180 + *   - Potential security issue if malicious guest trigger VT-d faults
   3.181 + */
   3.182 +void pci_vtd_quirk(struct pci_dev *pdev)
   3.183 +{
   3.184 +    int bus = pdev->bus;
   3.185 +    int dev = PCI_SLOT(pdev->devfn);
   3.186 +    int func = PCI_FUNC(pdev->devfn);
   3.187 +    int id, val;
   3.188 +
   3.189 +    id = pci_conf_read32(bus, dev, func, 0);
   3.190 +    if ( id == 0x342e8086 || id == 0x3c288086 )
   3.191 +    {
   3.192 +        val = pci_conf_read32(bus, dev, func, 0x1AC);
   3.193 +        pci_conf_write32(bus, dev, func, 0x1AC, val | (1 << 31));
   3.194 +    }
   3.195 +}