/* * Sandybridge RC6 power management inhibit state erratum. * This can cause power high power consumption. * Workaround is to prevent graphics get into RC6 * state when doing VT-d IOTLB operations, do the VT-d * IOTLB operation, and then re-enable RC6 state. */ static void snb_vtd_ops_preamble(struct iommu* iommu) { struct intel_iommu *intel = iommu->intel; struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL; s_time_t start_time; if ( !is_igd_drhd(drhd) || !is_snb_gfx ) return; if ( !map_igd_reg() ) return; *((volatile u32 *)(igd_reg_va + 0x54)) = 0x000FFFFF; *((volatile u32 *)(igd_reg_va + 0x700)) = 0; start_time = NOW(); while ( (*((volatile u32 *)(igd_reg_va + 0x2AC)) & 0xF) != 0 ) { if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT ) { dprintk(XENLOG_INFO VTDPREFIX, "snb_vtd_ops_preamble: failed to disable idle handshake\n"); break; } cpu_relax(); } *((volatile u32*)(igd_reg_va + 0x50)) = 0x10001; }
static void snb_vtd_ops_postamble(struct iommu* iommu) { struct intel_iommu *intel = iommu->intel; struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL; if ( !is_igd_drhd(drhd) || !is_snb_gfx ) return; if ( !map_igd_reg() ) return; *((volatile u32 *)(igd_reg_va + 0x54)) = 0xA; *((volatile u32 *)(igd_reg_va + 0x50)) = 0x10000; }
/* * force IGD to exit low power mode by accessing a IGD 3D regsiter. */ static int cantiga_vtd_ops_preamble(struct iommu* iommu) { struct intel_iommu *intel = iommu->intel; struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL; if ( !is_igd_drhd(drhd) || !is_cantiga_b3 ) return 0; if ( !igd_reg_va ) return 0; /* * Read IGD register at IGD MMIO + 0x20A4 to force IGD * to exit low power state. */ return *(volatile int *)(igd_reg_va + 0x20A4); }
/* * force IGD to exit low power mode by accessing a IGD 3D regsiter. */ static int cantiga_vtd_ops_preamble(struct iommu* iommu) { struct intel_iommu *intel = iommu->intel; struct acpi_drhd_unit *drhd = intel ? intel->drhd : NULL; if ( !is_igd_drhd(drhd) || !is_cantiga_b3 ) return 0; if ( !map_igd_reg() ) return 0; /* * read IGD register at IGD MMIO + 0x20A4 to force IGD * to exit low power state. Since map_igd_reg() * already mapped page starting 0x2000, we just need to * add page offset 0x0A4 to virtual address base. */ return ( *((volatile int *)(igd_reg_va + 0x0A4)) ); }