#define PCIBACK_CLASS_ID_USB 0x0c03
#define PCIBACK_CLASS_ID_VGA 0x0300
#define PCIBACK_USB_FLRCTRL 0x4
-#define PCIBACK_IGFX_FLRCTRL 0x4
#define PCIBACK_IGFX_CAP09_OFFSET 0xa4
#define PCIBACK_IGFX_CAP13_OFFSET 0xa4
-#define PCIBACK_IGFX_MEDIARST 0xd0
+#define PCIBACK_IGFX_MEDIARST 0x0d
#define PCIBACK_IGFX_MEDIARST_OFFSET 0xc0
int verbose_request = 0;
*/
static void pciback_do_pci_flr(struct pci_dev *dev, int af_pos)
{
+ u8 status;
+
pci_block_user_cfg_access(dev);
-
+
+ /* Clear the command register to prevent new transactions */
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+
+ /* Wait for Transaction Pending bit clean */
+ msleep(100);
+ pci_read_config_byte(dev, af_pos + PCI_AF_STA, &status);
+ if (status & PCI_AF_STA_TP) {
+ dev_dbg(&dev->dev, "Busy after 100ms while trying to reset; sleeping for 1 second\n");
+ ssleep(1);
+ pci_read_config_byte(dev, af_pos + PCI_AF_STA, &status);
+ if (status & PCI_AF_STA_TP)
+ dev_warn(&dev->dev, "Still busy after 1s; proceeding with reset anyway\n");
+ }
+
pci_write_config_word(dev, af_pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
mdelay(200);
-
+
pciback_reload_config_space(dev);
pci_unblock_user_cfg_access(dev);
/* Correct device and platform, assume vendor specific offset */
pci_read_config_dword(dev, PCIBACK_IGFX_CAP09_OFFSET, ®32);
- if ((reg32 & 0x000000F0) != 0x20 ||
+ if ((reg32 & 0x000000FF) != PCI_CAP_ID_VNDR ||
((reg32 >> 16) & 0x000000FF) != 0x06 ||
- ((reg32 >> 24) & 0x000000FF) != PCI_CAP_ID_VNDR)
+ ((reg32 >> 24) & 0x000000F0) != 0x20)
return -ENXIO;
vendor_pos = PCIBACK_IGFX_CAP09_OFFSET;
return -ENXIO;
}
else
- return -ENXIO;
-
- pci_block_user_cfg_access(dev);
+ return -ENXIO;
if (class_id == PCIBACK_CLASS_ID_VGA) {
pci_write_config_byte(dev, PCIBACK_IGFX_MEDIARST_OFFSET, PCIBACK_IGFX_MEDIARST);
goto out;
}
}
- pci_write_config_byte(dev, vendor_pos + PCIBACK_IGFX_FLRCTRL, 1);
+
+ /* The rest is the same as a PCI AF FLR */
+ pciback_do_pci_flr(dev, vendor_pos);
} else {
+ pci_block_user_cfg_access(dev);
+
pci_write_config_byte(dev, vendor_pos + PCIBACK_USB_FLRCTRL, 1);
- }
- mdelay(200);
+ mdelay(200);
- pciback_reload_config_space(dev);
+ pciback_reload_config_space(dev);
-out:
- pci_unblock_user_cfg_access(dev);
+ pci_unblock_user_cfg_access(dev);
+ }
+out:
return 0;
}
pci_read_config_word(gmch, PCI_DEVICE_ID, &device_id);
pci_dev_put(gmch);
- if (device_id != PCI_DEVICE_ID_INTEL_GMCHQ45 ||
- device_id != PCI_DEVICE_ID_INTEL_GMCHG45 ||
+ if (device_id != PCI_DEVICE_ID_INTEL_GMCHQ45 &&
+ device_id != PCI_DEVICE_ID_INTEL_GMCHG45 &&
device_id != PCI_DEVICE_ID_INTEL_GMCHG41)
break;