linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/47] PCI, x86: pci root bus hotplug support
@ 2012-03-19  5:45 Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 01/47] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
                   ` (48 more replies)
  0 siblings, 49 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

will add pci_stop_and_remove_bus() to support remove bus in
/sys/devices/pci.../pci_bus/...

To rescan root, need to
echo 1 > /sys/bus/pci/rescan_root

It supports acpi path root bus and legacy root bus.

This patcheset include some IOMM and dmar and pnpacpi fix with device refcount leaking.
        also include some bus remove/rescan cleanup.

The patches need to apply to pci/for-linus and pci/linux-next
	[PATCH -v3] PCI: pci_host_bridge related cleanup
	[PATCH -v11] PCI: allocate pci bus num range for unassigned bridge busn

could get from
        git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-root-bus-hotplug

-v2: Address most of Bjorn's review, except still keeping .../pci_bus/.../remove
     Separate pci root hot add support from acpiphp to pci_root_hp
     add hot removal to pci_root_hp
-v3: Reordering the patches about /sys changes at last that Bjorn objects.
     Claim hw/fw allocated bus after root bus hot add.
     add two patches for Jiang Liu about removal.

Ashok Raj (1):
  ACPI: Enable SCI_EMULATE to manually simulate physical hotplug
    testing.

Jiang Liu (2):
  Correctly clean up pci root buses in function pci_remove_bus()
  Fix an access-after-free issue in function pci_stop_and_remove_bus()

Yinghai Lu (44):
  IOMMU: Update dmar units devices list during hotplug
  PNPACPI: Fix device ref leaking in acpi_pnp_match
  IOMMU: Fix tboot force iommu logic
  x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn
  PCI: Separate out pci_assign_unassigned_bus_resources()
  PCI: Move back pci_rescan_bus()
  PCI: pci_bus_size_bridges() should not size own bridge
  PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources()
  PCI, sysfs: Use device_type and attr_groups with pci dev
  PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges
  PCI: Add pci_bus_add_single_device()
  PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead
  PCI: Clean up rescan_bus_bridge_resize()
  PCI: Rescan bus or bridge using callback method too
  PCI, sysfs: Clean up rescan/remove with scheule_callback
  x86, PCI: Separate pcibios_allocate_bridge_resources()
  x86, PCI: Separate pcibios_allocate_dev_resources()
  x86, PCI: Let pcibios_allocate_bus_resources() take bus instead
  PCI: Claim hw/fw allocated resources in hot add path.
  PCI: Move pci_stop_and_remove_behind_bridge() down
  PCI: Add __pci_remove_bus_devices()
  PCI: Use list_for_each_entry_safe instead of list_for_each_safe
  PCI: Add pci_stop_and_remove_bus()
  PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too
  PCI, acpiphp: Separate out hot-add support of pci host bridge
  PCI, ACPI: Add pci_root_hp hot removal notification support.
  PCI, ACPI: Add alloc_acpi_hp_work()
  PCI, acpiphp: Use acpi_hp_work
  PCI, pci_root_hp: Use acpi_hp_work
  PCI, ACPI: Make kacpi_hotplug_wq static
  PCI: Add debug print out for pci related dev release
  PCI, pciehp: Separate pci_hp_add_bridge()
  PCI, cphi_hotplug: Simplify configure_slot
  PCI, shpchp: Simplify configure_device
  PCI: Kill pci_is_reassignedev()
  PCI, sysfs: Prepare to kill pci device rescan
  PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  PCI, ACPI: Add acpi_pci_root_rescan()
  PCI: Add __pci_scan_root_bus() that can skip bus_add
  x86, PCI: add __pci_scan_root_bus_on_node() that can skip bus_add
  x86, PCI: add __pcibios_scan_specific_bus that can skip bus_add
  x86, PCI: Add pcibios_root_rescan()
  x86, PCI: Add arch version pci_root_rescan()
  PCI: Add /sys/bus/pci/rescan_root

 Documentation/ABI/testing/sysfs-bus-pci    |   27 +++
 Documentation/feature-removal-schedule.txt |    9 +
 arch/x86/include/asm/pci.h                 |    4 +
 arch/x86/pci/common.c                      |   35 +++-
 arch/x86/pci/i386.c                        |  122 ++++++++-----
 arch/x86/pci/legacy.c                      |   45 ++++-
 drivers/acpi/Kconfig                       |   10 +
 drivers/acpi/Makefile                      |    2 +
 drivers/acpi/bus.c                         |    2 +
 drivers/acpi/internal.h                    |    6 +
 drivers/acpi/osl.c                         |   24 ++-
 drivers/acpi/pci_root.c                    |   14 ++
 drivers/acpi/pci_root_hp.c                 |  288 ++++++++++++++++++++++++++++
 drivers/acpi/sci_emu.c                     |  141 ++++++++++++++
 drivers/iommu/intel-iommu.c                |  194 +++++++++++++++++--
 drivers/pci/bus.c                          |   41 ++++
 drivers/pci/hotplug-pci.c                  |   13 ++
 drivers/pci/hotplug/acpiphp.h              |    9 +-
 drivers/pci/hotplug/acpiphp_glue.c         |  149 +++------------
 drivers/pci/hotplug/cpci_hotplug_pci.c     |   35 +---
 drivers/pci/hotplug/pciehp_pci.c           |   18 +--
 drivers/pci/hotplug/shpchp_pci.c           |   45 ++---
 drivers/pci/pci-sysfs.c                    |  153 +++++++++++++--
 drivers/pci/pci.c                          |   17 +--
 drivers/pci/pci.h                          |    2 +
 drivers/pci/probe.c                        |   46 ++++-
 drivers/pci/remove.c                       |   96 ++++++----
 drivers/pci/setup-bus.c                    |   50 ++----
 drivers/pnp/pnpacpi/core.c                 |    7 +-
 include/acpi/acpiosxf.h                    |    9 +-
 include/linux/dmar.h                       |    4 +
 include/linux/pci-acpi.h                   |    7 +
 include/linux/pci.h                        |    8 +
 33 files changed, 1245 insertions(+), 387 deletions(-)
 create mode 100644 drivers/acpi/pci_root_hp.c
 create mode 100644 drivers/acpi/sci_emu.c

-- 
1.7.7


^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH -v3 01/47] IOMMU: Update dmar units devices list during hotplug
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 02/47] PNPACPI: Fix device ref leaking in acpi_pnp_match Yinghai Lu
                   ` (47 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, David Woodhouse, Vinod Koul,
	Dan Williams, iommu

When do pci remove/rescan on system that have more iommus, got

[  894.089745] Set context mapping for c4:00.0
[  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
[  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
[  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
[  894.361295] DRHD: handling fault status reg 2
[  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
[  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl

It turns out when remove/rescan, pci dev will be freed and will get another
new dev. But drhd units still keep old one... so dmar_find_matched_drhd_unit
will return wrong drhd and iommu for the device that is not on first iommu.

So need to update devices in drhd_units during pci remove/rescan.

Could save domain/bus/device/function aside in the list and according that
info restore new dev to drhd_units later.
Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd
and iommu.

Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
call them in device ADD_DEVICE and UNBOUND_DRIVER

Need to do the samething to atsr. (expose dmar_atsr_units and add
atsru->segment)

After patch, will have right iommu for the new dev and will not get DMAR
error anymore.

-v2: add pci_dev_put/pci_dev_get to make refcount consistent.
-v3: fix one left over CONFIG_DMAR
-v4: pass pci_dev *dev in save_dev_dmaru()/get_dev_dmaru() according to Bjorn.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/intel-iommu.c |  188 ++++++++++++++++++++++++++++++++++++++++---
 include/linux/dmar.h        |    4 +
 2 files changed, 180 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c9c6053..49eb412 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -665,6 +665,158 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
 	return NULL;
 }
 
+#ifdef CONFIG_HOTPLUG
+struct dev_dmaru {
+	struct list_head list;
+	void *dmaru;
+	int index;
+	int segment;
+	unsigned char bus;
+	unsigned int devfn;
+};
+
+static int save_dev_dmaru(struct pci_dev *dev, void *dmaru,
+			  int index, struct list_head *lh)
+{
+	struct dev_dmaru *m;
+
+	m = kzalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return -ENOMEM;
+
+	m->segment = pci_domain_nr(dev->bus);
+	m->bus     = dev->bus->number;
+	m->devfn   = dev->devfn;
+	m->dmaru   = dmaru;
+	m->index   = index;
+
+	list_add(&m->list, lh);
+
+	return 0;
+}
+
+static void *get_dev_dmaru(struct pci_dev *dev, int *index,
+				struct list_head *lh)
+{
+	int segment = pci_domain_nr(dev->bus);
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	struct dev_dmaru *m;
+	void *dmaru = NULL;
+
+	list_for_each_entry(m, lh, list) {
+		if (m->segment == segment &&
+		    m->bus == bus && m->devfn == devfn) {
+			*index = m->index;
+			dmaru  = m->dmaru;
+			list_del(&m->list);
+			kfree(m);
+			break;
+		}
+	}
+
+	return dmaru;
+}
+
+static LIST_HEAD(saved_dev_drhd_list);
+
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	for_each_drhd_unit(drhd) {
+		if (drhd->ignored)
+			continue;
+		if (segment != drhd->segment)
+			continue;
+
+		for (i = 0; i < drhd->devices_cnt; i++) {
+			if (drhd->devices[i] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(dev, drhd, i,
+						&saved_dev_drhd_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				drhd->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int i;
+
+	/* find the stored drhd */
+	drhd = get_dev_dmaru(dev, &i, &saved_dev_drhd_list);
+	/* restore that into drhd */
+	if (drhd)
+		drhd->devices[i] = pci_dev_get(dev);
+}
+#else
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+}
+#endif
+
+static LIST_HEAD(dmar_atsr_units);
+
+#if defined(CONFIG_INTEL_IOMMU) && defined(CONFIG_HOTPLUG)
+static LIST_HEAD(saved_dev_atsr_list);
+
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	for_each_atsr_unit(atsr) {
+		if (segment != atsr->segment)
+			continue;
+
+		for (i = 0; i < atsr->devices_cnt; i++) {
+			if (atsr->devices[i] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(dev, atsr, i,
+						&saved_dev_atsr_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				atsr->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int i;
+
+	/* find the stored atsr */
+	atsr = get_dev_dmaru(dev, &i, &saved_dev_atsr_list);
+	/* restore that into atsr */
+	if (atsr)
+		atsr->devices[i] = pci_dev_get(dev);
+}
+#else
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+}
+#endif
+
 static void domain_flush_cache(struct dmar_domain *domain,
 			       void *addr, int size)
 {
@@ -3460,8 +3612,6 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 	return ret;
 }
 
-static LIST_HEAD(dmar_atsr_units);
-
 int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 {
 	struct acpi_dmar_atsr *atsr;
@@ -3474,6 +3624,7 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 	atsru->hdr = hdr;
 	atsru->include_all = atsr->flags & 0x1;
+	atsru->segment = atsr->segment;
 
 	list_add(&atsru->list, &dmar_atsr_units);
 
@@ -3505,16 +3656,13 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
 {
 	int i;
 	struct pci_bus *bus;
-	struct acpi_dmar_atsr *atsr;
 	struct dmar_atsr_unit *atsru;
 
 	dev = pci_physfn(dev);
 
-	list_for_each_entry(atsru, &dmar_atsr_units, list) {
-		atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-		if (atsr->segment == pci_domain_nr(dev->bus))
+	list_for_each_entry(atsru, &dmar_atsr_units, list)
+		if (atsru->segment == pci_domain_nr(dev->bus))
 			goto found;
-	}
 
 	return 0;
 
@@ -3574,20 +3722,36 @@ static int device_notifier(struct notifier_block *nb,
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct dmar_domain *domain;
 
-	if (iommu_no_mapping(dev))
+	if (unlikely(dev->bus != &pci_bus_type))
 		return 0;
 
-	domain = find_domain(pdev);
-	if (!domain)
-		return 0;
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		if (iommu_no_mapping(dev))
+			goto out;
+
+		if (iommu_pass_through)
+			goto out;
+
+		domain = find_domain(pdev);
+		if (!domain)
+			goto out;
 
-	if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
 		domain_remove_one_dev_info(domain, pdev);
 
 		if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
 		    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
 		    list_empty(&domain->devices))
 			domain_exit(domain);
+out:
+		remove_dev_from_drhd(pdev);
+		remove_dev_from_atsr(pdev);
+
+		break;
+	case BUS_NOTIFY_ADD_DEVICE:
+		restore_dev_to_drhd(pdev);
+		restore_dev_to_atsr(pdev);
+		break;
 	}
 
 	return 0;
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 731a609..57e1375 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -236,9 +236,13 @@ struct dmar_atsr_unit {
 	struct acpi_dmar_header *hdr;	/* ACPI header */
 	struct pci_dev **devices;	/* target devices */
 	int devices_cnt;		/* target device count */
+	u16 segment;			/* PCI domain */
 	u8 include_all:1;		/* include all ports */
 };
 
+#define for_each_atsr_unit(atsr) \
+	list_for_each_entry(atsr, &dmar_atsr_units, list)
+
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 02/47] PNPACPI: Fix device ref leaking in acpi_pnp_match
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 01/47] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 03/47] IOMMU: Fix tboot force iommu logic Yinghai Lu
                   ` (46 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, stable, Len Brown,
	Adam Belay, linux-acpi

During testing pci root bus removal, found some root bus bridge is not freed.

If booting with pnpacpi=off, those hostbridge could be freed without problem.

It turns out that some devices reference are not released during acpi_pnp_match.

That match should not hold one device ref during every calling.

Add put_device calling before returning.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: stable@kernel.org
Cc: Len Brown <lenb@kernel.org>
Cc: Adam Belay <abelay@mit.edu>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-acpi@vger.kernel.org
---
 drivers/pnp/pnpacpi/core.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index b00c176..d21e8f5 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -321,9 +321,14 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp)
 {
 	struct acpi_device *acpi = to_acpi_device(dev);
 	struct pnp_dev *pnp = _pnp;
+	struct device *physical_device;
+
+	physical_device = acpi_get_physical_device(acpi->handle);
+	if (physical_device)
+		put_device(physical_device);
 
 	/* true means it matched */
-	return !acpi_get_physical_device(acpi->handle)
+	return !physical_device
 	    && compare_pnp_id(pnp->id, acpi_device_hid(acpi));
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 03/47] IOMMU: Fix tboot force iommu logic
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 01/47] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 02/47] PNPACPI: Fix device ref leaking in acpi_pnp_match Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 04/47] x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn Yinghai Lu
                   ` (45 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, David Woodhouse, iommu

Should check dmar_disabled just after tboot_force_iommu.

Otherwise when tboot is not used, and intel_iommu=off, and nointrmap
still get dmar_table_init() called. that will cause some get_device
calling, and it will have some device refcount leaking.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/intel-iommu.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 49eb412..7c71a3a 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3768,6 +3768,9 @@ int __init intel_iommu_init(void)
 	/* VT-d is required for a TXT/tboot launch, so enforce that */
 	force_on = tboot_force_iommu();
 
+	if (no_iommu || dmar_disabled)
+		return -ENODEV;
+
 	if (dmar_table_init()) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR table\n");
@@ -3780,9 +3783,6 @@ int __init intel_iommu_init(void)
 		return 	-ENODEV;
 	}
 
-	if (no_iommu || dmar_disabled)
-		return -ENODEV;
-
 	if (iommu_init_mempool()) {
 		if (force_on)
 			panic("tboot: Failed to initialize iommu memory\n");
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 04/47] x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (2 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 03/47] IOMMU: Fix tboot force iommu logic Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 05/47] PCI: Separate out pci_assign_unassigned_bus_resources() Yinghai Lu
                   ` (44 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Non acpi path, or root is not probed from acpi, during root bus removal
will get warning about leaking from pci_scan_bus_on_node.

Fix it with setting pci_host_bridge release function.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/common.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 8e04ec5..35931f6 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -618,17 +618,19 @@ int pci_ext_cfg_avail(struct pci_dev *dev)
 		return 0;
 }
 
+static void release_pci_sysdata(struct pci_host_bridge *bridge)
+{
+	struct pci_sysdata *sd = bridge->release_data;
+
+	kfree(sd);
+}
+
 struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
 {
 	LIST_HEAD(resources);
 	struct pci_bus *bus = NULL;
 	struct pci_sysdata *sd;
 
-	/*
-	 * Allocate per-root-bus (not per bus) arch-specific data.
-	 * TODO: leak; this memory is never freed.
-	 * It's arguable whether it's worth the trouble to care.
-	 */
 	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
 	if (!sd) {
 		printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
@@ -638,7 +640,10 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 	x86_pci_root_bus_resources(busno, &resources);
 	printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
 	bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
-	if (!bus) {
+	if (bus)
+		pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
+					release_pci_sysdata, sd);
+	else {
 		pci_free_resource_list(&resources);
 		kfree(sd);
 	}
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 05/47] PCI: Separate out pci_assign_unassigned_bus_resources()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (3 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 04/47] x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 06/47] PCI: Move back pci_rescan_bus() Yinghai Lu
                   ` (43 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

It is main portion of pci_rescan_bus().

Separate it out and need to use it for pci root bus rescan later.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/setup-bus.c |   32 ++++++++++++++++++--------------
 include/linux/pci.h     |    1 +
 2 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8fa2d4b..6443c81 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1488,25 +1488,12 @@ enable_all:
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
-#ifdef CONFIG_HOTPLUG
-/**
- * pci_rescan_bus - scan a PCI bus for devices.
- * @bus: PCI bus to scan
- *
- * Scan a PCI bus and child buses for new devices, adds them,
- * and enables them.
- *
- * Returns the max number of subordinate bus discovered.
- */
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 {
-	unsigned int max;
 	struct pci_dev *dev;
 	LIST_HEAD(add_list); /* list of resources that
 					want additional resources */
 
-	max = pci_scan_child_bus(bus);
-
 	down_read(&pci_bus_sem);
 	list_for_each_entry(dev, &bus->devices, bus_list)
 		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
@@ -1519,6 +1506,23 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 	BUG_ON(!list_empty(&add_list));
 
 	pci_enable_bridges(bus);
+}
+#ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+{
+	unsigned int max;
+
+	max = pci_scan_child_bus(bus);
+	pci_assign_unassigned_bus_resources(bus);
 	pci_bus_add_devices(bus);
 
 	return max;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 40606c1..634bbf5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -909,6 +909,7 @@ void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
+void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
 void pdev_enable_device(struct pci_dev *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 06/47] PCI: Move back pci_rescan_bus()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (4 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 05/47] PCI: Separate out pci_assign_unassigned_bus_resources() Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 07/47] PCI: pci_bus_size_bridges() should not size own bridge Yinghai Lu
                   ` (42 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Now we have pci_assign_unassigned_bus_resources() in place.

So move back pci_rescan_bus to probe.c where it should be.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/probe.c     |   21 +++++++++++++++++++++
 drivers/pci/setup-bus.c |   22 ----------------------
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 38e0448..3dc92b9 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2036,6 +2036,27 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 	return max;
 }
 
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+{
+	unsigned int max;
+
+	max = pci_scan_child_bus(bus);
+	pci_assign_unassigned_bus_resources(bus);
+	pci_bus_add_devices(bus);
+
+	return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bridge);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 6443c81..f35a679 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1507,25 +1507,3 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 
 	pci_enable_bridges(bus);
 }
-#ifdef CONFIG_HOTPLUG
-/**
- * pci_rescan_bus - scan a PCI bus for devices.
- * @bus: PCI bus to scan
- *
- * Scan a PCI bus and child buses for new devices, adds them,
- * and enables them.
- *
- * Returns the max number of subordinate bus discovered.
- */
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
-{
-	unsigned int max;
-
-	max = pci_scan_child_bus(bus);
-	pci_assign_unassigned_bus_resources(bus);
-	pci_bus_add_devices(bus);
-
-	return max;
-}
-EXPORT_SYMBOL_GPL(pci_rescan_bus);
-#endif
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 07/47] PCI: pci_bus_size_bridges() should not size own bridge
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (5 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 06/47] PCI: Move back pci_rescan_bus() Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 08/47] PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources() Yinghai Lu
                   ` (41 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

During checking acpiphp code, found following sequence:
        pci_bus_size_bridges(bus);
        pci_bus_assign_resources(bus);
	pci_enable_bridges(bus);

The problem is that when bus is not root bus, pci_bus_size_bridges would also size
own pci bridge bus->self if that bridge resource is not inserted before.
but later pci_bus_assign_resources will not allocate those size bridge res.

So try make it less confusing, let it does not include self sizing.
and add with_self parameter info __pci_bus_size_bridge()

Fixes caller in pci hotplug componets.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/hotplug/acpiphp_glue.c     |    3 ++-
 drivers/pci/hotplug/cpci_hotplug_pci.c |    2 +-
 drivers/pci/hotplug/shpchp_pci.c       |    2 +-
 drivers/pci/setup-bus.c                |   24 +++++++++++++++---------
 include/linux/pci.h                    |    1 +
 5 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 806c44f..6aaf9ff 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -816,7 +816,8 @@ static int __ref enable_device(struct acpiphp_slot *slot)
 			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 				max = pci_scan_bridge(bus, dev, max, pass);
 				if (pass && dev->subordinate)
-					pci_bus_size_bridges(dev->subordinate);
+					pci_bus_size_bridges_with_self(
+							dev->subordinate);
 			}
 		}
 	}
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index ae853cc..4ef80ad 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -313,7 +313,7 @@ int __ref cpci_configure_slot(struct slot *slot)
 				continue;
 			}
 			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges(child);
+			pci_bus_size_bridges_with_self(child);
 		}
 		pci_dev_put(dev);
 	}
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index df7e4bf..d92807b 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -85,7 +85,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
 				continue;
 			}
 			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges(child);
+			pci_bus_size_bridges_with_self(child);
 		}
 		pci_configure_slot(dev);
 		pci_dev_put(dev);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f35a679..ec2026c 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -982,8 +982,8 @@ handle_done:
 	;
 }
 
-void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-			struct list_head *realloc_head)
+static void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+			struct list_head *realloc_head, bool with_self)
 {
 	struct pci_dev *dev;
 	unsigned long mask, prefmask;
@@ -1001,13 +1001,13 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
 
 		case PCI_CLASS_BRIDGE_PCI:
 		default:
-			__pci_bus_size_bridges(b, realloc_head);
+			__pci_bus_size_bridges(b, realloc_head, true);
 			break;
 		}
 	}
 
-	/* The root bus? */
-	if (!bus->self)
+	/* Is root bus or not wanted? */
+	if (!bus->self || !with_self)
 		return;
 
 	switch (bus->self->class >> 8) {
@@ -1047,9 +1047,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
 	}
 }
 
+void __ref pci_bus_size_bridges_with_self(struct pci_bus *bus)
+{
+	__pci_bus_size_bridges(bus, NULL, true);
+}
+EXPORT_SYMBOL(pci_bus_size_bridges_with_self);
+
 void __ref pci_bus_size_bridges(struct pci_bus *bus)
 {
-	__pci_bus_size_bridges(bus, NULL);
+	__pci_bus_size_bridges(bus, NULL, false);
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
@@ -1362,7 +1368,7 @@ again:
 	/* Depth first, calculate sizes and alignments of all
 	   subordinate buses. */
 	list_for_each_entry(bus, &pci_root_buses, node)
-		__pci_bus_size_bridges(bus, add_list);
+		__pci_bus_size_bridges(bus, add_list, false);
 
 	/* Depth last, allocate resources and update the hardware. */
 	list_for_each_entry(bus, &pci_root_buses, node)
@@ -1439,7 +1445,7 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 				  IORESOURCE_PREFETCH;
 
 again:
-	__pci_bus_size_bridges(parent, &add_list);
+	__pci_bus_size_bridges(parent, &add_list, true);
 	__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
 	BUG_ON(!list_empty(&add_list));
 	tried_times++;
@@ -1500,7 +1506,7 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 			if (dev->subordinate)
 				__pci_bus_size_bridges(dev->subordinate,
-							 &add_list);
+						 &add_list, true);
 	up_read(&pci_bus_sem);
 	__pci_bus_assign_resources(bus, &add_list, NULL);
 	BUG_ON(!list_empty(&add_list));
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 634bbf5..87dceca 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -906,6 +906,7 @@ int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
+void pci_bus_size_bridges_with_self(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 08/47] PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (6 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 07/47] PCI: pci_bus_size_bridges() should not size own bridge Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 09/47] PCI, sysfs: Use device_type and attr_groups with pci dev Yinghai Lu
                   ` (40 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Now __pci_bus_size_bridges() will not include self bridge.
So we don't need to have our own version in
 pci_assign_unassigned_bus_resources anymore.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/setup-bus.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index ec2026c..d9a5500 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1496,17 +1496,11 @@ EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
 {
-	struct pci_dev *dev;
 	LIST_HEAD(add_list); /* list of resources that
 					want additional resources */
 
 	down_read(&pci_bus_sem);
-	list_for_each_entry(dev, &bus->devices, bus_list)
-		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
-		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
-			if (dev->subordinate)
-				__pci_bus_size_bridges(dev->subordinate,
-						 &add_list, true);
+	__pci_bus_size_bridges(bus, &add_list, false);
 	up_read(&pci_bus_sem);
 	__pci_bus_assign_resources(bus, &add_list, NULL);
 	BUG_ON(!list_empty(&add_list));
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 09/47] PCI, sysfs: Use device_type and attr_groups with pci dev
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (7 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 08/47] PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources() Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:45 ` [PATCH -v3 10/47] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges Yinghai Lu
                   ` (39 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

We want to create rescan in sys only for pci bridge instead of all pci dev.

We could use attribute_groups/is_visible method to do that.

Now pci dev does not use device type yet. So add pci_dev_type to take
attr_groups with it.

Add pci_dev_bridge_attrs_are_visible() to control attr_bridge_group only create
attr for bridge.

This is the framework related change, later could attr to bridge_attr_group,
to make those attr only show up on pci bridge device.

Also We could add more attr groups with is_visible to reduce messness in
	pci_create_sysfs_dev_files. ( at least for boot_vga one )

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/pci-sysfs.c |   30 ++++++++++++++++++++++++++++++
 drivers/pci/pci.h       |    1 +
 drivers/pci/probe.c     |    1 +
 3 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a55e248..39d15e6 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1335,3 +1335,33 @@ static int __init pci_sysfs_init(void)
 }
 
 late_initcall(pci_sysfs_init);
+
+static struct attribute *pci_dev_bridge_attrs[] = {
+	NULL,
+};
+
+static umode_t pci_dev_bridge_attrs_are_visible(struct kobject *kobj,
+						struct attribute *a, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!pdev->subordinate)
+		return 0;
+
+	return a->mode;
+}
+
+static struct attribute_group pci_dev_bridge_attr_group = {
+	.attrs = pci_dev_bridge_attrs,
+	.is_visible = pci_dev_bridge_attrs_are_visible,
+};
+
+static const struct attribute_group *pci_dev_attr_groups[] = {
+	&pci_dev_bridge_attr_group,
+	NULL,
+};
+
+struct device_type pci_dev_type = {
+	.groups = pci_dev_attr_groups,
+};
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e494347..13b1159 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -162,6 +162,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
 }
 extern struct device_attribute pci_dev_attrs[];
 extern struct device_attribute pcibus_dev_attrs[];
+extern struct device_type pci_dev_type;
 #ifdef CONFIG_HOTPLUG
 extern struct bus_attribute pci_bus_attrs[];
 #else
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 3dc92b9..e51e1a5 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1119,6 +1119,7 @@ int pci_setup_device(struct pci_dev *dev)
 	dev->sysdata = dev->bus->sysdata;
 	dev->dev.parent = dev->bus->bridge;
 	dev->dev.bus = &pci_bus_type;
+	dev->dev.type = &pci_dev_type;
 	dev->hdr_type = hdr_type & 0x7f;
 	dev->multifunction = !!(hdr_type & 0x80);
 	dev->error_state = pci_channel_io_normal;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 10/47] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (8 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 09/47] PCI, sysfs: Use device_type and attr_groups with pci dev Yinghai Lu
@ 2012-03-19  5:45 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 11/47] PCI: Add pci_bus_add_single_device() Yinghai Lu
                   ` (38 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:45 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Randy Dunlap

Current code will create rescan for every pci device under parent bus.
that is not right. The device is already there, there is no reason to rescan it.

We could have rescan for pci bridges. less confusing.

Need to move rescan attr to pci dev bridge attribute group.
And we should rescan bridge's secondary bus instead of primary bus.

-v3: Use device_type for pci dev.
-v4: Seperate pci device type change out
-v5: add rescan_bridge for bridge type, and still keep the old rescan.
	may remove the old rescan later.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 Documentation/ABI/testing/sysfs-bus-pci |   10 ++++++++++
 drivers/pci/pci-sysfs.c                 |   24 ++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 34f5110..95f0f37 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -111,6 +111,16 @@ Description:
 		from this part of the device tree.
 		Depends on CONFIG_HOTPLUG.
 
+What:		/sys/bus/pci/devices/.../rescan_bridge
+Date:		February 2012
+Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+		Writing a non-zero value to this attribute will
+		force a rescan of the bridge and all child buses, and
+		re-discover devices removed earlier from this part of
+		the device tree.
+		Depends on CONFIG_HOTPLUG.
+
 What:		/sys/bus/pci/devices/.../reset
 Date:		July 2009
 Contact:	Michael S. Tsirkin <mst@redhat.com>
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 39d15e6..d5c8ffb 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -325,6 +325,27 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+static ssize_t
+dev_bridge_rescan_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	unsigned long val;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (kstrtoul(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	if (val) {
+		mutex_lock(&pci_remove_rescan_mutex);
+		pci_rescan_bus(pdev->subordinate);
+		mutex_unlock(&pci_remove_rescan_mutex);
+	}
+	return count;
+}
+
+static struct device_attribute pci_dev_bridge_rescan_attr =
+	__ATTR(rescan_bridge, (S_IWUSR|S_IWGRP), NULL, dev_bridge_rescan_store);
+
 static void remove_callback(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
@@ -1337,6 +1358,9 @@ static int __init pci_sysfs_init(void)
 late_initcall(pci_sysfs_init);
 
 static struct attribute *pci_dev_bridge_attrs[] = {
+#ifdef CONFIG_HOTPLUG
+	&pci_dev_bridge_rescan_attr.attr,
+#endif
 	NULL,
 };
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 11/47] PCI: Add pci_bus_add_single_device()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (9 preceding siblings ...)
  2012-03-19  5:45 ` [PATCH -v3 10/47] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 12/47] PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead Yinghai Lu
                   ` (37 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Will use it to pci_bus_bridge_scan_resize() to make bridge will
have pci_bus directory created correctly.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/bus.c   |   39 +++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h |    1 +
 2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 4ce5ef2..1eb7944 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -255,6 +255,45 @@ void pci_bus_add_devices(const struct pci_bus *bus)
 	}
 }
 
+void pci_bus_add_single_device(struct pci_dev *dev)
+{
+	struct pci_bus *child;
+	int retval;
+
+	/* Skip already-added devices */
+	if (!dev->is_added) {
+		retval = pci_bus_add_device(dev);
+		if (retval)
+			dev_err(&dev->dev, "Error adding device, continuing\n");
+	}
+
+	BUG_ON(!dev->is_added);
+
+	child = dev->subordinate;
+	/*
+	 * If there is an unattached subordinate bus, attach
+	 * it and then scan for unattached PCI devices.
+	 */
+	if (child) {
+		if (list_empty(&child->node)) {
+			down_write(&pci_bus_sem);
+			list_add_tail(&child->node, &dev->bus->children);
+			up_write(&pci_bus_sem);
+		}
+		pci_bus_add_devices(child);
+
+		/*
+		 * register the bus with sysfs as the parent is now
+		 * properly registered.
+		 */
+		if (!child->is_added) {
+			retval = pci_bus_add_child(child);
+			if (retval)
+				dev_err(&dev->dev, "Error adding bus, continuing\n");
+		}
+	}
+}
+
 void pci_enable_bridges(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 87dceca..860091f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -665,6 +665,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
 void pcibios_scan_specific_bus(int busn);
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(const struct pci_bus *bus);
+void pci_bus_add_single_device(struct pci_dev *dev);
 struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
 				      struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 12/47] PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (10 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 11/47] PCI: Add pci_bus_add_single_device() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 13/47] PCI: Clean up rescan_bus_bridge_resize() Yinghai Lu
                   ` (36 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

So after remove all children and then using setpci change bus register and rescan
bridge could use new set bus number.

Otherwise need to rescan parent bus, it would have too much overhead.

also need to use pci_bus_add_single_device to make sure new change bus have directory
 /sys/../.../pci_bus.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/probe.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index e51e1a5..a819e76 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2025,14 +2025,16 @@ EXPORT_SYMBOL(pci_scan_bus);
  */
 unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 {
-	unsigned int max;
-	struct pci_bus *bus = bridge->subordinate;
+	unsigned int max = 0;
+	int pass;
+	struct pci_bus *bus = bridge->bus;
 
-	max = pci_scan_child_bus(bus);
+	for (pass = 0; pass < 2; pass++)
+		max = pci_scan_bridge(bus, bridge, max, pass);
 
 	pci_assign_unassigned_bridge_resources(bridge);
 
-	pci_bus_add_devices(bus);
+	pci_bus_add_single_device(bridge);
 
 	return max;
 }
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 13/47] PCI: Clean up rescan_bus_bridge_resize()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (11 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 12/47] PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 14/47] PCI: Rescan bus or bridge using callback method too Yinghai Lu
                   ` (35 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Should only use it with bridge instead of bus.
It could get new subordinate. so can not use it with reguar bus.

In that case, user may need to make sure all children devices get removed
already before rescan.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/pci-sysfs.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index d5c8ffb..2049b2f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -337,7 +337,7 @@ dev_bridge_rescan_store(struct device *dev, struct device_attribute *attr,
 
 	if (val) {
 		mutex_lock(&pci_remove_rescan_mutex);
-		pci_rescan_bus(pdev->subordinate);
+		pci_rescan_bus_bridge_resize(pdev);
 		mutex_unlock(&pci_remove_rescan_mutex);
 	}
 	return count;
@@ -387,10 +387,7 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
 
 	if (val) {
 		mutex_lock(&pci_remove_rescan_mutex);
-		if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
-			pci_rescan_bus_bridge_resize(bus->self);
-		else
-			pci_rescan_bus(bus);
+		pci_rescan_bus(bus);
 		mutex_unlock(&pci_remove_rescan_mutex);
 	}
 	return count;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 14/47] PCI: Rescan bus or bridge using callback method too
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (12 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 13/47] PCI: Clean up rescan_bus_bridge_resize() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 15/47] PCI, sysfs: Clean up rescan/remove with scheule_callback Yinghai Lu
                   ` (34 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Just like removal.

Because We could add new bus under the bridges...

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/pci-sysfs.c |   43 +++++++++++++++++++++++++++++++------------
 1 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 2049b2f..1794508 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -325,21 +325,31 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+static void bridge_rescan_callback(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	mutex_lock(&pci_remove_rescan_mutex);
+	pci_rescan_bus_bridge_resize(pdev);
+	mutex_unlock(&pci_remove_rescan_mutex);
+}
+
 static ssize_t
 dev_bridge_rescan_store(struct device *dev, struct device_attribute *attr,
 		 const char *buf, size_t count)
 {
+	int ret = 0;
 	unsigned long val;
-	struct pci_dev *pdev = to_pci_dev(dev);
 
 	if (kstrtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
-	if (val) {
-		mutex_lock(&pci_remove_rescan_mutex);
-		pci_rescan_bus_bridge_resize(pdev);
-		mutex_unlock(&pci_remove_rescan_mutex);
-	}
+	if (val)
+		ret = device_schedule_callback(dev, bridge_rescan_callback);
+
+	if (ret)
+		count = ret;
+
 	return count;
 }
 
@@ -375,21 +385,30 @@ remove_store(struct device *dev, struct device_attribute *dummy,
 	return count;
 }
 
+static void bus_rescan_callback(struct device *dev)
+{
+	struct pci_bus *bus = to_pci_bus(dev);
+
+	mutex_lock(&pci_remove_rescan_mutex);
+	pci_rescan_bus(bus);
+	mutex_unlock(&pci_remove_rescan_mutex);
+}
 static ssize_t
 dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
 		 const char *buf, size_t count)
 {
+	int ret = 0;
 	unsigned long val;
-	struct pci_bus *bus = to_pci_bus(dev);
 
 	if (strict_strtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
-	if (val) {
-		mutex_lock(&pci_remove_rescan_mutex);
-		pci_rescan_bus(bus);
-		mutex_unlock(&pci_remove_rescan_mutex);
-	}
+	if (val)
+		ret = device_schedule_callback(dev, bus_rescan_callback);
+
+	if (ret)
+		count = ret;
+
 	return count;
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 15/47] PCI, sysfs: Clean up rescan/remove with scheule_callback
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (13 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 14/47] PCI: Rescan bus or bridge using callback method too Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 16/47] x86, PCI: Separate pcibios_allocate_bridge_resources() Yinghai Lu
                   ` (33 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Change to use three return according to Bjorn.

Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/pci-sysfs.c |   37 ++++++++++++++++++++-----------------
 1 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 1794508..4697afe 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -338,17 +338,17 @@ static ssize_t
 dev_bridge_rescan_store(struct device *dev, struct device_attribute *attr,
 		 const char *buf, size_t count)
 {
-	int ret = 0;
+	int err;
 	unsigned long val;
 
 	if (kstrtoul(buf, 0, &val) < 0)
 		return -EINVAL;
+	if (!val)
+		return count;
 
-	if (val)
-		ret = device_schedule_callback(dev, bridge_rescan_callback);
-
-	if (ret)
-		count = ret;
+	err = device_schedule_callback(dev, bridge_rescan_callback);
+	if (err)
+		return err;
 
 	return count;
 }
@@ -369,7 +369,7 @@ static ssize_t
 remove_store(struct device *dev, struct device_attribute *dummy,
 	     const char *buf, size_t count)
 {
-	int ret = 0;
+	int err;
 	unsigned long val;
 
 	if (strict_strtoul(buf, 0, &val) < 0)
@@ -378,10 +378,13 @@ remove_store(struct device *dev, struct device_attribute *dummy,
 	/* An attribute cannot be unregistered by one of its own methods,
 	 * so we have to use this roundabout approach.
 	 */
-	if (val)
-		ret = device_schedule_callback(dev, remove_callback);
-	if (ret)
-		count = ret;
+	if (!val)
+		return count;
+
+	err = device_schedule_callback(dev, remove_callback);
+	if (err)
+		return err;
+
 	return count;
 }
 
@@ -397,17 +400,17 @@ static ssize_t
 dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
 		 const char *buf, size_t count)
 {
-	int ret = 0;
+	int err;
 	unsigned long val;
 
 	if (strict_strtoul(buf, 0, &val) < 0)
 		return -EINVAL;
+	if (!val)
+		return count;
 
-	if (val)
-		ret = device_schedule_callback(dev, bus_rescan_callback);
-
-	if (ret)
-		count = ret;
+	err = device_schedule_callback(dev, bus_rescan_callback);
+	if (err)
+		return err;
 
 	return count;
 }
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 16/47] x86, PCI: Separate pcibios_allocate_bridge_resources()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (14 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 15/47] PCI, sysfs: Clean up rescan/remove with scheule_callback Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 17/47] x86, PCI: Separate pcibios_allocate_dev_resources() Yinghai Lu
                   ` (32 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Thus pcibios_allocate_bus_resources() could more simple and clean

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/i386.c |   46 ++++++++++++++++++++++++----------------------
 1 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 831971e..c06f60f 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -193,34 +193,36 @@ EXPORT_SYMBOL(pcibios_align_resource);
  *	    as well.
  */
 
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+static void __init pcibios_allocate_bridge_resources(struct pci_dev *dev)
 {
-	struct pci_bus *bus;
-	struct pci_dev *dev;
 	int idx;
 	struct resource *r;
 
+	for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+		r = &dev->resource[idx];
+		if (!r->flags)
+			continue;
+		if (!r->start || pci_claim_resource(dev, idx) < 0) {
+			/*
+			 * Something is wrong with the region.
+			 * Invalidate the resource to prevent
+			 * child resource allocations in this
+			 * range.
+			 */
+			r->start = r->end = 0;
+			r->flags = 0;
+		}
+	}
+}
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct pci_bus *bus;
+
 	/* Depth-First Search on bus tree */
 	list_for_each_entry(bus, bus_list, node) {
-		if ((dev = bus->self)) {
-			for (idx = PCI_BRIDGE_RESOURCES;
-			    idx < PCI_NUM_RESOURCES; idx++) {
-				r = &dev->resource[idx];
-				if (!r->flags)
-					continue;
-				if (!r->start ||
-				    pci_claim_resource(dev, idx) < 0) {
-					/*
-					 * Something is wrong with the region.
-					 * Invalidate the resource to prevent
-					 * child resource allocations in this
-					 * range.
-					 */
-					r->start = r->end = 0;
-					r->flags = 0;
-				}
-			}
-		}
+		if (bus->self)
+			pcibios_allocate_bridge_resources(bus->self);
 		pcibios_allocate_bus_resources(&bus->children);
 	}
 }
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 17/47] x86, PCI: Separate pcibios_allocate_dev_resources()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (15 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 16/47] x86, PCI: Separate pcibios_allocate_bridge_resources() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 18/47] x86, PCI: Let pcibios_allocate_bus_resources() take bus instead Yinghai Lu
                   ` (31 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Thus pcibios_allocate_resources() could more simple and clean

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/i386.c |   42 +++++++++++++++++++++++-------------------
 1 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index c06f60f..bb84ff0 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -232,9 +232,8 @@ struct pci_check_idx_range {
 	int end;
 };
 
-static void __init pcibios_allocate_resources(int pass)
+static void __init pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
 {
-	struct pci_dev *dev = NULL;
 	int idx, disabled, i;
 	u16 command;
 	struct resource *r;
@@ -246,14 +245,13 @@ static void __init pcibios_allocate_resources(int pass)
 #endif
 	};
 
-	for_each_pci_dev(dev) {
-		pci_read_config_word(dev, PCI_COMMAND, &command);
-		for (i = 0; i < ARRAY_SIZE(idx_range); i++)
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	for (i = 0; i < ARRAY_SIZE(idx_range); i++)
 		for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
 			r = &dev->resource[idx];
-			if (r->parent)		/* Already allocated */
+			if (r->parent)	/* Already allocated */
 				continue;
-			if (!r->start)		/* Address not assigned at all */
+			if (!r->start)	/* Address not assigned at all */
 				continue;
 			if (r->flags & IORESOURCE_IO)
 				disabled = !(command & PCI_COMMAND_IO);
@@ -272,23 +270,29 @@ static void __init pcibios_allocate_resources(int pass)
 				}
 			}
 		}
-		if (!pass) {
-			r = &dev->resource[PCI_ROM_RESOURCE];
-			if (r->flags & IORESOURCE_ROM_ENABLE) {
-				/* Turn the ROM off, leave the resource region,
-				 * but keep it unregistered. */
-				u32 reg;
-				dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
-				r->flags &= ~IORESOURCE_ROM_ENABLE;
-				pci_read_config_dword(dev,
-						dev->rom_base_reg, &reg);
-				pci_write_config_dword(dev, dev->rom_base_reg,
+	if (!pass) {
+		r = &dev->resource[PCI_ROM_RESOURCE];
+		if (r->flags & IORESOURCE_ROM_ENABLE) {
+			/* Turn the ROM off, leave the resource region,
+			 * but keep it unregistered. */
+			u32 reg;
+			dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
+			r->flags &= ~IORESOURCE_ROM_ENABLE;
+			pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+			pci_write_config_dword(dev, dev->rom_base_reg,
 						reg & ~PCI_ROM_ADDRESS_ENABLE);
-			}
 		}
 	}
 }
 
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev)
+		pcibios_allocate_dev_resources(dev, pass);
+}
+
 static int __init pcibios_assign_resources(void)
 {
 	struct pci_dev *dev = NULL;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 18/47] x86, PCI: Let pcibios_allocate_bus_resources() take bus instead
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (16 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 17/47] x86, PCI: Separate pcibios_allocate_dev_resources() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 19/47] PCI: Claim hw/fw allocated resources in hot add path Yinghai Lu
                   ` (30 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Will need call the same code for one single root bus during hot add.
So try to make it take bus instead of bus_list.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/i386.c |   38 +++++++++++++++++++++++++-------------
 1 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index bb84ff0..cecb842 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -215,16 +215,15 @@ static void __init pcibios_allocate_bridge_resources(struct pci_dev *dev)
 	}
 }
 
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
-	struct pci_bus *bus;
+	struct pci_bus *child;
 
 	/* Depth-First Search on bus tree */
-	list_for_each_entry(bus, bus_list, node) {
-		if (bus->self)
-			pcibios_allocate_bridge_resources(bus->self);
-		pcibios_allocate_bus_resources(&bus->children);
-	}
+	if (bus->self)
+		pcibios_allocate_bridge_resources(bus->self);
+	list_for_each_entry(child, &bus->children, node)
+		pcibios_allocate_bus_resources(child);
 }
 
 struct pci_check_idx_range {
@@ -285,12 +284,18 @@ static void __init pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
 	}
 }
 
-static void __init pcibios_allocate_resources(int pass)
+static void __init pcibios_allocate_resources(struct pci_bus *bus, int pass)
 {
-	struct pci_dev *dev = NULL;
+	struct pci_dev *dev;
+	struct pci_bus *child;
 
-	for_each_pci_dev(dev)
+	list_for_each_entry(dev, &bus->devices, bus_list) {
 		pcibios_allocate_dev_resources(dev, pass);
+
+		child = dev->subordinate;
+		if (child)
+			pcibios_allocate_resources(child, pass);
+	}
 }
 
 static int __init pcibios_assign_resources(void)
@@ -323,10 +328,17 @@ static int __init pcibios_assign_resources(void)
 
 void __init pcibios_resource_survey(void)
 {
+	struct pci_bus *bus;
+
 	DBG("PCI: Allocating resources\n");
-	pcibios_allocate_bus_resources(&pci_root_buses);
-	pcibios_allocate_resources(0);
-	pcibios_allocate_resources(1);
+
+	list_for_each_entry(bus, &pci_root_buses, node)
+		pcibios_allocate_bus_resources(bus);
+
+	list_for_each_entry(bus, &pci_root_buses, node)
+		pcibios_allocate_resources(bus, 0);
+	list_for_each_entry(bus, &pci_root_buses, node)
+		pcibios_allocate_resources(bus, 1);
 
 	e820_reserve_resources_late();
 	/*
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 19/47] PCI: Claim hw/fw allocated resources in hot add path.
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (17 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 18/47] x86, PCI: Let pcibios_allocate_bus_resources() take bus instead Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 20/47] Correctly clean up pci root buses in function pci_remove_bus() Yinghai Lu
                   ` (29 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

During testing remove/rescan root bus 00, found
[  338.142574] bus: 'pci': really_probe: probing driver ata_piix with device 0000:00:01.1
[  338.146788] ata_piix 0000:00:01.1: device not available (can't reserve [io  0x01f0-0x01f7])
[  338.150565] ata_piix: probe of 0000:00:01.1 failed with error -22

because that fixed resource is not claimed from
        arch/x86/pci/i386.c::pcibios_allocate_resources()
that is init path.

Try to claim those resources, so on the remove/rescan will still use old
resources.

It is some kind honoring HW/FW setting in the registers during hot add.
esp root-bus hot add is through acpi, BIOS have chance to set some register
for us.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/i386.c |   20 ++++++++++++++++----
 drivers/pci/bus.c   |    2 ++
 include/linux/pci.h |    1 +
 3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index cecb842..e1ff375 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -193,13 +193,15 @@ EXPORT_SYMBOL(pcibios_align_resource);
  *	    as well.
  */
 
-static void __init pcibios_allocate_bridge_resources(struct pci_dev *dev)
+static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
 {
 	int idx;
 	struct resource *r;
 
 	for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
 		r = &dev->resource[idx];
+		if (r->parent)	/* Already allocated */
+			continue;
 		if (!r->flags)
 			continue;
 		if (!r->start || pci_claim_resource(dev, idx) < 0) {
@@ -215,7 +217,7 @@ static void __init pcibios_allocate_bridge_resources(struct pci_dev *dev)
 	}
 }
 
-static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
 	struct pci_bus *child;
 
@@ -231,7 +233,7 @@ struct pci_check_idx_range {
 	int end;
 };
 
-static void __init pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
+static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
 {
 	int idx, disabled, i;
 	u16 command;
@@ -284,7 +286,7 @@ static void __init pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
 	}
 }
 
-static void __init pcibios_allocate_resources(struct pci_bus *bus, int pass)
+static void pcibios_allocate_resources(struct pci_bus *bus, int pass)
 {
 	struct pci_dev *dev;
 	struct pci_bus *child;
@@ -326,6 +328,16 @@ static int __init pcibios_assign_resources(void)
 	return 0;
 }
 
+void pcibios_resource_survey_bus(struct pci_bus *bus)
+{
+	dev_printk(KERN_DEBUG, &bus->dev, "Allocating resources\n");
+
+	pcibios_allocate_bus_resources(bus);
+
+	pcibios_allocate_resources(bus, 0);
+	pcibios_allocate_resources(bus, 1);
+}
+
 void __init pcibios_resource_survey(void)
 {
 	struct pci_bus *bus;
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 1eb7944..672ffc8 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -94,6 +94,8 @@ void pci_bus_remove_resources(struct pci_bus *bus)
 	pci_free_resource_list(&bus->resources);
 }
 
+void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
+
 /**
  * pci_bus_alloc_resource - allocate a resource from a parent bus
  * @bus: PCI bus
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 860091f..b434401 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -643,6 +643,7 @@ extern struct list_head pci_root_buses;	/* list of all known PCI buses */
 /* Some device drivers need know if pci is initiated */
 extern int no_pci_devices(void);
 
+void pcibios_resource_survey_bus(struct pci_bus *bus);
 void pcibios_fixup_bus(struct pci_bus *);
 int __must_check pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup(char *str);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 20/47] Correctly clean up pci root buses in function pci_remove_bus()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (18 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 19/47] PCI: Claim hw/fw allocated resources in hot add path Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 21/47] PCI: Move pci_stop_and_remove_behind_bridge() down Yinghai Lu
                   ` (28 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Jiang Liu, Yinghai Lu

From: Jiang Liu <jiang.liu@huawei.com>

The function pci_create_root_bus() allocates the pci bus structure,
registers the bus device and creates the legacy files for a pci root
bus, but returns without setting the is_added flag. The is_added flag
for a pci root bus will be set by function pci_scan_child_bus().
If a pci root bus is destroyed before calling pci_scan_child_bus(),
the is_added flag will not be set.  So teach function pci_remove_bus()
to detect such a case and correctly clean up pci root buses.

Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |    9 ++++-----
 1 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 04a4861..bf4b46b 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -70,11 +70,10 @@ void pci_remove_bus(struct pci_bus *pci_bus)
 	list_del(&pci_bus->node);
 	pci_bus_release_busn_res(pci_bus);
 	up_write(&pci_bus_sem);
-	if (!pci_bus->is_added)
-		return;
-
-	pci_remove_legacy_files(pci_bus);
-	device_unregister(&pci_bus->dev);
+	if (pci_bus->is_added || pci_is_root_bus(pci_bus)) {
+		pci_remove_legacy_files(pci_bus);
+		device_unregister(&pci_bus->dev);
+	}
 }
 EXPORT_SYMBOL(pci_remove_bus);
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 21/47] PCI: Move pci_stop_and_remove_behind_bridge() down
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (19 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 20/47] Correctly clean up pci root buses in function pci_remove_bus() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 22/47] PCI: Add __pci_remove_bus_devices() Yinghai Lu
                   ` (27 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Later it will use pci_stop_bus_devices instead of pci_stop_behind_bridge.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |   30 +++++++++++++++---------------
 1 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index bf4b46b..3f540ce 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -128,21 +128,6 @@ static void pci_stop_behind_bridge(struct pci_dev *dev)
 			pci_stop_bus_device(pci_dev_b(l));
 }
 
-/**
- * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
- *					 a PCI bridge
- * @dev: PCI bridge device
- *
- * Remove all devices on the bus, except for the parent bridge.
- * This also removes any child buses, and any devices they may
- * contain in a depth-first manner.
- */
-void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
-{
-	pci_stop_behind_bridge(dev);
-	__pci_remove_behind_bridge(dev);
-}
-
 static void pci_stop_bus_devices(struct pci_bus *bus)
 {
 	struct list_head *l, *n;
@@ -162,6 +147,21 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
 }
 
 /**
+ * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
+ *					 a PCI bridge
+ * @dev: PCI bridge device
+ *
+ * Remove all devices on the bus, except for the parent bridge.
+ * This also removes any child buses, and any devices they may
+ * contain in a depth-first manner.
+ */
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
+{
+	pci_stop_behind_bridge(dev);
+	__pci_remove_behind_bridge(dev);
+}
+
+/**
  * pci_stop_bus_device - stop a PCI device and any children
  * @dev: the device to stop
  *
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 22/47] PCI: Add __pci_remove_bus_devices()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (20 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 21/47] PCI: Move pci_stop_and_remove_behind_bridge() down Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 23/47] PCI: Use list_for_each_entry_safe instead of list_for_each_safe Yinghai Lu
                   ` (26 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Will use it with pci_stop_and_remove_bus later.

Also remove __pci_remove_behind_bridge and pci_stop_behind_bridge.

They are same except one take bridge and one take bus.

We already have pci_stop_bus_devices().

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |   28 +++++++++++-----------------
 1 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 3f540ce..4bdda43 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -77,7 +77,7 @@ void pci_remove_bus(struct pci_bus *pci_bus)
 }
 EXPORT_SYMBOL(pci_remove_bus);
 
-static void __pci_remove_behind_bridge(struct pci_dev *dev);
+static void __pci_remove_bus_devices(struct pci_bus *bus);
 /**
  * pci_stop_and_remove_bus_device - remove a PCI device and any children
  * @dev: the device to remove
@@ -95,7 +95,7 @@ void __pci_remove_bus_device(struct pci_dev *dev)
 	if (dev->subordinate) {
 		struct pci_bus *b = dev->subordinate;
 
-		__pci_remove_behind_bridge(dev);
+		__pci_remove_bus_devices(b);
 		pci_remove_bus(b);
 		dev->subordinate = NULL;
 	}
@@ -110,22 +110,12 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 	__pci_remove_bus_device(dev);
 }
 
-static void __pci_remove_behind_bridge(struct pci_dev *dev)
+static void __pci_remove_bus_devices(struct pci_bus *bus)
 {
 	struct list_head *l, *n;
 
-	if (dev->subordinate)
-		list_for_each_safe(l, n, &dev->subordinate->devices)
-			__pci_remove_bus_device(pci_dev_b(l));
-}
-
-static void pci_stop_behind_bridge(struct pci_dev *dev)
-{
-	struct list_head *l, *n;
-
-	if (dev->subordinate)
-		list_for_each_safe(l, n, &dev->subordinate->devices)
-			pci_stop_bus_device(pci_dev_b(l));
+	list_for_each_safe(l, n, &bus->devices)
+		__pci_remove_bus_device(pci_dev_b(l));
 }
 
 static void pci_stop_bus_devices(struct pci_bus *bus)
@@ -157,8 +147,12 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
  */
 void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
 {
-	pci_stop_behind_bridge(dev);
-	__pci_remove_behind_bridge(dev);
+	struct pci_bus *bus = dev->subordinate;
+
+	if (bus) {
+		pci_stop_bus_devices(bus);
+		__pci_remove_bus_devices(bus);
+	}
 }
 
 /**
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 23/47] PCI: Use list_for_each_entry_safe instead of list_for_each_safe
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (21 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 22/47] PCI: Add __pci_remove_bus_devices() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 24/47] PCI: Add pci_stop_and_remove_bus() Yinghai Lu
                   ` (25 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

So could skip using pci_dev_b().

Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 4bdda43..64ba5b1 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -112,15 +112,15 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 
 static void __pci_remove_bus_devices(struct pci_bus *bus)
 {
-	struct list_head *l, *n;
+	struct pci_dev *dev, *tmp;
 
-	list_for_each_safe(l, n, &bus->devices)
-		__pci_remove_bus_device(pci_dev_b(l));
+	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list)
+		__pci_remove_bus_device(dev);
 }
 
 static void pci_stop_bus_devices(struct pci_bus *bus)
 {
-	struct list_head *l, *n;
+	struct pci_dev *dev, *tmp;
 
 	/*
 	 * VFs could be removed by pci_stop_and_remove_bus_device() in the
@@ -130,10 +130,8 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
 	 * We can iterate the list backwards to get prev valid PF instead
 	 *  of removed VF.
 	 */
-	list_for_each_prev_safe(l, n, &bus->devices) {
-		struct pci_dev *dev = pci_dev_b(l);
+	list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list)
 		pci_stop_bus_device(dev);
-	}
 }
 
 /**
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 24/47] PCI: Add pci_stop_and_remove_bus()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (22 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 23/47] PCI: Use list_for_each_entry_safe instead of list_for_each_safe Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 25/47] Fix an access-after-free issue in function pci_stop_and_remove_bus() Yinghai Lu
                   ` (24 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

It supports both pci root bus and pci bus under pci bridge.

-v2: clear pci_bridge's subordinate.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |   32 ++++++++++++++++++++++++++++++++
 include/linux/pci.h  |    1 +
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 64ba5b1..75b0092 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -169,6 +169,38 @@ void pci_stop_bus_device(struct pci_dev *dev)
 	pci_stop_dev(dev);
 }
 
+static void pci_stop_host_bridge(struct pci_host_bridge *bridge)
+{
+	device_unregister(&bridge->dev);
+}
+/*
+ * it will support pci root bus too, in that case we need
+ *  stop and remove host bridge
+ */
+void pci_stop_and_remove_bus(struct pci_bus *bus)
+{
+	struct pci_host_bridge *host_bridge = NULL;
+	struct pci_dev *pci_bridge = NULL;
+
+	pci_stop_bus_devices(bus);
+
+	if (pci_is_root_bus(bus)) {
+		host_bridge = to_pci_host_bridge(bus->bridge);
+		pci_stop_host_bridge(host_bridge);
+	} else
+		pci_bridge = bus->self;
+
+	__pci_remove_bus_devices(bus);
+
+	pci_remove_bus(bus);
+
+	if (host_bridge)
+		host_bridge->bus = NULL;
+
+	if (pci_bridge)
+		pci_bridge->subordinate = NULL;
+}
+
 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
 EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);
 EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b434401..aec945d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -703,6 +703,7 @@ extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
 extern void __pci_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_stop_and_remove_bus(struct pci_bus *bus);
 extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);
 extern void pci_sort_breadthfirst(void);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 25/47] Fix an access-after-free issue in function pci_stop_and_remove_bus()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (23 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 24/47] PCI: Add pci_stop_and_remove_bus() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 26/47] PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too Yinghai Lu
                   ` (23 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Jiang Liu, Yinghai Lu

From: Jiang Liu <jiang.liu@huawei.com>

If pci_stop_and_remove_bus() is called to remove a pci root bus,
the host_bridge structure may have already been freed after returning
from pci_remove_bus(). To avoid that, hold an extra reference count
to the root bus before calling pci_remove_bus(), so we can safely
access the pci_host_bridge structure after returning from function
pci_remove_bus().

Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/remove.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 75b0092..18efb31 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -186,6 +186,7 @@ void pci_stop_and_remove_bus(struct pci_bus *bus)
 
 	if (pci_is_root_bus(bus)) {
 		host_bridge = to_pci_host_bridge(bus->bridge);
+		get_device(&host_bridge->dev);
 		pci_stop_host_bridge(host_bridge);
 	} else
 		pci_bridge = bus->self;
@@ -194,8 +195,10 @@ void pci_stop_and_remove_bus(struct pci_bus *bus)
 
 	pci_remove_bus(bus);
 
-	if (host_bridge)
+	if (host_bridge) {
 		host_bridge->bus = NULL;
+		put_device(&host_bridge->dev);
+	}
 
 	if (pci_bridge)
 		pci_bridge->subordinate = NULL;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 26/47] PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (24 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 25/47] Fix an access-after-free issue in function pci_stop_and_remove_bus() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 27/47] PCI, acpiphp: Separate out hot-add support of pci host bridge Yinghai Lu
                   ` (22 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

It will call new added pci_stop_and_remove_bus() to stop/remove pci root bus.

Also checking if that pci_root_bus get removed already in bus remove in /sys

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/pci_root.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7aff631..b38e347 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -643,10 +643,24 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
 {
 	struct acpi_pci_root *root = acpi_driver_data(device);
 
+	/* that root bus could be removed already */
+	if (!pci_find_bus(root->segment, root->secondary.start)) {
+		dev_printk(KERN_DEBUG, &device->dev,
+		  "freeing acpi_pci_root, but pci root bus was removed before");
+		goto out;
+	}
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
+	dev_printk(KERN_DEBUG, &device->dev,
+		"freeing acpi_pci_root, will remove pci root bus at first");
+	pci_stop_and_remove_bus(root->bus);
+
+out:
+	list_del(&root->node);
 	kfree(root);
+
 	return 0;
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 27/47] PCI, acpiphp: Separate out hot-add support of pci host bridge
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (25 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 26/47] PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 28/47] PCI, ACPI: Add pci_root_hp hot removal notification support Yinghai Lu
                   ` (21 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

It causes confusion.

We may only need acpi hp for pci host bridge.

Split host bridge hot-add support to pci_root_hp, and keep acpiphp simple.

Also remove not used res_lock in the struct.

-v2: put back pci_root_hp change in one patch
-v3: add pcibios_resource_survey_bus() calling

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/acpi/Makefile              |    1 +
 drivers/acpi/pci_root_hp.c         |  238 ++++++++++++++++++++++++++++++++++++
 drivers/pci/hotplug/acpiphp.h      |    9 +--
 drivers/pci/hotplug/acpiphp_glue.c |  104 +++-------------
 4 files changed, 260 insertions(+), 92 deletions(-)
 create mode 100644 drivers/acpi/pci_root_hp.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 1567028..bc6e53f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -36,6 +36,7 @@ acpi-y				+= processor_core.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o pci_bind.o
+acpi-$(CONFIG_HOTPLUG)		+= pci_root_hp.o
 acpi-y				+= power.o
 acpi-y				+= event.o
 acpi-y				+= sysfs.o
diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c
new file mode 100644
index 0000000..e07c31b
--- /dev/null
+++ b/drivers/acpi/pci_root_hp.c
@@ -0,0 +1,238 @@
+/*
+ * Separated from drivers/pci/hotplug/acpiphp_glue.c
+ *	only support root bridge
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+
+static LIST_HEAD(acpi_root_bridge_list);
+struct acpi_root_bridge {
+	struct list_head list;
+	acpi_handle handle;
+	u32 flags;
+};
+
+/* bridge flags */
+#define ROOT_BRIDGE_HAS_EJ0	(0x00000002)
+#define ROOT_BRIDGE_HAS_PS3	(0x00000080)
+
+#define ACPI_STA_FUNCTIONING	(0x00000008)
+
+static struct acpi_root_bridge *acpi_root_handle_to_bridge(acpi_handle handle)
+{
+	struct acpi_root_bridge *bridge;
+
+	list_for_each_entry(bridge, &acpi_root_bridge_list, list)
+		if (bridge->handle == handle)
+			return bridge;
+
+	return NULL;
+}
+
+/* allocate and initialize host bridge data structure */
+static void add_acpi_root_bridge(acpi_handle handle)
+{
+	struct acpi_root_bridge *bridge;
+	acpi_handle dummy_handle;
+	acpi_status status;
+
+	/* if the bridge doesn't have _STA, we assume it is always there */
+	status = acpi_get_handle(handle, "_STA", &dummy_handle);
+	if (ACPI_SUCCESS(status)) {
+		unsigned long long tmp;
+
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_DEBUG "%s: _STA evaluation failure\n",
+						 __func__);
+			return;
+		}
+		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
+			/* don't register this object */
+			return;
+	}
+
+	bridge = kzalloc(sizeof(struct acpi_root_bridge), GFP_KERNEL);
+	if (!bridge)
+		return;
+
+	bridge->handle = handle;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &dummy_handle)))
+		bridge->flags |= ROOT_BRIDGE_HAS_EJ0;
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &dummy_handle)))
+		bridge->flags |= ROOT_BRIDGE_HAS_PS3;
+
+	list_add(&bridge->list, &acpi_root_bridge_list);
+}
+
+struct acpi_root_hp_work {
+	struct work_struct work;
+	acpi_handle handle;
+	u32 type;
+	void *context;
+};
+
+static void alloc_acpi_root_hp_work(acpi_handle handle, u32 type,
+					void *context,
+					void (*func)(struct work_struct *work))
+{
+	struct acpi_root_hp_work *hp_work;
+	int ret;
+
+	hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
+	if (!hp_work)
+		return;
+
+	hp_work->handle = handle;
+	hp_work->type = type;
+	hp_work->context = context;
+
+	INIT_WORK(&hp_work->work, func);
+	ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
+	if (!ret)
+		kfree(hp_work);
+}
+
+/* Program resources in newly inserted bridge */
+static void acpi_root_configure_bridge(acpi_handle handle)
+{
+	struct acpi_pci_root *root = acpi_pci_find_root(handle);
+
+	pcibios_resource_survey_bus(root->bus);
+	pci_assign_unassigned_bus_resources(root->bus);
+}
+
+static void handle_root_bridge_insertion(acpi_handle handle)
+{
+	struct acpi_device *device, *pdevice;
+	acpi_handle phandle;
+	int ret_val;
+
+	acpi_get_parent(handle, &phandle);
+	if (acpi_bus_get_device(phandle, &pdevice)) {
+		printk(KERN_DEBUG "no parent device, assuming NULL\n");
+		pdevice = NULL;
+	}
+	if (!acpi_bus_get_device(handle, &device)) {
+		/* check if  pci root_bus is removed */
+		struct acpi_pci_root *root = acpi_driver_data(device);
+		if (pci_find_bus(root->segment, root->secondary.start))
+			return;
+
+		printk(KERN_DEBUG "bus exists... trim\n");
+		/* this shouldn't be in here, so remove
+		 * the bus then re-add it...
+		 */
+		ret_val = acpi_bus_trim(device, 1);
+		printk(KERN_DEBUG "acpi_bus_trim return %x\n", ret_val);
+	}
+	if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
+		printk(KERN_ERR "cannot add bridge to acpi list\n");
+		return;
+	}
+	acpi_root_configure_bridge(handle);
+	if (acpi_bus_start(device))
+		printk(KERN_ERR "cannot start bridge\n");
+}
+
+static void _handle_hotplug_event_root(struct work_struct *work)
+{
+	struct acpi_root_bridge *bridge;
+	char objname[64];
+	struct acpi_buffer buffer = { .length = sizeof(objname),
+				      .pointer = objname };
+	struct acpi_root_hp_work *hp_work;
+	acpi_handle handle;
+	u32 type;
+
+	hp_work = container_of(work, struct acpi_root_hp_work, work);
+	handle = hp_work->handle;
+	type = hp_work->type;
+
+	bridge = acpi_root_handle_to_bridge(handle);
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus enumerate */
+		printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
+				 objname);
+		if (!bridge) {
+			handle_root_bridge_insertion(handle);
+			add_acpi_root_bridge(handle);
+		}
+
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check */
+		printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
+				 objname);
+		if (!bridge) {
+			handle_root_bridge_insertion(handle);
+			add_acpi_root_bridge(handle);
+		}
+		break;
+
+	default:
+		printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
+				 type, objname);
+		break;
+	}
+
+	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
+}
+
+static void handle_hotplug_event_root(acpi_handle handle, u32 type,
+					void *context)
+{
+	alloc_acpi_root_hp_work(handle, type, context,
+				_handle_hotplug_event_root);
+}
+
+static acpi_status __init
+find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	char objname[64];
+	struct acpi_buffer buffer = { .length = sizeof(objname),
+				      .pointer = objname };
+	int *count = (int *)context;
+
+	if (!acpi_is_root_bridge(handle))
+		return AE_OK;
+
+	(*count)++;
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+				handle_hotplug_event_root, NULL);
+	printk(KERN_DEBUG "acpi root: %s notify handler installed\n", objname);
+
+	add_acpi_root_bridge(handle);
+
+	return AE_OK;
+}
+
+static int __init acpi_pci_root_hp_init(void)
+{
+	int num = 0;
+
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+		ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
+
+	printk(KERN_DEBUG "Found %d acpi root devices\n", num);
+
+	return 0;
+}
+
+subsys_initcall(acpi_pci_root_hp_init);
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 7722108..1a62e7b 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -79,18 +79,15 @@ struct acpiphp_bridge {
 	/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
 	struct acpiphp_func *func;
 
-	int type;
 	int nr_slots;
 
 	u32 flags;
 
-	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
+	/* Secondary bus (PCI-to-PCI bridge) */
 	struct pci_bus *pci_bus;
 
 	/* PCI-to-PCI bridge device */
 	struct pci_dev *pci_dev;
-
-	spinlock_t res_lock;
 };
 
 
@@ -148,10 +145,6 @@ struct acpiphp_attention_info
 /* PCI bus bridge HID */
 #define ACPI_PCI_HOST_HID		"PNP0A03"
 
-/* PCI BRIDGE type */
-#define BRIDGE_TYPE_HOST		0
-#define BRIDGE_TYPE_P2P			1
-
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_PRESENT		(0x00000001)
 #define ACPI_STA_ENABLED		(0x00000002)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 6aaf9ff..ae78c3d 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -283,7 +283,7 @@ static int detect_ejectable_slots(acpi_handle handle)
 	return found;
 }
 
-/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
+/* initialize miscellaneous stuff for PCI-to-PCI bridge */
 static void init_bridge_misc(struct acpiphp_bridge *bridge)
 {
 	acpi_status status;
@@ -300,25 +300,21 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
 	}
 
 	/* install notify handler */
-	if (bridge->type != BRIDGE_TYPE_HOST) {
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			status = acpi_remove_notify_handler(bridge->func->handle,
-						ACPI_SYSTEM_NOTIFY,
-						handle_hotplug_event_func);
-			if (ACPI_FAILURE(status))
-				err("failed to remove notify handler\n");
-		}
-		status = acpi_install_notify_handler(bridge->handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event_bridge,
-					     bridge);
-
-		if (ACPI_FAILURE(status)) {
-			err("failed to register interrupt notify handler\n");
-		}
+	if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
+		status = acpi_remove_notify_handler(bridge->func->handle,
+					ACPI_SYSTEM_NOTIFY,
+					handle_hotplug_event_func);
+		if (ACPI_FAILURE(status))
+			err("failed to remove notify handler\n");
 	}
-}
+	status = acpi_install_notify_handler(bridge->handle,
+				     ACPI_SYSTEM_NOTIFY,
+				     handle_hotplug_event_bridge,
+				     bridge);
 
+	if (ACPI_FAILURE(status))
+		err("failed to register interrupt notify handler\n");
+}
 
 /* find acpiphp_func from acpiphp_bridge */
 static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
@@ -375,28 +371,6 @@ static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
 	}
 }
 
-
-/* allocate and initialize host bridge data structure */
-static void add_host_bridge(acpi_handle *handle)
-{
-	struct acpiphp_bridge *bridge;
-	struct acpi_pci_root *root = acpi_pci_find_root(handle);
-
-	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-	if (bridge == NULL)
-		return;
-
-	bridge->type = BRIDGE_TYPE_HOST;
-	bridge->handle = handle;
-
-	bridge->pci_bus = root->bus;
-
-	spin_lock_init(&bridge->res_lock);
-
-	init_bridge_misc(bridge);
-}
-
-
 /* allocate and initialize PCI-to-PCI bridge data structure */
 static void add_p2p_bridge(acpi_handle *handle)
 {
@@ -408,7 +382,6 @@ static void add_p2p_bridge(acpi_handle *handle)
 		return;
 	}
 
-	bridge->type = BRIDGE_TYPE_P2P;
 	bridge->handle = handle;
 	config_p2p_bridge_flags(bridge);
 
@@ -425,7 +398,6 @@ static void add_p2p_bridge(acpi_handle *handle)
 	 * (which we access during module unload).
 	 */
 	get_device(&bridge->pci_bus->dev);
-	spin_lock_init(&bridge->res_lock);
 
 	init_bridge_misc(bridge);
 	return;
@@ -485,12 +457,6 @@ static int add_bridge(acpi_handle handle)
 			return 0;
 	}
 
-	/* check if this bridge has ejectable slots */
-	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
-		add_host_bridge(handle);
-	}
-
 	/* search P2P bridges under this host bridge */
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
 				     find_p2p_bridge, NULL, NULL, NULL);
@@ -524,8 +490,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
 	if (ACPI_FAILURE(status))
 		err("failed to remove notify handler\n");
 
-	if ((bridge->type != BRIDGE_TYPE_HOST) &&
-	    ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
+	if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
 		status = acpi_install_notify_handler(bridge->func->handle,
 						ACPI_SYSTEM_NOTIFY,
 						handle_hotplug_event_func,
@@ -1079,15 +1044,10 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
 static int acpiphp_configure_bridge (acpi_handle handle)
 {
 	struct pci_bus *bus;
+	struct pci_dev *pdev = acpi_get_pci_dev(handle);
 
-	if (acpi_is_root_bridge(handle)) {
-		struct acpi_pci_root *root = acpi_pci_find_root(handle);
-		bus = root->bus;
-	} else {
-		struct pci_dev *pdev = acpi_get_pci_dev(handle);
-		bus = pdev->subordinate;
-		pci_dev_put(pdev);
-	}
+	bus = pdev->subordinate;
+	pci_dev_put(pdev);
 
 	pci_bus_size_bridges(bus);
 	pci_bus_assign_resources(bus);
@@ -1250,8 +1210,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if ((bridge->type != BRIDGE_TYPE_HOST) &&
-		    (bridge->flags & BRIDGE_HAS_EJ0)) {
+		if (bridge->flags & BRIDGE_HAS_EJ0) {
 			struct acpiphp_slot *slot;
 			slot = bridge->func->slot;
 			if (!acpiphp_disable_slot(slot))
@@ -1382,21 +1341,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
 			      _handle_hotplug_event_func);
 }
 
-static acpi_status
-find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	int *count = (int *)context;
-
-	if (!acpi_is_root_bridge(handle))
-		return AE_OK;
-
-	(*count)++;
-	acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-				    handle_hotplug_event_bridge, NULL);
-
-	return AE_OK ;
-}
-
 static struct acpi_pci_driver acpi_pci_hp_driver = {
 	.add =		add_bridge,
 	.remove =	remove_bridge,
@@ -1407,15 +1351,7 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
  */
 int __init acpiphp_glue_init(void)
 {
-	int num = 0;
-
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-			ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
-
-	if (num <= 0)
-		return -1;
-	else
-		acpi_pci_register_driver(&acpi_pci_hp_driver);
+	acpi_pci_register_driver(&acpi_pci_hp_driver);
 
 	return 0;
 }
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 28/47] PCI, ACPI: Add pci_root_hp hot removal notification support.
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (26 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 27/47] PCI, acpiphp: Separate out hot-add support of pci host bridge Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 29/47] PCI, ACPI: Add alloc_acpi_hp_work() Yinghai Lu
                   ` (20 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

Add missing hot_remove support for root device.

How to use it?
Find out root bus number to acpi root name mapping from dmesg or /sys

  echo "\_SB.PCIB 3" > /proc/acpi/sci/notify
to remove root bus

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/pci_root_hp.c |   61 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c
index e07c31b..214adcb 100644
--- a/drivers/acpi/pci_root_hp.c
+++ b/drivers/acpi/pci_root_hp.c
@@ -73,6 +73,12 @@ static void add_acpi_root_bridge(acpi_handle handle)
 	list_add(&bridge->list, &acpi_root_bridge_list);
 }
 
+static void remove_acpi_root_bridge(struct acpi_root_bridge *bridge)
+{
+	list_del(&bridge->list);
+	kfree(bridge);
+}
+
 struct acpi_root_hp_work {
 	struct work_struct work;
 	acpi_handle handle;
@@ -143,6 +149,55 @@ static void handle_root_bridge_insertion(acpi_handle handle)
 		printk(KERN_ERR "cannot start bridge\n");
 }
 
+static int acpi_root_evaluate_object(acpi_handle handle, char *cmd, int val)
+{
+	acpi_status status;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = val;
+
+	status = acpi_evaluate_object(handle, cmd, &arg_list, NULL);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_WARNING "%s: %s to %d failed\n",
+				 __func__, cmd, val);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void handle_root_bridge_removal(acpi_handle handle,
+		 struct acpi_root_bridge *bridge)
+{
+	u32 flags = 0;
+	struct acpi_device *device;
+
+	if (bridge) {
+		flags = bridge->flags;
+		remove_acpi_root_bridge(bridge);
+	}
+
+	if (!acpi_bus_get_device(handle, &device)) {
+		int ret_val = acpi_bus_trim(device, 1);
+
+		printk(KERN_DEBUG "acpi_bus_trim return %x\n", ret_val);
+	}
+
+	if (flags & ROOT_BRIDGE_HAS_PS3) {
+		acpi_status status;
+
+		status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
+		if (ACPI_FAILURE(status))
+			printk(KERN_WARNING "%s: _PS3 failed\n", __func__);
+	}
+	if (flags & ROOT_BRIDGE_HAS_EJ0)
+		acpi_root_evaluate_object(handle, "_EJ0", 1);
+}
+
 static void _handle_hotplug_event_root(struct work_struct *work)
 {
 	struct acpi_root_bridge *bridge;
@@ -183,6 +238,12 @@ static void _handle_hotplug_event_root(struct work_struct *work)
 		}
 		break;
 
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
+				 objname);
+		handle_root_bridge_removal(handle, bridge);
+		break;
 	default:
 		printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
 				 type, objname);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 29/47] PCI, ACPI: Add alloc_acpi_hp_work()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (27 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 28/47] PCI, ACPI: Add pci_root_hp hot removal notification support Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 30/47] PCI, acpiphp: Use acpi_hp_work Yinghai Lu
                   ` (19 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

Will use it with acpiphp and pci_root_hp events handling

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/osl.c      |   21 +++++++++++++++++++++
 include/acpi/acpiosxf.h |    9 +++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 412a1e0..fdcf4a5 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1641,3 +1641,24 @@ acpi_status acpi_os_terminate(void)
 
 	return AE_OK;
 }
+
+void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
+			void (*func)(struct work_struct *work))
+{
+	struct acpi_hp_work *hp_work;
+	int ret;
+
+	hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
+	if (!hp_work)
+		return;
+
+	hp_work->handle = handle;
+	hp_work->type = type;
+	hp_work->context = context;
+
+	INIT_WORK(&hp_work->work, func);
+	ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
+	if (!ret)
+		kfree(hp_work);
+}
+EXPORT_SYMBOL(alloc_acpi_hp_work);
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 7c9aebe..62326ae 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -191,6 +191,15 @@ void acpi_os_fixed_event_count(u32 fixed_event_number);
  */
 extern struct workqueue_struct *kacpi_hotplug_wq;
 
+struct acpi_hp_work {
+	struct work_struct work;
+	acpi_handle handle;
+	u32 type;
+	void *context;
+};
+void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
+			void (*func)(struct work_struct *work));
+
 acpi_thread_id acpi_os_get_thread_id(void);
 
 acpi_status
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 30/47] PCI, acpiphp: Use acpi_hp_work
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (28 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 29/47] PCI, ACPI: Add alloc_acpi_hp_work() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 31/47] PCI, pci_root_hp: " Yinghai Lu
                   ` (18 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

Remove local defined acpiphp_hp_work.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/pci/hotplug/acpiphp_glue.c |   42 +++++------------------------------
 1 files changed, 6 insertions(+), 36 deletions(-)

diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index ae78c3d..9d781a7 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -1119,34 +1119,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 	return AE_OK ;
 }
 
-struct acpiphp_hp_work {
-	struct work_struct work;
-	acpi_handle handle;
-	u32 type;
-	void *context;
-};
-
-static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
-				  void *context,
-				  void (*func)(struct work_struct *work))
-{
-	struct acpiphp_hp_work *hp_work;
-	int ret;
-
-	hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
-	if (!hp_work)
-		return;
-
-	hp_work->handle = handle;
-	hp_work->type = type;
-	hp_work->context = context;
-
-	INIT_WORK(&hp_work->work, func);
-	ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
-	if (!ret)
-		kfree(hp_work);
-}
-
 static void _handle_hotplug_event_bridge(struct work_struct *work)
 {
 	struct acpiphp_bridge *bridge;
@@ -1155,11 +1127,11 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 				      .pointer = objname };
 	struct acpi_device *device;
 	int num_sub_bridges = 0;
-	struct acpiphp_hp_work *hp_work;
+	struct acpi_hp_work *hp_work;
 	acpi_handle handle;
 	u32 type;
 
-	hp_work = container_of(work, struct acpiphp_hp_work, work);
+	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
 
@@ -1261,8 +1233,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	alloc_acpiphp_hp_work(handle, type, context,
-			      _handle_hotplug_event_bridge);
+	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
 }
 
 static void _handle_hotplug_event_func(struct work_struct *work)
@@ -1271,12 +1242,12 @@ static void _handle_hotplug_event_func(struct work_struct *work)
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpiphp_hp_work *hp_work;
+	struct acpi_hp_work *hp_work;
 	acpi_handle handle;
 	u32 type;
 	void *context;
 
-	hp_work = container_of(work, struct acpiphp_hp_work, work);
+	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
 	context = hp_work->context;
@@ -1337,8 +1308,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	alloc_acpiphp_hp_work(handle, type, context,
-			      _handle_hotplug_event_func);
+	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
 }
 
 static struct acpi_pci_driver acpi_pci_hp_driver = {
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 31/47] PCI, pci_root_hp: Use acpi_hp_work
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (29 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 30/47] PCI, acpiphp: Use acpi_hp_work Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 32/47] PCI, ACPI: Make kacpi_hotplug_wq static Yinghai Lu
                   ` (17 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

Remove local copy: acpi_root_hp_work

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/pci_root_hp.c |   34 +++-------------------------------
 1 files changed, 3 insertions(+), 31 deletions(-)

diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c
index 214adcb..d2ace81 100644
--- a/drivers/acpi/pci_root_hp.c
+++ b/drivers/acpi/pci_root_hp.c
@@ -79,34 +79,6 @@ static void remove_acpi_root_bridge(struct acpi_root_bridge *bridge)
 	kfree(bridge);
 }
 
-struct acpi_root_hp_work {
-	struct work_struct work;
-	acpi_handle handle;
-	u32 type;
-	void *context;
-};
-
-static void alloc_acpi_root_hp_work(acpi_handle handle, u32 type,
-					void *context,
-					void (*func)(struct work_struct *work))
-{
-	struct acpi_root_hp_work *hp_work;
-	int ret;
-
-	hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
-	if (!hp_work)
-		return;
-
-	hp_work->handle = handle;
-	hp_work->type = type;
-	hp_work->context = context;
-
-	INIT_WORK(&hp_work->work, func);
-	ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
-	if (!ret)
-		kfree(hp_work);
-}
-
 /* Program resources in newly inserted bridge */
 static void acpi_root_configure_bridge(acpi_handle handle)
 {
@@ -204,11 +176,11 @@ static void _handle_hotplug_event_root(struct work_struct *work)
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpi_root_hp_work *hp_work;
+	struct acpi_hp_work *hp_work;
 	acpi_handle handle;
 	u32 type;
 
-	hp_work = container_of(work, struct acpi_root_hp_work, work);
+	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
 
@@ -256,7 +228,7 @@ static void _handle_hotplug_event_root(struct work_struct *work)
 static void handle_hotplug_event_root(acpi_handle handle, u32 type,
 					void *context)
 {
-	alloc_acpi_root_hp_work(handle, type, context,
+	alloc_acpi_hp_work(handle, type, context,
 				_handle_hotplug_event_root);
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 32/47] PCI, ACPI: Make kacpi_hotplug_wq static
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (30 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 31/47] PCI, pci_root_hp: " Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 33/47] PCI: Add debug print out for pci related dev release Yinghai Lu
                   ` (16 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

No external user anymore.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/osl.c      |    3 +--
 include/acpi/acpiosxf.h |    2 --
 2 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index fdcf4a5..09be602 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -81,8 +81,7 @@ static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 static struct workqueue_struct *kacpi_notify_wq;
-struct workqueue_struct *kacpi_hotplug_wq;
-EXPORT_SYMBOL(kacpi_hotplug_wq);
+static struct workqueue_struct *kacpi_hotplug_wq;
 
 /*
  * This list of permanent mappings is for memory that may be accessed from
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 62326ae..2326622 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -189,8 +189,6 @@ void acpi_os_fixed_event_count(u32 fixed_event_number);
 /*
  * Threads and Scheduling
  */
-extern struct workqueue_struct *kacpi_hotplug_wq;
-
 struct acpi_hp_work {
 	struct work_struct work;
 	acpi_handle handle;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 33/47] PCI: Add debug print out for pci related dev release
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (31 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 32/47] PCI, ACPI: Make kacpi_hotplug_wq static Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 34/47] PCI, pciehp: Separate pci_hp_add_bridge() Yinghai Lu
                   ` (15 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

In some case, they could not be called because some users just use
get_device() without put device back.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/probe.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a819e76..14f2e69 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -57,6 +57,7 @@ static void release_pcibus_dev(struct device *dev)
 
 	if (pci_bus->bridge)
 		put_device(pci_bus->bridge);
+	dev_printk(KERN_DEBUG, dev, "freeing pci_bus info\n");
 	pci_bus_remove_resources(pci_bus);
 	pci_release_bus_of_node(pci_bus);
 	kfree(pci_bus);
@@ -1259,6 +1260,7 @@ static void pci_release_dev(struct device *dev)
 {
 	struct pci_dev *pci_dev;
 
+	dev_printk(KERN_DEBUG, dev, "freeing pci_dev info\n");
 	pci_dev = to_pci_dev(dev);
 	pci_release_capabilities(pci_dev);
 	pci_release_of_node(pci_dev);
@@ -1323,6 +1325,7 @@ static void pci_release_bus_bridge_dev(struct device *dev)
 {
 	struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
 
+	dev_printk(KERN_DEBUG, dev, "freeing pci_host_bridge info\n");
 	if (bridge->release_fn)
 		bridge->release_fn(bridge);
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 34/47] PCI, pciehp: Separate pci_hp_add_bridge()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (32 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 33/47] PCI: Add debug print out for pci related dev release Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 35/47] PCI, cphi_hotplug: Simplify configure_slot Yinghai Lu
                   ` (14 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Will use it for other pci hp hotplug support

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/hotplug-pci.c        |   13 +++++++++++++
 drivers/pci/hotplug/pciehp_pci.c |   18 ++----------------
 drivers/pci/pci.h                |    1 +
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c
index d3509cd..24de840 100644
--- a/drivers/pci/hotplug-pci.c
+++ b/drivers/pci/hotplug-pci.c
@@ -4,6 +4,19 @@
 #include <linux/export.h>
 #include "pci.h"
 
+int __ref pci_hp_add_bridge(struct pci_dev *dev)
+{
+	struct pci_bus *parent = dev->bus;
+	int pass, busnr = parent->secondary;
+
+	for (pass = 0; pass < 2; pass++)
+		busnr = pci_scan_bridge(parent, dev, busnr, pass);
+	if (!dev->subordinate)
+		return -1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_hp_add_bridge);
 
 unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
 {
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index e21171c..b9a9fce 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -34,19 +34,6 @@
 #include "../pci.h"
 #include "pciehp.h"
 
-static int __ref pciehp_add_bridge(struct pci_dev *dev)
-{
-	struct pci_bus *parent = dev->bus;
-	int pass, busnr = parent->secondary;
-
-	for (pass = 0; pass < 2; pass++)
-		busnr = pci_scan_bridge(parent, dev, busnr, pass);
-	if (!dev->subordinate)
-		return -1;
-
-	return 0;
-}
-
 int pciehp_configure_device(struct slot *p_slot)
 {
 	struct pci_dev *dev;
@@ -75,9 +62,8 @@ int pciehp_configure_device(struct slot *p_slot)
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			pciehp_add_bridge(dev);
-		}
+		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
 		pci_dev_put(dev);
 	}
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13b1159..9378d81 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -124,6 +124,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
 #endif
 
 /* Functions for PCI Hotplug drivers to use */
+int pci_hp_add_bridge(struct pci_dev *dev);
 extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
 
 #ifdef HAVE_PCI_LEGACY
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 35/47] PCI, cphi_hotplug: Simplify configure_slot
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (33 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 34/47] PCI, pciehp: Separate pci_hp_add_bridge() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 36/47] PCI, shpchp: Simplify configure_device Yinghai Lu
                   ` (13 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

For child p2p bridge hotplug support should use pci_scan_bridge instead.

Make it more simillar to pciehp, just use pci_hp_add_bridge()

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/hotplug/cpci_hotplug_pci.c |   35 +++++--------------------------
 1 files changed, 6 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 4ef80ad..dcc75c7 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -285,42 +285,19 @@ int __ref cpci_configure_slot(struct slot *slot)
 	for (fn = 0; fn < 8; fn++) {
 		struct pci_dev *dev;
 
-		dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
+		dev = pci_get_slot(parent,
+				   PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			/* Find an unused bus number for the new bridge */
-			struct pci_bus *child;
-			unsigned char busnr, start = parent->secondary;
-			unsigned char end = parent->subordinate;
-
-			for (busnr = start; busnr <= end; busnr++) {
-				if (!pci_find_bus(pci_domain_nr(parent),
-						  busnr))
-					break;
-			}
-			if (busnr >= end) {
-				err("No free bus for hot-added bridge\n");
-				pci_dev_put(dev);
-				continue;
-			}
-			child = pci_add_new_bus(parent, dev, busnr);
-			if (!child) {
-				err("Cannot add new bus for %s\n",
-				    pci_name(dev));
-				pci_dev_put(dev);
-				continue;
-			}
-			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges_with_self(child);
-		}
+		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
 		pci_dev_put(dev);
 	}
 
-	pci_bus_assign_resources(parent);
+	pci_assign_unassigned_bridge_resources(parent->self);
+
 	pci_bus_add_devices(parent);
-	pci_enable_bridges(parent);
 
 	dbg("%s - exit", __func__);
 	return 0;
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 36/47] PCI, shpchp: Simplify configure_device
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (34 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 35/47] PCI, cphi_hotplug: Simplify configure_slot Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 37/47] PCI: Kill pci_is_reassignedev() Yinghai Lu
                   ` (12 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

For child p2p bridge hotplug support should use pci_scan_bridge instead.

Make it more simillar to pciehp, just use pci_hp_add_bridge()

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/hotplug/shpchp_pci.c |   45 ++++++++++++-------------------------
 1 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index d92807b..c627ed9 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -37,9 +37,10 @@
 int __ref shpchp_configure_device(struct slot *p_slot)
 {
 	struct pci_dev *dev;
-	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
-	int num, fn;
 	struct controller *ctrl = p_slot->ctrl;
+	struct pci_dev *bridge = ctrl->pci_dev;
+	struct pci_bus *parent = bridge->subordinate;
+	int num, fn;
 
 	dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
 	if (dev) {
@@ -61,39 +62,23 @@ int __ref shpchp_configure_device(struct slot *p_slot)
 		if (!dev)
 			continue;
 		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
-				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
-			/* Find an unused bus number for the new bridge */
-			struct pci_bus *child;
-			unsigned char busnr, start = parent->secondary;
-			unsigned char end = parent->subordinate;
-			for (busnr = start; busnr <= end; busnr++) {
-				if (!pci_find_bus(pci_domain_nr(parent),
-							busnr))
-					break;
-			}
-			if (busnr > end) {
-				ctrl_err(ctrl,
-					 "No free bus for hot-added bridge\n");
-				pci_dev_put(dev);
-				continue;
-			}
-			child = pci_add_new_bus(parent, dev, busnr);
-			if (!child) {
-				ctrl_err(ctrl, "Cannot add new bus for %s\n",
-					 pci_name(dev));
-				pci_dev_put(dev);
-				continue;
-			}
-			child->subordinate = pci_do_scan_bus(child);
-			pci_bus_size_bridges_with_self(child);
-		}
+		    (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
+			pci_hp_add_bridge(dev);
+		pci_dev_put(dev);
+	}
+
+	pci_assign_unassigned_bridge_resources(bridge);
+
+	for (fn = 0; fn < 8; fn++) {
+		dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
+		if (!dev)
+			continue;
 		pci_configure_slot(dev);
 		pci_dev_put(dev);
 	}
 
-	pci_bus_assign_resources(parent);
 	pci_bus_add_devices(parent);
-	pci_enable_bridges(parent);
+
 	return 0;
 }
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 37/47] PCI: Kill pci_is_reassignedev()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (35 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 36/47] PCI, shpchp: Simplify configure_device Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 38/47] PCI, sysfs: Prepare to kill pci device rescan Yinghai Lu
                   ` (11 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Only one user. Just use pci_specified_resource_alignement() directly.
So could only get get align one time for the dev that in the list

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/pci.c |   17 +++--------------
 1 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8156744..82ed56a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3685,18 +3685,6 @@ resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
 	return align;
 }
 
-/**
- * pci_is_reassigndev - check if specified PCI is target device to reassign
- * @dev: the PCI device to check
- *
- * RETURNS: non-zero for PCI device is a target device to reassign,
- *          or zero is not.
- */
-int pci_is_reassigndev(struct pci_dev *dev)
-{
-	return (pci_specified_resource_alignment(dev) != 0);
-}
-
 /*
  * This function disables memory decoding and releases memory resources
  * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
@@ -3711,7 +3699,9 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
 	resource_size_t align, size;
 	u16 command;
 
-	if (!pci_is_reassigndev(dev))
+	/* check if specified PCI is target device to reassign */
+	align = pci_specified_resource_alignment(dev);
+	if (!align)
 		return;
 
 	if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
@@ -3727,7 +3717,6 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
 	command &= ~PCI_COMMAND_MEMORY;
 	pci_write_config_word(dev, PCI_COMMAND, command);
 
-	align = pci_specified_resource_alignment(dev);
 	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
 		r = &dev->resource[i];
 		if (!(r->flags & IORESOURCE_MEM))
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 38/47] PCI, sysfs: Prepare to kill pci device rescan
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (36 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 37/47] PCI: Kill pci_is_reassignedev() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 39/47] ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing Yinghai Lu
                   ` (10 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Hope we can kill it after one year.

Print warning to catch real users for that feature.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 Documentation/feature-removal-schedule.txt |    9 +++++++++
 drivers/pci/pci-sysfs.c                    |    3 +++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index a0ffac0..1b984a1 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -299,6 +299,15 @@ Why:	In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
 	fakephp interface.
 Who:	Alex Chiang <achiang@hp.com>
 
+-----------------------------
+
+What:	/sys/bus/pci/devices/.../rescan
+When:	April 2013
+Why:	That rescan will rescan pci parent's bus. It is confusing.
+	Now we have bridge rescan_bridge and bus rescan, and they could
+	be used on exact device and bus that need to be rescaned.
+Who:	Yinghai Lu <yinghai@kernel.org>
+
 ---------------------------
 
 What:	CONFIG_RFKILL_INPUT
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 4697afe..d33a1bc 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -318,6 +318,9 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
 		return -EINVAL;
 
 	if (val) {
+		printk(KERN_WARNING "rescan with pci device will be removed "
+			 "shortly, please use bridge rescan_bridge\n"
+			 "or bus/rescan instead\n");
 		mutex_lock(&pci_remove_rescan_mutex);
 		pci_rescan_bus(pdev->bus);
 		mutex_unlock(&pci_remove_rescan_mutex);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 39/47] ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing.
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (37 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 38/47] PCI, sysfs: Prepare to kill pci device rescan Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove Yinghai Lu
                   ` (9 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Ashok Raj, Yinghai Lu, Len Brown,
	linux-acpi

From: Ashok Raj <ashok.raj@intel.com>

Emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful
for testing ACPI based hot-plug on systems that don't have the
necessary firmware support.

Enable CONFIG_ACPI_SCI_EMULATE on kernel compile.

Now you will notice /proc/acpi/sci/notify when new kernel is booted.

echo "\_SB.CPU4 1" > /proc/acpi/sci/notify to trigger a hot-add of CPU4.
You will now notice an entry /sys/firmware/acpi/namespace/ACPI/_SB/CPU4
if the namespace had an entry CPU4 under _SB scope. If the entry had a
_EJ0 method, you will also notice a file "eject" under the CPU4 directory.

-v2: Update to current upstream, and remove not related stuff.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org

===================================================================
---
 drivers/acpi/Kconfig    |   10 +++
 drivers/acpi/Makefile   |    1 +
 drivers/acpi/bus.c      |    2 +
 drivers/acpi/internal.h |    6 ++
 drivers/acpi/sci_emu.c  |  141 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 drivers/acpi/sci_emu.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 7556913..b7b8541 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -272,6 +272,16 @@ config ACPI_BLACKLIST_YEAR
 	  Enter 0 to disable this mechanism and allow ACPI to
 	  run by default no matter what the year.  (default)
 
+config ACPI_SCI_EMULATE
+	bool "ACPI SCI Event Emulation Support"
+	depends on ACPI
+	default n
+	help
+	  This will enable your system to emulate sci hotplug event
+	  notification through proc file system. For example user needs to
+	  echo "XXX 0" > /proc/acpi/sci/notify (where, XXX is a target ACPI
+	  device object name present under \_SB scope).
+
 config ACPI_DEBUG
 	bool "Debug Statements"
 	default n
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bc6e53f..3580f04 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -31,6 +31,7 @@ acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o
 # ACPI Bus and Device Drivers
 #
 acpi-y				+= bus.o glue.o
+acpi-$(CONFIG_ACPI_SCI_EMULATE)	+= sci_emu.o
 acpi-y				+= scan.o
 acpi-y				+= processor_core.o
 acpi-y				+= ec.o
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9ecec98..512235e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1001,6 +1001,8 @@ static int __init acpi_bus_init(void)
 	 */
 	acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
 
+	acpi_init_sci_emulate();
+
 	return 0;
 
 	/* Mimic structured exception handling */
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index ca75b9c..5b22cd2 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -34,6 +34,12 @@ int acpi_debugfs_init(void);
 static inline void acpi_debugfs_init(void) { return; }
 #endif
 
+#ifdef CONFIG_ACPI_SCI_EMULATE
+int acpi_init_sci_emulate(void);
+#else
+static inline int acpi_init_sci_emulate(void) { return 0; }
+#endif
+
 /* --------------------------------------------------------------------------
                                   Power Resource
    -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/sci_emu.c b/drivers/acpi/sci_emu.c
new file mode 100644
index 0000000..d972436
--- /dev/null
+++ b/drivers/acpi/sci_emu.c
@@ -0,0 +1,141 @@
+/*
+ *  Code to emulate SCI interrupt for Hotplug node insertion/removal
+ */
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/acpi.h>
+
+#include "internal.h"
+
+#include "acpica/accommon.h"
+#include "acpica/acnamesp.h"
+#include "acpica/acevents.h"
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME("sci_emu");
+
+static void acpi_sci_notify_client(char *acpi_name, u32 event);
+static int acpi_sci_notify_write_proc(struct file *file, const char *buffer, \
+	unsigned long count, void *data);
+struct proc_dir_entry *acpi_sci_dir;
+
+static int acpi_sci_notify_write_proc(struct file *file, const char *buffer,
+				      unsigned long count, void *data)
+{
+	u32 event;
+	char *name1 = NULL;
+	char *name2 = NULL;
+	char *end_name = NULL;
+	const char *delim = " ";
+	char *temp_buf = NULL;
+	char *temp_buf_addr = NULL;
+
+	temp_buf = kmalloc(count+1, GFP_ATOMIC);
+	if (!temp_buf) {
+		printk(KERN_WARNING PREFIX
+		 "acpi_sci_notify_wire_proc: Memory allocation failed\n");
+		return count;
+	}
+	temp_buf[count] = '\0';
+	temp_buf_addr = temp_buf;
+	memcpy(temp_buf, buffer, count);
+	name1 = strsep(&temp_buf, delim);
+	name2 = strsep(&temp_buf, delim);
+
+	if (name1 && name2)
+		event = simple_strtoul(name2, &end_name, 10);
+	else {
+		printk(KERN_WARNING PREFIX "unknown device\n");
+		kfree(temp_buf_addr);
+		return count;
+	}
+
+	printk(KERN_INFO PREFIX
+		"ACPI device name is <%s>, event code is <%d>\n",
+		name1, event);
+
+	acpi_sci_notify_client(name1, event);
+
+	kfree(temp_buf_addr);
+
+	return count;
+}
+
+static void acpi_sci_notify_client(char *acpi_name, u32 event)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status, status1;
+	acpi_handle hlsb, hsb;
+	union acpi_operand_object *obj_desc;
+
+	status = acpi_get_handle(NULL, "\\_SB", &hsb);
+	status1 = acpi_get_handle(hsb, acpi_name, &hlsb);
+	if (ACPI_FAILURE(status) || ACPI_FAILURE(status1)) {
+		printk(KERN_ERR PREFIX
+	"acpi getting handle to <\\_SB.%s> failed inside notify_client\n",
+			acpi_name);
+		return;
+	}
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR PREFIX "Acquiring acpi namespace mutext failed\n");
+		return;
+	}
+
+	node = acpi_ns_validate_handle(hlsb);
+	if (!node) {
+		acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+		printk(KERN_ERR PREFIX "Mapping handle to node failed\n");
+		return;
+	}
+
+	/*
+	 * Check for internal object and make sure there is a handler
+	 * registered for this object
+	 */
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
+		if (obj_desc->common_notify.system_notify) {
+			/*
+			 * Release the lock and queue the item for later
+			 * exectuion
+			 */
+			acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+			status = acpi_ev_queue_notify_request(node, event);
+			if (ACPI_FAILURE(status))
+				printk(KERN_ERR PREFIX "acpi_ev_queue_notify_request failed\n");
+			else
+				printk(KERN_INFO PREFIX "Notify event is queued\n");
+			return;
+		}
+	} else {
+		printk(KERN_INFO PREFIX "Notify handler not registered for this device\n");
+	}
+
+	acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+	return;
+}
+
+int __init acpi_init_sci_emulate(void)
+{
+	struct proc_dir_entry   *notify_entry = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_init_sci_emulate");
+
+	acpi_sci_dir = proc_mkdir("sci", acpi_root_dir);
+	if (!acpi_sci_dir)
+		return_VALUE(-ENODEV);
+
+	notify_entry = create_proc_entry("notify", \
+		S_IWUGO|S_IRUGO, acpi_sci_dir);
+	if (!notify_entry) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
+			"Unable to create '%s' fs entry\n", "notify"));
+	} else {
+		notify_entry->write_proc = acpi_sci_notify_write_proc;
+		notify_entry->data = NULL;
+	}
+
+	return_VALUE(0);
+}
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (38 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 39/47] ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-04-06 15:50   ` Jiang Liu
  2012-03-19  5:46 ` [PATCH -v3 41/47] PCI, ACPI: Add acpi_pci_root_rescan() Yinghai Lu
                   ` (8 subsequent siblings)
  48 siblings, 1 reply; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Randy Dunlap, linux-doc

it supports both pci root bus and pci bus under pci bridge.

-v2: Change to three returns way in dev_bus_remove_store.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-doc@vger.kernel.org
---
 Documentation/ABI/testing/sysfs-bus-pci |    8 ++++++++
 drivers/pci/pci-sysfs.c                 |   30 ++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 95f0f37..22392de 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -92,6 +92,14 @@ Description:
 		hot-remove the PCI device and any of its children.
 		Depends on CONFIG_HOTPLUG.
 
+What:		/sys/bus/pci/devices/.../pci_bus/.../remove
+Date:		March 2012
+Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+		Writing a non-zero value to this attribute will
+		hot-remove the PCI bus and any of its children.
+		Depends on CONFIG_HOTPLUG.
+
 What:		/sys/bus/pci/devices/.../pci_bus/.../rescan
 Date:		May 2011
 Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index d33a1bc..afba77b 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -391,6 +391,35 @@ remove_store(struct device *dev, struct device_attribute *dummy,
 	return count;
 }
 
+static void bus_remove_callback(struct device *dev)
+{
+	struct pci_bus *bus = to_pci_bus(dev);
+
+	mutex_lock(&pci_remove_rescan_mutex);
+	pci_stop_and_remove_bus(bus);
+	mutex_unlock(&pci_remove_rescan_mutex);
+}
+static ssize_t
+dev_bus_remove_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	int err;
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	if (!val)
+		return count;
+
+	err = device_schedule_callback(dev, bus_remove_callback);
+
+	if (err)
+		return err;
+
+	return count;
+}
+
 static void bus_rescan_callback(struct device *dev)
 {
 	struct pci_bus *bus = to_pci_bus(dev);
@@ -450,6 +479,7 @@ struct device_attribute pci_dev_attrs[] = {
 struct device_attribute pcibus_dev_attrs[] = {
 #ifdef CONFIG_HOTPLUG
 	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
+	__ATTR(remove, (S_IWUSR|S_IWGRP), NULL, dev_bus_remove_store),
 #endif
 	__ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
 	__ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 41/47] PCI, ACPI: Add acpi_pci_root_rescan()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (39 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 42/47] PCI: Add __pci_scan_root_bus() that can skip bus_add Yinghai Lu
                   ` (7 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Len Brown, linux-acpi

It will rescan all acpi pci root if related pci root bus get removed before.

Signed-off-by: Yinghai <yinghai@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: linux-acpi@vger.kernel.org
---
 drivers/acpi/pci_root_hp.c |   17 +++++++++++++++++
 include/linux/pci-acpi.h   |    7 +++++++
 2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c
index d2ace81..e16b53d 100644
--- a/drivers/acpi/pci_root_hp.c
+++ b/drivers/acpi/pci_root_hp.c
@@ -269,3 +269,20 @@ static int __init acpi_pci_root_hp_init(void)
 }
 
 subsys_initcall(acpi_pci_root_hp_init);
+
+static acpi_status
+rescan_root_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	if (!acpi_is_root_bridge(handle))
+		return AE_OK;
+
+	handle_root_bridge_insertion(handle);
+
+	return AE_OK;
+}
+
+void acpi_pci_root_rescan(void)
+{
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+		ACPI_UINT32_MAX, rescan_root_bridge, NULL, NULL, NULL);
+}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 4462350..ac93634 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -35,6 +35,13 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 	return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
 					      pbus->number);
 }
+
+void acpi_pci_root_rescan(void);
+
+#else
+
+static inline void acpi_pci_root_rescan(void) { }
+
 #endif
 
 #ifdef CONFIG_ACPI_APEI
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 42/47] PCI: Add __pci_scan_root_bus() that can skip bus_add
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (40 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 41/47] PCI, ACPI: Add acpi_pci_root_rescan() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 43/47] x86, PCI: add __pci_scan_root_bus_on_node() " Yinghai Lu
                   ` (6 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

So could insert pus pci_assign_unassigned_bus_resources() before do bus_add.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 drivers/pci/probe.c |   13 ++++++++++---
 include/linux/pci.h |    3 +++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 14f2e69..d626c4e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1938,8 +1938,9 @@ void pci_bus_release_busn_res(struct pci_bus *b)
 			res, ret ? "can not be" : "is");
 }
 
-struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
-		struct pci_ops *ops, void *sysdata, struct list_head *resources)
+struct pci_bus * __devinit __pci_scan_root_bus(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources,
+		bool bus_add)
 {
 	struct pci_bus *b;
 	struct pci_host_bridge_window *window, *n;
@@ -1970,9 +1971,15 @@ struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
 	if (!found)
 		pci_bus_update_busn_res_end(b, b->subordinate);
 
-	pci_bus_add_devices(b);
+	if (bus_add)
+		pci_bus_add_devices(b);
 	return b;
 }
+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+	return __pci_scan_root_bus(parent, bus, ops, sysdata, resources, true);
+}
 EXPORT_SYMBOL(pci_scan_root_bus);
 
 /* Deprecated; use pci_scan_root_bus() instead */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index aec945d..161f6c0 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -676,6 +676,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 void pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
 void pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
 void pci_bus_release_busn_res(struct pci_bus *b);
+struct pci_bus * __devinit __pci_scan_root_bus(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources,
+		bool bus_add);
 struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
 					     struct pci_ops *ops, void *sysdata,
 					     struct list_head *resources);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 43/47] x86, PCI: add __pci_scan_root_bus_on_node() that can skip bus_add
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (41 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 42/47] PCI: Add __pci_scan_root_bus() that can skip bus_add Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 44/47] x86, PCI: add __pcibios_scan_specific_bus " Yinghai Lu
                   ` (5 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

So could insert pus pci_assign_unassigned_bus_resources() before do bus_add.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/include/asm/pci.h |    2 ++
 arch/x86/pci/common.c      |   11 ++++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index df75d07..bb015c7 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -24,6 +24,8 @@ extern int noioapicquirk;
 extern int noioapicreroute;
 
 /* scan a bus after allocating a pci_sysdata for it */
+struct pci_bus * __devinit __pci_scan_bus_on_node(int busno,
+			 struct pci_ops *ops, int node, bool bus_add);
 extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 					    int node);
 extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 35931f6..2ebdc231 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -625,7 +625,8 @@ static void release_pci_sysdata(struct pci_host_bridge *bridge)
 	kfree(sd);
 }
 
-struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
+struct pci_bus * __devinit __pci_scan_bus_on_node(int busno,
+			 struct pci_ops *ops, int node, bool bus_add)
 {
 	LIST_HEAD(resources);
 	struct pci_bus *bus = NULL;
@@ -639,7 +640,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 	sd->node = node;
 	x86_pci_root_bus_resources(busno, &resources);
 	printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
-	bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
+	bus = __pci_scan_root_bus(NULL, busno, ops, sd, &resources, bus_add);
 	if (bus)
 		pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
 					release_pci_sysdata, sd);
@@ -650,7 +651,11 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 
 	return bus;
 }
-
+struct pci_bus * __devinit pci_scan_bus_on_node(int busno,
+			 struct pci_ops *ops, int node)
+{
+	return __pci_scan_bus_on_node(busno, ops, node, true);
+}
 struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno)
 {
 	return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 44/47] x86, PCI: add __pcibios_scan_specific_bus that can skip bus_add
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (42 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 43/47] x86, PCI: add __pci_scan_root_bus_on_node() " Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 45/47] x86, PCI: Add pcibios_root_rescan() Yinghai Lu
                   ` (4 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

So could insert pci_assign_unassigned_bus_resources() before do bus_add.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/legacy.c |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index a1df191..aab0e41 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -34,25 +34,32 @@ int __init pci_legacy_init(void)
 	return 0;
 }
 
-void __devinit pcibios_scan_specific_bus(int busn)
+static __devinit struct pci_bus *__pcibios_scan_specific_bus(int busn,
+					 bool bus_add)
 {
 	int devfn;
 	long node;
 	u32 l;
 
-	if (pci_find_bus(0, busn))
-		return;
-
 	node = get_mp_bus_to_node(busn);
 	for (devfn = 0; devfn < 256; devfn += 8) {
 		if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
 		    l != 0x0000 && l != 0xffff) {
 			DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
 			printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
-			pci_scan_bus_on_node(busn, &pci_root_ops, node);
-			return;
+			return __pci_scan_bus_on_node(busn, &pci_root_ops, node,
+					 bus_add);
 		}
 	}
+
+	return NULL;
+}
+void __devinit pcibios_scan_specific_bus(int busn)
+{
+	if (pci_find_bus(0, busn))
+		return;
+
+	__pcibios_scan_specific_bus(busn, true);
 }
 EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 45/47] x86, PCI: Add pcibios_root_rescan()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (43 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 44/47] x86, PCI: add __pcibios_scan_specific_bus " Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 46/47] x86, PCI: Add arch version pci_root_rescan() Yinghai Lu
                   ` (3 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

Need use it to rescan root bus that was not added via acpi probe.

-v2: add pcibios_resource_survey_bus() calling...

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/include/asm/pci.h |    2 ++
 arch/x86/pci/legacy.c      |   26 ++++++++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index bb015c7..332c191 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -30,6 +30,8 @@ extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 					    int node);
 extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
 
+void pcibios_root_rescan(void);
+
 #ifdef CONFIG_PCI
 
 #ifdef CONFIG_PCI_DOMAINS
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index aab0e41..8b6048a 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -79,3 +79,29 @@ int __init pci_subsys_init(void)
 	return 0;
 }
 subsys_initcall(pci_subsys_init);
+
+void __ref pcibios_root_rescan(void)
+{
+	int busn;
+	struct pci_bus *bus;
+
+	if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
+		return;
+
+	for (busn = 0; busn <= pcibios_last_bus; busn++) {
+		bus = pci_find_bus(0, busn);
+
+		if (bus)
+			continue;
+
+		bus = __pcibios_scan_specific_bus(busn, false);
+
+		if (!bus)
+			continue;
+
+		pcibios_resource_survey_bus(bus);
+		pci_assign_unassigned_bus_resources(bus);
+
+		pci_bus_add_devices(bus);
+	}
+}
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 46/47] x86, PCI: Add arch version pci_root_rescan()
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (44 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 45/47] x86, PCI: Add pcibios_root_rescan() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19  5:46 ` [PATCH -v3 47/47] PCI: Add /sys/bus/pci/rescan_root Yinghai Lu
                   ` (2 subsequent siblings)
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

It will call acpi version pci_root_rescan and legacy pci_root_rescan.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/pci/common.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 2ebdc231..0ec860f 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/pci-acpi.h>
 
 #include <asm/acpi.h>
 #include <asm/segment.h>
@@ -661,6 +662,12 @@ struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno)
 	return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
 }
 
+void arch_pci_root_rescan(void)
+{
+	acpi_pci_root_rescan();
+	pcibios_root_rescan();
+}
+
 /*
  * NUMA info for PCI busses
  *
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH -v3 47/47] PCI: Add /sys/bus/pci/rescan_root
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (45 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 46/47] x86, PCI: Add arch version pci_root_rescan() Yinghai Lu
@ 2012-03-19  5:46 ` Yinghai Lu
  2012-03-19 21:37 ` [PATCH 00/47] PCI, x86: pci root bus hotplug support Bjorn Helgaas
  2012-03-30 18:27 ` Yinghai Lu
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-19  5:46 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu, Randy Dunlap, linux-doc

It will be used to rediscover removed pci root buses.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-doc@vger.kernel.org
---
 Documentation/ABI/testing/sysfs-bus-pci |    9 +++++++++
 drivers/pci/pci-sysfs.c                 |   19 +++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 22392de..eb826bd 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -66,6 +66,15 @@ Description:
 		re-discover previously removed devices.
 		Depends on CONFIG_HOTPLUG.
 
+What:		/sys/bus/pci/rescan_root
+Date:		March 2012
+Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+		Writing a non-zero value to this attribute will
+		cause a rescan of all PCI root buses in the system, and
+		re-discover previously removed PCI root buses.
+		Depends on CONFIG_HOTPLUG.
+
 What:		/sys/bus/pci/devices/.../msi_irqs/
 Date:		September, 2011
 Contact:	Neil Horman <nhorman@tuxdriver.com>
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index afba77b..c348048 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -302,8 +302,27 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
 	return count;
 }
 
+void __weak arch_pci_root_rescan(void) { }
+
+static ssize_t bus_rescan_root_store(struct bus_type *bus, const char *buf,
+				size_t count)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	if (val) {
+		mutex_lock(&pci_remove_rescan_mutex);
+		arch_pci_root_rescan();
+		mutex_unlock(&pci_remove_rescan_mutex);
+	}
+	return count;
+}
+
 struct bus_attribute pci_bus_attrs[] = {
 	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
+	__ATTR(rescan_root, (S_IWUSR|S_IWGRP), NULL, bus_rescan_root_store),
 	__ATTR_NULL
 };
 
-- 
1.7.7


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH 00/47] PCI, x86: pci root bus hotplug support
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (46 preceding siblings ...)
  2012-03-19  5:46 ` [PATCH -v3 47/47] PCI: Add /sys/bus/pci/rescan_root Yinghai Lu
@ 2012-03-19 21:37 ` Bjorn Helgaas
  2012-03-20 17:20   ` Yinghai Lu
  2012-03-30 18:27 ` Yinghai Lu
  48 siblings, 1 reply; 58+ messages in thread
From: Bjorn Helgaas @ 2012-03-19 21:37 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jesse Barnes, x86, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel

On Sun, Mar 18, 2012 at 11:45 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> will add pci_stop_and_remove_bus() to support remove bus in
> /sys/devices/pci.../pci_bus/...
>
> To rescan root, need to
> echo 1 > /sys/bus/pci/rescan_root
>
> It supports acpi path root bus and legacy root bus.

I tried to start discussions about some interesting issues such as
acpi_pci_root_rescan() and /sys/bus/pci/rescan_root.

I don't think it's a good use of my time to re-review all these
patches until after we make some progress on those conversations.

Bjorn

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 00/47] PCI, x86: pci root bus hotplug support
  2012-03-19 21:37 ` [PATCH 00/47] PCI, x86: pci root bus hotplug support Bjorn Helgaas
@ 2012-03-20 17:20   ` Yinghai Lu
  0 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-20 17:20 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jesse Barnes, x86, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel

On Mon, Mar 19, 2012 at 2:37 PM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> On Sun, Mar 18, 2012 at 11:45 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>> will add pci_stop_and_remove_bus() to support remove bus in
>> /sys/devices/pci.../pci_bus/...
>>
>> To rescan root, need to
>> echo 1 > /sys/bus/pci/rescan_root
>>
>> It supports acpi path root bus and legacy root bus.
>
> I tried to start discussions about some interesting issues such as
> acpi_pci_root_rescan() and /sys/bus/pci/rescan_root.
>
> I don't think it's a good use of my time to re-review all these
> patches until after we make some progress on those conversations.

Actually I reordered that patch applying sequence.

 PCI, ACPI: Add acpi_pci_root_rescan()
 x86, PCI: Add arch version pci_root_rescan()
 PCI: Add /sys/bus/pci/rescan_root

will be applied at last. So Jesse could skip those 3 or so patches,
and upstream will only support really physical root-bus hotplug that
user need to press attention button.

     Yinghai

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 00/47] PCI, x86: pci root bus hotplug support
  2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
                   ` (47 preceding siblings ...)
  2012-03-19 21:37 ` [PATCH 00/47] PCI, x86: pci root bus hotplug support Bjorn Helgaas
@ 2012-03-30 18:27 ` Yinghai Lu
  48 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-03-30 18:27 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Bjorn Helgaas, Andrew Morton, Linus Torvalds, Greg Kroah-Hartman,
	linux-pci, linux-kernel, Yinghai Lu

[-- Attachment #1: Type: text/plain, Size: 1264 bytes --]

On Sun, Mar 18, 2012 at 10:45 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> will add pci_stop_and_remove_bus() to support remove bus in
> /sys/devices/pci.../pci_bus/...
>
> To rescan root, need to
> echo 1 > /sys/bus/pci/rescan_root
>
> It supports acpi path root bus and legacy root bus.
>
> This patcheset include some IOMM and dmar and pnpacpi fix with device refcount leaking.
>        also include some bus remove/rescan cleanup.
>
> The patches need to apply to pci/for-linus and pci/linux-next
>        [PATCH -v3] PCI: pci_host_bridge related cleanup
>        [PATCH -v11] PCI: allocate pci bus num range for unassigned bridge busn
>
> could get from
>        git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-root-bus-hotplug
>
> -v2: Address most of Bjorn's review, except still keeping .../pci_bus/.../remove
>     Separate pci root hot add support from acpiphp to pci_root_hp
>     add hot removal to pci_root_hp
> -v3: Reordering the patches about /sys changes at last that Bjorn objects.
>     Claim hw/fw allocated bus after root bus hot add.
>     add two patches for Jiang Liu about removal.

Add attached patch to the tree for making ioapic and iommu hotplug working.

Thanks

Yinghai

[-- Attachment #2: stop_pci_drivers_before_ioapic_dmar.patch --]
[-- Type: application/octet-stream, Size: 2500 bytes --]

Subject: [PATCH] ACPI, PCI: Stop pci devices before acpi_pci_driver remove calling

During stop pci drivers, it still need to access ioapic and iommu.
So need to make sure those drivers need to be stop at first.

Also change the acpi_pci_drivers remove calling sequence to reverse.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>

---
 drivers/acpi/pci_root.c |   11 +++++++----
 drivers/pci/remove.c    |    2 +-
 include/linux/pci.h     |    1 +
 3 files changed, 9 insertions(+), 5 deletions(-)

Index: linux-2.6/drivers/acpi/pci_root.c
===================================================================
--- linux-2.6.orig/drivers/acpi/pci_root.c
+++ linux-2.6/drivers/acpi/pci_root.c
@@ -657,10 +657,6 @@ static int acpi_pci_root_remove(struct a
 
 	mutex_lock(&acpi_pci_root_lock);
 
-	list_for_each_entry(driver, &acpi_pci_drivers, node)
-		if (driver->remove)
-			driver->remove(root->device->handle);
-
 	/* that root bus could be removed already */
 	if (!pci_find_bus(root->segment, root->secondary.start)) {
 		dev_printk(KERN_DEBUG, &device->dev,
@@ -668,6 +664,13 @@ static int acpi_pci_root_remove(struct a
 		goto out;
 	}
 
+	/* stop normal pci drivers before we stop ioapic and dmar etc */
+	pci_stop_bus_devices(root->bus);
+
+	list_for_each_entry_reverse(driver, &acpi_pci_drivers, node)
+		if (driver->remove)
+			driver->remove(root->device->handle);
+
 	device_set_run_wake(root->bus->bridge, false);
 	pci_acpi_remove_bus_pm_notifier(device);
 
Index: linux-2.6/drivers/pci/remove.c
===================================================================
--- linux-2.6.orig/drivers/pci/remove.c
+++ linux-2.6/drivers/pci/remove.c
@@ -117,7 +117,7 @@ static void __pci_remove_bus_devices(str
 		__pci_remove_bus_device(dev);
 }
 
-static void pci_stop_bus_devices(struct pci_bus *bus)
+void pci_stop_bus_devices(struct pci_bus *bus)
 {
 	struct pci_dev *dev, *tmp;
 
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -782,6 +782,7 @@ extern void pci_dev_put(struct pci_dev *
 extern void pci_remove_bus(struct pci_bus *b);
 extern void __pci_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_stop_bus_devices(struct pci_bus *bus);
 void pci_stop_and_remove_bus(struct pci_bus *bus);
 extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-03-19  5:46 ` [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove Yinghai Lu
@ 2012-04-06 15:50   ` Jiang Liu
  2012-04-06 16:01     ` Yinghai Lu
  0 siblings, 1 reply; 58+ messages in thread
From: Jiang Liu @ 2012-04-06 15:50 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jesse Barnes, x86, Bjorn Helgaas, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel, Randy Dunlap,
	linux-doc

Hi Yinghai,
	I found many other drivers assume that a pci bus won't disappear if
the corresponding PCI bridge device still exists. The sysfs interface proposed
here breaks that assumption and may cause many access-after-free issues.
So what's the purpose of this interface? Should we remove this interface or
enhance other drivers to avoid invalid memory access issues?
	Thanks!
	Gerry
 
On 03/19/2012 01:46 PM, Yinghai Lu wrote:
> it supports both pci root bus and pci bus under pci bridge.
> 
> -v2: Change to three returns way in dev_bus_remove_store.
> 
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> Cc: Randy Dunlap <rdunlap@xenotime.net>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: linux-doc@vger.kernel.org
> ---
>  Documentation/ABI/testing/sysfs-bus-pci |    8 ++++++++
>  drivers/pci/pci-sysfs.c                 |   30 ++++++++++++++++++++++++++++++
>  2 files changed, 38 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
> index 95f0f37..22392de 100644
> --- a/Documentation/ABI/testing/sysfs-bus-pci
> +++ b/Documentation/ABI/testing/sysfs-bus-pci
> @@ -92,6 +92,14 @@ Description:
>  		hot-remove the PCI device and any of its children.
>  		Depends on CONFIG_HOTPLUG.
>  
> +What:		/sys/bus/pci/devices/.../pci_bus/.../remove
> +Date:		March 2012
> +Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
> +Description:
> +		Writing a non-zero value to this attribute will
> +		hot-remove the PCI bus and any of its children.
> +		Depends on CONFIG_HOTPLUG.
> +
>  What:		/sys/bus/pci/devices/.../pci_bus/.../rescan
>  Date:		May 2011
>  Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index d33a1bc..afba77b 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -391,6 +391,35 @@ remove_store(struct device *dev, struct device_attribute *dummy,
>  	return count;
>  }
>  
> +static void bus_remove_callback(struct device *dev)
> +{
> +	struct pci_bus *bus = to_pci_bus(dev);
> +
> +	mutex_lock(&pci_remove_rescan_mutex);
> +	pci_stop_and_remove_bus(bus);
> +	mutex_unlock(&pci_remove_rescan_mutex);
> +}
> +static ssize_t
> +dev_bus_remove_store(struct device *dev, struct device_attribute *attr,
> +		 const char *buf, size_t count)
> +{
> +	int err;
> +	unsigned long val;
> +
> +	if (kstrtoul(buf, 0, &val) < 0)
> +		return -EINVAL;
> +
> +	if (!val)
> +		return count;
> +
> +	err = device_schedule_callback(dev, bus_remove_callback);
> +
> +	if (err)
> +		return err;
> +
> +	return count;
> +}
> +
>  static void bus_rescan_callback(struct device *dev)
>  {
>  	struct pci_bus *bus = to_pci_bus(dev);
> @@ -450,6 +479,7 @@ struct device_attribute pci_dev_attrs[] = {
>  struct device_attribute pcibus_dev_attrs[] = {
>  #ifdef CONFIG_HOTPLUG
>  	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
> +	__ATTR(remove, (S_IWUSR|S_IWGRP), NULL, dev_bus_remove_store),
>  #endif
>  	__ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
>  	__ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-04-06 15:50   ` Jiang Liu
@ 2012-04-06 16:01     ` Yinghai Lu
  2012-04-06 16:07       ` Bjorn Helgaas
  0 siblings, 1 reply; 58+ messages in thread
From: Yinghai Lu @ 2012-04-06 16:01 UTC (permalink / raw)
  To: Jiang Liu
  Cc: Jesse Barnes, x86, Bjorn Helgaas, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel, Randy Dunlap,
	linux-doc

On Fri, Apr 6, 2012 at 8:50 AM, Jiang Liu <liuj97@gmail.com> wrote:
> Hi Yinghai,
>        I found many other drivers assume that a pci bus won't disappear if
> the corresponding PCI bridge device still exists. The sysfs interface proposed
> here breaks that assumption and may cause many access-after-free issues.
> So what's the purpose of this interface? Should we remove this interface or
> enhance other drivers to avoid invalid memory access issues?

ok, will make it only show up on root bus.

Yinghai

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-04-06 16:01     ` Yinghai Lu
@ 2012-04-06 16:07       ` Bjorn Helgaas
  2012-04-06 16:22         ` Jiang Liu
       [not found]         ` <CAE9FiQUjsiEvGGZz4sPux5AM7ipDsqgqgh5bh2QA7GJVBTqDKw@mail.gmail.com>
  0 siblings, 2 replies; 58+ messages in thread
From: Bjorn Helgaas @ 2012-04-06 16:07 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jiang Liu, Jesse Barnes, x86, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel, Randy Dunlap,
	linux-doc

On Fri, Apr 6, 2012 at 10:01 AM, Yinghai Lu <yhlu.kernel@gmail.com> wrote:
> On Fri, Apr 6, 2012 at 8:50 AM, Jiang Liu <liuj97@gmail.com> wrote:
>> Hi Yinghai,
>>        I found many other drivers assume that a pci bus won't disappear if
>> the corresponding PCI bridge device still exists. The sysfs interface proposed
>> here breaks that assumption and may cause many access-after-free issues.
>> So what's the purpose of this interface? Should we remove this interface or
>> enhance other drivers to avoid invalid memory access issues?

Can you point out some of the specifics about drivers making this
assumption?  I'm not thrilled about the idea of removing a pci_bus
while the upstream bridge pci_dev still exists either.

> ok, will make it only show up on root bus.

OK.  I'm still interested in the specifics because I don't like the
way the pci_bus is exposed, even inside the kernel.  The bus itself is
not an active entity, and we can't really do anything with it except
by touching a device connected to it.

Bjorn

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-04-06 16:07       ` Bjorn Helgaas
@ 2012-04-06 16:22         ` Jiang Liu
       [not found]         ` <CAE9FiQUjsiEvGGZz4sPux5AM7ipDsqgqgh5bh2QA7GJVBTqDKw@mail.gmail.com>
  1 sibling, 0 replies; 58+ messages in thread
From: Jiang Liu @ 2012-04-06 16:22 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Yinghai Lu, Jesse Barnes, x86, Andrew Morton, Linus Torvalds,
	Greg Kroah-Hartman, linux-pci, linux-kernel, Randy Dunlap,
	linux-doc

On 04/07/2012 12:07 AM, Bjorn Helgaas wrote:
> On Fri, Apr 6, 2012 at 10:01 AM, Yinghai Lu <yhlu.kernel@gmail.com> wrote:
>> On Fri, Apr 6, 2012 at 8:50 AM, Jiang Liu <liuj97@gmail.com> wrote:
>>> Hi Yinghai,
>>>        I found many other drivers assume that a pci bus won't disappear if
>>> the corresponding PCI bridge device still exists. The sysfs interface proposed
>>> here breaks that assumption and may cause many access-after-free issues.
>>> So what's the purpose of this interface? Should we remove this interface or
>>> enhance other drivers to avoid invalid memory access issues?
> 
> Can you point out some of the specifics about drivers making this
> assumption?  I'm not thrilled about the idea of removing a pci_bus
> while the upstream bridge pci_dev still exists either.
According to my understanding, following drivers may have such an assumption:
acpiphp, pciehp, shpcphp, acpi/pci_slot, acpi/pci_bind.
I suspect there are still other drivers have such issues.

> 
>> ok, will make it only show up on root bus.
> 
> OK.  I'm still interested in the specifics because I don't like the
> way the pci_bus is exposed, even inside the kernel.  The bus itself is
> not an active entity, and we can't really do anything with it except
> by touching a device connected to it.
> 
> Bjorn


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Fwd: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
       [not found]         ` <CAE9FiQUjsiEvGGZz4sPux5AM7ipDsqgqgh5bh2QA7GJVBTqDKw@mail.gmail.com>
@ 2012-04-06 17:42           ` Yinghai Lu
  2012-04-06 18:05             ` Bjorn Helgaas
  0 siblings, 1 reply; 58+ messages in thread
From: Yinghai Lu @ 2012-04-06 17:42 UTC (permalink / raw)
  To: Jiang Liu, Linux Kernel Mailing List, linux-pci

[-- Attachment #1: Type: text/plain, Size: 1655 bytes --]

adding back the CC list


---------- Forwarded message ----------
From: Yinghai Lu <yhlu.kernel@gmail.com>
Date: Fri, Apr 6, 2012 at 9:24 AM
Subject: Re: [PATCH -v3 40/47] PCI: Add pci bus removal through
/sys/.../pci_bus/.../remove
To: Bjorn Helgaas <bhelgaas@google.com>


On Fri, Apr 6, 2012 at 9:07 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> On Fri, Apr 6, 2012 at 10:01 AM, Yinghai Lu <yhlu.kernel@gmail.com> wrote:
>> On Fri, Apr 6, 2012 at 8:50 AM, Jiang Liu <liuj97@gmail.com> wrote:
>>> Hi Yinghai,
>>>        I found many other drivers assume that a pci bus won't disappear if
>>> the corresponding PCI bridge device still exists. The sysfs interface proposed
>>> here breaks that assumption and may cause many access-after-free issues.
>>> So what's the purpose of this interface? Should we remove this interface or
>>> enhance other drivers to avoid invalid memory access issues?
>
> Can you point out some of the specifics about drivers making this
> assumption?  I'm not thrilled about the idea of removing a pci_bus
> while the upstream bridge pci_dev still exists either.

I noticed that too. some hotplug driver link to those child bus
instead of bridge...
So have prepared some local patches to handle them.

>
>> ok, will make it only show up on root bus.
>
> OK.  I'm still interested in the specifics because I don't like the
> way the pci_bus is exposed, even inside the kernel.  The bus itself is
> not an active entity, and we can't really do anything with it except
> by touching a device connected to it.

I want to keep that to remove root bus that is not added acpi root.

Yinghai

[-- Attachment #2: fix_pciehcp_after_remove_bus_panic.patch --]
[-- Type: application/octet-stream, Size: 1857 bytes --]

---
 drivers/pci/hotplug/pciehp_hpc.c |   19 +++++++++++++++++++
 drivers/pci/hotplug/pciehp_pci.c |    6 +++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/pci/hotplug/pciehp_pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_pci.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_pci.c
@@ -81,7 +81,7 @@ int pciehp_configure_device(struct slot
 		pci_dev_put(dev);
 	}
 
-	pci_bus_add_devices(parent);
+	pci_bus_add_single_device(bridge);
 
 	return 0;
 }
@@ -96,6 +96,10 @@ int pciehp_unconfigure_device(struct slo
 	u16 command;
 	struct controller *ctrl = p_slot->ctrl;
 
+	/* Someone removed the bus already */
+	if (!parent)
+		return 0;
+
 	ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n",
 		 __func__, pci_domain_nr(parent), parent->number);
 	ret = pciehp_get_adapter_status(p_slot, &presence);
Index: linux-2.6/drivers/pci/hotplug/pciehp_hpc.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_hpc.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_hpc.c
@@ -283,6 +283,21 @@ static void pcie_wait_link_not_active(st
 	__pcie_wait_link_active(ctrl, false);
 }
 
+
+static bool pci_hp_check_subordinate(struct pci_dev *dev)
+{
+	if (dev->subordinate)
+		return true;
+
+	/* someone remove it already, get it back */
+	if (pci_hp_add_bridge(dev))
+		return false;
+
+	pci_stop_and_remove_behind_bridge(dev);
+
+	return true;
+}
+
 static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
 {
 	u32 l;
@@ -327,6 +342,10 @@ int pciehp_check_link_status(struct cont
 
 	/* wait 100ms before read pci conf, and try in 1s */
 	msleep(100);
+
+	if (!pci_hp_check_subordinate(ctrl->pcie->port))
+		return -1;
+
 	found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
 					PCI_DEVFN(0, 0));
 

[-- Attachment #3: fix_pcie_hotplug_null_subordinate.patch --]
[-- Type: application/octet-stream, Size: 11043 bytes --]

---
 drivers/pci/hotplug/pci_hotplug_core.c |    6 -
 drivers/pci/probe.c                    |    1 
 drivers/pci/slot.c                     |  147 +++++++++++++++++++++++++++------
 include/linux/pci.h                    |   10 +-
 include/linux/pci_hotplug.h            |   12 +-
 5 files changed, 141 insertions(+), 35 deletions(-)

Index: linux-2.6/drivers/pci/hotplug/pci_hotplug_core.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pci_hotplug_core.c
+++ linux-2.6/drivers/pci/hotplug/pci_hotplug_core.c
@@ -431,8 +431,8 @@ static struct hotplug_slot *get_slot_fro
  *
  * Returns 0 if successful, anything else for an error.
  */
-int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus,
-		      int devnr, const char *name,
+int __pci_hp_register(struct hotplug_slot *slot, struct pci_dev *b_dev,
+		      struct pci_bus *bus, int devnr, const char *name,
 		      struct module *owner, const char *mod_name)
 {
 	int result;
@@ -457,7 +457,7 @@ int __pci_hp_register(struct hotplug_slo
 	 * driver and call it here again. If we've already created the
 	 * pci_slot, the interface will simply bump the refcount.
 	 */
-	pci_slot = pci_create_slot(bus, devnr, name, slot);
+	pci_slot = __pci_create_slot(b_dev, bus, devnr, name, slot);
 	if (IS_ERR(pci_slot)) {
 		result = PTR_ERR(pci_slot);
 		goto out;
Index: linux-2.6/drivers/pci/probe.c
===================================================================
--- linux-2.6.orig/drivers/pci/probe.c
+++ linux-2.6/drivers/pci/probe.c
@@ -1454,6 +1454,7 @@ struct pci_dev *alloc_pci_dev(void)
 
 	INIT_LIST_HEAD(&dev->bus_list);
 	INIT_LIST_HEAD(&dev->addon_resources);
+	INIT_LIST_HEAD(&dev->slots);
 
 	return dev;
 }
Index: linux-2.6/drivers/pci/slot.c
===================================================================
--- linux-2.6.orig/drivers/pci/slot.c
+++ linux-2.6/drivers/pci/slot.c
@@ -38,14 +38,24 @@ static const struct sysfs_ops pci_slot_s
 
 static ssize_t address_read_file(struct pci_slot *slot, char *buf)
 {
+	struct pci_bus *bus;
+
+	if (slot->b_dev)
+		bus = slot->b_dev->subordinate;
+	else
+		bus = slot->bus;
+
+	if (!bus)
+		return sprintf(buf, "none\n");
+
 	if (slot->number == 0xff)
 		return sprintf(buf, "%04x:%02x\n",
-				pci_domain_nr(slot->bus),
-				slot->bus->number);
+				pci_domain_nr(bus),
+				bus->number);
 	else
 		return sprintf(buf, "%04x:%02x:%02x\n",
-				pci_domain_nr(slot->bus),
-				slot->bus->number,
+				pci_domain_nr(bus),
+				bus->number,
 				slot->number);
 }
 
@@ -90,25 +100,67 @@ static ssize_t bus_speed_read(enum pci_b
 
 static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf)
 {
-	return bus_speed_read(slot->bus->max_bus_speed, buf);
+	struct pci_bus *bus;
+	enum pci_bus_speed speed;
+
+	if (slot->b_dev)
+		bus = slot->b_dev->subordinate;
+	else
+		bus = slot->bus;
+
+	if (!bus)
+		speed = ARRAY_SIZE(pci_bus_speed_strings);
+	else
+		speed = bus->max_bus_speed;
+
+	return bus_speed_read(speed, buf);
 }
 
 static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
 {
-	return bus_speed_read(slot->bus->cur_bus_speed, buf);
+	struct pci_bus *bus;
+	enum pci_bus_speed speed;
+
+	if (slot->b_dev)
+		bus = slot->b_dev->subordinate;
+	else
+		bus = slot->bus;
+
+	if (!bus)
+		speed = ARRAY_SIZE(pci_bus_speed_strings);
+	else
+		speed = bus->cur_bus_speed;
+
+	return bus_speed_read(speed, buf);
 }
 
 static void pci_slot_release(struct kobject *kobj)
 {
-	struct pci_dev *dev;
 	struct pci_slot *slot = to_pci_slot(kobj);
+	struct pci_dev *b_dev = slot->b_dev;
+	struct pci_bus *bus;
+	struct device *device;
+
+	if (b_dev) {
+		bus = b_dev->subordinate;
+		if (bus)
+			device = &bus->dev;
+		else
+			device = &b_dev->dev;
+	} else {
+		bus = slot->bus;
+		device = &bus->dev;
+	}
 
-	dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
+	dev_dbg(device, "dev %02x, released physical slot %s\n",
 		slot->number, pci_slot_name(slot));
 
-	list_for_each_entry(dev, &slot->bus->devices, bus_list)
-		if (PCI_SLOT(dev->devfn) == slot->number)
-			dev->slot = NULL;
+	if (bus) {
+		struct pci_dev *dev;
+		list_for_each_entry(dev, &bus->devices, bus_list)
+			if (PCI_SLOT(dev->devfn) == slot->number)
+				dev->slot = NULL;
+	}
 
 	list_del(&slot->list);
 
@@ -191,13 +243,20 @@ static int rename_slot(struct pci_slot *
 	return result;
 }
 
-static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
+static struct pci_slot *get_slot(struct pci_dev *b_dev,
+			struct pci_bus *parent, int slot_nr)
 {
 	struct pci_slot *slot;
+	struct list_head *slots;
 	/*
 	 * We already hold pci_bus_sem so don't worry
 	 */
-	list_for_each_entry(slot, &parent->slots, list)
+	if (b_dev)
+		slots = &b_dev->slots;
+	else
+		slots = &parent->slots;
+
+	list_for_each_entry(slot, slots, list)
 		if (slot->number == slot_nr) {
 			kobject_get(&slot->kobj);
 			return slot;
@@ -244,14 +303,16 @@ static struct pci_slot *get_slot(struct
  * %struct pci_bus and bb is the bus number. In other words, the devfn of
  * the 'placeholder' slot will not be displayed.
  */
-struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
-				 const char *name,
+struct pci_slot *__pci_create_slot(struct pci_dev *b_dev,
+				 struct pci_bus *parent,
+				 int slot_nr, const char *name,
 				 struct hotplug_slot *hotplug)
 {
-	struct pci_dev *dev;
+	struct pci_bus *bus;
 	struct pci_slot *slot;
 	int err = 0;
 	char *slot_name = NULL;
+	struct device *device;
 
 	down_write(&pci_bus_sem);
 
@@ -262,7 +323,7 @@ struct pci_slot *pci_create_slot(struct
 	 * Hotplug drivers are allowed to rename an existing slot,
 	 * but only if not already claimed.
 	 */
-	slot = get_slot(parent, slot_nr);
+	slot = get_slot(b_dev, parent, slot_nr);
 	if (slot) {
 		if (hotplug) {
 			if ((err = slot->hotplug ? -EBUSY : 0)
@@ -282,6 +343,7 @@ placeholder:
 		goto err;
 	}
 
+	slot->b_dev = b_dev;
 	slot->bus = parent;
 	slot->number = slot_nr;
 
@@ -299,14 +361,28 @@ placeholder:
 		goto err;
 
 	INIT_LIST_HEAD(&slot->list);
-	list_add(&slot->list, &parent->slots);
-
-	list_for_each_entry(dev, &parent->devices, bus_list)
-		if (PCI_SLOT(dev->devfn) == slot_nr)
-			dev->slot = slot;
+	if (b_dev) {
+		list_add(&slot->list, &b_dev->slots);
+		bus = b_dev->subordinate;
+		if (bus)
+			device = &bus->dev;
+		else
+			device = &b_dev->dev;
+	}
+	else {
+		list_add(&slot->list, &parent->slots);
+		bus = parent;
+		device = &bus->dev;
+	}
 
-	dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
+	dev_dbg(device, "dev %02x, created physical slot %s\n",
 		slot_nr, pci_slot_name(slot));
+	if (bus) {
+		struct pci_dev *dev;
+		list_for_each_entry(dev, &bus->devices, bus_list)
+			if (PCI_SLOT(dev->devfn) == slot_nr)
+				dev->slot = slot;
+	}
 
 out:
 	kfree(slot_name);
@@ -317,6 +393,13 @@ err:
 	slot = ERR_PTR(err);
 	goto out;
 }
+EXPORT_SYMBOL_GPL(__pci_create_slot);
+struct pci_slot *pci_create_slot(struct pci_bus *parent,
+				 int slot_nr, const char *name,
+				 struct hotplug_slot *hotplug)
+{
+	return __pci_create_slot(NULL, parent, slot_nr, name, hotplug);
+}
 EXPORT_SYMBOL_GPL(pci_create_slot);
 
 /**
@@ -331,14 +414,19 @@ EXPORT_SYMBOL_GPL(pci_create_slot);
 void pci_renumber_slot(struct pci_slot *slot, int slot_nr)
 {
 	struct pci_slot *tmp;
+	struct list_head *slots;
 
 	down_write(&pci_bus_sem);
 
-	list_for_each_entry(tmp, &slot->bus->slots, list) {
+	if (slot->b_dev)
+		slots = &slot->b_dev->slots;
+	else
+		slots = &slot->bus->slots;
+
+	list_for_each_entry(tmp, slots, list) {
 		WARN_ON(tmp->number == slot_nr);
 		goto out;
 	}
-
 	slot->number = slot_nr;
 out:
 	up_write(&pci_bus_sem);
@@ -355,7 +443,14 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot);
  */
 void pci_destroy_slot(struct pci_slot *slot)
 {
-	dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
+	struct device *dev;
+
+	if (slot->b_dev)
+		dev = &slot->b_dev->dev;
+	else
+		dev = &slot->bus->dev;
+
+	dev_dbg(dev, "dev %02x, dec refcount to %d\n",
 		slot->number, atomic_read(&slot->kobj.kref.refcount) - 1);
 
 	down_write(&pci_bus_sem);
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -59,6 +59,7 @@
 
 /* pci_slot represents a physical slot */
 struct pci_slot {
+	struct pci_dev *b_dev;		/* the bridge this slot is under */
 	struct pci_bus *bus;		/* The bus this slot is on */
 	struct list_head list;		/* node in list of slots on this bus */
 	struct hotplug_slot *hotplug;	/* Hotplug info (migrate over time) */
@@ -243,6 +244,7 @@ struct pci_dev {
 	void		*sysdata;	/* hook for sys-specific extension */
 	struct proc_dir_entry *procent;	/* device entry in /proc/bus/pci */
 	struct pci_slot	*slot;		/* Physical slot this device is in */
+	struct list_head slots;		/* list of slots under this bridge */
 
 	unsigned int	devfn;		/* encoded device & function index */
 	unsigned short	vendor;
@@ -767,8 +769,12 @@ void pcie_update_link_speed(struct pci_b
 void pcie_link_disable_set(struct pci_dev *dev, int bit);
 int pcie_link_disable_get(struct pci_dev *dev);
 int pcie_link_retrain(struct pci_dev *dev);
-struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
-				 const char *name,
+struct pci_slot *__pci_create_slot(struct pci_dev *b_dev,
+				 struct pci_bus *parent,
+				 int slot_nr, const char *name,
+				 struct hotplug_slot *hotplug);
+struct pci_slot *pci_create_slot(struct pci_bus *parent,
+				 int slot_nr, const char *name,
 				 struct hotplug_slot *hotplug);
 void pci_destroy_slot(struct pci_slot *slot);
 void pci_renumber_slot(struct pci_slot *slot, int slot_nr);
Index: linux-2.6/include/linux/pci_hotplug.h
===================================================================
--- linux-2.6.orig/include/linux/pci_hotplug.h
+++ linux-2.6/include/linux/pci_hotplug.h
@@ -125,16 +125,20 @@ static inline const char *hotplug_slot_n
 	return pci_slot_name(slot->pci_slot);
 }
 
-extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus,
-			     int nr, const char *name,
+extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_dev *b_dev,
+			     struct pci_bus *pbus, int nr, const char *name,
 			     struct module *owner, const char *mod_name);
 extern int pci_hp_deregister(struct hotplug_slot *slot);
 extern int __must_check pci_hp_change_slot_info	(struct hotplug_slot *slot,
 						 struct hotplug_slot_info *info);
 
 /* use a define to avoid include chaining to get THIS_MODULE & friends */
-#define pci_hp_register(slot, pbus, devnr, name) \
-	__pci_hp_register(slot, pbus, devnr, name, THIS_MODULE, KBUILD_MODNAME)
+#define pci_hp_register(slot, pbus, devnr, name)			\
+	__pci_hp_register(slot, NULL, pbus, devnr, name, THIS_MODULE,	\
+				 KBUILD_MODNAME)
+#define pci_hp_register_bridge(slot, b_dev, devnr, name)			\
+	__pci_hp_register(slot, b_dev, NULL, devnr, name, THIS_MODULE,	\
+				 KBUILD_MODNAME)
 
 /* PCI Setting Record (Type 0) */
 struct hpp_type0 {

[-- Attachment #4: fix_pcie_hotplug_null_subordinate_pciehp.patch --]
[-- Type: application/octet-stream, Size: 796 bytes --]

---
 drivers/pci/hotplug/pciehp_core.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_core.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_core.c
@@ -130,8 +130,7 @@ static int init_slot(struct controller *
 	ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:00 sun=%x\n",
 		 pci_domain_nr(ctrl->pcie->port->subordinate),
 		 ctrl->pcie->port->subordinate->number, PSN(ctrl));
-	retval = pci_hp_register(hotplug,
-				 ctrl->pcie->port->subordinate, 0, name);
+	retval = pci_hp_register_bridge(hotplug, ctrl->pcie->port, 0, name);
 	if (retval)
 		ctrl_err(ctrl,
 			 "pci_hp_register failed with error %d\n", retval);

[-- Attachment #5: fix_pcie_hotplug_null_subordinate_acpiphp.patch --]
[-- Type: application/octet-stream, Size: 2438 bytes --]

---
 drivers/acpi/pci_slot.c            |   17 ++++++++++++++---
 drivers/pci/hotplug/acpiphp_core.c |    8 +++++++-
 2 files changed, 21 insertions(+), 4 deletions(-)

Index: linux-2.6/drivers/acpi/pci_slot.c
===================================================================
--- linux-2.6.orig/drivers/acpi/pci_slot.c
+++ linux-2.6/drivers/acpi/pci_slot.c
@@ -152,7 +152,10 @@ register_slot(acpi_handle handle, u32 lv
 	}
 
 	snprintf(name, sizeof(name), "%llu", sun);
-	pci_slot = pci_create_slot(pci_bus, device, name, NULL);
+	if (pci_bus->self)
+		pci_slot = __pci_create_slot(pci_bus->self, NULL, device, name, NULL);
+	else
+		pci_slot = pci_create_slot(pci_bus, device, name, NULL);
 	if (IS_ERR(pci_slot)) {
 		err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
 		kfree(slot);
@@ -166,7 +169,10 @@ register_slot(acpi_handle handle, u32 lv
 	list_add(&slot->list, &slot_list);
 	mutex_unlock(&slot_list_lock);
 
-	get_device(&pci_bus->dev);
+	if (pci_bus->self)
+		get_device(&pci_bus->self->dev);
+	else
+		get_device(&pci_bus->dev);
 
 	dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n",
 		pci_slot, pci_bus->number, device, name);
@@ -315,14 +321,19 @@ acpi_pci_slot_remove(acpi_handle handle)
 {
 	struct acpi_pci_slot *slot, *tmp;
 	struct pci_bus *pbus;
+	struct pci_dev *b_dev;
 
 	mutex_lock(&slot_list_lock);
 	list_for_each_entry_safe(slot, tmp, &slot_list, list) {
 		if (slot->root_handle == handle) {
 			list_del(&slot->list);
+			b_dev = slot->pci_slot->b_dev;
 			pbus = slot->pci_slot->bus;
 			pci_destroy_slot(slot->pci_slot);
-			put_device(&pbus->dev);
+			if (b_dev)
+				put_device(&b_dev->dev);
+			else
+				put_device(&pbus->dev);
 			kfree(slot);
 		}
 	}
Index: linux-2.6/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-2.6/drivers/pci/hotplug/acpiphp_core.c
@@ -315,7 +315,13 @@ int acpiphp_register_hotplug_slot(struct
 	acpiphp_slot->slot = slot;
 	snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
 
-	retval = pci_hp_register(slot->hotplug_slot,
+	if (acpiphp_slot->bridge->pci_dev)
+		retval = pci_hp_register_bridge(slot->hotplug_slot,
+					acpiphp_slot->bridge->pci_dev,
+					acpiphp_slot->device,
+					name);
+	else
+		retval = pci_hp_register(slot->hotplug_slot,
 					acpiphp_slot->bridge->pci_bus,
 					acpiphp_slot->device,
 					name);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-04-06 17:42           ` Fwd: " Yinghai Lu
@ 2012-04-06 18:05             ` Bjorn Helgaas
  2012-04-06 18:11               ` Yinghai Lu
  0 siblings, 1 reply; 58+ messages in thread
From: Bjorn Helgaas @ 2012-04-06 18:05 UTC (permalink / raw)
  To: Yinghai Lu; +Cc: Jiang Liu, Linux Kernel Mailing List, linux-pci

On Fri, Apr 6, 2012 at 11:42 AM, Yinghai Lu <yinghai@kernel.org> wrote:
> adding back the CC list
>
>
> ---------- Forwarded message ----------
> From: Yinghai Lu <yhlu.kernel@gmail.com>
> Date: Fri, Apr 6, 2012 at 9:24 AM
> Subject: Re: [PATCH -v3 40/47] PCI: Add pci bus removal through
> /sys/.../pci_bus/.../remove
> To: Bjorn Helgaas <bhelgaas@google.com>
>
>
> On Fri, Apr 6, 2012 at 9:07 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>> On Fri, Apr 6, 2012 at 10:01 AM, Yinghai Lu <yhlu.kernel@gmail.com> wrote:
>>> On Fri, Apr 6, 2012 at 8:50 AM, Jiang Liu <liuj97@gmail.com> wrote:
>>>> Hi Yinghai,
>>>>        I found many other drivers assume that a pci bus won't disappear if
>>>> the corresponding PCI bridge device still exists. The sysfs interface proposed
>>>> here breaks that assumption and may cause many access-after-free issues.
>>>> So what's the purpose of this interface? Should we remove this interface or
>>>> enhance other drivers to avoid invalid memory access issues?
>>
>> Can you point out some of the specifics about drivers making this
>> assumption?  I'm not thrilled about the idea of removing a pci_bus
>> while the upstream bridge pci_dev still exists either.
>
> I noticed that too. some hotplug driver link to those child bus
> instead of bridge...
> So have prepared some local patches to handle them.

I know you sometimes send patches as attachments because gmail makes
it hard to send them inline.  Gmail also makes it a pain to *review*
things sent as attachments, so it's hard on both ends.  I wish I could
fix that, but I can't.  Attachments also don't show up in patchwork,
which I hope to use to help keep track of things.  Bottom line:
attachments get less attention than they probably deserve.

>>> ok, will make it only show up on root bus.
>>
>> OK.  I'm still interested in the specifics because I don't like the
>> way the pci_bus is exposed, even inside the kernel.  The bus itself is
>> not an active entity, and we can't really do anything with it except
>> by touching a device connected to it.
>
> I want to keep that to remove root bus that is not added acpi root.

What's the use case for this?  I understand there are systems where
you can physically add or remove host bridges by plugging or
unplugging cables.  But in that case, I expect the host bridges to be
ACPI devices, and I expect an ACPI hotplug flow.

But I'm not aware of cases where we can hotplug non-ACPI host bridges,
so I don't understand the value of supporting this.  Is this related
to the cases where we blindly probe and discover CPU memory
controllers and things that the BIOS decided not to expose to the OS?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
  2012-04-06 18:05             ` Bjorn Helgaas
@ 2012-04-06 18:11               ` Yinghai Lu
  0 siblings, 0 replies; 58+ messages in thread
From: Yinghai Lu @ 2012-04-06 18:11 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Jiang Liu, Linux Kernel Mailing List, linux-pci

On Fri, Apr 6, 2012 at 11:05 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> But I'm not aware of cases where we can hotplug non-ACPI host bridges,
> so I don't understand the value of supporting this.  Is this related
> to the cases where we blindly probe and discover CPU memory
> controllers and things that the BIOS decided not to expose to the OS?

Yes.

Let's drop the last 8 patches in this patchset. I will keep them local
for debug purpose.

Yinghai

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2012-04-06 18:11 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-19  5:45 [PATCH 00/47] PCI, x86: pci root bus hotplug support Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 01/47] IOMMU: Update dmar units devices list during hotplug Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 02/47] PNPACPI: Fix device ref leaking in acpi_pnp_match Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 03/47] IOMMU: Fix tboot force iommu logic Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 04/47] x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 05/47] PCI: Separate out pci_assign_unassigned_bus_resources() Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 06/47] PCI: Move back pci_rescan_bus() Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 07/47] PCI: pci_bus_size_bridges() should not size own bridge Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 08/47] PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources() Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 09/47] PCI, sysfs: Use device_type and attr_groups with pci dev Yinghai Lu
2012-03-19  5:45 ` [PATCH -v3 10/47] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 11/47] PCI: Add pci_bus_add_single_device() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 12/47] PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 13/47] PCI: Clean up rescan_bus_bridge_resize() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 14/47] PCI: Rescan bus or bridge using callback method too Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 15/47] PCI, sysfs: Clean up rescan/remove with scheule_callback Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 16/47] x86, PCI: Separate pcibios_allocate_bridge_resources() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 17/47] x86, PCI: Separate pcibios_allocate_dev_resources() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 18/47] x86, PCI: Let pcibios_allocate_bus_resources() take bus instead Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 19/47] PCI: Claim hw/fw allocated resources in hot add path Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 20/47] Correctly clean up pci root buses in function pci_remove_bus() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 21/47] PCI: Move pci_stop_and_remove_behind_bridge() down Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 22/47] PCI: Add __pci_remove_bus_devices() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 23/47] PCI: Use list_for_each_entry_safe instead of list_for_each_safe Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 24/47] PCI: Add pci_stop_and_remove_bus() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 25/47] Fix an access-after-free issue in function pci_stop_and_remove_bus() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 26/47] PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 27/47] PCI, acpiphp: Separate out hot-add support of pci host bridge Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 28/47] PCI, ACPI: Add pci_root_hp hot removal notification support Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 29/47] PCI, ACPI: Add alloc_acpi_hp_work() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 30/47] PCI, acpiphp: Use acpi_hp_work Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 31/47] PCI, pci_root_hp: " Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 32/47] PCI, ACPI: Make kacpi_hotplug_wq static Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 33/47] PCI: Add debug print out for pci related dev release Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 34/47] PCI, pciehp: Separate pci_hp_add_bridge() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 35/47] PCI, cphi_hotplug: Simplify configure_slot Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 36/47] PCI, shpchp: Simplify configure_device Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 37/47] PCI: Kill pci_is_reassignedev() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 38/47] PCI, sysfs: Prepare to kill pci device rescan Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 39/47] ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 40/47] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove Yinghai Lu
2012-04-06 15:50   ` Jiang Liu
2012-04-06 16:01     ` Yinghai Lu
2012-04-06 16:07       ` Bjorn Helgaas
2012-04-06 16:22         ` Jiang Liu
     [not found]         ` <CAE9FiQUjsiEvGGZz4sPux5AM7ipDsqgqgh5bh2QA7GJVBTqDKw@mail.gmail.com>
2012-04-06 17:42           ` Fwd: " Yinghai Lu
2012-04-06 18:05             ` Bjorn Helgaas
2012-04-06 18:11               ` Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 41/47] PCI, ACPI: Add acpi_pci_root_rescan() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 42/47] PCI: Add __pci_scan_root_bus() that can skip bus_add Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 43/47] x86, PCI: add __pci_scan_root_bus_on_node() " Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 44/47] x86, PCI: add __pcibios_scan_specific_bus " Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 45/47] x86, PCI: Add pcibios_root_rescan() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 46/47] x86, PCI: Add arch version pci_root_rescan() Yinghai Lu
2012-03-19  5:46 ` [PATCH -v3 47/47] PCI: Add /sys/bus/pci/rescan_root Yinghai Lu
2012-03-19 21:37 ` [PATCH 00/47] PCI, x86: pci root bus hotplug support Bjorn Helgaas
2012-03-20 17:20   ` Yinghai Lu
2012-03-30 18:27 ` Yinghai Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).