From 364e4705512acb2ea41039538346e8f9ab6d2c54 Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Fri, 27 Mar 2009 09:31:47 -0400 Subject: [PATCH] FLR - intermediate checkin 7 3/27 - Added GMCH platform check, fixed and cleaned up some code. Changes to be committed: modified: drivers/xen/pciback/pciback_ops.c modified: include/linux/pci_ids.h --- drivers/xen/pciback/pciback_ops.c | 85 ++++++++++++++++++++----------- include/linux/pci_ids.h | 12 ++++- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c index 94391db6..f016ccdc 100644 --- a/drivers/xen/pciback/pciback_ops.c +++ b/drivers/xen/pciback/pciback_ops.c @@ -10,10 +10,8 @@ #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_CLASS_ID_VGA 0x0300 #define PCIBACK_USB_FLRCTRL 0x4 #define PCIBACK_IGFX_FLRCTRL 0x4 @@ -131,12 +129,11 @@ static void pciback_do_pci_flr(struct pci_dev *dev, int af_pos) */ static int pciback_do_vendor_specific_reset(struct pci_dev *dev) { + struct pci_dev *gmch; int vendor_pos, i; - u16 vendor_id; - u16 device_id; - u16 class_id; u32 reg32; - u8 reg8; + u16 vendor_id, device_id, class_id; + u8 reg8; pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); if (vendor_id != PCIBACK_VENDOR_INTEL) @@ -144,10 +141,21 @@ static int pciback_do_vendor_specific_reset(struct pci_dev *dev) pci_read_config_word(dev, PCI_CLASS_DEVICE, &class_id); 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 ?*/ + if (dev->bus->number != 0 || dev->devfn != PCI_DEVFN(2,0)) return -ENXIO; + /* Locate the GMCH (north bridge) and test for specific Intel devices */ + gmch = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!gmch) + return -ENXIO; + + pci_read_config_word(gmch, PCI_DEVICE_ID, &device_id); + pci_dev_put(gmch); + + if (device_id != PCI_DEVICE_ID_INTEL_GMCHGM45) + return -ENXIO; + + /* Correct device and platform, assume vendor specific offset */ pci_read_config_dword(dev, PCIBACK_IGFX_CAP09_OFFSET, ®32); if ((reg32 & 0x000000F0) != 0x20 || ((reg32 >> 16) & 0x000000FF) != 0x06 || @@ -397,11 +405,10 @@ static int pciback_find_pcie_flr_caps(struct pci_dev *dev) */ static int pciback_find_pci_flr_caps(struct pci_dev *dev) { + struct pci_dev *gmch; int af_pos; - u8 cap; - u16 vendor_id; - u16 device_id; - u8 reg8; + u16 vendor_id, device_id, class_id; + u8 cap, 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). @@ -417,24 +424,44 @@ static int pciback_find_pci_flr_caps(struct pci_dev *dev) } } - /* Next look for the unchained AF capabilities for FLR using specific logic */ - pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); - if (vendor_id != PCIBACK_VENDOR_INTEL) - return -ENXIO; + /* Next look for the unchained AF capabilities for FLR using specific + * logic. Currently only the graphics device on the Intel Q45 etc + * systems has special logic for locating the hidden FLR caps. + */ + do { + if (dev->bus->number != 0 || dev->devfn != PCI_DEVFN(2,0)) + break; + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + if (vendor_id != PCIBACK_VENDOR_INTEL) + break; + pci_read_config_word(dev, PCI_CLASS_DEVICE, &class_id); + if (class_id != PCIBACK_CLASS_ID_VGA) + break; - 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; + /* Locate the GMCH (north bridge) and test for specific Intel devices */ + gmch = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!gmch) + break; + + 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 || + device_id != PCI_DEVICE_ID_INTEL_GMCHG41) + break; + + /* Correct device and platform, assume AF offset */ + 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; + } } - } - + } while (0); + /* Else not found */ return 0; } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d81bc132..642eaf20 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2522,11 +2522,19 @@ #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca -#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb +#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb #define PCI_DEVICE_ID_INTEL_84460GX 0x84ea #define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 #define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 -#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 +#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 + +#define PCI_DEVICE_ID_INTEL_GMCHQ45 0x2e10 +#define PCI_DEVICE_ID_INTEL_GMCHG45 0x2e20 +#define PCI_DEVICE_ID_INTEL_MCHP45 0x2e20 +#define PCI_DEVICE_ID_INTEL_GMCHG41 0x2e30 +#define PCI_DEVICE_ID_INTEL_GMCHGM45 0x2a40 + +#define PCI_DEVICE_ID_INTEL_GMCHG41 0x2e30 #define PCI_VENDOR_ID_SCALEMP 0x8686 #define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 -- 2.39.5