X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fpci%2Fpcie%2Fportdrv_pci.c;h=02260141dc8107be19d943f4e35475b65559cf30;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=478d0d28f7ad1e6b573e5e3c3a26f37b9dc1e557;hpb=3944158a6d33f94668dbd6bdc32ff5c67bb53ec2;p=linux-2.6.git diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 478d0d28f..02260141d 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -30,6 +30,82 @@ MODULE_LICENSE("GPL"); /* global data */ static const char device_name[] = "pcieport-driver"; +static void pci_save_msi_state(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int i = 0, pos; + u16 control; + + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) + return; + + pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); + control = p_ext->saved_msi_config_space[0] >> 16; + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, + &p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, + &p_ext->saved_msi_config_space[i++]); + pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, + &p_ext->saved_msi_config_space[i++]); + } else + pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, + &p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, + &p_ext->saved_msi_config_space[i++]); +} + +static void pci_restore_msi_state(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int i = 0, pos; + u16 control; + + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) + return; + + control = p_ext->saved_msi_config_space[i++] >> 16; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, + p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, + p_ext->saved_msi_config_space[i++]); + pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, + p_ext->saved_msi_config_space[i++]); + } else + pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, + p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, + p_ext->saved_msi_config_space[i++]); +} + +static void pcie_portdrv_save_config(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + + pci_save_state(dev); + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) + pci_save_msi_state(dev); +} + +static int pcie_portdrv_restore_config(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int retval; + + pci_restore_state(dev); + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) + pci_restore_msi_state(dev); + retval = pci_enable_device(dev); + if (retval) + return retval; + pci_set_master(dev); + return 0; +} + /* * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed @@ -56,10 +132,8 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, "%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", __FUNCTION__, dev->device, dev->vendor); } - if (pcie_port_device_register(dev)) { - pci_disable_device(dev); + if (pcie_port_device_register(dev)) return -ENOMEM; - } return 0; } @@ -71,29 +145,11 @@ static void pcie_portdrv_remove (struct pci_dev *dev) } #ifdef CONFIG_PM -static int pcie_portdrv_save_config(struct pci_dev *dev) -{ - return pci_save_state(dev); -} - -static int pcie_portdrv_restore_config(struct pci_dev *dev) -{ - int retval; - - pci_restore_state(dev); - retval = pci_enable_device(dev); - if (retval) - return retval; - pci_set_master(dev); - return 0; -} - static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) { int ret = pcie_port_device_suspend(dev, state); - if (!ret) - ret = pcie_portdrv_save_config(dev); + pcie_portdrv_save_config(dev); return ret; }