mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
PCI / ACPI: Do not set ACPI companions for host bridges with parents
Commit97badf873a
(device property: Make it possible to use secondary firmware nodes) uncovered a bug in the x86 (and ia64) PCI host bridge initialization code that assumes bridge->bus->sysdata to always point to a struct pci_sysdata object which need not be the case (in particular, the Xen PCI frontend driver sets it to point to a different data type). If it is not the case, an incorrect pointer (or a piece of data that is not a pointer at all) will be passed to ACPI_COMPANION_SET() and that may cause interesting breakage to happen going forward. To work around this problem use the observation that the ACPI host bridge initialization always passes NULL as parent to pci_create_root_bus(), so if pcibios_root_bridge_prepare() sees a non-NULL parent of the bridge, it should not attempt to set an ACPI companion for it, because that means that pci_create_root_bus() has been called by someone else. Fixes:97badf873a
(device property: Make it possible to use secondary firmware nodes) Reported-and-tested-by: Sander Eikelenboom <linux@eikelenboom.it> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
ba155e2d21
commit
dc4fdaf0e4
2 changed files with 20 additions and 6 deletions
|
@ -478,9 +478,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
|||
|
||||
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
|
||||
{
|
||||
struct pci_controller *controller = bridge->bus->sysdata;
|
||||
|
||||
ACPI_COMPANION_SET(&bridge->dev, controller->companion);
|
||||
/*
|
||||
* We pass NULL as parent to pci_create_root_bus(), so if it is not NULL
|
||||
* here, pci_create_root_bus() has been called by someone else and
|
||||
* sysdata is likely to be different from what we expect. Let it go in
|
||||
* that case.
|
||||
*/
|
||||
if (!bridge->dev.parent) {
|
||||
struct pci_controller *controller = bridge->bus->sysdata;
|
||||
ACPI_COMPANION_SET(&bridge->dev, controller->companion);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,9 +482,16 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
|||
|
||||
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
|
||||
{
|
||||
struct pci_sysdata *sd = bridge->bus->sysdata;
|
||||
|
||||
ACPI_COMPANION_SET(&bridge->dev, sd->companion);
|
||||
/*
|
||||
* We pass NULL as parent to pci_create_root_bus(), so if it is not NULL
|
||||
* here, pci_create_root_bus() has been called by someone else and
|
||||
* sysdata is likely to be different from what we expect. Let it go in
|
||||
* that case.
|
||||
*/
|
||||
if (!bridge->dev.parent) {
|
||||
struct pci_sysdata *sd = bridge->bus->sysdata;
|
||||
ACPI_COMPANION_SET(&bridge->dev, sd->companion);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue