From patchwork Wed May 23 07:03:16 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jianjun Kong X-Patchwork-Id: 160892 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 578B9B6FBB for ; Wed, 23 May 2012 17:03:43 +1000 (EST) Received: from localhost ([::1]:55809 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SX5bh-0002vz-7r for incoming@patchwork.ozlabs.org; Wed, 23 May 2012 03:03:41 -0400 Received: from eggs.gnu.org ([208.118.235.92]:45247) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SX5bR-0002gm-LU for qemu-devel@nongnu.org; Wed, 23 May 2012 03:03:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SX5bL-0005aX-2F for qemu-devel@nongnu.org; Wed, 23 May 2012 03:03:25 -0400 Received: from mail-we0-f173.google.com ([74.125.82.173]:53917) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SX5bK-0005Z6-Ku for qemu-devel@nongnu.org; Wed, 23 May 2012 03:03:18 -0400 Received: by werf3 with SMTP id f3so5485433wer.4 for ; Wed, 23 May 2012 00:03:16 -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=zkN1cU/98uWKbt2dg1B3niho1sivgHfWFtDPGGGK4Yw=; b=uvTPimaKZlpEyk6DMBhEFL16tBSnkaXamUymgVQkT5VzChjAllEbCl8epc38xeJOpt a3QjfcLsl3ISQQDiFS5c+sx/RdXwu2GVeJjJgeyklcL/a2HQf0ZY6CRBW3Cw/WuRR5cQ hAW1vMv4FwrAS0iS1za0X+1BtkaARSjIS4oFme9Zx70ECk7LUVyfCsYp2LlqEMEiqF7Y mmV5a6Ted/nY4QAXf5pC0DDuMoOSjSGaHxraIW9Jp6VJaKpzQPlrY9c1Ngnsc9gCdG5o 6x9vlAbs9oH0DrM7EKVzN/XM8UHztfd/8iR+3XqLa6okX2apOlFjYhySLS3pPIJ9AlLE 7Xjw== MIME-Version: 1.0 Received: by 10.180.78.161 with SMTP id c1mr43294189wix.1.1337756596488; Wed, 23 May 2012 00:03:16 -0700 (PDT) Received: by 10.180.88.200 with HTTP; Wed, 23 May 2012 00:03:16 -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 15:03:16 +0800 Message-ID: From: Amos Kong To: Yinghai Lu X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 74.125.82.173 Cc: linux-pci@vger.kernel.org, qemu-devel@nongnu.org, jbarnes@virtuousgeek.org, kaneshige.kenji@jp.fujitsu.com, Bjorn Helgaas , liuj97@gmail.com Subject: [Qemu-devel] [PATCH v8 2/2] PCI: acpiphp: remove all functions in slot, even without ACPI _EJx X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org On Wed, May 23, 2012 at 1:29 PM, Yinghai Lu wrote: > On Tue, May 22, 2012 at 10:15 PM, Amos Kong wrote: >> Attached the v7,  test passed. > > would be better to have break... Yeah. Otherwise, it will delete from the last function. Attached v8, test passed. > +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; > +} > > ===> > > > +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); > +                      break; > +              } > +       up_read(&pci_bus_sem); > + > +       return ret; > +} From 32c42e815669837e114acbd14715eb60bc741bbe Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 22 May 2012 18:35:11 +0000 Subject: [PATCH V8 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 v8: break when the first available device is found --- drivers/pci/hotplug/acpiphp_glue.c | 42 +++++++++++++++++++++++++++-------- 1 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 0d87136..e37e73c 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -878,6 +878,24 @@ 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; + struct pci_dev *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); + break; + } + up_read(&pci_bus_sem); + + return ret; +} + /** * disable_device - disable a slot * @slot: ACPI PHP slot @@ -902,18 +920,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