From: Ross Philipson Date: Thu, 26 Mar 2009 20:59:32 +0000 (-0400) Subject: FLR - intermediate checkin 6 3/26 - FLR Intel specific logic, first X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=58c85fd0eeb5703a34fba0a73a145df99895470c;p=xenclient%2Fkernel.git FLR - intermediate checkin 6 3/26 - FLR Intel specific logic, first cut. Changes to be committed: modified: drivers/xen/pciback/pciback_ops.c modified: include/linux/pci_regs.h --- diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c index a9ba6c77..94391db6 100644 --- a/drivers/xen/pciback/pciback_ops.c +++ b/drivers/xen/pciback/pciback_ops.c @@ -9,6 +9,20 @@ #include #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); @@ -112,37 +126,66 @@ static void pciback_do_pci_flr(struct pci_dev *dev, int af_pos) } /* 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; @@ -343,10 +386,6 @@ static int pciback_find_pcie_flr_caps(struct pci_dev *dev) } } - /* Next look for the unchained PCIe capabilities for FLR using specific logic */ - /* TODO */ - - /* Else not found */ return 0; } @@ -359,7 +398,10 @@ static int pciback_find_pcie_flr_caps(struct pci_dev *dev) 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). @@ -370,16 +412,29 @@ static int pciback_find_pci_flr_caps(struct pci_dev *dev) 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; } diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index fbe835b7..8282c2fc 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -560,6 +560,7 @@ #define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ /* Advanced Features Capability */ +#define PCI_AF_LENFLD 0x02 /* Device length offset */ #define PCI_AF_LENGTH 0x06 #define PCI_AF_DEVCAP 0x03 /* Device capabilities offset */ #define PCI_AF_CAP_TP 0x01