diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2007-12-20 05:46:33 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 18:04:28 -0500 |
commit | 2326e2b99969e69fedc92de80d80b2d2f92fd942 (patch) | |
tree | fd7043125cc5e08b845907fd97dd8086544f8bbb /drivers/pci/hotplug | |
parent | f1050a35cd99d6cfded7ce1273757dca84e92f9b (diff) |
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 <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/pciehp_pci.c | 33 |
1 files changed, 21 insertions, 12 deletions
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) | |||
243 | u8 bctl = 0; | 243 | u8 bctl = 0; |
244 | u8 presence = 0; | 244 | u8 presence = 0; |
245 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; | 245 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; |
246 | u16 command; | ||
246 | 247 | ||
247 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, | 248 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, |
248 | p_slot->device); | 249 | p_slot->device); |
250 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence); | ||
251 | if (ret) | ||
252 | presence = 0; | ||
249 | 253 | ||
250 | for (j = 0; j < 8; j++) { | 254 | for (j = 0; j < 8; j++) { |
251 | struct pci_dev* temp = pci_get_slot(parent, | 255 | struct pci_dev* temp = pci_get_slot(parent, |
@@ -258,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
258 | pci_dev_put(temp); | 262 | pci_dev_put(temp); |
259 | continue; | 263 | continue; |
260 | } | 264 | } |
261 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 265 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { |
262 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, | 266 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); |
263 | &presence); | 267 | if (bctl & PCI_BRIDGE_CTL_VGA) { |
264 | if (!ret && presence) { | 268 | err("Cannot remove display device %s\n", |
265 | pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, | 269 | pci_name(temp)); |
266 | &bctl); | 270 | pci_dev_put(temp); |
267 | if (bctl & PCI_BRIDGE_CTL_VGA) { | 271 | continue; |
268 | err("Cannot remove display device %s\n", | ||
269 | pci_name(temp)); | ||
270 | pci_dev_put(temp); | ||
271 | continue; | ||
272 | } | ||
273 | } | 272 | } |
274 | } | 273 | } |
275 | pci_remove_bus_device(temp); | 274 | pci_remove_bus_device(temp); |
275 | /* | ||
276 | * Ensure that no new Requests will be generated from | ||
277 | * the device. | ||
278 | */ | ||
279 | if (presence) { | ||
280 | pci_read_config_word(temp, PCI_COMMAND, &command); | ||
281 | command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); | ||
282 | command |= PCI_COMMAND_INTX_DISABLE; | ||
283 | pci_write_config_word(temp, PCI_COMMAND, command); | ||
284 | } | ||
276 | pci_dev_put(temp); | 285 | pci_dev_put(temp); |
277 | } | 286 | } |
278 | /* | 287 | /* |