11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI PCI HotPlug glue functions to ACPI CA subsystem
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002,2003 NEC Corporation
742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * Copyright (C) 2003-2005 Hewlett Packard
98e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com)
108e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Copyright (C) 2005 Intel Corporation
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NON INFRINGEMENT.  See the GNU General Public License for more
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * details.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
29998be20fdff12274cd0e6a9f71ce1a93abf40718Kristen Carlson Accardi * Send feedback to <kristen.c.accardi@intel.com>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah/*
3442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * Lifetime rules for pci_dev:
3542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah *  - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
3642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah *    when the bridge is scanned and it loses a refcount when the bridge
3742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah *    is removed.
385d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang *  - When a P2P bridge is present, we elevate the refcount on the subordinate
395d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang *    bus. It loses the refcount when the the driver unloads.
4042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah */
4142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
477a54f25cef6c763f16c9fd49ae382de162147873Greg Kroah-Hartman#include <linux/pci_hotplug.h>
48e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige#include <linux/pci-acpi.h>
496aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar#include <linux/mutex.h>
505a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
516af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava#include <linux/acpi.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../pci.h"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "acpiphp.h"
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(bridge_list);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MY_NAME "acpiphp_glue"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge (acpi_handle, u32, void *);
618e5dce35221850759671b2847a2e51030f7626bdKristen Accardistatic void acpiphp_sanitize_bus(struct pci_bus *bus);
62fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus);
632b85e1307fe3a84eca2e1a21c6c857359908dab4Len Brownstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
648e5dce35221850759671b2847a2e51030f7626bdKristen Accardi
655a340ed87987c8c61dd9d1a8a5384dab1ace2566MUNEDA Takahiro/* callback routine to check for the existence of a pci dock device */
664e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic acpi_status
674e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardiis_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
684e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{
694e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	int *count = (int *)context;
704e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
714e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	if (is_dock_device(handle)) {
724e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		(*count)++;
734e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		return AE_CTRL_TERMINATE;
744e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	} else {
754e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		return AE_OK;
764e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	}
774e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi}
784e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
794e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi/*
804e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * the _DCK method can do funny things... and sometimes not
814e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * hah-hah funny.
824e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi *
834e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * TBD - figure out a way to only call fixups for
844e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * systems that require them.
854e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */
864e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic int post_dock_fixups(struct notifier_block *nb, unsigned long val,
874e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	void *v)
884e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{
894e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
904e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	struct pci_bus *bus = func->slot->bridge->pci_bus;
914e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	u32 buses;
924e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
934e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	if (!bus->self)
944e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		return  NOTIFY_OK;
954e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
964e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	/* fixup bad _DCK function that rewrites
974e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	 * secondary bridge on slot
984e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	 */
994e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	pci_read_config_dword(bus->self,
1004e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			PCI_PRIMARY_BUS,
1014e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			&buses);
1024e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
1034e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	if (((buses >> 8) & 0xff) != bus->secondary) {
1044e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		buses = (buses & 0xff000000)
1052a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang			| ((unsigned int)(bus->primary)     <<  0)
1062a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang			| ((unsigned int)(bus->secondary)   <<  8)
1072a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang			| ((unsigned int)(bus->subordinate) << 16);
1084e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
1094e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	}
1104e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	return NOTIFY_OK;
1114e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi}
1124e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
1134e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
1149c8b04be443b33939f374a811c82abeebe0a61d1Vasiliy Kulikovstatic const struct acpi_dock_ops acpiphp_dock_ops = {
1151253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li	.handler = handle_hotplug_event_func,
1161253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li};
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to register each ACPI PCI slot object */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsregister_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_slot *slot;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *newfunc;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_handle tmp;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status = AE_OK;
12727663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long adr, sun;
128e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	int device, function, retval;
129e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige	struct pci_bus *pbus = bridge->pci_bus;
1309d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	struct pci_dev *pdev;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
132e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return AE_OK;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
135619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki	pdev = pbus->self;
136619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki	if (pdev && pci_is_pcie(pdev)) {
137619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki		tmp = acpi_find_root_bridge_handle(pdev);
138619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki		if (tmp) {
139619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki			struct acpi_pci_root *root = acpi_pci_find_root(tmp);
140619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki
141619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki			if (root && (root->osc_control_set &
142619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki					OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
143619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki				return AE_OK;
144619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki		}
145619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki	}
146619a5182d1f38a3d629ee48e04fa182ef9170052Rafael J. Wysocki
14756ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett	acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device = (adr >> 16) & 0xffff;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	function = adr & 0xffff;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!newfunc)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return AE_NO_MEMORY;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&newfunc->sibling);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	newfunc->handle = handle;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	newfunc->function = function;
15856ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett
15956ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
16020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		newfunc->flags = FUNC_HAS_EJ0;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newfunc->flags |= FUNC_HAS_STA;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newfunc->flags |= FUNC_HAS_PS0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newfunc->flags |= FUNC_HAS_PS3;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1714e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
17220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		newfunc->flags |= FUNC_HAS_DCK;
17320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
17595b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi	if (ACPI_FAILURE(status)) {
17695b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi		/*
17795b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi		 * use the count of the number of slots we've found
17895b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi		 * for the number of the slot
17995b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi		 */
18095b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi		sun = bridge->nr_slots+1;
18195b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search for objects that share the same slot */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (slot = bridge->slots; slot; slot = slot->next)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (slot->device == device) {
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (slot->sun != sun)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				warn("sibling found, but _SUN doesn't match!\n");
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!slot) {
192f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn		slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!slot) {
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(newfunc);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return AE_NO_MEMORY;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot->bridge = bridge;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot->device = device;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot->sun = sun;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD(&slot->funcs);
2026aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar		mutex_init(&slot->crit_sect);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot->next = bridge->slots;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bridge->slots = slot;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bridge->nr_slots++;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
209b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
210e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
211e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		retval = acpiphp_register_hotplug_slot(slot);
212e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		if (retval) {
213f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang			if (retval == -EBUSY)
214b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen				warn("Slot %llu already registered by another "
215f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang					"hotplug driver\n", slot->sun);
216f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang			else
217f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang				warn("acpiphp_register_hotplug_slot failed "
218f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang					"(err code = 0x%x)\n", retval);
219e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro			goto err_exit;
220e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	newfunc->slot = slot;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&newfunc->sibling, &slot->funcs);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2269d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
2279d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	if (pdev) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
2299d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		pci_dev_put(pdev);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2324e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi	if (is_dock_device(handle)) {
2334e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		/* we don't want to call this device's _EJ0
2344e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		 * because we want the dock notify handler
2354e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		 * to call it after it calls _DCK
23620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		 */
23720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		newfunc->flags &= ~FUNC_HAS_EJ0;
2384e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		if (register_hotplug_dock_device(handle,
2391253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li			&acpiphp_dock_ops, newfunc))
2404e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			dbg("failed to register dock device\n");
2414e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi
2424e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		/* we need to be notified when dock events happen
2434e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		 * outside of the hotplug operation, since we may
2444e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		 * need to do fixups before we can hotplug.
2454e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		 */
2464e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		newfunc->nb.notifier_call = post_dock_fixups;
2474e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi		if (register_dock_notifier(&newfunc->nb))
2484e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			dbg("failed to register a dock notifier");
24920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	}
25020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install notify handler */
25220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	if (!(newfunc->flags & FUNC_HAS_DCK)) {
25320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		status = acpi_install_notify_handler(handle,
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     ACPI_SYSTEM_NOTIFY,
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     handle_hotplug_event_func,
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     newfunc);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		if (ACPI_FAILURE(status))
25920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi			err("failed to register interrupt notify handler\n");
26020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	} else
26120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		status = AE_OK;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	return status;
264e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro
265e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro err_exit:
266e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	bridge->nr_slots--;
267e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	bridge->slots = slot->next;
268e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	kfree(slot);
269e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	kfree(newfunc);
270e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro
271e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	return AE_OK;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* see if it's worth looking at this bridge */
2766edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic int detect_ejectable_slots(acpi_handle handle)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2787f53866932fd08add06ee2f93ead129949158490Alex Chiang	int found = acpi_pci_detect_ejectable(handle);
279e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige	if (!found) {
2806edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
2812263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				    is_pci_dock_device, NULL, (void *)&found, NULL);
282e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige	}
283e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige	return found;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_bridge_misc(struct acpiphp_bridge *bridge)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	/* must be added to the list prior to calling register_slot */
292e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	list_add(&bridge->list, &bridge_list);
293e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* register all slot objects under this bridge */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
2962263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				     register_slot, NULL, bridge, NULL);
297e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	if (ACPI_FAILURE(status)) {
298e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		list_del(&bridge->list);
299e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		return;
300e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro	}
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* install notify handler */
3038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if (bridge->type != BRIDGE_TYPE_HOST) {
304551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
305551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			status = acpi_remove_notify_handler(bridge->func->handle,
306551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						ACPI_SYSTEM_NOTIFY,
307551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						handle_hotplug_event_func);
308551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			if (ACPI_FAILURE(status))
309551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro				err("failed to remove notify handler\n");
310551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		}
3118e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		status = acpi_install_notify_handler(bridge->handle,
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     ACPI_SYSTEM_NOTIFY,
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     handle_hotplug_event_bridge,
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     bridge);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3168e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		if (ACPI_FAILURE(status)) {
3178e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah			err("failed to register interrupt notify handler\n");
3188e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
323551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro/* find acpiphp_func from acpiphp_bridge */
324551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
325551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{
326551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	struct acpiphp_bridge *bridge;
327551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	struct acpiphp_slot *slot;
328551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	struct acpiphp_func *func;
329551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
33058c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(bridge, &bridge_list, list) {
331551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		for (slot = bridge->slots; slot; slot = slot->next) {
33258c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang			list_for_each_entry(func, &slot->funcs, sibling) {
333551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro				if (func->handle == handle)
334551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro					return func;
335551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			}
336551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		}
337551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	}
338551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
339551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	return NULL;
340551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro}
341551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
342551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
343551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
344551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{
345551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	acpi_handle dummy_handle;
346551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
347551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
348551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro					"_STA", &dummy_handle)))
349551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		bridge->flags |= BRIDGE_HAS_STA;
350551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
351551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
352551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro					"_EJ0", &dummy_handle)))
353551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		bridge->flags |= BRIDGE_HAS_EJ0;
354551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
355551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
356551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro					"_PS0", &dummy_handle)))
357551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		bridge->flags |= BRIDGE_HAS_PS0;
358551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
359551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
360551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro					"_PS3", &dummy_handle)))
361551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		bridge->flags |= BRIDGE_HAS_PS3;
362551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
363551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	/* is this ejectable p2p bridge? */
364551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (bridge->flags & BRIDGE_HAS_EJ0) {
365551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		struct acpiphp_func *func;
366551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
367551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		dbg("found ejectable p2p bridge\n");
368551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
369551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		/* make link between PCI bridge and PCI function */
370551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		func = acpiphp_bridge_handle_to_function(bridge->handle);
371551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if (!func)
372551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			return;
373551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		bridge->func = func;
374551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		func->bridge = bridge;
375551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	}
376551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro}
377551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
378551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize host bridge data structure */
3806edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_host_bridge(acpi_handle *handle)
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge;
3836edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	struct acpi_pci_root *root = acpi_pci_find_root(handle);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
385f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bridge == NULL)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bridge->type = BRIDGE_TYPE_HOST;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bridge->handle = handle;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3926edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	bridge->pci_bus = root->bus;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&bridge->res_lock);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_bridge_misc(bridge);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize PCI-to-PCI bridge data structure */
4016edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_p2p_bridge(acpi_handle *handle)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
405f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bridge == NULL) {
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err("out of memory\n");
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bridge->type = BRIDGE_TYPE_P2P;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bridge->handle = handle;
413551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	config_p2p_bridge_flags(bridge);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4156edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	bridge->pci_dev = acpi_get_pci_dev(handle);
4166edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	bridge->pci_bus = bridge->pci_dev->subordinate;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bridge->pci_bus) {
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err("This is not a PCI-to-PCI bridge!\n");
41942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		goto err;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4225d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	/*
4235d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 * Grab a ref to the subordinate PCI bus in case the bus is
4245d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 * removed via PCI core logical hotplug. The ref pins the bus
4255d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 * (which we access during module unload).
4265d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 */
4275d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	get_device(&bridge->pci_bus->dev);
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&bridge->res_lock);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_bridge_misc(bridge);
43142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	return;
43242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err:
4336edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	pci_dev_put(bridge->pci_dev);
43442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	kfree(bridge);
43542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	return;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to find P2P bridges */
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfind_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *dev;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4466edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	dev = acpi_get_pci_dev(handle);
44742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	if (!dev || !dev->subordinate)
44842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		goto out;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this bridge has ejectable slots */
4516edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	if ((detect_ejectable_slots(handle) > 0)) {
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
4536edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang		add_p2p_bridge(handle);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4567c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige	/* search P2P bridges under this p2p bridge */
4577c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
4582263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				     find_p2p_bridge, NULL, NULL, NULL);
4597c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige	if (ACPI_FAILURE(status))
460551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
4617c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige
46242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah out:
46342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	pci_dev_put(dev);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return AE_OK;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* find hot-pluggable slots, and then find P2P bridge */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int add_bridge(acpi_handle handle)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
47227663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long tmp;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_handle dummy_handle;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if the bridge doesn't have _STA, we assume it is always there */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = acpi_get_handle(handle, "_STA", &dummy_handle);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_SUCCESS(status)) {
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ACPI_FAILURE(status)) {
48066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			dbg("%s: _STA evaluation failure\n", __func__);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* don't register this object */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this bridge has ejectable slots */
4896edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang	if (detect_ejectable_slots(handle) > 0) {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
4916edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang		add_host_bridge(handle);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search P2P bridges under this host bridge */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
4962263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				     find_p2p_bridge, NULL, NULL, NULL);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ACPI_FAILURE(status))
499551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
50542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah{
50658c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	struct acpiphp_bridge *bridge;
50758c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang
50858c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(bridge, &bridge_list, list)
50942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		if (bridge->handle == handle)
51042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah			return bridge;
51142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
51242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	return NULL;
51342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
515364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void cleanup_bridge(struct acpiphp_bridge *bridge)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
51758c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	struct acpiphp_slot *slot, *next;
51858c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	struct acpiphp_func *func, *tmp;
51942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	acpi_status status;
520364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah	acpi_handle handle = bridge->handle;
52142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
52242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
52342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah					    handle_hotplug_event_bridge);
52442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	if (ACPI_FAILURE(status))
52542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		err("failed to remove notify handler\n");
52642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
527551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if ((bridge->type != BRIDGE_TYPE_HOST) &&
528551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	    ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
529551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		status = acpi_install_notify_handler(bridge->func->handle,
530551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						ACPI_SYSTEM_NOTIFY,
531551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						handle_hotplug_event_func,
532551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						bridge->func);
533551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if (ACPI_FAILURE(status))
534551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			err("failed to install interrupt notify handler\n");
535551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	}
536551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
53742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	slot = bridge->slots;
53842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	while (slot) {
53958c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang		next = slot->next;
54058c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang		list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
5414e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			if (is_dock_device(func->handle)) {
5424e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi				unregister_hotplug_dock_device(func->handle);
5434e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi				unregister_dock_notifier(&func->nb);
5444e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi			}
54520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi			if (!(func->flags & FUNC_HAS_DCK)) {
54620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi				status = acpi_remove_notify_handler(func->handle,
54742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah						ACPI_SYSTEM_NOTIFY,
54842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah						handle_hotplug_event_func);
54920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi				if (ACPI_FAILURE(status))
55020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi					err("failed to remove notify handler\n");
55120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi			}
55258c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang			list_del(&func->sibling);
55342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah			kfree(func);
55442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		}
555e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		acpiphp_unregister_hotplug_slot(slot);
556e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro		list_del(&slot->funcs);
55742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		kfree(slot);
55842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		slot = next;
55942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	}
56042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
5615d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	/*
5625d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 * Only P2P bridges have a pci_dev
5635d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	 */
5645d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang	if (bridge->pci_dev)
5655d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang		put_device(&bridge->pci_bus->dev);
5665d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang
56742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	pci_dev_put(bridge->pci_dev);
56842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	list_del(&bridge->list);
56942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	kfree(bridge);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic acpi_status
573364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahcleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
574364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{
575364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah	struct acpiphp_bridge *bridge;
576364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah
577551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	/* cleanup p2p bridges under this P2P bridge
578551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	   in a depth-first manner */
579551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
5802263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				cleanup_p2p_bridge, NULL, NULL, NULL);
581551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
582a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	bridge = acpiphp_handle_to_bridge(handle);
583a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	if (bridge)
584a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang		cleanup_bridge(bridge);
585a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang
586364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah	return AE_OK;
587364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah}
588364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah
589364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void remove_bridge(acpi_handle handle)
590364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{
591364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah	struct acpiphp_bridge *bridge;
592364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah
593551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	/* cleanup p2p bridges under this host bridge
594551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	   in a depth-first manner */
595551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
5962263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				(u32)1, cleanup_p2p_bridge, NULL, NULL, NULL);
597551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
598a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	/*
599a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	 * On root bridges with hotplug slots directly underneath (ie,
60025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * no p2p bridge between), we call cleanup_bridge().
601a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	 *
602a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	 * The else clause cleans up root bridges that either had no
603a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	 * hotplug slots at all, or had a p2p bridge underneath.
604a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	 */
605364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah	bridge = acpiphp_handle_to_bridge(handle);
606551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	if (bridge)
607364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah		cleanup_bridge(bridge);
608a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang	else
609a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
610a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang					   handle_hotplug_event_bridge);
611364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_on_slot(struct acpiphp_slot *slot)
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if already enabled, just skip */
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (slot->flags & SLOT_POWEREDON)
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62358c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (func->flags & FUNC_HAS_PS0) {
62566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			dbg("%s: executing _PS0\n", __func__);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ACPI_FAILURE(status)) {
62866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				warn("%s: _PS0 failed\n", __func__);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				retval = -1;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_exit;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: evaluate _STA to check if the slot is enabled */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->flags |= SLOT_POWEREDON;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_off_slot(struct acpiphp_slot *slot)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if already disabled, just skip */
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((slot->flags & SLOT_POWEREDON) == 0)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65658c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
6572f523b15901f654a9448bbd47ebe1e783ec3195bRajesh Shah		if (func->flags & FUNC_HAS_PS3) {
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ACPI_FAILURE(status)) {
66066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				warn("%s: _PS3 failed\n", __func__);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				retval = -1;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_exit;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: evaluate _STA to check if the slot is disabled */
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->flags &= (~SLOT_POWEREDON);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
67815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/**
67926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
68015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @bus: bus to start search with
68115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */
68215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic unsigned char acpiphp_max_busnr(struct pci_bus *bus)
68315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{
68415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	struct list_head *tmp;
68515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	unsigned char max, n;
68615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
68715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	/*
68815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * pci_bus_max_busnr will return the highest
68915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * reserved busnr for all these children.
69015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * that is equivalent to the bus->subordinate
69115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * value.  We don't want to use the parent's
69215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * bus->subordinate value because it could have
69315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 * padding in it.
69415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	 */
69515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	max = bus->secondary;
69615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
69715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	list_for_each(tmp, &bus->children) {
69815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi		n = pci_bus_max_busnr(pci_bus_b(tmp));
69915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi		if (n > max)
70015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi			max = n;
70115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	}
70215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	return max;
70315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi}
70415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
70515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
70615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/**
70715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * acpiphp_bus_add - add a new bus to acpi subsystem
70815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @func: acpiphp_func of the bridge
70915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */
71015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic int acpiphp_bus_add(struct acpiphp_func *func)
71115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{
71215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	acpi_handle phandle;
71315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	struct acpi_device *device, *pdevice;
71415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	int ret_val;
71515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
71615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	acpi_get_parent(func->handle, &phandle);
71715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	if (acpi_bus_get_device(phandle, &pdevice)) {
71815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi		dbg("no parent device, assuming NULL\n");
71915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi		pdevice = NULL;
72015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	}
72120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	if (!acpi_bus_get_device(func->handle, &device)) {
72220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		dbg("bus exists... trim\n");
72320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		/* this shouldn't be in here, so remove
72420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		 * the bus then re-add it...
72520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		 */
72620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		ret_val = acpi_bus_trim(device, 1);
72720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		dbg("acpi_bus_trim return %x\n", ret_val);
72820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	}
72920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi
73020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	ret_val = acpi_bus_add(&device, pdevice, func->handle,
73120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		ACPI_BUS_TYPE_DEVICE);
73220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi	if (ret_val) {
73320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		dbg("error adding bus, %x\n",
73420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi			-ret_val);
73520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi		goto acpiphp_bus_add_out;
73615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	}
73715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	ret_val = acpi_bus_start(device);
73815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
73915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardiacpiphp_bus_add_out:
74015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	return ret_val;
74115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi}
74215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
74315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
74492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro/**
74592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * acpiphp_bus_trim - trim a bus from acpi subsystem
74692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * @handle: handle to acpi namespace
74792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro */
7486d47a5e4c3f8b6458002065d98a9cc6ff90fb597Adrian Bunkstatic int acpiphp_bus_trim(acpi_handle handle)
74992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro{
75092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	struct acpi_device *device;
75192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	int retval;
75292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro
75392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	retval = acpi_bus_get_device(handle, &device);
75492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	if (retval) {
75592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro		dbg("acpi_device not found\n");
75692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro		return retval;
75792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	}
75892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro
75992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	retval = acpi_bus_trim(device, 1);
76092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	if (retval)
76192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro		err("cannot remove from acpi list\n");
76292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro
76392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro	return retval;
76492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro}
76515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi
766d06070509147c948a06056da619c9dc2ed349805Shaohua Listatic void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
767d06070509147c948a06056da619c9dc2ed349805Shaohua Li{
768d06070509147c948a06056da619c9dc2ed349805Shaohua Li	struct acpiphp_func *func;
769d06070509147c948a06056da619c9dc2ed349805Shaohua Li	union acpi_object params[2];
770d06070509147c948a06056da619c9dc2ed349805Shaohua Li	struct acpi_object_list arg_list;
771d06070509147c948a06056da619c9dc2ed349805Shaohua Li
772d06070509147c948a06056da619c9dc2ed349805Shaohua Li	list_for_each_entry(func, &slot->funcs, sibling) {
773d06070509147c948a06056da619c9dc2ed349805Shaohua Li		arg_list.count = 2;
774d06070509147c948a06056da619c9dc2ed349805Shaohua Li		arg_list.pointer = params;
775d06070509147c948a06056da619c9dc2ed349805Shaohua Li		params[0].type = ACPI_TYPE_INTEGER;
776d06070509147c948a06056da619c9dc2ed349805Shaohua Li		params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG;
777d06070509147c948a06056da619c9dc2ed349805Shaohua Li		params[1].type = ACPI_TYPE_INTEGER;
778d06070509147c948a06056da619c9dc2ed349805Shaohua Li		params[1].integer.value = 1;
779d06070509147c948a06056da619c9dc2ed349805Shaohua Li		/* _REG is optional, we don't care about if there is failure */
780d06070509147c948a06056da619c9dc2ed349805Shaohua Li		acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
781d06070509147c948a06056da619c9dc2ed349805Shaohua Li	}
782d06070509147c948a06056da619c9dc2ed349805Shaohua Li}
783d06070509147c948a06056da619c9dc2ed349805Shaohua Li
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable_device - enable, configure a slot
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: slot to be enabled
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function should be called per *physical slot*,
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not per each slot object in ACPI namespace.
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7910ab2b57f8db8a1bcdf24089074f5d2856a3ffb42Sam Ravnborgstatic int __ref enable_device(struct acpiphp_slot *slot)
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *dev;
79442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	struct pci_bus *bus = slot->bridge->pci_bus;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
79742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	int num, max, pass;
798551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro	acpi_status status;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (slot->flags & SLOT_ENABLED)
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* sanity check: dev should be NULL when hot-plugged in */
80442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev) {
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This case shouldn't happen */
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err("pci_dev structure already exists.\n");
80842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		pci_dev_put(dev);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -1;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
81442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	if (num == 0) {
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err("No new device found\n");
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -1;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi	max = acpiphp_max_busnr(bus);
82142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	for (pass = 0; pass < 2; pass++) {
82242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		list_for_each_entry(dev, &bus->devices, bus_list) {
82342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah			if (PCI_SLOT(dev->devfn) != slot->device)
82442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah				continue;
82542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
826c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
82742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah				max = pci_scan_bridge(bus, dev, max, pass);
82892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro				if (pass && dev->subordinate)
829c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi					pci_bus_size_bridges(dev->subordinate);
830c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi			}
83142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		}
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
83458c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling)
83592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro		acpiphp_bus_add(func);
83692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro
83742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	pci_bus_assign_resources(bus);
8388e5dce35221850759671b2847a2e51030f7626bdKristen Accardi	acpiphp_sanitize_bus(bus);
839fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas	acpiphp_set_hpp_values(bus);
840d06070509147c948a06056da619c9dc2ed349805Shaohua Li	acpiphp_set_acpi_region(slot);
8418e5dce35221850759671b2847a2e51030f7626bdKristen Accardi	pci_enable_bridges(bus);
84269643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell
84369643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell	list_for_each_entry(dev, &bus->devices, bus_list) {
84469643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell		/* Assume that newly added devices are powered on already. */
84569643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell		if (!dev->is_added)
84669643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell			dev->current_state = PCI_D0;
84769643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell	}
84869643e4829c5cd13bafe44a6b9f3eb2086e0f618Ian Campbell
84942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	pci_bus_add_devices(bus);
85042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah
85158c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
8529d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
8539d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang						  func->function));
8549d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		if (!dev)
855551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			continue;
856551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
8579d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
8589d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		    dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
8599d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang			pci_dev_put(dev);
860551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			continue;
8619d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		}
862551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
863551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
864551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if (ACPI_FAILURE(status))
865551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			warn("find_p2p_bridge failed (error code = 0x%x)\n",
866551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro				status);
8679d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		pci_dev_put(dev);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->flags |= SLOT_ENABLED;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
876d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchistatic void disable_bridges(struct pci_bus *bus)
877d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi{
878d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi	struct pci_dev *dev;
879d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi	list_for_each_entry(dev, &bus->devices, bus_list) {
880d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi		if (dev->subordinate) {
881d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi			disable_bridges(dev->subordinate);
882d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi			pci_disable_device(dev);
883d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi		}
884d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi	}
885d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi}
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable_device - disable a slot
88926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int disable_device(struct acpiphp_slot *slot)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
8949d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	struct pci_dev *pdev;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* is this slot already disabled? */
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(slot->flags & SLOT_ENABLED))
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9009d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
901551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if (func->bridge) {
902551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			/* cleanup p2p bridges under this P2P bridge */
903551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			cleanup_p2p_bridge(func->bridge->handle,
904551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro						(u32)1, NULL, NULL);
905551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			func->bridge = NULL;
906551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		}
907551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro
9089d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		pdev = pci_get_slot(slot->bridge->pci_bus,
9099d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang				    PCI_DEVFN(slot->device, func->function));
9109d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang		if (pdev) {
9119d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang			pci_stop_bus_device(pdev);
9129d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang			if (pdev->subordinate) {
9139d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang				disable_bridges(pdev->subordinate);
9149d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang				pci_disable_device(pdev);
915d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi			}
9169d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang			pci_remove_bus_device(pdev);
9179d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang			pci_dev_put(pdev);
918d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi		}
919600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi	}
920600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi
9219d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
92292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro		acpiphp_bus_trim(func->handle);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	slot->flags &= (~SLOT_ENABLED);
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9279d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiangerr_exit:
9289d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang	return 0;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_slot_status - get ACPI slot status
93426e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
93626e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot has _STA for each function and if any one of them
93726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * returned non-zero status, return it.
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
93926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot doesn't have _STA and if any one of its functions'
94026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * configuration space is configured, return 0x0f as a _STA.
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
94226e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Otherwise return 0.
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_slot_status(struct acpiphp_slot *slot)
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_status status;
94727663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long sta = 0;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 dvid;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95158c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (func->flags & FUNC_HAS_STA) {
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ACPI_SUCCESS(status) && sta)
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword(slot->bridge->pci_bus,
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  PCI_DEVFN(slot->device,
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							    func->function),
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  PCI_VENDOR_ID, &dvid);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dvid != 0xffffffff) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sta = ACPI_STA_ALL;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (unsigned int)sta;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
9728d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah * acpiphp_eject_slot - physically eject the slot
97326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot
9748d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah */
975bfceafc5979d9055e04f03f970de6ff7a4bce1b6Gary Hadeint acpiphp_eject_slot(struct acpiphp_slot *slot)
9768d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah{
9778d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	acpi_status status;
9788d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	struct acpiphp_func *func;
9798d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	struct acpi_object_list arg_list;
9808d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	union acpi_object arg;
9818d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah
98258c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(func, &slot->funcs, sibling) {
9838d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah		/* We don't want to call _EJ0 on non-existing functions. */
9848d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah		if ((func->flags & FUNC_HAS_EJ0)) {
9858d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			/* _EJ0 method take one argument */
9868d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			arg_list.count = 1;
9878d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			arg_list.pointer = &arg;
9888d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			arg.type = ACPI_TYPE_INTEGER;
9898d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			arg.integer.value = 1;
9908d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah
9918d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
9928d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			if (ACPI_FAILURE(status)) {
99366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				warn("%s: _EJ0 failed\n", __func__);
9948d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah				return -1;
9958d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			} else
9968d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah				break;
9978d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah		}
9988d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	}
9998d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	return 0;
10008d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah}
10018d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah
10028d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah/**
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_check_bridge - re-enumerate devices
100426e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @bridge: where to begin re-enumeration
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate over all slots under this bridge and make sure that if a
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card is present they are enabled, and if not they are disabled.
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_slot *slot;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int enabled, disabled;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enabled = disabled = 0;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (slot = bridge->slots; slot; slot = slot->next) {
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int status = get_slot_status(slot);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (slot->flags & SLOT_ENABLED) {
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status == ACPI_STA_ALL)
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = acpiphp_disable_slot(slot);
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (retval) {
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err("Error occurred in disabling\n");
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_exit;
10268d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			} else {
10278d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah				acpiphp_eject_slot(slot);
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			disabled++;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status != ACPI_STA_ALL)
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = acpiphp_enable_slot(slot);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (retval) {
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err("Error occurred in enabling\n");
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_exit;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			enabled++;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison	dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1048fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus)
10498e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{
10508e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	struct pci_dev *dev;
10518e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
1052e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas	list_for_each_entry(dev, &bus->devices, bus_list)
1053e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas		pci_configure_slot(dev);
10548e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah}
10558e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
10568e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/*
10578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Remove devices for which we could not assign resources, call
10588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * arch specific code to fix-up the bus
10598e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah */
10608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void acpiphp_sanitize_bus(struct pci_bus *bus)
10618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{
10628e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	struct pci_dev *dev;
10638e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	int i;
10648e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
10658e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
10668e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	list_for_each_entry(dev, &bus->devices, bus_list) {
10678e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
10688e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah			struct resource *res = &dev->resource[i];
10698e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah			if ((res->flags & type_mask) && !res->start &&
10708e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah					res->end) {
10718e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah				/* Could not assign a required resources
10728e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah				 * for this device, remove it */
10738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah				pci_remove_bus_device(dev);
10748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah				break;
10758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah			}
10768e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		}
10778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
10788e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah}
10798e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
10808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* Program resources in newly inserted bridge */
10818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic int acpiphp_configure_bridge (acpi_handle handle)
10828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{
10837f53866932fd08add06ee2f93ead129949158490Alex Chiang	struct pci_bus *bus;
10847f53866932fd08add06ee2f93ead129949158490Alex Chiang
10857f53866932fd08add06ee2f93ead129949158490Alex Chiang	if (acpi_is_root_bridge(handle)) {
10867f53866932fd08add06ee2f93ead129949158490Alex Chiang		struct acpi_pci_root *root = acpi_pci_find_root(handle);
10877f53866932fd08add06ee2f93ead129949158490Alex Chiang		bus = root->bus;
10887f53866932fd08add06ee2f93ead129949158490Alex Chiang	} else {
10897f53866932fd08add06ee2f93ead129949158490Alex Chiang		struct pci_dev *pdev = acpi_get_pci_dev(handle);
10907f53866932fd08add06ee2f93ead129949158490Alex Chiang		bus = pdev->subordinate;
10917f53866932fd08add06ee2f93ead129949158490Alex Chiang		pci_dev_put(pdev);
10927f53866932fd08add06ee2f93ead129949158490Alex Chiang	}
10938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
10948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	pci_bus_size_bridges(bus);
10958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	pci_bus_assign_resources(bus);
10968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	acpiphp_sanitize_bus(bus);
1097fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas	acpiphp_set_hpp_values(bus);
10988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	pci_enable_bridges(bus);
10998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	return 0;
11008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah}
11018e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
11028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void handle_bridge_insertion(acpi_handle handle, u32 type)
11038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{
11048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	struct acpi_device *device, *pdevice;
11058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	acpi_handle phandle;
11068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
11078e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if ((type != ACPI_NOTIFY_BUS_CHECK) &&
11088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah			(type != ACPI_NOTIFY_DEVICE_CHECK)) {
11098e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		err("unexpected notification type %d\n", type);
11108e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		return;
11118e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
11128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
11138e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	acpi_get_parent(handle, &phandle);
11148e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if (acpi_bus_get_device(phandle, &pdevice)) {
11158e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		dbg("no parent device, assuming NULL\n");
11168e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		pdevice = NULL;
11178e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
11188e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
11198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		err("cannot add bridge to acpi list\n");
11208e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		return;
11218e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
11228e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if (!acpiphp_configure_bridge(handle) &&
11238e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		!acpi_bus_start(device))
11248e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		add_bridge(handle);
11258e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	else
11268e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		err("cannot configure and start bridge\n");
11278e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
11288e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah}
11298e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI event handlers
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11340bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status
11350bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecount_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
11360bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{
11370bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	int *count = (int *)context;
11380bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	struct acpiphp_bridge *bridge;
11390bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade
11400bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	bridge = acpiphp_handle_to_bridge(handle);
11410bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	if (bridge)
11420bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		(*count)++;
11430bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	return AE_OK ;
11440bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade}
11450bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade
11460bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status
11470bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecheck_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
11480bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{
11490bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	struct acpiphp_bridge *bridge;
11500bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	char objname[64];
11510bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	struct acpi_buffer buffer = { .length = sizeof(objname),
11520bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade				      .pointer = objname };
11530bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade
11540bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	bridge = acpiphp_handle_to_bridge(handle);
11550bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	if (bridge) {
11560bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
11570bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		dbg("%s: re-enumerating slots under %s\n",
115866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__, objname);
11590bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		acpiphp_check_bridge(bridge);
11600bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	}
11610bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	return AE_OK ;
11620bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade}
11630bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade
11646af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastruct acpiphp_hp_work {
11656af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	struct work_struct work;
11666af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	acpi_handle handle;
11676af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	u32 type;
11686af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	void *context;
11696af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava};
11706af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
11716af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastatic void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
11726af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava				  void *context,
11736af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava				  void (*func)(struct work_struct *work))
11746af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava{
11756af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	struct acpiphp_hp_work *hp_work;
11766af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	int ret;
11776af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
11786af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
11796af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	if (!hp_work)
11806af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava		return;
11816af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
11826af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work->handle = handle;
11836af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work->type = type;
11846af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work->context = context;
11856af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
11866af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	INIT_WORK(&hp_work->work, func);
11876af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
11886af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	if (!ret)
11896af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava		kfree(hp_work);
11906af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava}
11916af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
11926af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastatic void _handle_hotplug_event_bridge(struct work_struct *work)
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char objname[64];
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpi_buffer buffer = { .length = sizeof(objname),
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      .pointer = objname };
11988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	struct acpi_device *device;
11990bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	int num_sub_bridges = 0;
12006af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	struct acpiphp_hp_work *hp_work;
12016af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	acpi_handle handle;
12026af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	u32 type;
12036af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
12046af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work = container_of(work, struct acpiphp_hp_work, work);
12056af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	handle = hp_work->handle;
12066af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	type = hp_work->type;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	if (acpi_bus_get_device(handle, &device)) {
12098e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		/* This bridge must have just been physically inserted */
12108e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		handle_bridge_insertion(handle, type);
12116af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava		goto out;
12128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
12138e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
12148e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	bridge = acpiphp_handle_to_bridge(handle);
12150bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	if (type == ACPI_NOTIFY_BUS_CHECK) {
12160bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
12172263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming			count_sub_bridges, NULL, &num_sub_bridges, NULL);
12180bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	}
12190bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade
12200bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade	if (!bridge && !num_sub_bridges) {
12218e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		err("cannot get bridge info\n");
12226af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava		goto out;
12238e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (type) {
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_BUS_CHECK:
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bus re-enumerate */
123066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Bus check notify on %s\n", __func__, objname);
12310bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		if (bridge) {
12320bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade			dbg("%s: re-enumerating slots under %s\n",
123366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				__func__, objname);
12340bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade			acpiphp_check_bridge(bridge);
12350bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		}
12360bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade		if (num_sub_bridges)
12370bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade			acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
12382263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming				ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_DEVICE_CHECK:
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device check */
124366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device check notify on %s\n", __func__, objname);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpiphp_check_bridge(bridge);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_DEVICE_WAKE:
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* wake event */
124966bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device wake notify on %s\n", __func__, objname);
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_EJECT_REQUEST:
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* request device eject */
125466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device eject notify on %s\n", __func__, objname);
1255551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		if ((bridge->type != BRIDGE_TYPE_HOST) &&
1256551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		    (bridge->flags & BRIDGE_HAS_EJ0)) {
1257551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			struct acpiphp_slot *slot;
1258551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			slot = bridge->func->slot;
1259551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro			if (!acpiphp_disable_slot(slot))
1260551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro				acpiphp_eject_slot(slot);
1261551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro		}
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Device %s cannot be configured due"
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				" to a frequency mismatch\n", objname);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Device %s cannot be configured due"
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				" to a bus mode mismatch\n", objname);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_POWER_FAULT:
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Device %s has suffered a power fault\n",
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				objname);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12836af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
12846af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavaout:
12856af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12896af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * handle_hotplug_event_bridge - handle ACPI event on bridges
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code
12926af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * @context: pointer to acpiphp_bridge structure
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12946af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * Handles ACPI event notification on {host,p2p} bridges.
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12966af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastatic void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
12976af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava					void *context)
12986af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava{
12996af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	/*
13006af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * Currently the code adds all hotplug events to the kacpid_wq
13016af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
13026af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * The proper way to fix this is to reorganize the code so that
13036af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
13046af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * For now just re-add this work to the kacpi_hotplug_wq so we
13056af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * don't deadlock on hotplug actions.
13066af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 */
13076af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	alloc_acpiphp_hp_work(handle, type, context,
13086af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava			      _handle_hotplug_event_bridge);
13096af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava}
13106af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
13116af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastatic void _handle_hotplug_event_func(struct work_struct *work)
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_func *func;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char objname[64];
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpi_buffer buffer = { .length = sizeof(objname),
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      .pointer = objname };
13176af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	struct acpiphp_hp_work *hp_work;
13186af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	acpi_handle handle;
13196af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	u32 type;
13206af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	void *context;
13216af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
13226af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	hp_work = container_of(work, struct acpiphp_hp_work, work);
13236af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	handle = hp_work->handle;
13246af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	type = hp_work->type;
13256af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	context = hp_work->context;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = (struct acpiphp_func *)context;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (type) {
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_BUS_CHECK:
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bus re-enumerate */
133466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Bus check notify on %s\n", __func__, objname);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpiphp_enable_slot(func->slot);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_DEVICE_CHECK:
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device check : re-enumerate from parent bus */
134066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device check notify on %s\n", __func__, objname);
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acpiphp_check_bridge(func->slot->bridge);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_DEVICE_WAKE:
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* wake event */
134666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device wake notify on %s\n", __func__, objname);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ACPI_NOTIFY_EJECT_REQUEST:
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* request device eject */
135166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Device eject notify on %s\n", __func__, objname);
13528d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah		if (!(acpiphp_disable_slot(func->slot)))
13538d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah			acpiphp_eject_slot(func->slot);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13606af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava
13616af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	kfree(hp_work); /* allocated in handle_hotplug_event_func */
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13646af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava/**
13656af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
13666af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * @handle: Notify()'ed acpi_handle
13676af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * @type: Notify code
13686af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * @context: pointer to acpiphp_func structure
13696af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava *
13706af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava * Handles ACPI event notification on slots.
13716af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava */
13726af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargavastatic void handle_hotplug_event_func(acpi_handle handle, u32 type,
13736af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava				      void *context)
13746af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava{
13756af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	/*
13766af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * Currently the code adds all hotplug events to the kacpid_wq
13776af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
13786af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * The proper way to fix this is to reorganize the code so that
13796af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
13806af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * For now just re-add this work to the kacpi_hotplug_wq so we
13816af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 * don't deadlock on hotplug actions.
13826af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	 */
13836af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava	alloc_acpiphp_hp_work(handle, type, context,
13846af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava			      _handle_hotplug_event_func);
13856af8bef14d6fc9e4e52c83fd646412e9dedadd26Prarit Bhargava}
13868e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
13878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic acpi_status
13888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahfind_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
13898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{
13908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	int *count = (int *)context;
13918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah
13920d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki	if (!acpi_is_root_bridge(handle))
13930d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki		return AE_OK;
13940d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki
13950d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki	(*count)++;
13960d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki	acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
13970d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki				    handle_hotplug_event_bridge, NULL);
13980d52f54e2ef64c189dedc332e680b2eb4a34590aRafael J. Wysocki
13998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	return AE_OK ;
14008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah}
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_pci_driver acpi_pci_hp_driver = {
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.add =		add_bridge,
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove =	remove_bridge,
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_glue_init(void)
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	int num = 0;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14148e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
14152263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming			ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (num <= 0)
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
14198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah	else
14208e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah		acpi_pci_register_driver(&acpi_pci_hp_driver);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
142926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * This function frees all data allocated in acpiphp_glue_init().
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1431031f30d2bc69f78cf542c0e5874a9d67c03d0ffeKristen Carlson Accardivoid  acpiphp_glue_exit(void)
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	acpi_pci_unregister_driver(&acpi_pci_hp_driver);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_get_num_slots - count number of slots in a system
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_get_num_slots(void)
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge;
1443467c442f092e22acf86a3b4ad4863d097d7257daAkinobu Mita	int num_slots = 0;
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144558c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang	list_for_each_entry(bridge, &bridge_list, list) {
144642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah		dbg("Bus %04x:%02x has %d slot%s\n",
144742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah				pci_domain_nr(bridge->pci_bus),
144842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah				bridge->pci_bus->number, bridge->nr_slots,
144942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah				bridge->nr_slots == 1 ? "" : "s");
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num_slots += bridge->nr_slots;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah	dbg("Total %d slots\n", num_slots);
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return num_slots;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_for_each_slot - call function for each slot
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fn: callback function
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: context to be passed to callback function
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head *node;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_bridge *bridge;
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct acpiphp_slot *slot;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each (node, &bridge_list) {
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bridge = (struct acpiphp_bridge *)node;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (slot = bridge->slots; slot; slot = slot->next) {
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = fn(slot, data);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!retval)
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_exit;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_enable_slot - power on slot
148826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_enable_slot(struct acpiphp_slot *slot)
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14946aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&slot->crit_sect);
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wake up all functions */
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = power_on_slot(slot);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro	if (get_slot_status(slot) == ACPI_STA_ALL) {
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* configure all functions */
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = enable_device(slot);
1504cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro		if (retval)
1505cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro			power_off_slot(slot);
1506cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro	} else {
150766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
1508cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro		power_off_slot(slot);
1509cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro	}
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
15126aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_unlock(&slot->crit_sect);
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_disable_slot - power off slot
151826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_disable_slot(struct acpiphp_slot *slot)
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval = 0;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15246aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_lock(&slot->crit_sect);
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* unconfigure all functions */
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = disable_device(slot);
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* power off all functions */
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = power_off_slot(slot);
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_exit;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit:
15376aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar	mutex_unlock(&slot->crit_sect);
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot enabled:  1
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot disabled: 0
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_power_status(struct acpiphp_slot *slot)
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15488d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah	return (slot->flags & SLOT_POWEREDON);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
155335ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch   open:  1
155435ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch closed:  0
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sta;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sta = get_slot_status(slot);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156235ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro	return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter presence : 1
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          absence : 0
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int sta;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sta = get_slot_status(slot);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (sta == 0) ? 0 : 1;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1578