From patchwork Wed May 23 05:15:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jianjun Kong X-Patchwork-Id: 160838 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 03BB9B7010 for ; Wed, 23 May 2012 15:15:11 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752619Ab2EWFPJ (ORCPT ); Wed, 23 May 2012 01:15:09 -0400 Received: from mail-wi0-f172.google.com ([209.85.212.172]:39873 "EHLO mail-wi0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752120Ab2EWFPH (ORCPT ); Wed, 23 May 2012 01:15:07 -0400 Received: by wibhj8 with SMTP id hj8so4139237wib.1 for ; Tue, 22 May 2012 22:15:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=ZOlncvafMVZRjsuHmLO5CakXzp2pgK7e3/LfnA8Un6k=; b=uQ3zLGzSONvjh4bVemRRJ+P+Y6N2wj+fHD+6YiKUJYLCGtmNumorjNNlflZ56tG6TG kzU0mdefoHxc3uRqlAK87r/W0/DmVJwIcBGYJJcYFD0tKN/Dd5xHMVYSR3uXJrHnKyIa 3NnUnknrCykH2xkzv4jL9Mz5mKJ+j/79UDHBIsB372EecRrmbNpVn4yXgeFHsu5yQUAB 5XzmolORtXgGAg8ELrnzfgl7Mcil0gXhBiB47n7/JXrKxV5Xs9YUk4NU/slD9pMqD+3u BZiidJs+La/3Sj7VnIcrd5glKqMfJX/1UbkrLEvMjYqRSzCf+8yqATJ2q+DMsp8tXRcl ujmg== MIME-Version: 1.0 Received: by 10.180.95.137 with SMTP id dk9mr32996579wib.1.1337750105782; Tue, 22 May 2012 22:15:05 -0700 (PDT) Received: by 10.180.88.200 with HTTP; Tue, 22 May 2012 22:15:05 -0700 (PDT) In-Reply-To: References: <20120523043347.13449.1063.stgit@bhelgaas.mtv.corp.google.com> <20120523043511.13449.22006.stgit@bhelgaas.mtv.corp.google.com> Date: Wed, 23 May 2012 13:15:05 +0800 Message-ID: Subject: [PATCH v7 2/2] PCI: acpiphp: remove all functions in slot, even without ACPI _EJx From: Amos Kong To: Yinghai Lu Cc: Bjorn Helgaas , linux-pci@vger.kernel.org, liuj97@gmail.com, qemu-devel@nongnu.org, jbarnes@virtuousgeek.org, kaneshige.kenji@jp.fujitsu.com Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Attached the v7, test passed. From bec7ec71dbeb92dc830719be7c11f87786830863 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 22 May 2012 18:35:11 +0000 Subject: [PATCH 2/2] PCI: acpiphp: remove all functions in slot, even without ACPI _EJx When we add a device with acpiphp, we enumerate all functions in the slot with pci_scan_slot(), regardless of whether they have associated ACPI methods such as _EJ0. When removing the device, we previously removed only the functions with those ACPI methods. This patch makes the remove symmetric with the add: we remove all functions in the slot, whether they have associated ACPI methods or not. With qemu-kvm and SeaBIOS, we can build a multi-function device where only function 0 has _EJ0 and _ADR (see bugzilla below). Removing and re-adding that device works correctly with Windows guests. This patch makes it also work in Linux guests. [bhelgaas: restructure loop iteration, pull out of slot->funcs loop] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=43219 Signed-off-by: Amos Kong Signed-off-by: Bjorn Helgaas --- v7: keep that pci_bus_sem operation pair on return path --- drivers/pci/hotplug/acpiphp_glue.c | 40 +++++++++++++++++++++++++++--------- 1 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 0d87136..c94a12f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -878,6 +878,22 @@ static void disable_bridges(struct pci_bus *bus) } } +/* return first device in slot, acquiring a reference on it */ +static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) +{ + struct pci_bus *bus = slot->bridge->pci_bus; + struct pci_dev *dev; + int ret = NULL; + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + ret = pci_dev_get(dev); + up_read(&pci_bus_sem); + + return ret; +} + /** * disable_device - disable a slot * @slot: ACPI PHP slot @@ -902,18 +918,22 @@ static int disable_device(struct acpiphp_slot *slot) (u32)1, NULL, NULL); func->bridge = NULL; } + } - pdev = pci_get_slot(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, func->function)); - if (pdev) { - pci_stop_bus_device(pdev); - if (pdev->subordinate) { - disable_bridges(pdev->subordinate); - pci_disable_device(pdev); - } - __pci_remove_bus_device(pdev); - pci_dev_put(pdev); + /* + * enable_device() enumerates all functions in this device via + * pci_scan_slot(), whether they have associated ACPI hotplug + * methods (_EJ0, etc.) or not. Therefore, we remove all functions + * here. + */ + while ((pdev = dev_in_slot(slot))) { + pci_stop_bus_device(pdev); + if (pdev->subordinate) { + disable_bridges(pdev->subordinate); + pci_disable_device(pdev); } + __pci_remove_bus_device(pdev); + pci_dev_put(pdev); } list_for_each_entry(func, &slot->funcs, sibling) { -- 1.7.1