From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753228AbdJMSgX (ORCPT ); Fri, 13 Oct 2017 14:36:23 -0400 Received: from mga04.intel.com ([192.55.52.120]:21842 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751339AbdJMSf5 (ORCPT ); Fri, 13 Oct 2017 14:35:57 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.43,372,1503385200"; d="scan'208";a="1230534183" From: Mika Westerberg To: Bjorn Helgaas Cc: Ashok Raj , Keith Busch , "Rafael J . Wysocki" , Lukas Wunner , Michael Jamet , Yehezkel Bernat , Mario.Limonciello@dell.com, Mika Westerberg , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 8/8] PCI: pciehp: Check that the device is really present before touching it Date: Fri, 13 Oct 2017 21:35:48 +0300 Message-Id: <20171013183548.68283-9-mika.westerberg@linux.intel.com> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20171013183548.68283-1-mika.westerberg@linux.intel.com> References: <20171013183548.68283-1-mika.westerberg@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org During surprise hot-unplug the device is not there anymore. When that happens we read 0xffffffff from the registers and pciehp_unconfigure_device() inadvertently thinks the device is a display device because bridge control register returns 0xff refusing to remove it: pciehp 0000:00:1c.0:pcie004: Slot(0): Link Down pciehp 0000:00:1c.0:pcie004: Slot(0): Card present pciehp 0000:00:1c.0:pcie004: Cannot remove display device 0000:01:00.0 This causes the hotplug functionality to leave the hierarcy untouched preventing further hotplug operations. To fix this verify presence of a device by calling pci_device_is_present() for it before we touch it any further. Signed-off-by: Mika Westerberg --- drivers/pci/hotplug/pciehp_pci.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 2a1ca020cf5a..fb4333168e23 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -100,8 +100,14 @@ int pciehp_unconfigure_device(struct slot *p_slot) */ list_for_each_entry_safe_reverse(dev, temp, &parent->devices, bus_list) { + bool present; + pci_dev_get(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + + /* Check if the device is really there anymore */ + present = presence ? pci_device_is_present(dev) : false; + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && present) { pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); if (bctl & PCI_BRIDGE_CTL_VGA) { ctrl_err(ctrl, @@ -112,7 +118,7 @@ int pciehp_unconfigure_device(struct slot *p_slot) break; } } - if (!presence) { + if (!present) { pci_dev_set_disconnected(dev, NULL); if (pci_has_subordinate(dev)) pci_walk_bus(dev->subordinate, @@ -123,7 +129,7 @@ int pciehp_unconfigure_device(struct slot *p_slot) * Ensure that no new Requests will be generated from * the device. */ - if (presence) { + if (present) { pci_read_config_word(dev, PCI_COMMAND, &command); command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); command |= PCI_COMMAND_INTX_DISABLE; -- 2.14.2