#include <xen/evtchn.h>
#include "pciback.h"
+#define PCIBACK_VENDOR_INTEL 0x8086
+#define PCIBACK_DEVICE_IGFX_GM45 0x2a42
+#define PCIBACK_DEVICE_IGFX_Q45 0x2e12
+#define PCIBACK_CLASS_ID_USB 0x0c03
+#define PCIBACK_CLASS_ID_VGA 0x0c00
+#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_OFFSET 0xc0
+
int verbose_request = 0;
module_param(verbose_request, int, 0644);
}
/* Vendor specific resets. These can be set in the vendor specific
- * capabilities structures. Currently only the Intel USB reset
- * is supported.
+ * capabilities structures. Currently only the Intel USB and iGFX
+ * reset is supported.
*/
static int pciback_do_vendor_specific_reset(struct pci_dev *dev)
{
-#define PCIBACK_VENDOR_INTEL 0x8086
-#define PCIBACK_CLASS_ID_USB 0x0c03
-#define PCIBACK_USB_FLRCTRL 0x4
- int vendor_pos;
+ int vendor_pos, i;
u16 vendor_id;
+ u16 device_id;
u16 class_id;
+ u32 reg32;
+ u8 reg8;
- vendor_pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
- if (vendor_pos == 0)
- return -ENXIO;
-
pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
if (vendor_id != PCIBACK_VENDOR_INTEL)
return -ENXIO;
pci_read_config_word(dev, PCI_CLASS_DEVICE, &class_id);
- if (class_id != PCIBACK_CLASS_ID_USB)
+ if (class_id == PCIBACK_CLASS_ID_VGA) {
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
+ if (device_id == PCIBACK_DEVICE_IGFX_GM45) /* TODO sufficient test ?*/
+ return -ENXIO;
+
+ pci_read_config_dword(dev, PCIBACK_IGFX_CAP09_OFFSET, ®32);
+ if ((reg32 & 0x000000F0) != 0x20 ||
+ ((reg32 >> 16) & 0x000000FF) != 0x06 ||
+ ((reg32 >> 24) & 0x000000FF) != PCI_CAP_ID_VNDR)
+ return -ENXIO;
+
+ vendor_pos = PCIBACK_IGFX_CAP09_OFFSET;
+ } else if (class_id == PCIBACK_CLASS_ID_USB) {
+ vendor_pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
+ if (vendor_pos == 0)
+ return -ENXIO;
+ }
+ else
return -ENXIO;
pci_block_user_cfg_access(dev);
- pci_write_config_byte(dev, vendor_pos + PCIBACK_USB_FLRCTRL, 1);
- mdelay(100);
+ if (class_id == PCIBACK_CLASS_ID_VGA) {
+ pci_write_config_byte(dev, PCIBACK_IGFX_MEDIARST_OFFSET, PCIBACK_IGFX_MEDIARST);
+ for (i = 0; i <= 10; i++) {
+ msleep(100);
+ pci_read_config_byte(dev, PCIBACK_IGFX_MEDIARST_OFFSET, ®8);
+ if ((reg8 & 0x01) == 0)
+ break;
+ if (i == 10) {
+ dev_warn(&dev->dev, "media not reset after 1s; skipping FLR\n");
+ goto out;
+ }
+ }
+ pci_write_config_byte(dev, vendor_pos + PCIBACK_IGFX_FLRCTRL, 1);
+ } else {
+ pci_write_config_byte(dev, vendor_pos + PCIBACK_USB_FLRCTRL, 1);
+ }
+ mdelay(200);
pciback_reload_config_space(dev);
+out:
pci_unblock_user_cfg_access(dev);
return 0;
}
}
- /* Next look for the unchained PCIe capabilities for FLR using specific logic */
- /* TODO */
-
- /* Else not found */
return 0;
}
static int pciback_find_pci_flr_caps(struct pci_dev *dev)
{
int af_pos;
- u8 cap;
+ u8 cap;
+ u16 vendor_id;
+ u16 device_id;
+ u8 reg8;
/* First look for the PCI AF capabilities for FLR using the capabilities list. This
* is only used on the devices on the root/host bus (integrated devices).
af_pos = pci_find_capability(dev, PCI_CAP_ID_AF);
if (af_pos) {
pci_read_config_byte(dev, af_pos + PCI_AF_DEVCAP, &cap);
- if (cap & PCI_EXP_DEVCAP_FLR) {
+ if (cap & PCI_AF_CAP_FLR) {
return af_pos;
}
}
/* Next look for the unchained AF capabilities for FLR using specific logic */
- /* TODO */
-
- /* TODO DEPENDING ON LOGIC - MAYBE MERGE W/ ABOVE */
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
+ if (vendor_id != PCIBACK_VENDOR_INTEL)
+ return -ENXIO;
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
+ if (device_id == PCIBACK_DEVICE_IGFX_Q45) /* TODO need more IDs ?*/
+ return -ENXIO;
+
+ af_pos = PCIBACK_IGFX_CAP13_OFFSET;
+ pci_read_config_byte(dev, af_pos + PCI_AF_LENFLD, ®8);
+ if (reg8 == PCI_AF_LENGTH) {
+ pci_read_config_byte(dev, af_pos + PCI_AF_DEVCAP, &cap);
+ if (cap & PCI_AF_CAP_FLR) {
+ return af_pos;
+ }
+ }
+
/* Else not found */
return 0;
}