[PATCH] PCI: acpi tg3 ethernet not coming back properly after S3 suspendon DellM70

This patch, is based on kernel 2.6.12, provides a fix for PCIe
port bus driver suspend/resume.

Signed-off-by: T. Long Nguyen <tom.l.nguyen@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by long and committed by Greg Kroah-Hartman 5823d100 a00db371

+91 -1
+5
drivers/pci/pcie/portdrv.h
··· 27 27 28 28 #define get_descriptor_id(type, service) (((type - 4) << 4) | service) 29 29 30 + struct pcie_port_device_ext { 31 + int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ 32 + unsigned int saved_msi_config_space[5]; 33 + }; 34 + 30 35 extern struct bus_type pcie_port_bus_type; 31 36 extern int pcie_port_device_probe(struct pci_dev *dev); 32 37 extern int pcie_port_device_register(struct pci_dev *dev);
+8
drivers/pci/pcie/portdrv_core.c
··· 275 275 276 276 int pcie_port_device_register(struct pci_dev *dev) 277 277 { 278 + struct pcie_port_device_ext *p_ext; 278 279 int status, type, capabilities, irq_mode, i; 279 280 int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; 280 281 u16 reg16; 282 + 283 + /* Allocate port device extension */ 284 + if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) 285 + return -ENOMEM; 286 + 287 + pci_set_drvdata(dev, p_ext); 281 288 282 289 /* Get port type */ 283 290 pci_read_config_word(dev, ··· 295 288 /* Now get port services */ 296 289 capabilities = get_port_device_capability(dev); 297 290 irq_mode = assign_interrupt_mode(dev, vectors, capabilities); 291 + p_ext->interrupt_mode = irq_mode; 298 292 299 293 /* Allocate child services if any */ 300 294 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+78 -1
drivers/pci/pcie/portdrv_pci.c
··· 29 29 /* global data */ 30 30 static const char device_name[] = "pcieport-driver"; 31 31 32 + static void pci_save_msi_state(struct pci_dev *dev) 33 + { 34 + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); 35 + int i = 0, pos; 36 + u16 control; 37 + 38 + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) 39 + return; 40 + 41 + pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); 42 + control = p_ext->saved_msi_config_space[0] >> 16; 43 + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, 44 + &p_ext->saved_msi_config_space[i++]); 45 + if (control & PCI_MSI_FLAGS_64BIT) { 46 + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, 47 + &p_ext->saved_msi_config_space[i++]); 48 + pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, 49 + &p_ext->saved_msi_config_space[i++]); 50 + } else 51 + pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, 52 + &p_ext->saved_msi_config_space[i++]); 53 + if (control & PCI_MSI_FLAGS_MASKBIT) 54 + pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, 55 + &p_ext->saved_msi_config_space[i++]); 56 + } 57 + 58 + static void pci_restore_msi_state(struct pci_dev *dev) 59 + { 60 + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); 61 + int i = 0, pos; 62 + u16 control; 63 + 64 + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) 65 + return; 66 + 67 + control = p_ext->saved_msi_config_space[i++] >> 16; 68 + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); 69 + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, 70 + p_ext->saved_msi_config_space[i++]); 71 + if (control & PCI_MSI_FLAGS_64BIT) { 72 + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, 73 + p_ext->saved_msi_config_space[i++]); 74 + pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, 75 + p_ext->saved_msi_config_space[i++]); 76 + } else 77 + pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, 78 + p_ext->saved_msi_config_space[i++]); 79 + if (control & PCI_MSI_FLAGS_MASKBIT) 80 + pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, 81 + p_ext->saved_msi_config_space[i++]); 82 + } 83 + 84 + static void pcie_portdrv_save_config(struct pci_dev *dev) 85 + { 86 + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); 87 + 88 + pci_save_state(dev); 89 + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) 90 + pci_save_msi_state(dev); 91 + } 92 + 93 + static void pcie_portdrv_restore_config(struct pci_dev *dev) 94 + { 95 + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); 96 + 97 + pci_restore_state(dev); 98 + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) 99 + pci_restore_msi_state(dev); 100 + pci_enable_device(dev); 101 + pci_set_master(dev); 102 + } 103 + 32 104 /* 33 105 * pcie_portdrv_probe - Probe PCI-Express port devices 34 106 * @dev: PCI-Express port device being probed ··· 136 64 static void pcie_portdrv_remove (struct pci_dev *dev) 137 65 { 138 66 pcie_port_device_remove(dev); 67 + kfree(pci_get_drvdata(dev)); 139 68 } 140 69 141 70 #ifdef CONFIG_PM 142 71 static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) 143 72 { 144 - return pcie_port_device_suspend(dev, state); 73 + int ret = pcie_port_device_suspend(dev, state); 74 + 75 + pcie_portdrv_save_config(dev); 76 + return ret; 145 77 } 146 78 147 79 static int pcie_portdrv_resume (struct pci_dev *dev) 148 80 { 81 + pcie_portdrv_restore_config(dev); 149 82 return pcie_port_device_resume(dev); 150 83 } 151 84 #endif