acpiphp_glue.c revision d06070509147c948a06056da619c9dc2ed349805
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> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../pci.h" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "acpiphp.h" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(bridge_list); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MY_NAME "acpiphp_glue" 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge (acpi_handle, u32, void *); 598e5dce35221850759671b2847a2e51030f7626bdKristen Accardistatic void acpiphp_sanitize_bus(struct pci_bus *bus); 60fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus); 612b85e1307fe3a84eca2e1a21c6c857359908dab4Len Brownstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); 628e5dce35221850759671b2847a2e51030f7626bdKristen Accardi 635a340ed87987c8c61dd9d1a8a5384dab1ace2566MUNEDA Takahiro/* callback routine to check for the existence of a pci dock device */ 644e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic acpi_status 654e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardiis_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) 664e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{ 674e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi int *count = (int *)context; 684e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 694e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(handle)) { 704e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi (*count)++; 714e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return AE_CTRL_TERMINATE; 724e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } else { 734e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return AE_OK; 744e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 754e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi} 764e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 774e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi/* 784e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * the _DCK method can do funny things... and sometimes not 794e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * hah-hah funny. 804e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * 814e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * TBD - figure out a way to only call fixups for 824e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * systems that require them. 834e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 844e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic int post_dock_fixups(struct notifier_block *nb, unsigned long val, 854e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi void *v) 864e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{ 874e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); 884e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi struct pci_bus *bus = func->slot->bridge->pci_bus; 894e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi u32 buses; 904e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 914e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (!bus->self) 924e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return NOTIFY_OK; 934e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 944e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* fixup bad _DCK function that rewrites 954e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * secondary bridge on slot 964e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 974e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi pci_read_config_dword(bus->self, 984e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi PCI_PRIMARY_BUS, 994e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi &buses); 1004e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1014e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (((buses >> 8) & 0xff) != bus->secondary) { 1024e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi buses = (buses & 0xff000000) 1032a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->primary) << 0) 1042a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->secondary) << 8) 1052a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->subordinate) << 16); 1064e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); 1074e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 1084e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return NOTIFY_OK; 1094e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi} 1104e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1114e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1121253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Listatic struct acpi_dock_ops acpiphp_dock_ops = { 1131253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li .handler = handle_hotplug_event_func, 1141253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li}; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to register each ACPI PCI slot object */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsregister_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *newfunc; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle tmp; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status = AE_OK; 12527663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long adr, sun; 126e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro int device, function, retval; 127e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige struct pci_bus *pbus = bridge->pci_bus; 1289d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang struct pci_dev *pdev; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13356ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett acpi_evaluate_integer(handle, "_ADR", NULL, &adr); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device = (adr >> 16) & 0xffff; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = adr & 0xffff; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 137f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!newfunc) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&newfunc->sibling); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->handle = handle; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->function = function; 14456ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett 14556ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) 14620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags = FUNC_HAS_EJ0; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_STA; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS0; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS3; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1574e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) 15820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags |= FUNC_HAS_DCK; 15920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 16195b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi if (ACPI_FAILURE(status)) { 16295b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi /* 16395b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi * use the count of the number of slots we've found 16495b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi * for the number of the slot 16595b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi */ 16695b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi sun = bridge->nr_slots+1; 16795b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi } 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search for objects that share the same slot */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->device == device) { 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->sun != sun) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("sibling found, but _SUN doesn't match!\n"); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 178f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(newfunc); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->bridge = bridge; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->device = device; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->sun = sun; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&slot->funcs); 1886aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_init(&slot->crit_sect); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->next = bridge->slots; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->slots = slot; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->nr_slots++; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 195b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", 196e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige slot->sun, pci_domain_nr(pbus), pbus->number, device); 197e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro retval = acpiphp_register_hotplug_slot(slot); 198e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro if (retval) { 199f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang if (retval == -EBUSY) 200b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen warn("Slot %llu already registered by another " 201f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang "hotplug driver\n", slot->sun); 202f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang else 203f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang warn("acpiphp_register_hotplug_slot failed " 204f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang "(err code = 0x%x)\n", retval); 205e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro goto err_exit; 206e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->slot = slot; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&newfunc->sibling, &slot->funcs); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2129d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); 2139d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev) { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 2159d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(pdev); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2184e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(handle)) { 2194e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* we don't want to call this device's _EJ0 2204e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * because we want the dock notify handler 2214e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * to call it after it calls _DCK 22220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi */ 22320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags &= ~FUNC_HAS_EJ0; 2244e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (register_hotplug_dock_device(handle, 2251253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li &acpiphp_dock_ops, newfunc)) 2264e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi dbg("failed to register dock device\n"); 2274e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 2284e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* we need to be notified when dock events happen 2294e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * outside of the hotplug operation, since we may 2304e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * need to do fixups before we can hotplug. 2314e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 2324e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi newfunc->nb.notifier_call = post_dock_fixups; 2334e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (register_dock_notifier(&newfunc->nb)) 2344e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi dbg("failed to register a dock notifier"); 23520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 23620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 23820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!(newfunc->flags & FUNC_HAS_DCK)) { 23920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = acpi_install_notify_handler(handle, 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_func, 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ACPI_FAILURE(status)) 24520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi err("failed to register interrupt notify handler\n"); 24620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } else 24720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = AE_OK; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi return status; 250e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 251e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro err_exit: 252e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro bridge->nr_slots--; 253e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro bridge->slots = slot->next; 254e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro kfree(slot); 255e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro kfree(newfunc); 256e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 257e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro return AE_OK; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* see if it's worth looking at this bridge */ 2626edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic int detect_ejectable_slots(acpi_handle handle) 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2647f53866932fd08add06ee2f93ead129949158490Alex Chiang int found = acpi_pci_detect_ejectable(handle); 265e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige if (!found) { 2666edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 2672263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming is_pci_dock_device, NULL, (void *)&found, NULL); 268e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige } 269e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige return found; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_bridge_misc(struct acpiphp_bridge *bridge) 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 277e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro /* must be added to the list prior to calling register_slot */ 278e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_add(&bridge->list, &bridge_list); 279e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register all slot objects under this bridge */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, 2822263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming register_slot, NULL, bridge, NULL); 283e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro if (ACPI_FAILURE(status)) { 284e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_del(&bridge->list); 285e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro return; 286e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro } 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 2898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->type != BRIDGE_TYPE_HOST) { 290551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { 291551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = acpi_remove_notify_handler(bridge->func->handle, 292551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ACPI_SYSTEM_NOTIFY, 293551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro handle_hotplug_event_func); 294551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 295551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro err("failed to remove notify handler\n"); 296551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 2978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah status = acpi_install_notify_handler(bridge->handle, 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_bridge, 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (ACPI_FAILURE(status)) { 3038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("failed to register interrupt notify handler\n"); 3048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 309551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro/* find acpiphp_func from acpiphp_bridge */ 310551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) 311551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{ 312551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_bridge *bridge; 313551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_slot *slot; 314551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_func *func; 315551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 31658c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(bridge, &bridge_list, list) { 317551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro for (slot = bridge->slots; slot; slot = slot->next) { 31858c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 319551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (func->handle == handle) 320551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return func; 321551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 322551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 323551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 324551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 325551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return NULL; 326551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro} 327551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 328551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 329551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) 330551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{ 331551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_handle dummy_handle; 332551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 333551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 334551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_STA", &dummy_handle))) 335551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_STA; 336551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 337551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 338551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_EJ0", &dummy_handle))) 339551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_EJ0; 340551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 341551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 342551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_PS0", &dummy_handle))) 343551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_PS0; 344551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 345551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 346551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_PS3", &dummy_handle))) 347551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_PS3; 348551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 349551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* is this ejectable p2p bridge? */ 350551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (bridge->flags & BRIDGE_HAS_EJ0) { 351551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_func *func; 352551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 353551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro dbg("found ejectable p2p bridge\n"); 354551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 355551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* make link between PCI bridge and PCI function */ 356551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func = acpiphp_bridge_handle_to_function(bridge->handle); 357551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (!func) 358551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return; 359551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->func = func; 360551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func->bridge = bridge; 361551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 362551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro} 363551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 364551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize host bridge data structure */ 3666edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_host_bridge(acpi_handle *handle) 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3696edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang struct acpi_pci_root *root = acpi_pci_find_root(handle); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_HOST; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3786edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_bus = root->bus; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize PCI-to-PCI bridge data structure */ 3876edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_p2p_bridge(acpi_handle *handle) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) { 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("out of memory\n"); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_P2P; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 399551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro config_p2p_bridge_flags(bridge); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4016edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_dev = acpi_get_pci_dev(handle); 4026edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_bus = bridge->pci_dev->subordinate; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bridge->pci_bus) { 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("This is not a PCI-to-PCI bridge!\n"); 40542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto err; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4085d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang /* 4095d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * Grab a ref to the subordinate PCI bus in case the bus is 4105d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * removed via PCI core logical hotplug. The ref pins the bus 4115d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * (which we access during module unload). 4125d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang */ 4135d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang get_device(&bridge->pci_bus->dev); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 41742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 41842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err: 4196edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang pci_dev_put(bridge->pci_dev); 42042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 42142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to find P2P bridges */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfind_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4326edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang dev = acpi_get_pci_dev(handle); 43342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (!dev || !dev->subordinate) 43442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto out; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4376edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang if ((detect_ejectable_slots(handle) > 0)) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 4396edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang add_p2p_bridge(handle); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4427c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige /* search P2P bridges under this p2p bridge */ 4437c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 4442263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming find_p2p_bridge, NULL, NULL, NULL); 4457c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige if (ACPI_FAILURE(status)) 446551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", status); 4477c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige 44842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah out: 44942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* find hot-pluggable slots, and then find P2P bridge */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int add_bridge(acpi_handle handle) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 45827663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long tmp; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle dummy_handle; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if the bridge doesn't have _STA, we assume it is always there */ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_STA", &dummy_handle); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status)) { 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 46666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: _STA evaluation failure\n", __func__); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tmp & ACPI_STA_FUNCTIONING) == 0) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't register this object */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4756edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang if (detect_ejectable_slots(handle) > 0) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI host-bus bridge with hot-pluggable slots\n"); 4776edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang add_host_bridge(handle); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search P2P bridges under this host bridge */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 4822263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming find_p2p_bridge, NULL, NULL, NULL); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 485551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", status); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) 49142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah{ 49258c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang struct acpiphp_bridge *bridge; 49358c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang 49458c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(bridge, &bridge_list, list) 49542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (bridge->handle == handle) 49642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return bridge; 49742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 49842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return NULL; 49942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah} 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void cleanup_bridge(struct acpiphp_bridge *bridge) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 50358c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang struct acpiphp_slot *slot, *next; 50458c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang struct acpiphp_func *func, *tmp; 50542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah acpi_status status; 506364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah acpi_handle handle = bridge->handle; 50742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 50842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 50942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_bridge); 51042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (ACPI_FAILURE(status)) 51142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err("failed to remove notify handler\n"); 51242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 513551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->type != BRIDGE_TYPE_HOST) && 514551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { 515551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = acpi_install_notify_handler(bridge->func->handle, 516551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ACPI_SYSTEM_NOTIFY, 517551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro handle_hotplug_event_func, 518551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->func); 519551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 520551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro err("failed to install interrupt notify handler\n"); 521551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 522551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 52342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = bridge->slots; 52442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah while (slot) { 52558c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang next = slot->next; 52658c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { 5274e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(func->handle)) { 5284e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi unregister_hotplug_dock_device(func->handle); 5294e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi unregister_dock_notifier(&func->nb); 5304e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 53120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!(func->flags & FUNC_HAS_DCK)) { 53220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = acpi_remove_notify_handler(func->handle, 53342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah ACPI_SYSTEM_NOTIFY, 53442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_func); 53520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ACPI_FAILURE(status)) 53620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi err("failed to remove notify handler\n"); 53720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 53858c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_del(&func->sibling); 53942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(func); 54042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 541e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro acpiphp_unregister_hotplug_slot(slot); 542e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_del(&slot->funcs); 54342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(slot); 54442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = next; 54542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 54642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 5475d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang /* 5485d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * Only P2P bridges have a pci_dev 5495d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang */ 5505d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang if (bridge->pci_dev) 5515d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang put_device(&bridge->pci_bus->dev); 5525d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang 55342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(bridge->pci_dev); 55442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_del(&bridge->list); 55542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 558364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic acpi_status 559364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahcleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 560364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 561364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 562364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 563551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this P2P bridge 564551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro in a depth-first manner */ 565551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 5662263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming cleanup_p2p_bridge, NULL, NULL, NULL); 567551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 568a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang bridge = acpiphp_handle_to_bridge(handle); 569a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang if (bridge) 570a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang cleanup_bridge(bridge); 571a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang 572364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah return AE_OK; 573364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 574364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 575364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void remove_bridge(acpi_handle handle) 576364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 577364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 578364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 579551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this host bridge 580551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro in a depth-first manner */ 581551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 5822263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL); 583551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 584a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang /* 585a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * On root bridges with hotplug slots directly underneath (ie, 586a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * no p2p bridge inbetween), we call cleanup_bridge(). 587a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * 588a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * The else clause cleans up root bridges that either had no 589a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * hotplug slots at all, or had a p2p bridge underneath. 590a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang */ 591364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 592551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (bridge) 593364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah cleanup_bridge(bridge); 594a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang else 595a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 596a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang handle_hotplug_event_bridge); 597364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_on_slot(struct acpiphp_slot *slot) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already enabled, just skip */ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_POWEREDON) 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60958c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_PS0) { 61166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: executing _PS0\n", __func__); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 61466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _PS0 failed\n", __func__); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is enabled */ 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_POWEREDON; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_off_slot(struct acpiphp_slot *slot) 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already disabled, just skip */ 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slot->flags & SLOT_POWEREDON) == 0) 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64258c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 6432f523b15901f654a9448bbd47ebe1e783ec3195bRajesh Shah if (func->flags & FUNC_HAS_PS3) { 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 64666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _PS3 failed\n", __func__); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is disabled */ 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_POWEREDON); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 66415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/** 66526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * acpiphp_max_busnr - return the highest reserved bus number under the given bus. 66615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @bus: bus to start search with 66715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 66815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic unsigned char acpiphp_max_busnr(struct pci_bus *bus) 66915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{ 67015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi struct list_head *tmp; 67115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi unsigned char max, n; 67215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 67315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi /* 67415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * pci_bus_max_busnr will return the highest 67515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * reserved busnr for all these children. 67615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * that is equivalent to the bus->subordinate 67715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * value. We don't want to use the parent's 67815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * bus->subordinate value because it could have 67915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * padding in it. 68015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 68115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = bus->secondary; 68215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 68315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi list_for_each(tmp, &bus->children) { 68415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi n = pci_bus_max_busnr(pci_bus_b(tmp)); 68515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi if (n > max) 68615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = n; 68715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 68815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi return max; 68915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi} 69015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 69115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 69215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/** 69315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * acpiphp_bus_add - add a new bus to acpi subsystem 69415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @func: acpiphp_func of the bridge 69515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 69615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic int acpiphp_bus_add(struct acpiphp_func *func) 69715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{ 69815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi acpi_handle phandle; 69915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi struct acpi_device *device, *pdevice; 70015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi int ret_val; 70115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 70215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi acpi_get_parent(func->handle, &phandle); 70315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi if (acpi_bus_get_device(phandle, &pdevice)) { 70415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi dbg("no parent device, assuming NULL\n"); 70515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi pdevice = NULL; 70615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 70720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!acpi_bus_get_device(func->handle, &device)) { 70820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("bus exists... trim\n"); 70920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi /* this shouldn't be in here, so remove 71020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi * the bus then re-add it... 71120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi */ 71220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ret_val = acpi_bus_trim(device, 1); 71320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("acpi_bus_trim return %x\n", ret_val); 71420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 71520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 71620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ret_val = acpi_bus_add(&device, pdevice, func->handle, 71720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ACPI_BUS_TYPE_DEVICE); 71820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ret_val) { 71920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("error adding bus, %x\n", 72020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi -ret_val); 72120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi goto acpiphp_bus_add_out; 72215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 72315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi ret_val = acpi_bus_start(device); 72415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 72515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardiacpiphp_bus_add_out: 72615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi return ret_val; 72715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi} 72815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 72915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 73092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro/** 73192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * acpiphp_bus_trim - trim a bus from acpi subsystem 73292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * @handle: handle to acpi namespace 73392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro */ 7346d47a5e4c3f8b6458002065d98a9cc6ff90fb597Adrian Bunkstatic int acpiphp_bus_trim(acpi_handle handle) 73592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro{ 73692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro struct acpi_device *device; 73792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro int retval; 73892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 73992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro retval = acpi_bus_get_device(handle, &device); 74092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (retval) { 74192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro dbg("acpi_device not found\n"); 74292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro return retval; 74392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro } 74492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 74592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro retval = acpi_bus_trim(device, 1); 74692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (retval) 74792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro err("cannot remove from acpi list\n"); 74892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 74992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro return retval; 75092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro} 75115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 752d06070509147c948a06056da619c9dc2ed349805Shaohua Listatic void acpiphp_set_acpi_region(struct acpiphp_slot *slot) 753d06070509147c948a06056da619c9dc2ed349805Shaohua Li{ 754d06070509147c948a06056da619c9dc2ed349805Shaohua Li struct acpiphp_func *func; 755d06070509147c948a06056da619c9dc2ed349805Shaohua Li union acpi_object params[2]; 756d06070509147c948a06056da619c9dc2ed349805Shaohua Li struct acpi_object_list arg_list; 757d06070509147c948a06056da619c9dc2ed349805Shaohua Li 758d06070509147c948a06056da619c9dc2ed349805Shaohua Li list_for_each_entry(func, &slot->funcs, sibling) { 759d06070509147c948a06056da619c9dc2ed349805Shaohua Li arg_list.count = 2; 760d06070509147c948a06056da619c9dc2ed349805Shaohua Li arg_list.pointer = params; 761d06070509147c948a06056da619c9dc2ed349805Shaohua Li params[0].type = ACPI_TYPE_INTEGER; 762d06070509147c948a06056da619c9dc2ed349805Shaohua Li params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG; 763d06070509147c948a06056da619c9dc2ed349805Shaohua Li params[1].type = ACPI_TYPE_INTEGER; 764d06070509147c948a06056da619c9dc2ed349805Shaohua Li params[1].integer.value = 1; 765d06070509147c948a06056da619c9dc2ed349805Shaohua Li /* _REG is optional, we don't care about if there is failure */ 766d06070509147c948a06056da619c9dc2ed349805Shaohua Li acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL); 767d06070509147c948a06056da619c9dc2ed349805Shaohua Li } 768d06070509147c948a06056da619c9dc2ed349805Shaohua Li} 769d06070509147c948a06056da619c9dc2ed349805Shaohua Li 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable_device - enable, configure a slot 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: slot to be enabled 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function should be called per *physical slot*, 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not per each slot object in ACPI namespace. 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7770ab2b57f8db8a1bcdf24089074f5d2856a3ffb42Sam Ravnborgstatic int __ref enable_device(struct acpiphp_slot *slot) 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 78042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *bus = slot->bridge->pci_bus; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 78342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah int num, max, pass; 784551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_status status; 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* sanity check: dev should be NULL when hot-plugged in */ 79042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This case shouldn't happen */ 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("pci_dev structure already exists.\n"); 79442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); 80042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (num == 0) { 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("No new device found\n"); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = acpiphp_max_busnr(bus); 80742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah for (pass = 0; pass < 2; pass++) { 80842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 80942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (PCI_SLOT(dev->devfn) != slot->device) 81042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah continue; 81142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || 812c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { 81342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah max = pci_scan_bridge(bus, dev, max, pass); 81492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (pass && dev->subordinate) 815c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi pci_bus_size_bridges(dev->subordinate); 816c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi } 81742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82058c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) 82192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro acpiphp_bus_add(func); 82292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 82342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_assign_resources(bus); 8248e5dce35221850759671b2847a2e51030f7626bdKristen Accardi acpiphp_sanitize_bus(bus); 825fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas acpiphp_set_hpp_values(bus); 826d06070509147c948a06056da619c9dc2ed349805Shaohua Li acpiphp_set_acpi_region(slot); 8278e5dce35221850759671b2847a2e51030f7626bdKristen Accardi pci_enable_bridges(bus); 82842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_add_devices(bus); 82942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 83058c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 8319d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 8329d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang func->function)); 8339d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (!dev) 834551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro continue; 835551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 8369d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && 8379d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { 8389d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(dev); 839551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro continue; 8409d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang } 841551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 842551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); 843551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 844551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", 845551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status); 8469d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(dev); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_ENABLED; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 855d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchistatic void disable_bridges(struct pci_bus *bus) 856d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi{ 857d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi struct pci_dev *dev; 858d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi list_for_each_entry(dev, &bus->devices, bus_list) { 859d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi if (dev->subordinate) { 860d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi disable_bridges(dev->subordinate); 861d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi pci_disable_device(dev); 862d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 863d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 864d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi} 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable_device - disable a slot 86826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int disable_device(struct acpiphp_slot *slot) 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 8739d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang struct pci_dev *pdev; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* is this slot already disabled? */ 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(slot->flags & SLOT_ENABLED)) 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8799d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 880551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (func->bridge) { 881551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this P2P bridge */ 882551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro cleanup_p2p_bridge(func->bridge->handle, 883551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro (u32)1, NULL, NULL); 884551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func->bridge = NULL; 885551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 886551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 8879d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pdev = pci_get_slot(slot->bridge->pci_bus, 8889d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang PCI_DEVFN(slot->device, func->function)); 8899d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev) { 8909d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_stop_bus_device(pdev); 8919d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev->subordinate) { 8929d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang disable_bridges(pdev->subordinate); 8939d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_disable_device(pdev); 894d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 8959d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_remove_bus_device(pdev); 8969d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(pdev); 897d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 898600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi } 899600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 9009d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 90192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro acpiphp_bus_trim(func->handle); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_ENABLED); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9069d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiangerr_exit: 9079d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang return 0; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_slot_status - get ACPI slot status 91326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot has _STA for each function and if any one of them 91626e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * returned non-zero status, return it. 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot doesn't have _STA and if any one of its functions' 91926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * configuration space is configured, return 0x0f as a _STA. 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 92126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Otherwise return 0. 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_slot_status(struct acpiphp_slot *slot) 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 92627663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta = 0; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dvid; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93058c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_STA) { 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status) && sta) 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_bus_read_config_dword(slot->bridge->pci_bus, 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVFN(slot->device, 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func->function), 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_VENDOR_ID, &dvid); 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvid != 0xffffffff) { 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = ACPI_STA_ALL; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (unsigned int)sta; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 9518d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah * acpiphp_eject_slot - physically eject the slot 95226e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 9538d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah */ 954bfceafc5979d9055e04f03f970de6ff7a4bce1b6Gary Hadeint acpiphp_eject_slot(struct acpiphp_slot *slot) 9558d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah{ 9568d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpi_status status; 9578d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpiphp_func *func; 9588d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpi_object_list arg_list; 9598d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah union acpi_object arg; 9608d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 96158c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 9628d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* We don't want to call _EJ0 on non-existing functions. */ 9638d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if ((func->flags & FUNC_HAS_EJ0)) { 9648d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* _EJ0 method take one argument */ 9658d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.count = 1; 9668d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.pointer = &arg; 9678d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.type = ACPI_TYPE_INTEGER; 9688d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.integer.value = 1; 9698d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9708d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); 9718d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (ACPI_FAILURE(status)) { 97266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _EJ0 failed\n", __func__); 9738d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return -1; 9748d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else 9758d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah break; 9768d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 9778d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 9788d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return 0; 9798d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah} 9808d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9818d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah/** 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_check_bridge - re-enumerate devices 98326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @bridge: where to begin re-enumeration 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate over all slots under this bridge and make sure that if a 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card is present they are enabled, and if not they are disabled. 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_check_bridge(struct acpiphp_bridge *bridge) 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int enabled, disabled; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled = disabled = 0; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status = get_slot_status(slot); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) { 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == ACPI_STA_ALL) 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_disable_slot(slot); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in disabling\n"); 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 10058d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else { 10068d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(slot); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disabled++; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != ACPI_STA_ALL) 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_enable_slot(slot); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in enabling\n"); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled++; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled); 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1027fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus) 10288e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10298e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 10308e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 1031e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas list_for_each_entry(dev, &bus->devices, bus_list) 1032e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas pci_configure_slot(dev); 10338e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10348e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10358e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* 10368e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Remove devices for which we could not assign resources, call 10378e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * arch specific code to fix-up the bus 10388e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah */ 10398e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void acpiphp_sanitize_bus(struct pci_bus *bus) 10408e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10418e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 10428e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int i; 10438e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; 10448e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10458e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 10468e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { 10478e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct resource *res = &dev->resource[i]; 10488e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((res->flags & type_mask) && !res->start && 10498e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah res->end) { 10508e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* Could not assign a required resources 10518e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * for this device, remove it */ 10528e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_remove_bus_device(dev); 10538e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah break; 10548e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10558e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10568e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10598e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* Program resources in newly inserted bridge */ 10608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic int acpiphp_configure_bridge (acpi_handle handle) 10618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10627f53866932fd08add06ee2f93ead129949158490Alex Chiang struct pci_bus *bus; 10637f53866932fd08add06ee2f93ead129949158490Alex Chiang 10647f53866932fd08add06ee2f93ead129949158490Alex Chiang if (acpi_is_root_bridge(handle)) { 10657f53866932fd08add06ee2f93ead129949158490Alex Chiang struct acpi_pci_root *root = acpi_pci_find_root(handle); 10667f53866932fd08add06ee2f93ead129949158490Alex Chiang bus = root->bus; 10677f53866932fd08add06ee2f93ead129949158490Alex Chiang } else { 10687f53866932fd08add06ee2f93ead129949158490Alex Chiang struct pci_dev *pdev = acpi_get_pci_dev(handle); 10697f53866932fd08add06ee2f93ead129949158490Alex Chiang bus = pdev->subordinate; 10707f53866932fd08add06ee2f93ead129949158490Alex Chiang pci_dev_put(pdev); 10717f53866932fd08add06ee2f93ead129949158490Alex Chiang } 10728e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_size_bridges(bus); 10748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_assign_resources(bus); 10758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpiphp_sanitize_bus(bus); 1076fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas acpiphp_set_hpp_values(bus); 10778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_enable_bridges(bus); 10788e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 0; 10798e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void handle_bridge_insertion(acpi_handle handle, u32 type) 10828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10838e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device, *pdevice; 10848e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_handle phandle; 10858e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10868e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((type != ACPI_NOTIFY_BUS_CHECK) && 10878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (type != ACPI_NOTIFY_DEVICE_CHECK)) { 10888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("unexpected notification type %d\n", type); 10898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 10908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_get_parent(handle, &phandle); 10938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(phandle, &pdevice)) { 10948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah dbg("no parent device, assuming NULL\n"); 10958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pdevice = NULL; 10968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { 10988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot add bridge to acpi list\n"); 10998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11018e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!acpiphp_configure_bridge(handle) && 11028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah !acpi_bus_start(device)) 11038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah add_bridge(handle); 11048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 11058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot configure and start bridge\n"); 11068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11078e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 11088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI event handlers 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11130bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status 11140bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecount_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 11150bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{ 11160bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade int *count = (int *)context; 11170bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpiphp_bridge *bridge; 11180bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 11190bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade bridge = acpiphp_handle_to_bridge(handle); 11200bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) 11210bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade (*count)++; 11220bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade return AE_OK ; 11230bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade} 11240bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 11250bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status 11260bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecheck_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 11270bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{ 11280bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpiphp_bridge *bridge; 11290bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade char objname[64]; 11300bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpi_buffer buffer = { .length = sizeof(objname), 11310bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade .pointer = objname }; 11320bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 11330bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade bridge = acpiphp_handle_to_bridge(handle); 11340bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) { 11350bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 11360bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade dbg("%s: re-enumerating slots under %s\n", 113766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison __func__, objname); 11380bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpiphp_check_bridge(bridge); 11390bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 11400bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade return AE_OK ; 11410bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade} 11420bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_bridge - handle ACPI event on bridges 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_bridge structure 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 114926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Handles ACPI event notification on {host,p2p} bridges. 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 11578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device; 11580bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade int num_sub_bridges = 0; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(handle, &device)) { 11618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* This bridge must have just been physically inserted */ 11628e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_bridge_insertion(handle, type); 11638e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11648e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11658e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11668e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 11670bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (type == ACPI_NOTIFY_BUS_CHECK) { 11680bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, 11692263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming count_sub_bridges, NULL, &num_sub_bridges, NULL); 11700bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 11710bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 11720bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (!bridge && !num_sub_bridges) { 11738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot get bridge info\n"); 11748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 118266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Bus check notify on %s\n", __func__, objname); 11830bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) { 11840bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade dbg("%s: re-enumerating slots under %s\n", 118566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison __func__, objname); 11860bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpiphp_check_bridge(bridge); 11870bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 11880bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (num_sub_bridges) 11890bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 11902263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check */ 119566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device check notify on %s\n", __func__, objname); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(bridge); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 120166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device wake notify on %s\n", __func__, objname); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 120666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device eject notify on %s\n", __func__, objname); 1207551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->type != BRIDGE_TYPE_HOST) && 1208551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro (bridge->flags & BRIDGE_HAS_EJ0)) { 1209551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_slot *slot; 1210551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro slot = bridge->func->slot; 1211551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (!acpiphp_disable_slot(slot)) 1212551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpiphp_eject_slot(slot); 1213551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_FREQUENCY_MISMATCH: 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a frequency mismatch\n", objname); 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_MODE_MISMATCH: 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a bus mode mismatch\n", objname); 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_POWER_FAULT: 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s has suffered a power fault\n", 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds objname); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_func structure 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 124326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Handles ACPI event notification on slots. 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12452b85e1307fe3a84eca2e1a21c6c857359908dab4Len Brownstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = (struct acpiphp_func *)context; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 125966bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Bus check notify on %s\n", __func__, objname); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_enable_slot(func->slot); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check : re-enumerate from parent bus */ 126566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device check notify on %s\n", __func__, objname); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(func->slot->bridge); 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 127166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device wake notify on %s\n", __func__, objname); 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 127666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device eject notify on %s\n", __func__, objname); 12778d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (!(acpiphp_disable_slot(func->slot))) 12788d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(func->slot); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic acpi_status 12898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahfind_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 12908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int *count = (int *)context; 12928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 1293275582031f9b3597a1b973f3ff617adfe639faa2Alexander Chiang if (acpi_is_root_bridge(handle)) { 12948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 12958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_hotplug_event_bridge, NULL); 12968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (*count)++; 12978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return AE_OK ; 12998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_pci_driver acpi_pci_hp_driver = { 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .add = add_bridge, 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = remove_bridge, 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_glue_init(void) 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13118e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int num = 0; 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13138e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 13142263576cfc6e8f6ab038126c3254404b9fcb1c33Lin Ming ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num <= 0) 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 13188e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 13198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_pci_register_driver(&acpi_pci_hp_driver); 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 132826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * This function frees all data allocated in acpiphp_glue_init(). 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1330031f30d2bc69f78cf542c0e5874a9d67c03d0ffeKristen Carlson Accardivoid acpiphp_glue_exit(void) 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_unregister_driver(&acpi_pci_hp_driver); 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_get_num_slots - count number of slots in a system 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_get_num_slots(void) 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 1342467c442f092e22acf86a3b4ad4863d097d7257daAkinobu Mita int num_slots = 0; 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134458c08628c4fe664bfd5f8b7e773b4b157bb9686fAlex Chiang list_for_each_entry(bridge, &bridge_list, list) { 134542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Bus %04x:%02x has %d slot%s\n", 134642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_domain_nr(bridge->pci_bus), 134742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus->number, bridge->nr_slots, 134842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->nr_slots == 1 ? "" : "s"); 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_slots += bridge->nr_slots; 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 135242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Total %d slots\n", num_slots); 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num_slots; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_for_each_slot - call function for each slot 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fn: callback function 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: context to be passed to callback function 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_for_each_slot(acpiphp_callback fn, void *data) 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *node; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (node, &bridge_list) { 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = (struct acpiphp_bridge *)node; 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = fn(slot, data); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_enable_slot - power on slot 138726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_enable_slot(struct acpiphp_slot *slot) 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13936aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_lock(&slot->crit_sect); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake up all functions */ 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_on_slot(slot); 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1400cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro if (get_slot_status(slot) == ACPI_STA_ALL) { 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* configure all functions */ 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = enable_device(slot); 1403cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro if (retval) 1404cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro power_off_slot(slot); 1405cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro } else { 140666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__); 1407cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro power_off_slot(slot); 1408cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro } 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 14116aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_unlock(&slot->crit_sect); 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_disable_slot - power off slot 141726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_disable_slot(struct acpiphp_slot *slot) 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14236aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_lock(&slot->crit_sect); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unconfigure all functions */ 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = disable_device(slot); 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* power off all functions */ 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_off_slot(slot); 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 14366aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_unlock(&slot->crit_sect); 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot enabled: 1 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot disabled: 0 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_power_status(struct acpiphp_slot *slot) 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14478d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return (slot->flags & SLOT_POWEREDON); 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 145235ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch open: 1 145335ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch closed: 0 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_latch_status(struct acpiphp_slot *slot) 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146135ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter presence : 1 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * absence : 0 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (sta == 0) ? 0 : 1; 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1477