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