From 2326e2b99969e69fedc92de80d80b2d2f92fd942 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 20 Dec 2007 19:46:33 +0900 Subject: pciehp: block new requests from the device before power off Disable Bus Master, SERR# and INTx to ensure that no new Requests will be generated from the device before turning power off, in accordance with the specification. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/pci/hotplug') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index bc87d64a33f1..dd50713966d1 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -243,9 +243,13 @@ int pciehp_unconfigure_device(struct slot *p_slot) u8 bctl = 0; u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; + u16 command; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, p_slot->device); + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); + if (ret) + presence = 0; for (j = 0; j < 8; j++) { struct pci_dev* temp = pci_get_slot(parent, @@ -258,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot) pci_dev_put(temp); continue; } - if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - ret = p_slot->hpc_ops->get_adapter_status(p_slot, - &presence); - if (!ret && presence) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, - &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", - pci_name(temp)); - pci_dev_put(temp); - continue; - } + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", + pci_name(temp)); + pci_dev_put(temp); + continue; } } pci_remove_bus_device(temp); + /* + * Ensure that no new Requests will be generated from + * the device. + */ + if (presence) { + pci_read_config_word(temp, PCI_COMMAND, &command); + command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + command |= PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(temp, PCI_COMMAND, command); + } pci_dev_put(temp); } /* -- cgit v1.2.3