acpiphp_glue.c revision e81995bb1c0077a312cb621abc406a36f65a986a
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); 55600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchistatic LIST_HEAD(ioapic_list); 56600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchistatic DEFINE_SPINLOCK(ioapic_list_lock); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MY_NAME "acpiphp_glue" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge (acpi_handle, u32, void *); 618e5dce35221850759671b2847a2e51030f7626bdKristen Accardistatic void acpiphp_sanitize_bus(struct pci_bus *bus); 62fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus); 632b85e1307fe3a84eca2e1a21c6c857359908dab4Len Brownstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); 648e5dce35221850759671b2847a2e51030f7626bdKristen Accardi 655a340ed87987c8c61dd9d1a8a5384dab1ace2566MUNEDA Takahiro/* callback routine to check for the existence of a pci dock device */ 664e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic acpi_status 674e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardiis_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) 684e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{ 694e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi int *count = (int *)context; 704e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 714e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(handle)) { 724e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi (*count)++; 734e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return AE_CTRL_TERMINATE; 744e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } else { 754e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return AE_OK; 764e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 774e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi} 784e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 794e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi/* 804e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * the _DCK method can do funny things... and sometimes not 814e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * hah-hah funny. 824e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * 834e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * TBD - figure out a way to only call fixups for 844e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * systems that require them. 854e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 864e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardistatic int post_dock_fixups(struct notifier_block *nb, unsigned long val, 874e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi void *v) 884e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi{ 894e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); 904e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi struct pci_bus *bus = func->slot->bridge->pci_bus; 914e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi u32 buses; 924e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 934e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (!bus->self) 944e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return NOTIFY_OK; 954e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 964e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* fixup bad _DCK function that rewrites 974e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * secondary bridge on slot 984e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 994e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi pci_read_config_dword(bus->self, 1004e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi PCI_PRIMARY_BUS, 1014e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi &buses); 1024e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1034e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (((buses >> 8) & 0xff) != bus->secondary) { 1044e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi buses = (buses & 0xff000000) 1052a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->primary) << 0) 1062a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->secondary) << 8) 1072a9d35219c593bdf46ec21f2b75a6370af7af1b0Alex Chiang | ((unsigned int)(bus->subordinate) << 16); 1084e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); 1094e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 1104e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi return NOTIFY_OK; 1114e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi} 1124e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1134e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 1141253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Listatic struct acpi_dock_ops acpiphp_dock_ops = { 1151253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li .handler = handle_hotplug_event_func, 1161253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li}; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to register each ACPI PCI slot object */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsregister_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *newfunc; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle tmp; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status = AE_OK; 12727663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long adr, sun; 128e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro int device, function, retval; 129e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige struct pci_bus *pbus = bridge->pci_bus; 1309d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang struct pci_dev *pdev; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13556ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett acpi_evaluate_integer(handle, "_ADR", NULL, &adr); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device = (adr >> 16) & 0xffff; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = adr & 0xffff; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 139f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!newfunc) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&newfunc->sibling); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->handle = handle; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->function = function; 14656ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett 14756ee325e25a0f76fc3267872867b3d70af179aadMatthew Garrett if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) 14820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags = FUNC_HAS_EJ0; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_STA; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS0; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS3; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1594e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) 16020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags |= FUNC_HAS_DCK; 16120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 16395b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi if (ACPI_FAILURE(status)) { 16495b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi /* 16595b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi * use the count of the number of slots we've found 16695b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi * for the number of the slot 16795b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi */ 16895b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi sun = bridge->nr_slots+1; 16995b38b3f453c16de0f8cddcde3e71050bbfb37b9Kristen Accardi } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search for objects that share the same slot */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->device == device) { 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->sun != sun) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("sibling found, but _SUN doesn't match!\n"); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 180f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(newfunc); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->bridge = bridge; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->device = device; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->sun = sun; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&slot->funcs); 1906aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_init(&slot->crit_sect); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->next = bridge->slots; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->slots = slot; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->nr_slots++; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 197b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", 198e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige slot->sun, pci_domain_nr(pbus), pbus->number, device); 199e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro retval = acpiphp_register_hotplug_slot(slot); 200e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro if (retval) { 201f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang if (retval == -EBUSY) 202b6adc1955d31515be6631e63b1fe4bcdcd41db77Justin Chen warn("Slot %llu already registered by another " 203f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang "hotplug driver\n", slot->sun); 204f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang else 205f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang warn("acpiphp_register_hotplug_slot failed " 206f46753c5e354b857b20ab8e0fe7b2579831dc369Alex Chiang "(err code = 0x%x)\n", retval); 207e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro goto err_exit; 208e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro } 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->slot = slot; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&newfunc->sibling, &slot->funcs); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2149d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); 2159d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 2179d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(pdev); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2204e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(handle)) { 2214e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* we don't want to call this device's _EJ0 2224e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * because we want the dock notify handler 2234e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * to call it after it calls _DCK 22420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi */ 22520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi newfunc->flags &= ~FUNC_HAS_EJ0; 2264e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (register_hotplug_dock_device(handle, 2271253f7aabfebc51446dbec5c8895c5c8846dfe06Shaohua Li &acpiphp_dock_ops, newfunc)) 2284e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi dbg("failed to register dock device\n"); 2294e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi 2304e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi /* we need to be notified when dock events happen 2314e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * outside of the hotplug operation, since we may 2324e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi * need to do fixups before we can hotplug. 2334e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi */ 2344e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi newfunc->nb.notifier_call = post_dock_fixups; 2354e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (register_dock_notifier(&newfunc->nb)) 2364e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi dbg("failed to register a dock notifier"); 23720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 23820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 24020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!(newfunc->flags & FUNC_HAS_DCK)) { 24120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = acpi_install_notify_handler(handle, 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_func, 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ACPI_FAILURE(status)) 24720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi err("failed to register interrupt notify handler\n"); 24820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } else 24920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = AE_OK; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi return status; 252e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 253e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro err_exit: 254e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro bridge->nr_slots--; 255e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro bridge->slots = slot->next; 256e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro kfree(slot); 257e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro kfree(newfunc); 258e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 259e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro return AE_OK; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* see if it's worth looking at this bridge */ 2646edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic int detect_ejectable_slots(acpi_handle handle) 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2667f53866932fd08add06ee2f93ead129949158490Alex Chiang int found = acpi_pci_detect_ejectable(handle); 267e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige if (!found) { 2686edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 269e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige is_pci_dock_device, (void *)&found, NULL); 270e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige } 271e8c331e963c58b83db24b7d0e39e8c07f687dbc6Kenji Kaneshige return found; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_bridge_misc(struct acpiphp_bridge *bridge) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 279e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro /* must be added to the list prior to calling register_slot */ 280e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_add(&bridge->list, &bridge_list); 281e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register all slot objects under this bridge */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_slot, bridge, NULL); 285e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro if (ACPI_FAILURE(status)) { 286e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_del(&bridge->list); 287e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro return; 288e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro } 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 2918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->type != BRIDGE_TYPE_HOST) { 292551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { 293551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = acpi_remove_notify_handler(bridge->func->handle, 294551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ACPI_SYSTEM_NOTIFY, 295551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro handle_hotplug_event_func); 296551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 297551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro err("failed to remove notify handler\n"); 298551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 2998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah status = acpi_install_notify_handler(bridge->handle, 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_bridge, 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (ACPI_FAILURE(status)) { 3058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("failed to register interrupt notify handler\n"); 3068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro/* find acpiphp_func from acpiphp_bridge */ 312551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) 313551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{ 314551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct list_head *node, *l; 315551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_bridge *bridge; 316551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_slot *slot; 317551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_func *func; 318551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 319551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro list_for_each(node, &bridge_list) { 320551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge = list_entry(node, struct acpiphp_bridge, list); 321551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro for (slot = bridge->slots; slot; slot = slot->next) { 322551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro list_for_each(l, &slot->funcs) { 323551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func = list_entry(l, struct acpiphp_func, 324551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro sibling); 325551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (func->handle == handle) 326551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return func; 327551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 328551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 329551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 330551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 331551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return NULL; 332551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro} 333551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 334551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 335551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahirostatic inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) 336551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro{ 337551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_handle dummy_handle; 338551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 339551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 340551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_STA", &dummy_handle))) 341551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_STA; 342551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 343551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 344551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_EJ0", &dummy_handle))) 345551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_EJ0; 346551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 347551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 348551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_PS0", &dummy_handle))) 349551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_PS0; 350551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 351551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, 352551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro "_PS3", &dummy_handle))) 353551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->flags |= BRIDGE_HAS_PS3; 354551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 355551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* is this ejectable p2p bridge? */ 356551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (bridge->flags & BRIDGE_HAS_EJ0) { 357551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_func *func; 358551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 359551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro dbg("found ejectable p2p bridge\n"); 360551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 361551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* make link between PCI bridge and PCI function */ 362551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func = acpiphp_bridge_handle_to_function(bridge->handle); 363551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (!func) 364551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro return; 365551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->func = func; 366551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func->bridge = bridge; 367551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 368551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro} 369551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 370551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize host bridge data structure */ 3726edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_host_bridge(acpi_handle *handle) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3756edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang struct acpi_pci_root *root = acpi_pci_find_root(handle); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 377f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_HOST; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3846edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_bus = root->bus; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize PCI-to-PCI bridge data structure */ 3936edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiangstatic void add_p2p_bridge(acpi_handle *handle) 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 397f5afe8064f3087bead8fea7e32547c2a3ada5fd0Eric Sesterhenn bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("out of memory\n"); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_P2P; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 405551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro config_p2p_bridge_flags(bridge); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4076edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_dev = acpi_get_pci_dev(handle); 4086edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang bridge->pci_bus = bridge->pci_dev->subordinate; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bridge->pci_bus) { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("This is not a PCI-to-PCI bridge!\n"); 41142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto err; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4145d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang /* 4155d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * Grab a ref to the subordinate PCI bus in case the bus is 4165d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * removed via PCI core logical hotplug. The ref pins the bus 4175d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * (which we access during module unload). 4185d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang */ 4195d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang get_device(&bridge->pci_bus->dev); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 42342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 42442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err: 4256edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang pci_dev_put(bridge->pci_dev); 42642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 42742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to find P2P bridges */ 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfind_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4386edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang dev = acpi_get_pci_dev(handle); 43942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (!dev || !dev->subordinate) 44042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto out; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4436edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang if ((detect_ejectable_slots(handle) > 0)) { 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 4456edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang add_p2p_bridge(handle); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4487c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige /* search P2P bridges under this p2p bridge */ 4497c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 4506edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang find_p2p_bridge, NULL, NULL); 4517c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige if (ACPI_FAILURE(status)) 452551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", status); 4537c8f25da12a3dda46fb730699582895d5fc51287Kenji Kaneshige 45442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah out: 45542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* find hot-pluggable slots, and then find P2P bridge */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int add_bridge(acpi_handle handle) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 46427663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long tmp; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle dummy_handle; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if the bridge doesn't have _STA, we assume it is always there */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_STA", &dummy_handle); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status)) { 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 47266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: _STA evaluation failure\n", __func__); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tmp & ACPI_STA_FUNCTIONING) == 0) 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't register this object */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4816edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang if (detect_ejectable_slots(handle) > 0) { 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI host-bus bridge with hot-pluggable slots\n"); 4836edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang add_host_bridge(handle); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search P2P bridges under this host bridge */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 4886edd7679db92376ca54f328d6b0f12291c2dab35Alex Chiang find_p2p_bridge, NULL, NULL); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 491551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", status); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) 49742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah{ 49842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct list_head *head; 49942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each(head, &bridge_list) { 50042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_bridge *bridge = list_entry(head, 50142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_bridge, list); 50242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (bridge->handle == handle) 50342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return bridge; 50442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 50542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 50642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return NULL; 50742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 509364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void cleanup_bridge(struct acpiphp_bridge *bridge) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 51142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct list_head *list, *tmp; 51242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_slot *slot; 51342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah acpi_status status; 514364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah acpi_handle handle = bridge->handle; 51542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 51642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 51742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_bridge); 51842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (ACPI_FAILURE(status)) 51942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err("failed to remove notify handler\n"); 52042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 521551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->type != BRIDGE_TYPE_HOST) && 522551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { 523551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = acpi_install_notify_handler(bridge->func->handle, 524551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro ACPI_SYSTEM_NOTIFY, 525551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro handle_hotplug_event_func, 526551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro bridge->func); 527551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 528551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro err("failed to install interrupt notify handler\n"); 529551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 530551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 53142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = bridge->slots; 53242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah while (slot) { 53342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_slot *next = slot->next; 53442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each_safe (list, tmp, &slot->funcs) { 53542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_func *func; 53642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah func = list_entry(list, struct acpiphp_func, sibling); 5374e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi if (is_dock_device(func->handle)) { 5384e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi unregister_hotplug_dock_device(func->handle); 5394e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi unregister_dock_notifier(&func->nb); 5404e8662bbd680c54496189ac68f398e847f3ca374Kristen Accardi } 54120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!(func->flags & FUNC_HAS_DCK)) { 54220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi status = acpi_remove_notify_handler(func->handle, 54342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah ACPI_SYSTEM_NOTIFY, 54442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_func); 54520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ACPI_FAILURE(status)) 54620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi err("failed to remove notify handler\n"); 54720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 54842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_del(list); 54942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(func); 55042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 551e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro acpiphp_unregister_hotplug_slot(slot); 552e27da3814170385a4d2797397d706e554635812dMUNEDA Takahiro list_del(&slot->funcs); 55342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(slot); 55442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = next; 55542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 55642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 5575d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang /* 5585d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang * Only P2P bridges have a pci_dev 5595d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang */ 5605d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang if (bridge->pci_dev) 5615d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang put_device(&bridge->pci_bus->dev); 5625d4a4b25ddc3e864d3a562c024bebdc922118854Alex Chiang 56342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(bridge->pci_dev); 56442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_del(&bridge->list); 56542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 568364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic acpi_status 569364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahcleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 570364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 571364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 572364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 573551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this P2P bridge 574551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro in a depth-first manner */ 575551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 576551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro cleanup_p2p_bridge, NULL, NULL); 577551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 578a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang bridge = acpiphp_handle_to_bridge(handle); 579a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang if (bridge) 580a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang cleanup_bridge(bridge); 581a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang 582364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah return AE_OK; 583364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 584364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 585364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void remove_bridge(acpi_handle handle) 586364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 587364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 588364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 589551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this host bridge 590551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro in a depth-first manner */ 591551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 592551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro (u32)1, cleanup_p2p_bridge, NULL, NULL); 593551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 594a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang /* 595a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * On root bridges with hotplug slots directly underneath (ie, 596a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * no p2p bridge inbetween), we call cleanup_bridge(). 597a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * 598a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * The else clause cleans up root bridges that either had no 599a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang * hotplug slots at all, or had a p2p bridge underneath. 600a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang */ 601364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 602551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (bridge) 603364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah cleanup_bridge(bridge); 604a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang else 605a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 606a13307cef8bf51990ef1d525b1cbdcc2cfe07e2aAlex Chiang handle_hotplug_event_bridge); 607364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 609a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic struct pci_dev * get_apic_pci_info(acpi_handle handle) 610a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 611a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct pci_dev *dev; 612a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 613d6aa484c1c0cd39ff3a42f4050b55d2a5b285ef5Alexander Chiang dev = acpi_get_pci_dev(handle); 614a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (!dev) 615a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 616a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 617a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && 618a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) 619a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige { 620a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_dev_put(dev); 621a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 622a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 623a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 624a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return dev; 625a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 626a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 627a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic int get_gsi_base(acpi_handle handle, u32 *gsi_base) 628a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 629a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_status status; 630a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige int result = -1; 63127663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long gsb; 632a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 633a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige union acpi_object *obj; 634a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige void *table; 635a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 636a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); 637a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status)) { 638a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige *gsi_base = (u32)gsb; 639a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return 0; 640a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 641a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 642a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); 643a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) 644a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return -1; 645a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 646a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige obj = buffer.pointer; 647a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (obj->type != ACPI_TYPE_BUFFER) 648a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige goto out; 649a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 650a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige table = obj->buffer.pointer; 65115a58ed12142939d51076380e6e58af477ad96ecAlexey Starikovskiy switch (((struct acpi_subtable_header *)table)->type) { 65215a58ed12142939d51076380e6e58af477ad96ecAlexey Starikovskiy case ACPI_MADT_TYPE_IO_SAPIC: 65315a58ed12142939d51076380e6e58af477ad96ecAlexey Starikovskiy *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base; 654a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige result = 0; 655a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 65615a58ed12142939d51076380e6e58af477ad96ecAlexey Starikovskiy case ACPI_MADT_TYPE_IO_APIC: 65715a58ed12142939d51076380e6e58af477ad96ecAlexey Starikovskiy *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base; 658a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige result = 0; 659a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 660a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige default: 661a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 662a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 663a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige out: 66481b26bcacd5df0f65344fb430b1bf7fe9cfbfe2aKristen Accardi kfree(buffer.pointer); 665a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return result; 666a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 667a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 668a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic acpi_status 669a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigeioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) 670a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 671a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_status status; 67227663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta; 673a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_handle tmp; 674a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct pci_dev *pdev; 675a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige u32 gsi_base; 676a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige u64 phys_addr; 677600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi struct acpiphp_ioapic *ioapic; 678a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 679a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige /* Evaluate _STA if present */ 680a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 681a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) 682a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_CTRL_DEPTH; 683a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 684a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige /* Scan only PCI bus scope */ 685a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_get_handle(handle, "_HID", &tmp); 686a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status)) 687a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_CTRL_DEPTH; 688a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 689a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (get_gsi_base(handle, &gsi_base)) 690a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 691a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 692600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL); 693600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (!ioapic) 694600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_NO_MEMORY; 695600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 696a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pdev = get_apic_pci_info(handle); 697a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (!pdev) 698600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi goto exit_kfree; 699a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 700600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (pci_enable_device(pdev)) 701600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi goto exit_pci_dev_put; 702a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 703a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_set_master(pdev); 704a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 705600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) 706600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi goto exit_pci_disable_device; 707a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 708a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige phys_addr = pci_resource_start(pdev, 0); 709600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (acpi_register_ioapic(handle, phys_addr, gsi_base)) 710600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi goto exit_pci_release_region; 711600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 712600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ioapic->gsi_base = gsi_base; 713600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ioapic->dev = pdev; 714600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi spin_lock(&ioapic_list_lock); 715600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi list_add_tail(&ioapic->list, &ioapic_list); 716600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi spin_unlock(&ioapic_list_lock); 717600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 718600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_OK; 719600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 720600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi exit_pci_release_region: 721600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_release_region(pdev, 0); 722600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi exit_pci_disable_device: 723600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_disable_device(pdev); 724600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi exit_pci_dev_put: 725600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_dev_put(pdev); 726600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi exit_kfree: 727600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi kfree(ioapic); 728600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 729600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_OK; 730600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi} 731600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 732600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchistatic acpi_status 733600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchiioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv) 734600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi{ 735600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi acpi_status status; 73627663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta; 737600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi acpi_handle tmp; 738600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi u32 gsi_base; 739600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi struct acpiphp_ioapic *pos, *n, *ioapic = NULL; 740600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 741600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi /* Evaluate _STA if present */ 742600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 743600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) 744600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_CTRL_DEPTH; 745600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 746600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi /* Scan only PCI bus scope */ 747600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi status = acpi_get_handle(handle, "_HID", &tmp); 748600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (ACPI_SUCCESS(status)) 749600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_CTRL_DEPTH; 750600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 751600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (get_gsi_base(handle, &gsi_base)) 752a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 753600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 754600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi acpi_unregister_ioapic(handle, gsi_base); 755600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 756600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi spin_lock(&ioapic_list_lock); 757600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi list_for_each_entry_safe(pos, n, &ioapic_list, list) { 758600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (pos->gsi_base != gsi_base) 759600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi continue; 760600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ioapic = pos; 761600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi list_del(&ioapic->list); 762600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi break; 763a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 764600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi spin_unlock(&ioapic_list_lock); 765600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 766600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi if (!ioapic) 767600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return AE_OK; 768600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 769600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_release_region(ioapic->dev, 0); 770600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_disable_device(ioapic->dev); 771600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi pci_dev_put(ioapic->dev); 772600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi kfree(ioapic); 773a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 774a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 775a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 776a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 777a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic int acpiphp_configure_ioapics(acpi_handle handle) 778a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 7799b1d19ee86746618a8b43d2aaef8319c01af1514Satoru Takeuchi ioapic_add(handle, 0, NULL, NULL); 780a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 781a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige ACPI_UINT32_MAX, ioapic_add, NULL, NULL); 782a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return 0; 783a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 784a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 785600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchistatic int acpiphp_unconfigure_ioapics(acpi_handle handle) 786600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi{ 787600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ioapic_remove(handle, 0, NULL, NULL); 788600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 789600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi ACPI_UINT32_MAX, ioapic_remove, NULL, NULL); 790600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi return 0; 791600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi} 792600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_on_slot(struct acpiphp_slot *slot) 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already enabled, just skip */ 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_POWEREDON) 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_PS0) { 80866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: executing _PS0\n", __func__); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 81166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _PS0 failed\n", __func__); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is enabled */ 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_POWEREDON; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_off_slot(struct acpiphp_slot *slot) 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already disabled, just skip */ 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slot->flags & SLOT_POWEREDON) == 0) 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8432f523b15901f654a9448bbd47ebe1e783ec3195bRajesh Shah if (func->flags & FUNC_HAS_PS3) { 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 84666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _PS3 failed\n", __func__); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is disabled */ 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_POWEREDON); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 86415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/** 86526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * acpiphp_max_busnr - return the highest reserved bus number under the given bus. 86615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @bus: bus to start search with 86715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 86815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic unsigned char acpiphp_max_busnr(struct pci_bus *bus) 86915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{ 87015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi struct list_head *tmp; 87115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi unsigned char max, n; 87215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 87315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi /* 87415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * pci_bus_max_busnr will return the highest 87515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * reserved busnr for all these children. 87615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * that is equivalent to the bus->subordinate 87715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * value. We don't want to use the parent's 87815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * bus->subordinate value because it could have 87915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * padding in it. 88015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 88115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = bus->secondary; 88215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 88315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi list_for_each(tmp, &bus->children) { 88415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi n = pci_bus_max_busnr(pci_bus_b(tmp)); 88515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi if (n > max) 88615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = n; 88715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 88815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi return max; 88915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi} 89015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 89115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 89215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi/** 89315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * acpiphp_bus_add - add a new bus to acpi subsystem 89415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * @func: acpiphp_func of the bridge 89515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 89615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardistatic int acpiphp_bus_add(struct acpiphp_func *func) 89715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi{ 89815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi acpi_handle phandle; 89915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi struct acpi_device *device, *pdevice; 90015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi int ret_val; 90115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 90215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi acpi_get_parent(func->handle, &phandle); 90315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi if (acpi_bus_get_device(phandle, &pdevice)) { 90415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi dbg("no parent device, assuming NULL\n"); 90515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi pdevice = NULL; 90615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 90720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (!acpi_bus_get_device(func->handle, &device)) { 90820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("bus exists... trim\n"); 90920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi /* this shouldn't be in here, so remove 91020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi * the bus then re-add it... 91120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi */ 91220416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ret_val = acpi_bus_trim(device, 1); 91320416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("acpi_bus_trim return %x\n", ret_val); 91420416ea54087c25502d6fb973b8e119973e16341Kristen Accardi } 91520416ea54087c25502d6fb973b8e119973e16341Kristen Accardi 91620416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ret_val = acpi_bus_add(&device, pdevice, func->handle, 91720416ea54087c25502d6fb973b8e119973e16341Kristen Accardi ACPI_BUS_TYPE_DEVICE); 91820416ea54087c25502d6fb973b8e119973e16341Kristen Accardi if (ret_val) { 91920416ea54087c25502d6fb973b8e119973e16341Kristen Accardi dbg("error adding bus, %x\n", 92020416ea54087c25502d6fb973b8e119973e16341Kristen Accardi -ret_val); 92120416ea54087c25502d6fb973b8e119973e16341Kristen Accardi goto acpiphp_bus_add_out; 92215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi } 92315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi /* 92415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * try to start anyway. We could have failed to add 92515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * simply because this bus had previously been added 92615a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * on another add. Don't bother with the return value 92715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi * we just keep going. 92815a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi */ 92915a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi ret_val = acpi_bus_start(device); 93015a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 93115a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardiacpiphp_bus_add_out: 93215a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi return ret_val; 93315a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi} 93415a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 93515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 93692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro/** 93792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * acpiphp_bus_trim - trim a bus from acpi subsystem 93892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro * @handle: handle to acpi namespace 93992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro */ 9406d47a5e4c3f8b6458002065d98a9cc6ff90fb597Adrian Bunkstatic int acpiphp_bus_trim(acpi_handle handle) 94192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro{ 94292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro struct acpi_device *device; 94392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro int retval; 94492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 94592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro retval = acpi_bus_get_device(handle, &device); 94692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (retval) { 94792c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro dbg("acpi_device not found\n"); 94892c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro return retval; 94992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro } 95092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 95192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro retval = acpi_bus_trim(device, 1); 95292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (retval) 95392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro err("cannot remove from acpi list\n"); 95492c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 95592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro return retval; 95692c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro} 95715a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable_device - enable, configure a slot 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: slot to be enabled 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function should be called per *physical slot*, 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not per each slot object in ACPI namespace. 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9650ab2b57f8db8a1bcdf24089074f5d2856a3ffb42Sam Ravnborgstatic int __ref enable_device(struct acpiphp_slot *slot) 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 96842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *bus = slot->bridge->pci_bus; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 97242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah int num, max, pass; 973551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpi_status status; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* sanity check: dev should be NULL when hot-plugged in */ 97942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This case shouldn't happen */ 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("pci_dev structure already exists.\n"); 98342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); 98942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (num == 0) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("No new device found\n"); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 99515a1ae74879925d0d3f71ebc3f56d0a2c5db393aKristen Accardi max = acpiphp_max_busnr(bus); 99642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah for (pass = 0; pass < 2; pass++) { 99742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 99842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (PCI_SLOT(dev->devfn) != slot->device) 99942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah continue; 100042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || 1001c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { 100242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah max = pci_scan_bridge(bus, dev, max, pass); 100392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro if (pass && dev->subordinate) 1004c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi pci_bus_size_bridges(dev->subordinate); 1005c64b5eead93f9d3a8ca0e9ca0ffba0b99dc565b9Kristen Accardi } 100642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100992c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro list_for_each (l, &slot->funcs) { 101092c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro func = list_entry(l, struct acpiphp_func, sibling); 101192c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro acpiphp_bus_add(func); 101292c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro } 101392c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro 101442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_assign_resources(bus); 10158e5dce35221850759671b2847a2e51030f7626bdKristen Accardi acpiphp_sanitize_bus(bus); 1016fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas acpiphp_set_hpp_values(bus); 10179b1d19ee86746618a8b43d2aaef8319c01af1514Satoru Takeuchi list_for_each_entry(func, &slot->funcs, sibling) 10189b1d19ee86746618a8b43d2aaef8319c01af1514Satoru Takeuchi acpiphp_configure_ioapics(func->handle); 10198e5dce35221850759671b2847a2e51030f7626bdKristen Accardi pci_enable_bridges(bus); 102042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_add_devices(bus); 102142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 10249d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 10259d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang func->function)); 10269d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (!dev) 1027551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro continue; 1028551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 10299d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && 10309d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { 10319d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(dev); 1032551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro continue; 10339d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang } 1034551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 1035551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); 1036551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (ACPI_FAILURE(status)) 1037551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro warn("find_p2p_bridge failed (error code = 0x%x)\n", 1038551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro status); 10399d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(dev); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_ENABLED; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1048d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchistatic void disable_bridges(struct pci_bus *bus) 1049d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi{ 1050d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi struct pci_dev *dev; 1051d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi list_for_each_entry(dev, &bus->devices, bus_list) { 1052d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi if (dev->subordinate) { 1053d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi disable_bridges(dev->subordinate); 1054d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi pci_disable_device(dev); 1055d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 1056d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 1057d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi} 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable_device - disable a slot 106126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int disable_device(struct acpiphp_slot *slot) 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 10669d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang struct pci_dev *pdev; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* is this slot already disabled? */ 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(slot->flags & SLOT_ENABLED)) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10729d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 1073551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (func->bridge) { 1074551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro /* cleanup p2p bridges under this P2P bridge */ 1075551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro cleanup_p2p_bridge(func->bridge->handle, 1076551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro (u32)1, NULL, NULL); 1077551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro func->bridge = NULL; 1078551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 1079551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro 10809d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pdev = pci_get_slot(slot->bridge->pci_bus, 10819d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang PCI_DEVFN(slot->device, func->function)); 10829d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev) { 10839d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_stop_bus_device(pdev); 10849d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang if (pdev->subordinate) { 10859d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang disable_bridges(pdev->subordinate); 10869d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_disable_device(pdev); 1087d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 10889d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_remove_bus_device(pdev); 10899d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang pci_dev_put(pdev); 1090d5cdb67236dba94496de052c9f9f431e1fc658f4Satoru Takeuchi } 1091600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi } 1092600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi 10939d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang list_for_each_entry(func, &slot->funcs, sibling) { 1094600812ecead0da2e7b6f9e5f5aad68b1ad8ae581Satoru Takeuchi acpiphp_unconfigure_ioapics(func->handle); 109592c9be95549632da09088320f202fa5c05b21ddfMUNEDA Takahiro acpiphp_bus_trim(func->handle); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_ENABLED); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11009d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiangerr_exit: 11019d911d7903926a65ef49ec671bacd86bcee5eb51Alex Chiang return 0; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_slot_status - get ACPI slot status 110726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 110926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot has _STA for each function and if any one of them 111026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * returned non-zero status, return it. 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111226e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * If a slot doesn't have _STA and if any one of its functions' 111326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * configuration space is configured, return 0x0f as a _STA. 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Otherwise return 0. 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_slot_status(struct acpiphp_slot *slot) 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 112027663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta = 0; 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dvid; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_STA) { 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status) && sta) 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_bus_read_config_dword(slot->bridge->pci_bus, 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVFN(slot->device, 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func->function), 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_VENDOR_ID, &dvid); 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvid != 0xffffffff) { 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = ACPI_STA_ALL; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (unsigned int)sta; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11488d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah * acpiphp_eject_slot - physically eject the slot 114926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 11508d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah */ 1151bfceafc5979d9055e04f03f970de6ff7a4bce1b6Gary Hadeint acpiphp_eject_slot(struct acpiphp_slot *slot) 11528d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah{ 11538d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpi_status status; 11548d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpiphp_func *func; 11558d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct list_head *l; 11568d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpi_object_list arg_list; 11578d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah union acpi_object arg; 11588d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 11598d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah list_for_each (l, &slot->funcs) { 11608d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah func = list_entry(l, struct acpiphp_func, sibling); 11618d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 11628d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* We don't want to call _EJ0 on non-existing functions. */ 11638d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if ((func->flags & FUNC_HAS_EJ0)) { 11648d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* _EJ0 method take one argument */ 11658d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.count = 1; 11668d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.pointer = &arg; 11678d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.type = ACPI_TYPE_INTEGER; 11688d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.integer.value = 1; 11698d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 11708d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); 11718d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (ACPI_FAILURE(status)) { 117266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison warn("%s: _EJ0 failed\n", __func__); 11738d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return -1; 11748d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else 11758d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah break; 11768d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 11778d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 11788d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return 0; 11798d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah} 11808d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 11818d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah/** 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_check_bridge - re-enumerate devices 118326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @bridge: where to begin re-enumeration 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate over all slots under this bridge and make sure that if a 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card is present they are enabled, and if not they are disabled. 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_check_bridge(struct acpiphp_bridge *bridge) 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int enabled, disabled; 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled = disabled = 0; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status = get_slot_status(slot); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) { 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == ACPI_STA_ALL) 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_disable_slot(slot); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in disabling\n"); 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 12058d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else { 12068d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(slot); 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disabled++; 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != ACPI_STA_ALL) 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_enable_slot(slot); 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in enabling\n"); 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled++; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled); 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1227fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaasstatic void acpiphp_set_hpp_values(struct pci_bus *bus) 12288e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12298e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 12308e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 1231e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas list_for_each_entry(dev, &bus->devices, bus_list) 1232e81995bb1c0077a312cb621abc406a36f65a986aBjorn Helgaas pci_configure_slot(dev); 12338e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 12348e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12358e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* 12368e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Remove devices for which we could not assign resources, call 12378e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * arch specific code to fix-up the bus 12388e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah */ 12398e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void acpiphp_sanitize_bus(struct pci_bus *bus) 12408e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12418e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 12428e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int i; 12438e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; 12448e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12458e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 12468e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { 12478e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct resource *res = &dev->resource[i]; 12488e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((res->flags & type_mask) && !res->start && 12498e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah res->end) { 12508e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* Could not assign a required resources 12518e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * for this device, remove it */ 12528e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_remove_bus_device(dev); 12538e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah break; 12548e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12558e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12568e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 12588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12598e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* Program resources in newly inserted bridge */ 12608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic int acpiphp_configure_bridge (acpi_handle handle) 12618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12627f53866932fd08add06ee2f93ead129949158490Alex Chiang struct pci_bus *bus; 12637f53866932fd08add06ee2f93ead129949158490Alex Chiang 12647f53866932fd08add06ee2f93ead129949158490Alex Chiang if (acpi_is_root_bridge(handle)) { 12657f53866932fd08add06ee2f93ead129949158490Alex Chiang struct acpi_pci_root *root = acpi_pci_find_root(handle); 12667f53866932fd08add06ee2f93ead129949158490Alex Chiang bus = root->bus; 12677f53866932fd08add06ee2f93ead129949158490Alex Chiang } else { 12687f53866932fd08add06ee2f93ead129949158490Alex Chiang struct pci_dev *pdev = acpi_get_pci_dev(handle); 12697f53866932fd08add06ee2f93ead129949158490Alex Chiang bus = pdev->subordinate; 12707f53866932fd08add06ee2f93ead129949158490Alex Chiang pci_dev_put(pdev); 12717f53866932fd08add06ee2f93ead129949158490Alex Chiang } 12728e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_size_bridges(bus); 12748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_assign_resources(bus); 12758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpiphp_sanitize_bus(bus); 1276fca6825ad7382ae9df8ecda9068ac13ee9e343f4Bjorn Helgaas acpiphp_set_hpp_values(bus); 12778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_enable_bridges(bus); 1278a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpiphp_configure_ioapics(handle); 12798e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 0; 12808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 12818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void handle_bridge_insertion(acpi_handle handle, u32 type) 12838e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12848e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device, *pdevice; 12858e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_handle phandle; 12868e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((type != ACPI_NOTIFY_BUS_CHECK) && 12888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (type != ACPI_NOTIFY_DEVICE_CHECK)) { 12898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("unexpected notification type %d\n", type); 12908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 12918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_get_parent(handle, &phandle); 12948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(phandle, &pdevice)) { 12958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah dbg("no parent device, assuming NULL\n"); 12968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pdevice = NULL; 12978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { 12998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot add bridge to acpi list\n"); 13008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 13018e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 13028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!acpiphp_configure_bridge(handle) && 13038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah !acpi_bus_start(device)) 13048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah add_bridge(handle); 13058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 13068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot configure and start bridge\n"); 13078e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 13088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 13098e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI event handlers 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13140bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status 13150bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecount_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 13160bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{ 13170bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade int *count = (int *)context; 13180bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpiphp_bridge *bridge; 13190bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 13200bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade bridge = acpiphp_handle_to_bridge(handle); 13210bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) 13220bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade (*count)++; 13230bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade return AE_OK ; 13240bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade} 13250bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 13260bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadestatic acpi_status 13270bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hadecheck_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 13280bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade{ 13290bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpiphp_bridge *bridge; 13300bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade char objname[64]; 13310bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade struct acpi_buffer buffer = { .length = sizeof(objname), 13320bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade .pointer = objname }; 13330bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 13340bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade bridge = acpiphp_handle_to_bridge(handle); 13350bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) { 13360bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 13370bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade dbg("%s: re-enumerating slots under %s\n", 133866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison __func__, objname); 13390bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpiphp_check_bridge(bridge); 13400bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 13410bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade return AE_OK ; 13420bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade} 13430bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_bridge - handle ACPI event on bridges 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_bridge structure 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 135026e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Handles ACPI event notification on {host,p2p} bridges. 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 13588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device; 13590bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade int num_sub_bridges = 0; 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(handle, &device)) { 13628e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* This bridge must have just been physically inserted */ 13638e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_bridge_insertion(handle, type); 13648e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 13658e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 13668e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 13678e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 13680bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (type == ACPI_NOTIFY_BUS_CHECK) { 13690bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, 13700bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade count_sub_bridges, &num_sub_bridges, NULL); 13710bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 13720bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade 13730bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (!bridge && !num_sub_bridges) { 13748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot get bridge info\n"); 13758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 13768e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 138366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Bus check notify on %s\n", __func__, objname); 13840bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (bridge) { 13850bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade dbg("%s: re-enumerating slots under %s\n", 138666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison __func__, objname); 13870bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpiphp_check_bridge(bridge); 13880bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade } 13890bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade if (num_sub_bridges) 13900bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 13910bbd6424c55f0ab9e7fcd6a851bc49e265259ff5Gary Hade ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL); 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check */ 139666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device check notify on %s\n", __func__, objname); 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(bridge); 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 140266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device wake notify on %s\n", __func__, objname); 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 140766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device eject notify on %s\n", __func__, objname); 1408551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if ((bridge->type != BRIDGE_TYPE_HOST) && 1409551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro (bridge->flags & BRIDGE_HAS_EJ0)) { 1410551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro struct acpiphp_slot *slot; 1411551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro slot = bridge->func->slot; 1412551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro if (!acpiphp_disable_slot(slot)) 1413551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro acpiphp_eject_slot(slot); 1414551bcb75b3d9f23348a524210ccfff26d865e425MUNEDA Takahiro } 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_FREQUENCY_MISMATCH: 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a frequency mismatch\n", objname); 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_MODE_MISMATCH: 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a bus mode mismatch\n", objname); 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_POWER_FAULT: 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s has suffered a power fault\n", 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds objname); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_func structure 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 144426e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Handles ACPI event notification on slots. 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14462b85e1307fe3a84eca2e1a21c6c857359908dab4Len Brownstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = (struct acpiphp_func *)context; 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 146066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Bus check notify on %s\n", __func__, objname); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_enable_slot(func->slot); 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check : re-enumerate from parent bus */ 146666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device check notify on %s\n", __func__, objname); 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(func->slot->bridge); 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 147266bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device wake notify on %s\n", __func__, objname); 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 147766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Device eject notify on %s\n", __func__, objname); 14788d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (!(acpiphp_disable_slot(func->slot))) 14798d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(func->slot); 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 14898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic acpi_status 14908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahfind_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 14918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 14928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int *count = (int *)context; 14938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 1494275582031f9b3597a1b973f3ff617adfe639faa2Alexander Chiang if (acpi_is_root_bridge(handle)) { 14958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 14968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_hotplug_event_bridge, NULL); 14978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (*count)++; 14988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 14998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return AE_OK ; 15008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_pci_driver acpi_pci_hp_driver = { 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .add = add_bridge, 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = remove_bridge, 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_glue_init(void) 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int num = 0; 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15148e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 15158e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah ACPI_UINT32_MAX, find_root_bridges, &num, NULL); 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num <= 0) 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 15198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 15208e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_pci_register_driver(&acpi_pci_hp_driver); 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 152926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * This function frees all data allocated in acpiphp_glue_init(). 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1531031f30d2bc69f78cf542c0e5874a9d67c03d0ffeKristen Carlson Accardivoid acpiphp_glue_exit(void) 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_unregister_driver(&acpi_pci_hp_driver); 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_get_num_slots - count number of slots in a system 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_get_num_slots(void) 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 1543467c442f092e22acf86a3b4ad4863d097d7257daAkinobu Mita int num_slots = 0; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1545467c442f092e22acf86a3b4ad4863d097d7257daAkinobu Mita list_for_each_entry (bridge, &bridge_list, list) { 154642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Bus %04x:%02x has %d slot%s\n", 154742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_domain_nr(bridge->pci_bus), 154842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus->number, bridge->nr_slots, 154942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->nr_slots == 1 ? "" : "s"); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_slots += bridge->nr_slots; 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 155342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Total %d slots\n", num_slots); 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num_slots; 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_for_each_slot - call function for each slot 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fn: callback function 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: context to be passed to callback function 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_for_each_slot(acpiphp_callback fn, void *data) 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *node; 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (node, &bridge_list) { 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = (struct acpiphp_bridge *)node; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = fn(slot, data); 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_enable_slot - power on slot 158826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_enable_slot(struct acpiphp_slot *slot) 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15946aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_lock(&slot->crit_sect); 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake up all functions */ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_on_slot(slot); 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro if (get_slot_status(slot) == ACPI_STA_ALL) { 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* configure all functions */ 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = enable_device(slot); 1604cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro if (retval) 1605cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro power_off_slot(slot); 1606cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro } else { 160766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__); 1608cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro power_off_slot(slot); 1609cde0e5d722c77d1194f40de54a99c90afe365480MUNEDA Takahiro } 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 16126aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_unlock(&slot->crit_sect); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_disable_slot - power off slot 161826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @slot: ACPI PHP slot 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_disable_slot(struct acpiphp_slot *slot) 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16246aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_lock(&slot->crit_sect); 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unconfigure all functions */ 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = disable_device(slot); 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* power off all functions */ 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_off_slot(slot); 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 16376aa4cdd07139ba4d5b89139b0070d795cc4dea88Ingo Molnar mutex_unlock(&slot->crit_sect); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot enabled: 1 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot disabled: 0 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_power_status(struct acpiphp_slot *slot) 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16488d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return (slot->flags & SLOT_POWEREDON); 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 165335ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch open: 1 165435ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro * latch closed: 0 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_latch_status(struct acpiphp_slot *slot) 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 166235ae61a0f43ebbabc3cb4345136ca529fc4d6700MUNEDA Takahiro return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter presence : 1 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * absence : 0 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (sta == 0) ? 0 : 1; 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1678