@@ -29,6 +29,7 @@
#include <linux/sched.h>
#include <linux/ktime.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
+#include <asm/io.h>
#include "pci.h"
/*
@@ -3085,11 +3086,58 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
return 0;
}
+#include "../gpu/drm/i915/i915_reg.h"
+#define MSG_CTL 0x45010
+#define IGD_OPERATION_TIMEOUT 10000 /* set timeout 10 seconds */
+
+static int reset_ivb_igd(struct pci_dev *dev, int probe) {
+ void __iomem *mmio_base;
+ unsigned long timeout;
+ u32 val;
+
+ if (probe)
+ return 0;
+
+ mmio_base = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!mmio_base)
+ return -ENOMEM;
+
+ /* Work Around */
+ writel(0x00000002, mmio_base + MSG_CTL);
+ /* Clobbering SOUTH_CHICKEN2 register is fine only if the next
+ * driver loaded sets the right bits. However, this's a reset and
+ * the bits have been set by i915 previously, so we clobber
+ * SOUTH_CHICKEN2 register directly here.
+ */
+ writel(0x00000005, mmio_base + SOUTH_CHICKEN2);
+ val = readl(mmio_base + PCH_PP_CONTROL) & 0xfffffffe;
+ writel(val, mmio_base + PCH_PP_CONTROL);
+ timeout = jiffies + msecs_to_jiffies(IGD_OPERATION_TIMEOUT);
+ while (time_before(jiffies, timeout)) {
+ val = readl(mmio_base + PCH_PP_STATUS);
+ if ((val & 0xB0000000) == 0)
+ break;
+ cpu_relax();
+ }
+ writel(0x00000002, mmio_base + 0xd0100);
+
+ iounmap(pci_resource_start(dev, 0));
+ return 0;
+}
+
#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
+#define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156
+#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M_VGA,
+ reset_ivb_igd },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA,
+ reset_ivb_igd },
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
reset_intel_generic_dev },
{ 0 }
--
1.6.0.rc1