PCI, x86: pci root bus hotplug support
Subsystems (8)
v2 cover PCI, x86: pci root bus hotplug support
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
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 and [PATCH 00/36] PCI: pci_host_bridge related cleanup and busn_alloc
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
Thanks
Yinghai
Ashok Raj (1):
ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing.
Yinghai Lu (36):
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
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: Add pci bus removal through /sys/.../pci_bus/.../remove
PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too
PCI, acpiphp: remove hot-add support of pci host bridge
PCI, ACPI: Add pci_root_hp hot add hotplug notification
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, 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: Make /sys/bus/pci/rescan rescan root
PCI, sysfs: Prepare to kill pci device rescan
Documentation/ABI/testing/sysfs-bus-pci | 18 ++ Documentation/feature-removal-schedule.txt | 9 + arch/x86/include/asm/pci.h | 4 + arch/x86/pci/common.c | 35 +++- arch/x86/pci/legacy.c | 44 ++++- 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 | 287 ++++++++++++++++++++++++++++ drivers/acpi/sci_emu.c | 141 ++++++++++++++ drivers/iommu/intel-iommu.c | 194 +++++++++++++++++-- drivers/pci/bus.c | 39 ++++ drivers/pci/hotplug/acpiphp.h | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 148 +++------------ drivers/pci/hotplug/cpci_hotplug_pci.c | 2 +- drivers/pci/hotplug/shpchp_pci.c | 2 +- drivers/pci/pci-sysfs.c | 136 ++++++++++++-- drivers/pci/pci.h | 1 + drivers/pci/probe.c | 43 ++++- drivers/pci/remove.c | 84 ++++++--- 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 | 7 + 29 files changed, 1089 insertions(+), 249 deletions(-) create mode 100644 drivers/acpi/pci_root_hp.c create mode 100644 drivers/acpi/sci_emu.c
Signature · 1 line
1.7.7
PATCH v2 1/37 IOMMU: Update dmar units devices list during hotplug
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.
--- drivers/iommu/intel-iommu.c | 188 ++++++++++++++++++++++++++++++++++++++++--- include/linux/dmar.h | 4 + 2 files changed, 180 insertions(+), 12 deletions(-)
drivers/iommu/intel-iommu.c +176 -12
@@ -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 ;
include/linux/dmar.h +4 -0
@@ -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);
Signature · 1 line
1.7.7
PATCH v2 2/37 PNPACPI: Fix device ref leaking in acpi_pnp_match
In reply to Yinghai LuDuring 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.
--- drivers/pnp/pnpacpi/core.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
drivers/pnp/pnpacpi/core.c +6 -1
@@ -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)); }
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 02/37] PNPACPI: Fix device ref leaking in acpi_pnp_match
Quoted 9 lines · Yinghai Lu
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_devicecalling before returning.
Changelog doesn't fit in 80 columns when using "git log". I mentioned this before; please try it yourself.
Quoted 33 lines
Signed-off-by Yinghai Lu <[email protected]>Cc Len Brown <[email protected]>Cc Adam Belay <[email protected]>Cc Bjorn Helgaas <[email protected]>---
drivers/pnp/pnpacpi/core.c | 7 ++++++-1 files changed, 6 insertions(+), 1 deletions(-)drivers/pnp/pnpacpi/core.c +6
-2@@ -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
PATCH v2 3/37 IOMMU: Fix tboot force iommu logic
In reply to Yinghai LuShould 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.
--- drivers/iommu/intel-iommu.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/iommu/intel-iommu.c +3 -3
@@ -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" );
Signature · 1 line
1.7.7
PATCH v2 4/37 x86, PCI: Fix non acpi path pci_sysdata leaking with release_fn
In reply to Yinghai LuNon 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.
--- arch/x86/pci/common.c | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-)
arch/x86/pci/common.c +11 -6
@@ -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); }
Signature · 1 line
1.7.7
PATCH v2 5/37 PCI: Separate out pci_assign_unassigned_bus_resources()
In reply to Yinghai LuIt is main portion of pci_rescan_bus().
Separate it out and need to use it for pci root bus rescan later.
--- drivers/pci/setup-bus.c | 32 ++++++++++++++++++-------------- include/linux/pci.h | 1 + 2 files changed, 19 insertions(+), 14 deletions(-)
drivers/pci/setup-bus.c +18 -14
@@ -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;
include/linux/pci.h +1 -0
@@ -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 *),
Signature · 1 line
1.7.7
PATCH v2 6/37 PCI: Move back pci_rescan_bus()
In reply to Yinghai LuNow we have pci_assign_unassigned_bus_resources() in place.
So move back pci_rescan_bus to probe.c where it should be.
--- drivers/pci/probe.c | 21 +++++++++++++++++++++ drivers/pci/setup-bus.c | 22 ---------------------- 2 files changed, 21 insertions(+), 22 deletions(-)
drivers/pci/probe.c +21 -0
@@ -2054,6 +2054,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);
drivers/pci/setup-bus.c +0 -22
@@ -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
Signature · 1 line
1.7.7
PATCH v2 7/37 PCI: pci_bus_size_bridges() should not size own bridge
In reply to Yinghai LuDuring 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.
--- drivers/pci/hotplug/acpiphp_glue.c | 2 +- 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, 19 insertions(+), 12 deletions(-)
drivers/pci/hotplug/acpiphp_glue.c +1 -1
@@ -816,7 +816,7 @@ 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); } } }
drivers/pci/hotplug/cpci_hotplug_pci.c +1 -1
@@ -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); }
drivers/pci/hotplug/shpchp_pci.c +1 -1
@@ -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);
drivers/pci/setup-bus.c +15 -9
@@ -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));
include/linux/pci.h +1 -0
@@ -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);
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 07/37] PCI: pci_bus_size_bridges() should not size own bridge
Quoted 4 lines · Yinghai Lu
During checking acpiphp code, found following sequence:
pci_bus_size_bridges(bus);pci_bus_assign_resources(bus);pci_enable_bridges(bus);
One of these lines is indented with tab, the others with spaces, which makes it not line up when using "git log". Try it sometime.
Quoted 6 lines
The problem is that when bus is not root bus,
pci_bus_size_bridgeswould also size own pci bridgebus->selfif that bridge resource is not inserted before. but laterpci_bus_assign_resourceswill not allocate those size bridge res.So try make it less confusing, let it does not include self sizing. and add
with_selfparameter info__pci_bus_size_bridge()
You failed to make this less confusing. Adding words to function names, adding "__" prefixes, adding flags to say "include self" or not -- they all make things hard to read.
Quoted 1 line
Fixes caller in pci hotplug componets.
"components"
Quoted 140 lines
Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/hotplug/acpiphp_glue.c | 2 +-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, 19 insertions(+), 12 deletions(-)drivers/pci/hotplug/acpiphp_glue.c +1
-1@@ -816,7 +816,7 @@ 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); } } }drivers/pci/hotplug/cpci_hotplug_pci.c +1
-1@@ -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); }drivers/pci/hotplug/shpchp_pci.c +1
-1@@ -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);drivers/pci/setup-bus.c +2
-2@@ -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) {drivers/pci/setup-bus.c +7
-1@@ -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 allsubordinate 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)drivers/pci/setup-bus.c +0
-0@@ -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++;drivers/pci/setup-bus.c +1
-1@@ -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));include/linux/pci.h +1
-1@@ -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
PATCH v2 8/37 PCI: Use __pci_bus_size_bridges() directly in pci_assign_unassigned_bus_resources()
In reply to Yinghai LuNow __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.
--- drivers/pci/setup-bus.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-)
drivers/pci/setup-bus.c +1 -7
@@ -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));
Signature · 1 line
1.7.7
PATCH v2 9/37 PCI, sysfs: Use device_type and attr_groups with pci dev
In reply to Yinghai LuWe 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 )
--- drivers/pci/pci-sysfs.c | 30 ++++++++++++++++++++++++++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 1 + 3 files changed, 32 insertions(+), 0 deletions(-)
drivers/pci/pci-sysfs.c +30 -0
@@ -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, +};
drivers/pci/pci.h +1 -0
@@ -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
drivers/pci/probe.c +1 -0
@@ -1138,6 +1138,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;
Signature · 1 line
1.7.7
PATCH v2 10/37 PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges
In reply to Yinghai LuCurrent 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.
--- Documentation/ABI/testing/sysfs-bus-pci | 10 ++++++++++ drivers/pci/pci-sysfs.c | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 0 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci +10 -0
@@ -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 <[email protected]> +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 <[email protected]>
drivers/pci/pci-sysfs.c +24 -0
@@ -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, +#endifNULL , };
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 10/37] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges
Quoted 2 lines · Yinghai Lu
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.
"The device" (not "the device").
Quoted 4 lines
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.
"And we" (not "And We").
I think the idea of this patch makes sense.
You might want to consider having this actually read the bridge config again. That way, if the user manually changed the secondary bus number or the bridge windows using setpci or something, this rescan could use that new config if possible.
I still hate the fact that we will have three different rescan files (four if you count /sys/bus/pci/rescan), but I don't have a solution to offer:
device/rescan
device/rescan_bridge
bus/rescan
Quoted 79 lines
(quoted diff) +0
-3-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 <[email protected]>Cc Randy Dunlap <[email protected]>Cc Greg Kroah-Hartman <[email protected]>---
Documentation/ABI/testing/sysfs-bus-pci | 10 ++++++++++drivers/pci/pci-sysfs.c| 24 ++++++++++++++++++++++++2 files changed, 34 insertions(+), 0 deletions(-)Documentation/ABI/testing/sysfs-bus-pci +0
-0@@ -111,6 +111,16 @@ Description:from this part of the device tree.
Depends onCONFIG_HOTPLUG.Documentation/ABI/testing/sysfs-bus-pci +10
-0+What: /sys/bus/pci/devices/.../rescan_bridge +Date: February 2012 +Contact: Linux PCI developers <[email protected]> +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 <[email protected]>drivers/pci/pci-sysfs.c +24
-1@@ -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
Re: [PATCH v2 10/37] PCI, sysfs: create rescan_bridge under /sys/.../pci/devices/... for pci bridges
Quoted 5 lines · Bjorn Helgaas
Quoted 2 lines · Yinghai Lu
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.
"The device" (not "the device").
ok
Quoted 7 lines
Quoted 5 lines
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.
"And we" (not "And We").
ok
Quoted 7 lines
I think the idea of this patch makes sense.
You might want to consider having this actually read the bridge config again. That way, if the user manually changed the secondary bus number or the bridge windows using setpci or something, this rescan could use that new config if possible.
yes, in the following patches, change that topci_rescan_bus_bridge_resize()
and
will be
unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
{
unsigned int max = 0;
int pass;
struct pci_bus *bus = bridge->bus;
for (pass = 0; pass < 2; pass++)
max = pci_scan_bridge(bus, bridge, max, pass);
pci_assign_unassigned_bridge_resources(bridge);
pci_bus_add_single_device(bridge);at last pci_scan_bridge will check the bus register in the bridge.
Quoted 7 lines
I still hate the fact that we will have three different rescan files (four if you count
/sys/bus/pci/rescan), but I don't have a solution to offer:
device/rescan
device/rescan_bridge
bus/rescan
looks like we only need/sys/devices/pci.../device/rescan_bridge/sys/bus/pci/bus/rescan
device rescan and bus rescan should be removed.
Yinghai
PATCH v2 11/37 PCI: Add pci_bus_add_single_device()
In reply to Yinghai LuWill use it to pci_bus_bridge_scan_resize() to make bridge will have pci_bus directory created correctly.
--- drivers/pci/bus.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 40 insertions(+), 0 deletions(-)
drivers/pci/bus.c +39 -0
@@ -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;
include/linux/pci.h +1 -0
@@ -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);
Signature · 1 line
1.7.7
PATCH v2 12/37 PCI: Make pci_rescan_bus_bridge_resize() use pci_scan_bridge instead
In reply to Yinghai LuSo 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.
--- drivers/pci/probe.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-)
drivers/pci/probe.c +6 -4
@@ -2043,14 +2043,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; }
Signature · 1 line
1.7.7
PATCH v2 13/37 PCI: Clean up rescan_bus_bridge_resize()
In reply to Yinghai LuShould 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.
--- drivers/pci/pci-sysfs.c | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-)
drivers/pci/pci-sysfs.c +2 -5
@@ -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;
Signature · 1 line
1.7.7
PATCH v2 14/37 PCI: Rescan bus or bridge using callback method too
In reply to Yinghai LuJust like removal.
Because We could add new bus under the bridges...
--- drivers/pci/pci-sysfs.c | 43 +++++++++++++++++++++++++++++++------------ 1 files changed, 31 insertions(+), 12 deletions(-)
drivers/pci/pci-sysfs.c +31 -12
@@ -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; }
Signature · 1 line
1.7.7
PATCH v2 15/37 PCI, sysfs: Clean up rescan/remove with scheule_callback
In reply to Yinghai LuChange to use three return according to Bjorn.
--- drivers/pci/pci-sysfs.c | 37 ++++++++++++++++++++----------------- 1 files changed, 20 insertions(+), 17 deletions(-)
drivers/pci/pci-sysfs.c +20 -17
@@ -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; }
Signature · 1 line
1.7.7
PATCH v2 16/37 PCI: Move pci_stop_and_remove_behind_bridge() down
In reply to Yinghai LuLater it will use pci_stop_bus_devices instead of pci_stop_behind_bridge.
--- drivers/pci/remove.c | 30 +++++++++++++++--------------- 1 files changed, 15 insertions(+), 15 deletions(-)
drivers/pci/remove.c +15 -15
@@ -129,21 +129,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;
@@ -163,6 +148,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 *
Signature · 1 line
1.7.7
PATCH v2 17/37 PCI: Add __pci_remove_bus_devices()
In reply to Yinghai LuWill 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().
--- drivers/pci/remove.c | 28 +++++++++++----------------- 1 files changed, 11 insertions(+), 17 deletions(-)
drivers/pci/remove.c +11 -17
@@ -78,7 +78,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
@@ -96,7 +96,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 ; }
@@ -111,22 +111,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)
@@ -158,8 +148,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); + } }/**
Signature · 1 line
1.7.7
PATCH v2 18/37 PCI: Use list_for_each_entry_safe instead of list_for_each_safe
In reply to Yinghai LuSo could skip using pci_dev_b().
--- drivers/pci/remove.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-)
drivers/pci/remove.c +5 -7
@@ -113,15 +113,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
@@ -131,10 +131,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); - } }/**
Signature · 1 line
1.7.7
PATCH v2 19/37 PCI: Add pci_stop_and_remove_bus()
In reply to Yinghai LuIt supports both pci root bus and pci bus under pci bridge.
-v2: clear pci_bridge's subordinate.
--- drivers/pci/remove.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 33 insertions(+), 0 deletions(-)
drivers/pci/remove.c +32 -0
@@ -170,6 +170,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);
include/linux/pci.h +1 -0
@@ -702,6 +702,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 );
Signature · 1 line
1.7.7
Re: [PATCH v2 19/37] PCI: Add pci_stop_and_remove_bus()
Quoted 33 lines · 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 <[email protected]>--- drivers/pci/remove.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 33 insertions(+), 0 deletions(-)drivers/pci/remove.c +15
-0@@ -170,6 +170,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); +
drivers/pci/remove.c void pci_stop_bus_device(struct pci_dev *dev) · line 197
Quoted 10 lines
drivers/pci/remove.c +10
-0+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); +
It seems that the bus and host_bridge structures may have already been freed here, so should not access host_bridge structure any more.
Quoted 22 lines
drivers/pci/remove.c +7
-0+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);include/linux/pci.h +1
-0@@ -702,6 +702,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 );
Re: [PATCH v2 19/37] PCI: Add pci_stop_and_remove_bus()
Quoted 11 lines
Quoted 11 lines
drivers/pci/remove.c +11
-0+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
Quoted 11 lines
drivers/pci/remove.c void pci_stop_bus_device(struct pci_dev *dev) · line 197
Quoted 6 lines
+
pci_bridge=bus->self;drivers/pci/remove.c +5
-0+ + __pci_remove_bus_devices(bus); + + pci_remove_bus(bus); +It seems that the bus and
host_bridgestructures may have already been freed here, so should not accesshost_bridgestructure any more.Quoted 3 lines
+ if (
host_bridge)
+host_bridge->bus= NULL;
+
not really.
Yinghai
PATCH v2 20/37 PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
In reply to Yinghai Luit supports both pci root bus and pci bus under pci bridge.
-v2: Change to three returns way in dev_bus_remove_store.
--- Documentation/ABI/testing/sysfs-bus-pci | 8 ++++++++ drivers/pci/pci-sysfs.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-)
Documentation/ABI/testing/sysfs-bus-pci +8 -0
@@ -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 <[email protected]> +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 <[email protected]>
drivers/pci/pci-sysfs.c +30 -0
@@ -388,6 +388,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);
@@ -447,6 +476,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),
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 20/37] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
Quoted 21 lines · Yinghai Lu
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 <[email protected]>Cc Randy Dunlap <[email protected]>Cc Greg Kroah-Hartman <[email protected]>---
Documentation/ABI/testing/sysfs-bus-pci | 8 ++++++++drivers/pci/pci-sysfs.c| 30 ++++++++++++++++++++++++++++++2 files changed, 38 insertions(+), 0 deletions(-)Documentation/ABI/testing/sysfs-bus-pci +0
-0@@ -92,6 +92,14 @@ Description:hot-remove the PCI device and any of its children. Depends on
CONFIG_HOTPLUG.
Documentation/ABI/testing/sysfs-bus-pci Description: · line 101
Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-pci +7
-0+What: /sys/bus/pci/devices/.../pci_bus/.../remove +Date: March 2012 +Contact: Linux PCI developers <[email protected]> +Description: + Writing a non-zero value to this attribute will + hot-remove the PCI bus and any of its children. + Depends on CONFIG_HOTPLUG.
I don't think this interface makes sense. This stops every device on the bus, removes the bus, unregisters the host bridge device if we're removing a root bus.
I think we should just have a "remove *bridge*" interface. It makes no sense to me to remove a bus but leave the bridge, and it makes the code quite complicated.
The point of hotplug is to add and remove devices. We'll get interrupts saying "please remove this device" or "please rescan the bus behind this bridge because something might have changed."
If we're removing a host bridge, the platform, e.g., ACPI, will tell us about the bridge that is going away. The notification is attached to the *bridge*, not the bus it leads to.
The expected mechanism on x86 is an SCI from the platform, but if we need a sysfs way to start host bridge removal, I think it should be something like this:
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
That corresponds to the way ACPI works, and it corresponds to the way we manually remove PCI devices.
Quoted 54 lines
What: /sys/bus/pci/devices/.../pci_bus/.../rescan
Date: May 2011
Contact: Linux PCI developers <[email protected]>drivers/pci/pci-sysfs.c +30
-1@@ -388,6 +388,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);@@ -447,6 +476,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
Re: [PATCH v2 20/37] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
Quoted 22 lines · Bjorn Helgaas
Quoted 21 lines · Yinghai Lu
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 <[email protected]>Cc Randy Dunlap <[email protected]>Cc Greg Kroah-Hartman <[email protected]>---
Documentation/ABI/testing/sysfs-bus-pci | 8 ++++++++drivers/pci/pci-sysfs.c| 30 ++++++++++++++++++++++++++++++2 files changed, 38 insertions(+), 0 deletions(-)Documentation/ABI/testing/sysfs-bus-pci +0
-0@@ -92,6 +92,14 @@ Description:hot-remove the PCI device and any of its children. Depends on
CONFIG_HOTPLUG.
Quoted 11 lines
Documentation/ABI/testing/sysfs-bus-pci Description: · line 101
Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-pci +7
-0+What: /sys/bus/pci/devices/.../pci_bus/.../remove +Date: March 2012 +Contact: Linux PCI developers <[email protected]> +Description: + Writing a non-zero value to this attribute will + hot-remove the PCI bus and any of its children. + Depends on CONFIG_HOTPLUG.I don't think this interface makes sense. This stops every device on the bus, removes the bus, unregisters the host bridge device if we're removing a root bus.
it is some kind of handy. otherwise if there is several devices on the bus, will need to
remove the devices one by one.
Quoted 4 lines
I think we should just have a "remove *bridge*" interface. It makes no sense to me to remove a bus but leave the bridge, and it makes the code quite complicated.
I want to remove all devices under the bridge and then rescan the bridge. then if the bridge get removed.
then we have to rescan bridge's parent bus.
Quoted 9 lines
The point of hotplug is to add and remove devices. We'll get interrupts saying "please remove this device" or "please rescan the bus behind this bridge because something might have changed."
If we're removing a host bridge, the platform, e.g., ACPI, will tell us about the bridge that is going away. The notification is attached to the *bridge*, not the bus it leads to.
Quoted 5 lines
The expected mechanism on x86 is an SCI from the platform, but if we need a sysfs way to start host bridge removal, I think it should be something like this:
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
for that, let just use
echo "\_SB.PCI0 3" > /proc/acpi/sci/notify
Yinghai
Bjorn Helgaas
maintainerRe: [PATCH v2 20/37] PCI: Add pci bus removal through /sys/.../pci_bus/.../remove
Quoted 35 lines · Yinghai Lu
Quoted 22 lines · Bjorn Helgaas
Quoted 21 lines · Yinghai Lu
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 <[email protected]>Cc Randy Dunlap <[email protected]>Cc Greg Kroah-Hartman <[email protected]>---
Documentation/ABI/testing/sysfs-bus-pci | 8 ++++++++drivers/pci/pci-sysfs.c| 30 ++++++++++++++++++++++++++++++2 files changed, 38 insertions(+), 0 deletions(-)Documentation/ABI/testing/sysfs-bus-pci +0
-0@@ -92,6 +92,14 @@ Description:hot-remove the PCI device and any of its children. Depends on
CONFIG_HOTPLUG.Quoted 11 lines
Documentation/ABI/testing/sysfs-bus-pci Description: · line 101
Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-pci +7
-0+What: /sys/bus/pci/devices/.../pci_bus/.../remove +Date: March 2012 +Contact: Linux PCI developers <[email protected]> +Description: + Writing a non-zero value to this attribute will + hot-remove the PCI bus and any of its children. + Depends on CONFIG_HOTPLUG.I don't think this interface makes sense. This stops every device on the bus, removes the bus, unregisters the host bridge device if we're removing a root bus.
Quoted 3 lines
it is some kind of handy. otherwise if there is several devices on the bus, will need to
remove the devices one by one.
It might be handy, but that's not enough. You're doing a sysfs operation in the PCI namespace. It should not have effects outside that namespace. Host bridges are by definition outside the PCI namespace.
Quoted 17 lines
Quoted 3 lines
I think we should just have a "remove *bridge*" interface. It makes no sense to me to remove a bus but leave the bridge, and it makes the code quite complicated.
I want to remove all devices under the bridge and then rescan the bridge. then if the bridge get removed.
then we have to rescan bridge's parent bus.Quoted 9 lines
The point of hotplug is to add and remove devices. We'll get interrupts saying "please remove this device" or "please rescan the bus behind this bridge because something might have changed."
If we're removing a host bridge, the platform, e.g., ACPI, will tell us about the bridge that is going away. The notification is attached to the *bridge*, not the bus it leads to.
Quoted 8 lines
Quoted 5 lines
The expected mechanism on x86 is an SCI from the platform, but if we need a sysfs way to start host bridge removal, I think it should be something like this:
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
for that, let just use
echo "\_SB.PCI0 3" >/proc/acpi/sci/notify
That's a totally broken user interface. There's no way for the user to look at the sysfs tree and figure out how to do that. The ACPI namespace names like "PCI0" are platform-dependent internal things and should not be part of any user interface.
I don't object to /proc/acpi/sci/notify. That looks like a useful way to inject notification events that would normally come from the hardware/BIOS. But it's a development tool, not something that can be part of the normal user interface.
Bjorn
PATCH v2 21/37 PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too
In reply to Yinghai LuIt 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
--- drivers/acpi/pci_root.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
drivers/acpi/pci_root.c +14 -0
@@ -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 ; }
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 21/37] PCI, ACPI: Make acpi_pci_root_remove remove pci root bus too
Quoted 16 lines · Yinghai Lu
It will call new added
pci_stop_and_remove_bus()to stop/remove pci root bus.Also checking if that
pci_root_busget removed already in bus remove in /sys---
drivers/acpi/pci_root.c | 14 ++++++++++++++1 files changed, 14 insertions(+), 0 deletions(-)drivers/acpi/pci_root.c +0
-0
drivers/acpi/pci_root.c static int acpi_pci_root_remove(struct acpi_device *device, int type) · line 650
Quoted 8 lines
drivers/acpi/pci_root.c +5
-0@@ -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;
I don't think we should handle the root bus separately from the host bridge, as I mentioned before. If we handle them together, checks like this won't be needed.
Quoted 19 lines
drivers/acpi/pci_root.c +9
-1+ } + 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
PATCH v2 22/37 PCI, acpiphp: remove hot-add support of pci host bridge
In reply to Yinghai LuIt causes confusing.
We may only need acpi hp for pci host bridge.
Split host bridge hot-add support to another file, and keep acpiphp simple.
Also remove not used res_lock in the struct.
--- drivers/pci/hotplug/acpiphp.h | 9 +--- drivers/pci/hotplug/acpiphp_glue.c | 104 +++++++----------------------------- 2 files changed, 21 insertions(+), 92 deletions(-)
drivers/pci/hotplug/acpiphp.h +1 -8
@@ -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)
drivers/pci/hotplug/acpiphp_glue.c +20 -84
173 lines not on this page · raw message
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 22/37] PCI, acpiphp: remove hot-add support of pci host bridge
Quoted 1 line · Yinghai Lu
It causes confusing.
"causes confusion."
Quoted 3 lines
We may only need acpi hp for pci host bridge.
Split host bridge hot-add support to another file, and keep acpiphp simple.
I think it's a good thing to remove host bridge hotplug from acpiphp; thanks for doing that.
However, I think you removed it here, but didn't add it elsewhere until a different patch. That means we can't bisect across this. It would be better to do the entire move in a single patch.
Quoted 234 lines
Also remove not used
res_lockin the struct.Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/hotplug/acpiphp.h | 9 +---drivers/pci/hotplug/acpiphp_glue.c| 104 +++++++-----------------------------2 files changed, 21 insertions(+), 92 deletions(-)drivers/pci/hotplug/acpiphp.h +1
-8@@ -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)drivers/pci/hotplug/acpiphp_glue.c +18
-58@@ -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,@@ -1078,15 +1043,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);@@ -1249,8 +1209,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) {
structacpiphp_slot*slot;
slot =bridge->func->slot;
if (!acpiphp_disable_slot(slot))drivers/pci/hotplug/acpiphp_glue.c +1
-25@@ -1381,21 +1340,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,@@ -1406,15 +1350,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
Re: [PATCH v2 22/37] PCI, acpiphp: remove hot-add support of pci host bridge
Quoted 7 lines · Bjorn Helgaas
Quoted 1 line · Yinghai Lu
It causes confusing.
"causes confusion."
Quoted 2 lines
We may only need acpi hp for pci host bridge.
Quoted 8 lines
Quoted 1 line
Split host bridge hot-add support to another file, and keep acpiphp simple.
I think it's a good thing to remove host bridge hotplug from acpiphp; thanks for doing that.
However, I think you removed it here, but didn't add it elsewhere until a different patch. That means we can't bisect across this. It would be better to do the entire move in a single patch.
do you mean merge patch 22 and 23 together?
Bjorn Helgaas
maintainerRe: [PATCH v2 22/37] PCI, acpiphp: remove hot-add support of pci host bridge
Quoted 10 lines · Yinghai Lu
Quoted 9 lines · Bjorn Helgaas
Quoted 1 line · Yinghai Lu
It causes confusing.
"causes confusion."
Quoted 3 lines
We may only need acpi hp for pci host bridge.
Split host bridge hot-add support to another file, and keep acpiphp simple.
Quoted 8 lines
Quoted 6 lines
I think it's a good thing to remove host bridge hotplug from acpiphp; thanks for doing that.
However, I think you removed it here, but didn't add it elsewhere until a different patch. That means we can't bisect across this. It would be better to do the entire move in a single patch.
do you mean merge patch 22 and 23 together?
Yes, I think so. You should have a single "move," not separate patches that "remove" then "add."
PATCH v2 23/37 PCI, ACPI: Add pci_root_hp hot add hotplug notification
In reply to Yinghai LuIt is from acpiphp_glue.c
How to use it?
Find out root bus number to acpi root name mapping from dmesg or /sys
echo "\_SB.PCIB 0" > /proc/acpi/sci/notify
to add it back
--- drivers/acpi/Makefile | 1 + drivers/acpi/pci_root_hp.c | 237 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+), 0 deletions(-) create mode 100644 drivers/acpi/pci_root_hp.c
drivers/acpi/Makefile +1 -0
@@ -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
drivers/acpi/pci_root_hp.c new file +237 -0
237 lines not on this page · raw message
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 23/37] PCI, ACPI: Add pci_root_hp hot add hotplug notification
Quoted 7 lines · Yinghai Lu
It is from
acpiphp_glue.cHow to use it?
Find out root bus number to acpi root name mapping from dmesg or /sysecho "\_SB.PCIB 0" >
/proc/acpi/sci/notify
to add it back
Nope. That might be a way to exercise this for debug purposes (and it only works when /proc/acpi/sci/notify is compiled in), but we definitely don't want normal users to deal with ACPI pathnames like this.
Most of this functionality belongs in the ACPI core, not here. The core should be handling these notify events and turning them into .add() and .remove() calls to the driver.
But since the ACPI core doesn't do that yet, we have to do it in the driver, like we do for CPU, memory, etc. That part is fine. But I think it at least belongs *in* the driver, i.e., in pci_root.c, not in a new pci_root_hp.c file.
There definitely should not be another acpi_walk_namespace() and another list of ACPI host bridges. The core *does* already walk the namespace and call acpi_pci_root_add() for us. And the driver already has a list of host bridges (acpi_pci_roots).
Quoted 267 lines
---
drivers/acpi/Makefile | 1 +
drivers/acpi/pci_root_hp.c | 237 ++++++++++++++++++++++++++++++++++++++++++++2 files changed, 238 insertions(+), 0 deletions(-)create mode 100644
drivers/acpi/pci_root_hp.cdrivers/acpi/Makefile +0
-0@@ -36,6 +36,7 @@ acpi-y += processor_core.oacpi-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.odrivers/acpi/pci_root_hp.c new file +237
-1@@ -0,0 +1,237 @@ +/* +* 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); + + 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); --1.7.7
Re: [PATCH v2 23/37] PCI, ACPI: Add pci_root_hp hot add hotplug notification
Quoted 6 lines · Bjorn Helgaas
Quoted 5 lines · Yinghai Lu
It is from
acpiphp_glue.cHow to use it?
Find out root bus number to acpi root name mapping from dmesg or /sys
Quoted 7 lines
Quoted 2 lines
echo "\_SB.PCIB 0" >
/proc/acpi/sci/notify
to add it backNope. That might be a way to exercise this for debug purposes (and it only works when
/proc/acpi/sci/notifyis compiled in), but we definitely don't want normal users to deal with ACPI pathnames like this.
before this patch set, only way is: Users really put one root bus in and press buton etc to trigger notification
to get it work.
Quoted 9 lines
Most of this functionality belongs in the ACPI core, not here. The core should be handling these notify events and turning them into .add() and .remove() calls to the driver.
But since the ACPI core doesn't do that yet, we have to do it in the driver, like we do for CPU, memory, etc. That part is fine. But I think it at least belongs *in* the driver, i.e., in
pci_root.c, not in a newpci_root_hp.cfile.
don't want to pollute pci_root.c.
in separated file, we can use CONFIG_HOTPLUG in Makefile instead of pci_root.c
Quoted 5 lines
There definitely should not be another
acpi_walk_namespace()and another list of ACPI host bridges. The core *does* already walk the namespace and callacpi_pci_root_add()for us. And the driver already has a list of host bridges (acpi_pci_roots).
no, we may not have acpi_pci_root there.
Bjorn Helgaas
maintainerRe: [PATCH v2 23/37] PCI, ACPI: Add pci_root_hp hot add hotplug notification
Quoted 24 lines · Yinghai Lu
Quoted 6 lines · Bjorn Helgaas
Quoted 5 lines · Yinghai Lu
It is from
acpiphp_glue.cHow to use it?
Find out root bus number to acpi root name mapping from dmesg or /sysQuoted 7 lines
Quoted 2 lines
echo "\_SB.PCIB 0" >
/proc/acpi/sci/notify
to add it backNope. That might be a way to exercise this for debug purposes (and it only works when
/proc/acpi/sci/notifyis compiled in), but we definitely don't want normal users to deal with ACPI pathnames like this.before this patch set, only way is: Users really put one root bus in and press buton etc to trigger notification
to get it work.Quoted 5 lines
Most of this functionality belongs in the ACPI core, not here. The core should be handling these notify events and turning them into .add() and .remove() calls to the driver.
Quoted 8 lines
Quoted 4 lines
But since the ACPI core doesn't do that yet, we have to do it in the driver, like we do for CPU, memory, etc. That part is fine. But I think it at least belongs *in* the driver, i.e., in
pci_root.c, not in a newpci_root_hp.cfile.don't want to pollute
pci_root.c.in separated file, we can use
CONFIG_HOTPLUGinMakefileinstead ofpci_root.c
I don't buy this argument. Most of this functionality should someday be in the ACPI core. Until then, it is intimately connected to the stuff in pci_root.c. It is not "pollution."
Quoted 6 lines
Quoted 4 lines
There definitely should not be another
acpi_walk_namespace()and another list of ACPI host bridges. The core *does* already walk the namespace and callacpi_pci_root_add()for us. And the driver already has a list of host bridges (acpi_pci_roots).no, we may not have
acpi_pci_rootthere.
I don't understand what you're saying here. I think you should be basically implementing the "turn notify events into add/remove calls" functionality. This is what *should* be in the ACPI core, but isn't yet. If you put this in the driver, and hopefully follow the style already used by the processor/memory/etc. drivers, it will be easier to someday move it into the ACPI core.
Bjorn
PATCH v2 24/37 PCI, ACPI: Add pci_root_hp hot removal notification support.
In reply to Yinghai LuAdd 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
--- drivers/acpi/pci_root_hp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 61 insertions(+), 0 deletions(-)
drivers/acpi/pci_root_hp.c +61 -0
@@ -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;
@@ -142,6 +148,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;
@@ -182,6 +237,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);
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 24/37] PCI, ACPI: Add pci_root_hp hot removal notification support.
Quoted 7 lines · Yinghai Lu
Add missing
hot_removesupport for root device.How to use it?
Find out root bus number to acpi root name mapping from dmesg or /sysecho "\_SB.PCIB 3" >
/proc/acpi/sci/notify
to remove root bus
Same comments as before: this is definitely NOT the way users should use this. If you want to do that for debugging the ACPI notification path, fine, but the normal way is for the platform to generate this notification. I think the normal way for users to manually remove an ACPI device should be something like:
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
just like we do for PCI devices.
Quoted 37 lines
---
drivers/acpi/pci_root_hp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++1 files changed, 61 insertions(+), 0 deletions(-)drivers/acpi/pci_root_hp.c +15
-0@@ -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;@@ -142,6 +148,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;
drivers/acpi/pci_root_hp.c static void handle_root_bridge_insertion(acpi_handle handle) · line 169
Quoted 10 lines
drivers/acpi/pci_root_hp.c +10
-0+ 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;
This function really has nothing to do with host bridges. Are you sure there's no generic function you can use instead?
Quoted 49 lines
drivers/acpi/pci_root_hp.c +36
-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;@@ -182,6 +237,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
Re: [PATCH v2 24/37] PCI, ACPI: Add pci_root_hp hot removal notification support.
Quoted 15 lines · Bjorn Helgaas
Quoted 7 lines · Yinghai Lu
Add missing
hot_removesupport for root device.How to use it?
Find out root bus number to acpi root name mapping from dmesg or /sysecho "\_SB.PCIB 3" >
/proc/acpi/sci/notify
to remove root busSame comments as before: this is definitely NOT the way users should use this. If you want to do that for debugging the ACPI notification path, fine, but the normal way is for the platform to generate this notification. I think the normal way for users to manually remove an ACPI device should be something like:
Quoted 3 lines
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
just like we do for PCI devices.
notify way looks more like really physical hotadd/remove.
pci bus/remove and other is not really, because when you are using /sys, you may still need to hold
one reference to bus or device.
Quoted 43 lines
Quoted 43 lines
---
drivers/acpi/pci_root_hp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++1 files changed, 61 insertions(+), 0 deletions(-)drivers/acpi/pci_root_hp.c +20
-0@@ -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;@@ -142,6 +148,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",
Quoted 8 lines
drivers/acpi/pci_root_hp.c static void handle_root_bridge_insertion(acpi_handle handle) · line 169
Quoted 5 lines
drivers/acpi/pci_root_hp.c +5
-0+ __func__, cmd, val); + return -1; + } + + return 0;This function really has nothing to do with host bridges. Are you sure there's no generic function you can use instead?
seems not.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Bjorn Helgaas
maintainerRe: [PATCH v2 24/37] PCI, ACPI: Add pci_root_hp hot removal notification support.
Quoted 16 lines · Yinghai Lu
Quoted 15 lines · Bjorn Helgaas
Quoted 7 lines · Yinghai Lu
Add missing
hot_removesupport for root device.How to use it?
Find out root bus number to acpi root name mapping from dmesg or /sysecho "\_SB.PCIB 3" >
/proc/acpi/sci/notify
to remove root busSame comments as before: this is definitely NOT the way users should use this. If you want to do that for debugging the ACPI notification path, fine, but the normal way is for the platform to generate this notification. I think the normal way for users to manually remove an ACPI device should be something like:
Quoted 5 lines
Quoted 3 lines
echo 1 > /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove
just like we do for PCI devices.
notify way looks more like really physical hotadd/remove.
Sure, the 'echo "\_SB.PCIB 3" > /proc/acpi/sci/notify' way looks more like physical hotadd/remove because it is basically injecting the notify event that the hardware/BIOS should be generating itself. But it is platform-specific and therefore unacceptable as a general user interface.
Using /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove would be a more generic way. The PNP0A08:00/remove implementation would basically turn into an acpi_pci_root_remove() call, just like the 'echo "\_SB.PCIB 3" > /proc/acpi/sci/notify' does.
Both ways should exercise the same code path. The only difference is that using /proc/acpi/sci/notify should go through a little more of the ACPI notify path before reaching acpi_pci_root_remove().
Quoted 57 lines
pci bus/remove and other is not really, because when you are using /sys, you may still need to hold
one reference to bus or device.Quoted 43 lines
Quoted 43 lines
---
drivers/acpi/pci_root_hp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++1 files changed, 61 insertions(+), 0 deletions(-)drivers/acpi/pci_root_hp.c +20
-0@@ -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;@@ -142,6 +148,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",Quoted 8 lines
drivers/acpi/pci_root_hp.c static void handle_root_bridge_insertion(acpi_handle handle) · line 169
Quoted 5 lines
drivers/acpi/pci_root_hp.c +5
-0+ __func__, cmd, val); + return -1; + } + + return 0;This function really has nothing to do with host bridges. Are you sure there's no generic function you can use instead?
seems not.
Re: [PATCH v2 24/37] PCI, ACPI: Add pci_root_hp hot removal notification support.
Quoted 10 lines · Bjorn Helgaas
Sure, the 'echo "\_SB.PCIB 3" >
/proc/acpi/sci/notify' way looks more like physical hotadd/remove because it is basically injecting the notify event that the hardware/BIOS should be generating itself. But it is platform-specific and therefore unacceptable as a general user interface.Using /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove would be a more generic way. The PNP0A08:00/remove implementation would basically turn into an
acpi_pci_root_remove()call, just like the 'echo "\_SB.PCIB 3" >/proc/acpi/sci/notify' does.
if the users can not find _SB.PCIB etc, they may not find LNXSYSTM:00/device:00/PNP0A08:00.
so /sys/class/pci_bus/0000:80/remove is more easy for them?
Yinghai
Bjorn Helgaas
maintainerRe: [PATCH v2 24/37] PCI, ACPI: Add pci_root_hp hot removal notification support.
Quoted 12 lines · Yinghai Lu
Quoted 10 lines · Bjorn Helgaas
Sure, the 'echo "\_SB.PCIB 3" >
/proc/acpi/sci/notify' way looks more like physical hotadd/remove because it is basically injecting the notify event that the hardware/BIOS should be generating itself. But it is platform-specific and therefore unacceptable as a general user interface.Using /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/remove would be a more generic way. The PNP0A08:00/remove implementation would basically turn into an
acpi_pci_root_remove()call, just like the 'echo "\_SB.PCIB 3" >/proc/acpi/sci/notify' does.
Quoted 4 lines
if the users can not find _SB.PCIB etc, they may not find LNXSYSTM:00/device:00/PNP0A08:00.
so /sys/class/pci_bus/0000:80/remove is more easy for them?
I don't think so. LNXSYSTM:00/... is the canonical machine description on x86. I think there should probably be a link from the PCI device to the upstream bridge. The upstream bridge could be either a P2P bridge or a host bridge.
Bjorn
PATCH v2 25/37 PCI, ACPI: Add alloc_acpi_hp_work()
In reply to Yinghai LuWill use it with acpiphp and pci_root_hp events handling
--- drivers/acpi/osl.c | 21 +++++++++++++++++++++ include/acpi/acpiosxf.h | 9 +++++++++ 2 files changed, 30 insertions(+), 0 deletions(-)
drivers/acpi/osl.c +21 -0
@@ -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);
include/acpi/acpiosxf.h +9 -0
@@ -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
Signature · 1 line
1.7.7
PATCH v2 26/37 PCI, acpiphp: Use acpi_hp_work
In reply to Yinghai LuRemove local defined acpiphp_hp_work.
--- drivers/pci/hotplug/acpiphp_glue.c | 42 +++++------------------------------ 1 files changed, 6 insertions(+), 36 deletions(-)
drivers/pci/hotplug/acpiphp_glue.c +6 -36
@@ -1118,34 +1118,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;
@@ -1154,11 +1126,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;
@@ -1260,8 +1232,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)
@@ -1270,12 +1241,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;
@@ -1336,8 +1307,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 = {
Signature · 1 line
1.7.7
PATCH v2 27/37 PCI, pci_root_hp: Use acpi_hp_work
In reply to Yinghai LuRemove local copy: acpi_root_hp_work
--- drivers/acpi/pci_root_hp.c | 34 +++------------------------------- 1 files changed, 3 insertions(+), 31 deletions(-)
drivers/acpi/pci_root_hp.c +3 -31
@@ -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) {
@@ -203,11 +175,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;
@@ -255,7 +227,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); }
Signature · 1 line
1.7.7
PATCH v2 28/37 PCI, ACPI: Make kacpi_hotplug_wq static
In reply to Yinghai LuNo external user anymore.
--- drivers/acpi/osl.c | 3 +-- include/acpi/acpiosxf.h | 2 -- 2 files changed, 1 insertions(+), 4 deletions(-)
drivers/acpi/osl.c +1 -2
@@ -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
include/acpi/acpiosxf.h +0 -2
@@ -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;
Signature · 1 line
1.7.7
PATCH v2 29/37 PCI, ACPI: Add acpi_pci_root_rescan()
In reply to Yinghai LuIt will rescan all acpi pci root if related pci root bus get removed before.
--- drivers/acpi/pci_root_hp.c | 17 +++++++++++++++++ include/linux/pci-acpi.h | 7 +++++++ 2 files changed, 24 insertions(+), 0 deletions(-)
drivers/acpi/pci_root_hp.c +17 -0
@@ -268,3 +268,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 ); +}
include/linux/pci-acpi.h +7 -0
@@ -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
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 29/37] PCI, ACPI: Add acpi_pci_root_rescan()
Quoted 1 line · Yinghai Lu
It will rescan all acpi pci root if related pci root bus get removed before.
I think this is a bad idea. The ACPI core already walks the entire ACPI namespace, finding devices and binding drivers to them.
Walking the whole thing again looking for "hotplug" things we can do is just a hack. Maybe you want it for debugging, but I don't want it in Linux.
Quoted 52 lines
---
drivers/acpi/pci_root_hp.c | 17 +++++++++++++++++include/linux/pci-acpi.h| 7 +++++++2 files changed, 24 insertions(+), 0 deletions(-)drivers/acpi/pci_root_hp.c +17
-0@@ -268,3 +268,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); +}include/linux/pci-acpi.h +7
-1@@ -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 --
Quoted 2 lines
1.7.7
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 30/37 PCI: Add __pci_scan_root_bus() that can skip bus_add
In reply to Yinghai LuSo could insert pus pci_assign_unassigned_bus_resources() before do bus_add.
--- drivers/pci/probe.c | 13 ++++++++++--- include/linux/pci.h | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-)
drivers/pci/probe.c +10 -3
@@ -1953,8 +1953,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;
@@ -1985,9 +1986,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 */
include/linux/pci.h +3 -0
@@ -675,6 +675,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);
Signature · 1 line
1.7.7
PATCH v2 31/37 x86, PCI: add __pci_scan_root_bus_on_node() that can skip bus_add
In reply to Yinghai LuSo could insert pus pci_assign_unassigned_bus_resources() before do bus_add.
--- arch/x86/include/asm/pci.h | 2 ++ arch/x86/pci/common.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-)
arch/x86/include/asm/pci.h +2 -0
@@ -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);
arch/x86/pci/common.c +8 -3
@@ -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 );
Signature · 1 line
1.7.7
PATCH v2 32/37 x86, PCI: add __pcibios_scan_specific_bus that can skip bus_add
In reply to Yinghai LuSo could insert pci_assign_unassigned_bus_resources() before do bus_add.
--- arch/x86/pci/legacy.c | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-)
arch/x86/pci/legacy.c +13 -6
@@ -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);
Signature · 1 line
1.7.7
PATCH v2 33/37 x86, PCI: Add pcibios_root_rescan()
In reply to Yinghai LuNeed use it to rescan root bus that was not added via acpi probe.
--- arch/x86/include/asm/pci.h | 2 ++ arch/x86/pci/legacy.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 0 deletions(-)
arch/x86/include/asm/pci.h +2 -0
@@ -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
arch/x86/pci/legacy.c +25 -0
@@ -79,3 +79,28 @@ 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 ; + +pci_assign_unassigned_bus_resources (bus); + +pci_bus_add_devices (bus); + } +}
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 33/37] x86, PCI: Add pcibios_root_rescan()
Quoted 1 line · Yinghai Lu
Need use it to rescan root bus that was not added via acpi probe.
Why would we ever need to rescan for this? If we're doing host bridge hotplug on x86, it's via ACPI, so we'll always have an ACPI host bridge object.
There's no way to even express the idea of "adding or removing buses we found by blindly probing," so there's no need to do any kind of rescanning to find them again. We find them once at boot-time, and that's more than enough.
Quoted 55 lines
Signed-off-by Yinghai Lu <[email protected]>---
arch/x86/include/asm/pci.h | 2 ++arch/x86/pci/legacy.c| 25 +++++++++++++++++++++++++2 files changed, 27 insertions(+), 0 deletions(-)arch/x86/include/asm/pci.h +2
-0@@ -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_DOMAINSarch/x86/pci/legacy.c +25
-1@@ -79,3 +79,28 @@ 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; + + pci_assign_unassigned_bus_resources(bus); + + pci_bus_add_devices(bus); + } +} --1.7.7
PATCH v2 34/37 x86, PCI: Add arch version pci_root_rescan()
In reply to Yinghai LuIt will call acpi version pci_root_rescan and legacy pci_root_rescan.
--- arch/x86/pci/common.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
arch/x86/pci/common.c +7 -0
@@ -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 *
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 34/37] x86, PCI: Add arch version pci_root_rescan()
Quoted 20 lines · Yinghai Lu
It will call acpi version
pci_root_rescanand legacypci_root_rescan.Signed-off-by Yinghai Lu <[email protected]>---
arch/x86/pci/common.c | 7 +++++++1 files changed, 7 insertions(+), 0 deletions(-)arch/x86/pci/common.c +1
-0@@ -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>
arch/x86/pci/common.c struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno) · line 668
Quoted 7 lines
arch/x86/pci/common.c +4
-0@@ -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();
I don't think we need this either.
We don't need pcibios_root_rescan() because there's no way to add or remove buses except via the normal ACPI hotplug mechanisms. (Well, you did add sysfs ways to do it, but I don't like those either, and they certainly don't work for any kind of normal hotplug users might do.)
We don't need acpi_pci_root_rescan(), because for actual host bridge add/remove, we will get ACPI notify events, and we can use the normal ways of handling those events. For debug purposes, we can have a sysfs interface that kicks things off the same way a notify event would.
Quoted 8 lines
arch/x86/pci/common.c +2
-1+} + /** NUMA info for PCI busses * -- 1.7.7
PATCH v2 35/37 PCI: Make /sys/bus/pci/rescan rescan root
In reply to Yinghai LuIt will rediscover removed pci root buses.
--- drivers/pci/pci-sysfs.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/pci/pci-sysfs.c +2 -0
@@ -284,6 +284,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,#ifdef CONFIG_HOTPLUG static DEFINE_MUTEX (pci_remove_rescan_mutex); +void __weak arch_pci_root_rescan (void ) { }static ssize_t bus_rescan_store (struct bus_type *bus,const char *buf,size_t count) {
@@ -295,6 +296,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,if (val) {mutex_lock (&pci_remove_rescan_mutex); +arch_pci_root_rescan ();while ((b =pci_find_next_bus (b)) !=NULL )pci_rescan_bus (b);mutex_unlock (&pci_remove_rescan_mutex);
Signature · 1 line
1.7.7
Bjorn Helgaas
maintainerRe: [PATCH v2 35/37] PCI: Make /sys/bus/pci/rescan rescan root
Quoted 20 lines · Yinghai Lu
It will rediscover removed pci root buses.
Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/pci-sysfs.c | 2 ++1 files changed, 2 insertions(+), 0 deletions(-)drivers/pci/pci-sysfs.c +1
-0@@ -284,6 +284,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, #ifdef CONFIG_HOTPLUG static DEFINE_MUTEX(pci_remove_rescan_mutex); +void __weak arch_pci_root_rescan (void ) { } static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, size_t count) {
drivers/pci/pci-sysfs.c static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, · line 302
Quoted 7 lines
drivers/pci/pci-sysfs.c +1
-0@@ -295,6 +296,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, if (val) { mutex_lock(&pci_remove_rescan_mutex); + arch_pci_root_rescan(); while ((b = pci_find_next_bus(b)) != NULL) pci_rescan_bus(b); mutex_unlock(&pci_remove_rescan_mutex);
This is gross. We used to rescan every previously-discovered PCI root bus.
Now, we do the same, plus:
1) Scan the ACPI namespace for PCI host bridges, adding and scanning any we haven't seen before, and
2) scan domain 0, buses 0 - pcibios_last_bus, looking for any we haven't seen before.
These just don't fit with the previous functionality. The scan should be done on the *ACPI namespace*, which is where any new bridges would live. It shouldn't be done in the PCI namespace. The new bridges aren't part of PCI.
Re: [PATCH v2 35/37] PCI: Make /sys/bus/pci/rescan rescan root
Quoted 31 lines · Bjorn Helgaas
Quoted 20 lines · Yinghai Lu
It will rediscover removed pci root buses.
Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/pci-sysfs.c | 2 ++1 files changed, 2 insertions(+), 0 deletions(-)drivers/pci/pci-sysfs.c +1
-0@@ -284,6 +284,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, #ifdef CONFIG_HOTPLUG static DEFINE_MUTEX(pci_remove_rescan_mutex); +void __weak arch_pci_root_rescan (void ) { } static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, size_t count) {drivers/pci/pci-sysfs.c static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, · line 302
Quoted 7 lines
drivers/pci/pci-sysfs.c +1
-0@@ -295,6 +296,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, if (val) { mutex_lock(&pci_remove_rescan_mutex); + arch_pci_root_rescan(); while ((b = pci_find_next_bus(b)) != NULL) pci_rescan_bus(b); mutex_unlock(&pci_remove_rescan_mutex);This is gross. We used to rescan every previously-discovered PCI root bus.
Quoted 5 lines
Now, we do the same, plus:
1) Scan the ACPI namespace for PCI host bridges, adding and scanning any we haven't seen before, and
2) scan domain 0, buses 0 -pcibios_last_bus, looking for any we haven't seen before.
to have /sys/bus/pci/scan_root again?
Yinghai
Bjorn Helgaas
maintainerRe: [PATCH v2 35/37] PCI: Make /sys/bus/pci/rescan rescan root
Quoted 32 lines · Yinghai Lu
Quoted 31 lines · Bjorn Helgaas
Quoted 20 lines · Yinghai Lu
It will rediscover removed pci root buses.
Signed-off-by Yinghai Lu <[email protected]>---
drivers/pci/pci-sysfs.c | 2 ++1 files changed, 2 insertions(+), 0 deletions(-)drivers/pci/pci-sysfs.c +1
-0@@ -284,6 +284,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, #ifdef CONFIG_HOTPLUG static DEFINE_MUTEX(pci_remove_rescan_mutex); +void __weak arch_pci_root_rescan (void ) { } static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, size_t count) {drivers/pci/pci-sysfs.c static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, · line 302
Quoted 7 lines
drivers/pci/pci-sysfs.c +1
-0@@ -295,6 +296,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, if (val) { mutex_lock(&pci_remove_rescan_mutex); + arch_pci_root_rescan(); while ((b = pci_find_next_bus(b)) != NULL) pci_rescan_bus(b); mutex_unlock(&pci_remove_rescan_mutex);This is gross. We used to rescan every previously-discovered PCI root bus.
Quoted 7 lines
Quoted 5 lines
Now, we do the same, plus:
1) Scan the ACPI namespace for PCI host bridges, adding and scanning any we haven't seen before, and
2) scan domain 0, buses 0 -pcibios_last_bus, looking for any we haven't seen before.to have
/sys/bus/pci/scan_rootagain?
Host bridges are not PCI devices, so scanning for them is not a PCI operation. It should not be in the /sys/bus/pci hierarchy.
PATCH v2 36/37 ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing.
In reply to Yinghai LuFrom: Ashok Raj <[email protected]>
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.
===================================================================
--- 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
drivers/acpi/Kconfig +10 -0
@@ -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
drivers/acpi/Makefile +1 -0
@@ -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
drivers/acpi/bus.c +2 -0
@@ -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 */
drivers/acpi/internal.h +6 -0
@@ -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 -------------------------------------------------------------------------- */
drivers/acpi/sci_emu.c new file +141 -0
141 lines not on this page · raw message
Signature · 1 line
1.7.7
PATCH v2 37/37 PCI, sysfs: Prepare to kill pci device rescan
In reply to Yinghai LuHope we can kill it after one year.
Print warning to catch real users for that feature.
--- Documentation/feature-removal-schedule.txt | 9 +++++++++ drivers/pci/pci-sysfs.c | 3 +++ 2 files changed, 12 insertions(+), 0 deletions(-)
Documentation/feature-removal-schedule.txt +9 -0
@@ -299,6 +299,15 @@ Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to fakephp interface. Who: Alex Chiang <[email protected]> +----------------------------- + +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 <[email protected]> + --------------------------- What: CONFIG_RFKILL_INPUT
drivers/pci/pci-sysfs.c +3 -0
@@ -320,6 +320,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);
Signature · 1 line
1.7.7