Patchwork [5/8] PCI: Add pci_stop_and_remove_root_bus()

login
register
mail settings
Submitter Yinghai Lu
Date Sept. 27, 2012, 8:11 a.m.
Message ID <1348733519-24684-6-git-send-email-yinghai@kernel.org>
Download mbox | patch
Permalink /patch/187305/
State Accepted
Headers show

Comments

Yinghai Lu - Sept. 27, 2012, 8:11 a.m.
It supports both pci root bus and pci bus under pci bridge.

-v2: clear pci_bridge's subordinate.
-v3: only handle root bus. and also put Jiang's get/put pair in
-v4: fold pci_stop/remove_bus_devices in... reducing confusing.
-v5: split device_register/unregister to avoid extra get...
     also remove extra blank line.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |   36 ++++++++++++++++++++++++++++++++++++
 include/linux/pci.h  |    2 ++
 2 files changed, 38 insertions(+), 0 deletions(-)
Bjorn Helgaas - Sept. 28, 2012, 11:46 p.m.
On Thu, Sep 27, 2012 at 2:11 AM, Yinghai Lu <yinghai@kernel.org> wrote:
> It supports both pci root bus and pci bus under pci bridge.
>
> -v2: clear pci_bridge's subordinate.
> -v3: only handle root bus. and also put Jiang's get/put pair in
> -v4: fold pci_stop/remove_bus_devices in... reducing confusing.
> -v5: split device_register/unregister to avoid extra get...
>      also remove extra blank line.
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> ---
>  drivers/pci/remove.c |   36 ++++++++++++++++++++++++++++++++++++
>  include/linux/pci.h  |    2 ++
>  2 files changed, 38 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
> index 513972f..7c0fd92 100644
> --- a/drivers/pci/remove.c
> +++ b/drivers/pci/remove.c
> @@ -111,3 +111,39 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
>         pci_remove_bus_device(dev);
>  }
>  EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
> +
> +void pci_stop_root_bus(struct pci_bus *bus)
> +{
> +       struct pci_dev *child, *tmp;
> +       struct pci_host_bridge *host_bridge;
> +
> +       if (!pci_is_root_bus(bus))
> +               return;
> +
> +       host_bridge = to_pci_host_bridge(bus->bridge);

What if we made these functions just take a "struct pci_host_bridge *"
directly instead of a "struct pci_bus *"?  Then the caller
(acpi_pci_root_remove()) could just look up the pci_host_bridge
pointer itself, or even keep that pointer in struct acpi_pci_root
instead of keeping the pci_bus pointer.

> +       list_for_each_entry_safe_reverse(child, tmp,
> +                                        &bus->devices, bus_list)
> +               pci_stop_bus_device(child);
> +
> +       /* stop the host bridge */
> +       device_del(&host_bridge->dev);
> +}
> +
> +void pci_remove_root_bus(struct pci_bus *bus)
> +{
> +       struct pci_dev *child, *tmp;
> +       struct pci_host_bridge *host_bridge;
> +
> +       if (!pci_is_root_bus(bus))
> +               return;
> +
> +       host_bridge = to_pci_host_bridge(bus->bridge);
> +       list_for_each_entry_safe(child, tmp,
> +                                &bus->devices, bus_list)
> +               pci_remove_bus_device(child);
> +       pci_remove_bus(bus);
> +       host_bridge->bus = NULL;
> +
> +       /* remove the host bridge */
> +       put_device(&host_bridge->dev);
> +}
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 505c05a..a5cd03b 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -734,6 +734,8 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
>  extern void pci_dev_put(struct pci_dev *dev);
>  extern void pci_remove_bus(struct pci_bus *b);
>  extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
> +void pci_stop_root_bus(struct pci_bus *bus);
> +void pci_remove_root_bus(struct pci_bus *bus);
>  void pci_setup_cardbus(struct pci_bus *bus);
>  extern void pci_sort_breadthfirst(void);
>  #define dev_is_pci(d) ((d)->bus == &pci_bus_type)
> --
> 1.7.7
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yinghai Lu - Sept. 29, 2012, 2:05 a.m.
On Fri, Sep 28, 2012 at 4:46 PM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> On Thu, Sep 27, 2012 at 2:11 AM, Yinghai Lu <yinghai@kernel.org> wrote:
>> It supports both pci root bus and pci bus under pci bridge.
>>
>> -v2: clear pci_bridge's subordinate.
>> -v3: only handle root bus. and also put Jiang's get/put pair in
>> -v4: fold pci_stop/remove_bus_devices in... reducing confusing.
>> -v5: split device_register/unregister to avoid extra get...
>>      also remove extra blank line.
>>
>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>> ---
>>  drivers/pci/remove.c |   36 ++++++++++++++++++++++++++++++++++++
>>  include/linux/pci.h  |    2 ++
>>  2 files changed, 38 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
>> index 513972f..7c0fd92 100644
>> --- a/drivers/pci/remove.c
>> +++ b/drivers/pci/remove.c
>> @@ -111,3 +111,39 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
>>         pci_remove_bus_device(dev);
>>  }
>>  EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
>> +
>> +void pci_stop_root_bus(struct pci_bus *bus)
>> +{
>> +       struct pci_dev *child, *tmp;
>> +       struct pci_host_bridge *host_bridge;
>> +
>> +       if (!pci_is_root_bus(bus))
>> +               return;
>> +
>> +       host_bridge = to_pci_host_bridge(bus->bridge);
>
> What if we made these functions just take a "struct pci_host_bridge *"
> directly instead of a "struct pci_bus *"?  Then the caller
> (acpi_pci_root_remove()) could just look up the pci_host_bridge
> pointer itself,

yes, that could save pci_is_root_bus checking.

> or even keep that pointer in struct acpi_pci_root
> instead of keeping the pci_bus pointer.

that could be a lot of change. could be next one stage.

actually acpi root is bound to pci host bridge instead of root bus.
so it is more reasonable to save host_bridge pointer.

we also can think in another way.
host_bridge and pci bus should be one part.
we may could just embed pci bus into pci_host_bridge instead.

-Yinghai
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 513972f..7c0fd92 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -111,3 +111,39 @@  void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 	pci_remove_bus_device(dev);
 }
 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+
+void pci_stop_root_bus(struct pci_bus *bus)
+{
+	struct pci_dev *child, *tmp;
+	struct pci_host_bridge *host_bridge;
+
+	if (!pci_is_root_bus(bus))
+		return;
+
+	host_bridge = to_pci_host_bridge(bus->bridge);
+	list_for_each_entry_safe_reverse(child, tmp,
+					 &bus->devices, bus_list)
+		pci_stop_bus_device(child);
+
+	/* stop the host bridge */
+	device_del(&host_bridge->dev);
+}
+
+void pci_remove_root_bus(struct pci_bus *bus)
+{
+	struct pci_dev *child, *tmp;
+	struct pci_host_bridge *host_bridge;
+
+	if (!pci_is_root_bus(bus))
+		return;
+
+	host_bridge = to_pci_host_bridge(bus->bridge);
+	list_for_each_entry_safe(child, tmp,
+				 &bus->devices, bus_list)
+		pci_remove_bus_device(child);
+	pci_remove_bus(bus);
+	host_bridge->bus = NULL;
+
+	/* remove the host bridge */
+	put_device(&host_bridge->dev);
+}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 505c05a..a5cd03b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -734,6 +734,8 @@  extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
 extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_stop_root_bus(struct pci_bus *bus);
+void pci_remove_root_bus(struct pci_bus *bus);
 void pci_setup_cardbus(struct pci_bus *bus);
 extern void pci_sort_breadthfirst(void);
 #define dev_is_pci(d) ((d)->bus == &pci_bus_type)