acpiphp_glue.c revision 8e5dce35221850759671b2847a2e51030f7626bd
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 * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send feedback to <t-kochi@bq.jp.nec.com> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah/* 3442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * Lifetime rules for pci_dev: 3542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * - The one in acpiphp_func has its refcount elevated by pci_get_slot() 3642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * when the driver is loaded or when an insertion event occurs. It loses 3742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * a refcount when its ejected or the driver unloads. 3842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() 3942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * when the bridge is scanned and it loses a refcount when the bridge 4042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah * is removed. 4142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah */ 4242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp_lock.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/semaphore.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../pci.h" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pci_hotplug.h" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "acpiphp.h" 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(bridge_list); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MY_NAME "acpiphp_glue" 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge (acpi_handle, u32, void *); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_func (acpi_handle, u32, void *); 618e5dce35221850759671b2847a2e51030f7626bdKristen Accardistatic void acpiphp_sanitize_bus(struct pci_bus *bus); 628e5dce35221850759671b2847a2e51030f7626bdKristen Accardistatic void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); 638e5dce35221850759671b2847a2e51030f7626bdKristen Accardi 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialization & terminatation routines 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is_ejectable - determine if a slot is ejectable 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: handle to acpi namespace 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ejectable slot should satisfy at least these conditions: 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. has _ADR method 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. has _EJ0 method 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * optionally 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. has _STA method 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. has _PS0 method 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. has _PS3 method 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4. .. 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int is_ejectable(acpi_handle handle) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle tmp; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_ADR", &tmp); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_EJ0", &tmp); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to check the existence of ejectable slots */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *count = (int *)context; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_ejectable(handle)) { 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*count)++; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* only one ejectable slot is enough */ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_CTRL_TERMINATE; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to register each ACPI PCI slot object */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsregister_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *newfunc; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle tmp; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status = AE_OK; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long adr, sun; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int device, function; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int num_slots = 0; /* XXX if we support I/O node hotplug... */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_EJ0", &tmp); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device = (adr >> 16) & 0xffff; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = adr & 0xffff; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!newfunc) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(newfunc, 0, sizeof(struct acpiphp_func)); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&newfunc->sibling); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->handle = handle; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->function = function; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags = FUNC_HAS_EJ0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_STA; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS0; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->flags |= FUNC_HAS_PS3; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sun = -1; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search for objects that share the same slot */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->device == device) { 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->sun != sun) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("sibling found, but _SUN doesn't match!\n"); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slot) { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(newfunc); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_NO_MEMORY; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(slot, 0, sizeof(struct acpiphp_slot)); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->bridge = bridge; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->id = num_slots++; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->device = device; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->sun = sun; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&slot->funcs); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_MUTEX(&slot->crit_sect); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->next = bridge->slots; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->slots = slot; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->nr_slots++; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", 19942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot->sun, pci_domain_nr(bridge->pci_bus), 20042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus->number, slot->device); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc->slot = slot; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&newfunc->sibling, &slot->funcs); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* associate corresponding pci_dev */ 20742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah newfunc->pci_dev = pci_get_slot(bridge->pci_bus, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVFN(device, function)); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (newfunc->pci_dev) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_install_notify_handler(handle, 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_func, 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newfunc); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("failed to register interrupt notify handler\n"); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* see if it's worth looking at this bridge */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int detect_ejectable_slots(acpi_handle *bridge_handle) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = 0; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* only check slots defined directly below bridge object */ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is_ejectable_slot, (void *)&count, NULL); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* decode ACPI 2.0 _HPP hot plug parameters */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void decode_hpp(struct acpiphp_bridge *bridge) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = NULL}; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union acpi_object *package; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* default numbers */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.cache_line_size = 0x10; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.latency_timer = 0x40; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_SERR = 0; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_PERR = 0; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("_HPP evaluation failed\n"); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds package = (union acpi_object *) buffer.pointer; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!package || package->type != ACPI_TYPE_PACKAGE || 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds package->package.count != 4 || !package->package.elements) { 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("invalid _HPP object; ignoring\n"); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("invalid _HPP parameter type; ignoring\n"); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.cache_line_size = package->package.elements[0].integer.value; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.latency_timer = package->package.elements[1].integer.value; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_SERR = package->package.elements[2].integer.value; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_PERR = package->package.elements[3].integer.value; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.cache_line_size, 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.latency_timer, 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_SERR, 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->hpp.enable_PERR); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->flags |= BRIDGE_HAS_HPP; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buffer.pointer); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_bridge_misc(struct acpiphp_bridge *bridge) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* decode ACPI 2.0 _HPP (hot plug parameters) */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds decode_hpp(bridge); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register all slot objects under this bridge */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_slot, bridge, NULL); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* install notify handler */ 3128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->type != BRIDGE_TYPE_HOST) { 3138e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah status = acpi_install_notify_handler(bridge->handle, 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_SYSTEM_NOTIFY, 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_hotplug_event_bridge, 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3188e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (ACPI_FAILURE(status)) { 3198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("failed to register interrupt notify handler\n"); 3208e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&bridge->list, &bridge_list); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize host bridge data structure */ 32842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bridge, 0, sizeof(struct acpiphp_bridge)); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_HOST; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus = pci_bus; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* allocate and initialize PCI-to-PCI bridge data structure */ 35042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bridge == NULL) { 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("out of memory\n"); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bridge, 0, sizeof(struct acpiphp_bridge)); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->type = BRIDGE_TYPE_P2P; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge->handle = handle; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_dev = pci_dev_get(pci_dev); 36642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus = pci_dev->subordinate; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bridge->pci_bus) { 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("This is not a PCI-to-PCI bridge!\n"); 36942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto err; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bridge->res_lock); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_bridge_misc(bridge); 37542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 37642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err: 37742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(pci_dev); 37842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 37942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* callback routine to find P2P bridges */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic acpi_status 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfind_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle dummy_handle; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 39042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah int device, function; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 39242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *pci_bus = context; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_ADR", &dummy_handle); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; /* continue */ 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: _ADR evaluation failure\n", __FUNCTION__); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device = (tmp >> 16) & 0xffff; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = tmp & 0xffff; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (!dev || !dev->subordinate) 41042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah goto out; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (detect_ejectable_slots(handle) > 0) { 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 41542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah add_p2p_bridge(handle, dev); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah out: 41942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return AE_OK; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* find hot-pluggable slots, and then find P2P bridge */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int add_bridge(acpi_handle handle) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int seg, bus; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_handle dummy_handle; 43142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *pci_bus; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if the bridge doesn't have _STA, we assume it is always there */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_get_handle(handle, "_STA", &dummy_handle); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status)) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: _STA evaluation failure\n", __FUNCTION__); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tmp & ACPI_STA_FUNCTIONING) == 0) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't register this object */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get PCI segment number */ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seg = ACPI_SUCCESS(status) ? tmp : 0; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get PCI bus number */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status)) { 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus = tmp; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("can't get bus number, assuming 0\n"); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus = 0; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus = pci_find_bus(seg, bus); 46242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (!pci_bus) { 46342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err("Can't find bus %04x:%02x\n", seg, bus); 46442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return 0; 46542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 46642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if this bridge has ejectable slots */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (detect_ejectable_slots(handle) > 0) { 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("found PCI host-bus bridge with hot-pluggable slots\n"); 47042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah add_host_bridge(handle, pci_bus); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* search P2P bridges under this host bridge */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 47642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah find_p2p_bridge, pci_bus, NULL); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("find_p2p_bridge faied (error code = 0x%x)\n",status); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shahstatic struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) 48542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah{ 48642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct list_head *head; 48742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each(head, &bridge_list) { 48842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_bridge *bridge = list_entry(head, 48942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_bridge, list); 49042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (bridge->handle == handle) 49142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return bridge; 49242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 49342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 49442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah return NULL; 49542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah} 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 497364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void cleanup_bridge(struct acpiphp_bridge *bridge) 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct list_head *list, *tmp; 50042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_slot *slot; 50142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah acpi_status status; 502364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah acpi_handle handle = bridge->handle; 50342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 50442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 50542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_bridge); 50642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (ACPI_FAILURE(status)) 50742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err("failed to remove notify handler\n"); 50842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 50942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = bridge->slots; 51042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah while (slot) { 51142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_slot *next = slot->next; 51242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each_safe (list, tmp, &slot->funcs) { 51342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct acpiphp_func *func; 51442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah func = list_entry(list, struct acpiphp_func, sibling); 51542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah status = acpi_remove_notify_handler(func->handle, 51642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah ACPI_SYSTEM_NOTIFY, 51742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah handle_hotplug_event_func); 51842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (ACPI_FAILURE(status)) 51942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah err("failed to remove notify handler\n"); 52042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(func->pci_dev); 52142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_del(list); 52242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(func); 52342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 52442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(slot); 52542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah slot = next; 52642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 52742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 52842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(bridge->pci_dev); 52942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_del(&bridge->list); 53042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah kfree(bridge); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 533364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic acpi_status 534364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahcleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 535364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 536364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 537364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 538364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah if (!(bridge = acpiphp_handle_to_bridge(handle))) 539364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah return AE_OK; 540364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah cleanup_bridge(bridge); 541364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah return AE_OK; 542364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 543364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 544364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shahstatic void remove_bridge(acpi_handle handle) 545364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah{ 546364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah struct acpiphp_bridge *bridge; 547364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah 548364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 549364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah if (bridge) { 550364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah cleanup_bridge(bridge); 551364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah } else { 552364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah /* clean-up p2p bridges under this host bridge */ 553364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 554364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah (u32)1, cleanup_p2p_bridge, NULL, NULL); 555364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah } 556364d5094a43ff2ceff3d19e40c4199771cb6cb8fRajesh Shah} 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 558a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic struct pci_dev * get_apic_pci_info(acpi_handle handle) 559a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 560a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct acpi_pci_id id; 561a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct pci_bus *bus; 562a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct pci_dev *dev; 563a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 564a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) 565a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 566a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 567a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige bus = pci_find_bus(id.segment, id.bus); 568a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (!bus) 569a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 570a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 571a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); 572a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (!dev) 573a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 574a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 575a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && 576a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) 577a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige { 578a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_dev_put(dev); 579a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return NULL; 580a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 581a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 582a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return dev; 583a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 584a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 585a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic int get_gsi_base(acpi_handle handle, u32 *gsi_base) 586a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 587a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_status status; 588a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige int result = -1; 589a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige unsigned long gsb; 590a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 591a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige union acpi_object *obj; 592a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige void *table; 593a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 594a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); 595a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status)) { 596a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige *gsi_base = (u32)gsb; 597a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return 0; 598a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 599a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 600a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); 601a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) 602a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return -1; 603a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 604a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige obj = buffer.pointer; 605a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (obj->type != ACPI_TYPE_BUFFER) 606a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige goto out; 607a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 608a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige table = obj->buffer.pointer; 609a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige switch (((acpi_table_entry_header *)table)->type) { 610a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige case ACPI_MADT_IOSAPIC: 611a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; 612a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige result = 0; 613a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 614a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige case ACPI_MADT_IOAPIC: 615a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; 616a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige result = 0; 617a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 618a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige default: 619a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige break; 620a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 621a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige out: 622a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_os_free(buffer.pointer); 623a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return result; 624a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 625a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 626a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic acpi_status 627a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigeioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) 628a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 629a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_status status; 630a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige unsigned long sta; 631a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_handle tmp; 632a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige struct pci_dev *pdev; 633a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige u32 gsi_base; 634a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige u64 phys_addr; 635a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 636a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige /* Evaluate _STA if present */ 637a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 638a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) 639a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_CTRL_DEPTH; 640a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 641a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige /* Scan only PCI bus scope */ 642a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige status = acpi_get_handle(handle, "_HID", &tmp); 643a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (ACPI_SUCCESS(status)) 644a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_CTRL_DEPTH; 645a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 646a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (get_gsi_base(handle, &gsi_base)) 647a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 648a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 649a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pdev = get_apic_pci_info(handle); 650a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (!pdev) 651a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 652a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 653a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (pci_enable_device(pdev)) { 654a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_dev_put(pdev); 655a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 656a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 657a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 658a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_set_master(pdev); 659a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 660a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { 661a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_disable_device(pdev); 662a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_dev_put(pdev); 663a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 664a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 665a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 666a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige phys_addr = pci_resource_start(pdev, 0); 667a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { 668a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_release_region(pdev, 0); 669a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_disable_device(pdev); 670a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige pci_dev_put(pdev); 671a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 672a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige } 673a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 674a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return AE_OK; 675a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 676a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 677a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshigestatic int acpiphp_configure_ioapics(acpi_handle handle) 678a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige{ 679a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 680a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige ACPI_UINT32_MAX, ioapic_add, NULL, NULL); 681a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige return 0; 682a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige} 683a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_on_slot(struct acpiphp_slot *slot) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already enabled, just skip */ 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_POWEREDON) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_PS0) { 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: executing _PS0\n", __FUNCTION__); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("%s: _PS0 failed\n", __FUNCTION__); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is enabled */ 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_POWEREDON; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int power_off_slot(struct acpiphp_slot *slot) 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if already disabled, just skip */ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slot->flags & SLOT_POWEREDON) == 0) 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7342f523b15901f654a9448bbd47ebe1e783ec3195bRajesh Shah if (func->flags & FUNC_HAS_PS3) { 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("%s: _PS3 failed\n", __FUNCTION__); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: evaluate _STA to check if the slot is disabled */ 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_POWEREDON); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable_device - enable, configure a slot 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: slot to be enabled 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function should be called per *physical slot*, 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not per each slot object in ACPI namespace. 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int enable_device(struct acpiphp_slot *slot) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 76542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *bus = slot->bridge->pci_bus; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 76942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah int num, max, pass; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* sanity check: dev should be NULL when hot-plugged in */ 77542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This case shouldn't happen */ 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("pci_dev structure already exists.\n"); 77942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(dev); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); 78542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (num == 0) { 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("No new device found\n"); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -1; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah max = bus->secondary; 79242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah for (pass = 0; pass < 2; pass++) { 79342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 79442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (PCI_SLOT(dev->devfn) != slot->device) 79542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah continue; 79642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || 79742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) 79842f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah max = pci_scan_bridge(bus, dev, max, pass); 79942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah } 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8028e5dce35221850759671b2847a2e51030f7626bdKristen Accardi pci_bus_size_bridges(bus); 80342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_assign_resources(bus); 8048e5dce35221850759671b2847a2e51030f7626bdKristen Accardi acpiphp_sanitize_bus(bus); 8058e5dce35221850759671b2847a2e51030f7626bdKristen Accardi pci_enable_bridges(bus); 80642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_bus_add_devices(bus); 8078e5dce35221850759671b2847a2e51030f7626bdKristen Accardi acpiphp_set_hpp_values(DEVICE_ACPI_HANDLE(&bus->self->dev), bus); 8088e5dce35221850759671b2847a2e51030f7626bdKristen Accardi acpiphp_configure_ioapics(DEVICE_ACPI_HANDLE(&bus->self->dev)); 80942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* associate pci_dev to our representation */ 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 81342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func->function)); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags |= SLOT_ENABLED; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable_device - disable a slot 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int disable_device(struct acpiphp_slot *slot) 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* is this slot already disabled? */ 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(slot->flags & SLOT_ENABLED)) 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 83942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah if (!func->pci_dev) 84042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah continue; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84242f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_remove_bus_device(func->pci_dev); 84342f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_dev_put(func->pci_dev); 84442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah func->pci_dev = NULL; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->flags &= (~SLOT_ENABLED); 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_slot_status - get ACPI slot status 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if a slot has _STA for each function and if any one of them 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returned non-zero status, return it 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if a slot doesn't have _STA and if any one of its functions' 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configuration space is configured, return 0x0f as a _STA 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise return 0 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_slot_status(struct acpiphp_slot *slot) 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_status status; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long sta = 0; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dvid; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (l, &slot->funcs) { 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = list_entry(l, struct acpiphp_func, sibling); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func->flags & FUNC_HAS_STA) { 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_SUCCESS(status) && sta) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_bus_read_config_dword(slot->bridge->pci_bus, 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVFN(slot->device, 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func->function), 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_VENDOR_ID, &dvid); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvid != 0xffffffff) { 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = ACPI_STA_ALL; 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (unsigned int)sta; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8968d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah * acpiphp_eject_slot - physically eject the slot 8978d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah */ 8988d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shahstatic int acpiphp_eject_slot(struct acpiphp_slot *slot) 8998d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah{ 9008d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpi_status status; 9018d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpiphp_func *func; 9028d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct list_head *l; 9038d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah struct acpi_object_list arg_list; 9048d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah union acpi_object arg; 9058d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9068d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah list_for_each (l, &slot->funcs) { 9078d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah func = list_entry(l, struct acpiphp_func, sibling); 9088d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9098d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* We don't want to call _EJ0 on non-existing functions. */ 9108d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if ((func->flags & FUNC_HAS_EJ0)) { 9118d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah /* _EJ0 method take one argument */ 9128d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.count = 1; 9138d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg_list.pointer = &arg; 9148d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.type = ACPI_TYPE_INTEGER; 9158d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah arg.integer.value = 1; 9168d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9178d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); 9188d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (ACPI_FAILURE(status)) { 9198d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah warn("%s: _EJ0 failed\n", __FUNCTION__); 9208d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return -1; 9218d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else 9228d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah break; 9238d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 9248d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } 9258d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return 0; 9268d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah} 9278d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah 9288d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah/** 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_check_bridge - re-enumerate devices 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Iterate over all slots under this bridge and make sure that if a 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card is present they are enabled, and if not they are disabled. 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_check_bridge(struct acpiphp_bridge *bridge) 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int enabled, disabled; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled = disabled = 0; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status = get_slot_status(slot); 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->flags & SLOT_ENABLED) { 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == ACPI_STA_ALL) 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_disable_slot(slot); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in disabling\n"); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 9518d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah } else { 9528d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(slot); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disabled++; 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != ACPI_STA_ALL) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = acpiphp_enable_slot(slot); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("Error occurred in enabling\n"); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled++; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) 9748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 9758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah u16 pci_cmd, pci_bctl; 9768e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *cdev; 9778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 9788e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* Program hpp values for this device */ 9798e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || 9808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && 9818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 9828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 9838e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 9848e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge->hpp.cache_line_size); 9858e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_write_config_byte(dev, PCI_LATENCY_TIMER, 9868e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge->hpp.latency_timer); 9878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); 9888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->hpp.enable_SERR) 9898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_cmd |= PCI_COMMAND_SERR; 9908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 9918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_cmd &= ~PCI_COMMAND_SERR; 9928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->hpp.enable_PERR) 9938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_cmd |= PCI_COMMAND_PARITY; 9948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 9958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_cmd &= ~PCI_COMMAND_PARITY; 9968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_write_config_word(dev, PCI_COMMAND, pci_cmd); 9978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 9988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* Program bridge control value and child devices */ 9998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 10008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 10018e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge->hpp.latency_timer); 10028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); 10038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->hpp.enable_SERR) 10048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bctl |= PCI_BRIDGE_CTL_SERR; 10058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 10068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bctl &= ~PCI_BRIDGE_CTL_SERR; 10078e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (bridge->hpp.enable_PERR) 10088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bctl |= PCI_BRIDGE_CTL_PARITY; 10098e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 10108e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; 10118e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); 10128e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (dev->subordinate) { 10138e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah list_for_each_entry(cdev, &dev->subordinate->devices, 10148e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bus_list) 10158e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah program_hpp(cdev, bridge); 10168e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10178e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10188e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10198e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10208e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) 10218e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10228e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpiphp_bridge bridge; 10238e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 10248e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10258e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah memset(&bridge, 0, sizeof(bridge)); 10268e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge.handle = handle; 10278e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah decode_hpp(&bridge); 10288e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) 10298e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah program_hpp(dev, &bridge); 10308e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10318e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10328e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10338e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* 10348e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * Remove devices for which we could not assign resources, call 10358e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * arch specific code to fix-up the bus 10368e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah */ 10378e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void acpiphp_sanitize_bus(struct pci_bus *bus) 10388e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10398e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_dev *dev; 10408e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int i; 10418e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; 10428e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10438e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah list_for_each_entry(dev, &bus->devices, bus_list) { 10448e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { 10458e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct resource *res = &dev->resource[i]; 10468e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((res->flags & type_mask) && !res->start && 10478e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah res->end) { 10488e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* Could not assign a required resources 10498e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah * for this device, remove it */ 10508e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_remove_bus_device(dev); 10518e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah break; 10528e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10538e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10548e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10558e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10568e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah/* Program resources in newly inserted bridge */ 10588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic int acpiphp_configure_bridge (acpi_handle handle) 10598e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_pci_id pci_id; 10618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct pci_bus *bus; 10628e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10638e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { 10648e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot get PCI domain and bus number for bridge\n"); 10658e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return -EINVAL; 10668e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10678e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bus = pci_find_bus(pci_id.segment, pci_id.bus); 10688e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!bus) { 10698e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot find bus %d:%d\n", 10708e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_id.segment, pci_id.bus); 10718e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return -EINVAL; 10728e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_size_bridges(bus); 10758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_bus_assign_resources(bus); 10768e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpiphp_sanitize_bus(bus); 10778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpiphp_set_hpp_values(handle, bus); 10788e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pci_enable_bridges(bus); 1079a0d399a808916d22c1c222c6b5ca4e8edd6d91a9Kenji Kaneshige acpiphp_configure_ioapics(handle); 10808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 0; 10818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 10828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10838e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic void handle_bridge_insertion(acpi_handle handle, u32 type) 10848e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 10858e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device, *pdevice; 10868e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_handle phandle; 10878e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10888e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((type != ACPI_NOTIFY_BUS_CHECK) && 10898e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (type != ACPI_NOTIFY_DEVICE_CHECK)) { 10908e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("unexpected notification type %d\n", type); 10918e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 10928e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10938e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 10948e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_get_parent(handle, &phandle); 10958e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(phandle, &pdevice)) { 10968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah dbg("no parent device, assuming NULL\n"); 10978e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah pdevice = NULL; 10988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 10998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { 11008e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot add bridge to acpi list\n"); 11018e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11028e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!acpiphp_configure_bridge(handle) && 11048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah !acpi_bus_start(device)) 11058e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah add_bridge(handle); 11068e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 11078e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot configure and start bridge\n"); 11088e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11098e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 11108e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI event handlers 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_bridge - handle ACPI event on bridges 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_bridge structure 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handles ACPI event notification on {host,p2p} bridges 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 11318e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device *device; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11338e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (acpi_bus_get_device(handle, &device)) { 11348e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah /* This bridge must have just been physically inserted */ 11358e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_bridge_insertion(handle, type); 11368e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11378e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11388e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 11398e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah bridge = acpiphp_handle_to_bridge(handle); 11408e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!bridge) { 11418e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah err("cannot get bridge info\n"); 11428e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return; 11438e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(bridge); 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check */ 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(bridge); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_FREQUENCY_MISMATCH: 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a frequency mismatch\n", objname); 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_MODE_MISMATCH: 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s cannot be configured due" 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to a bus mode mismatch\n", objname); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_POWER_FAULT: 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Device %s has suffered a power fault\n", 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds objname); 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @handle: Notify()'ed acpi_handle 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @type: Notify code 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @context: pointer to acpiphp_func structure 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handles ACPI event notification on slots 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_func *func; 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char objname[64]; 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_buffer buffer = { .length = sizeof(objname), 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = objname }; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func = (struct acpiphp_func *)context; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_BUS_CHECK: 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bus re-enumerate */ 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_enable_slot(func->slot); 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_CHECK: 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* device check : re-enumerate from parent bus */ 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpiphp_check_bridge(func->slot->bridge); 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_DEVICE_WAKE: 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake event */ 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_NOTIFY_EJECT_REQUEST: 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* request device eject */ 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 12338d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah if (!(acpiphp_disable_slot(func->slot))) 12348d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah acpiphp_eject_slot(func->slot); 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12438e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic int is_root_bridge(acpi_handle handle) 12448e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12458e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_status status; 12468e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_device_info *info; 12478e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 12488e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int i; 12498e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12508e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah status = acpi_get_object_info(handle, &buffer); 12518e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (ACPI_SUCCESS(status)) { 12528e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah info = buffer.pointer; 12538e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if ((info->valid & ACPI_VALID_HID) && 12548e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah !strcmp(PCI_ROOT_HID_STRING, 12558e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah info->hardware_id.value)) { 12568e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_os_free(buffer.pointer); 12578e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 1; 12588e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12598e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (info->valid & ACPI_VALID_CID) { 12608e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah for (i=0; i < info->compatibility_id.count; i++) { 12618e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (!strcmp(PCI_ROOT_HID_STRING, 12628e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah info->compatibility_id.id[i].value)) { 12638e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_os_free(buffer.pointer); 12648e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 1; 12658e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12668e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12678e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12688e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12698e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return 0; 12708e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 12718e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12728e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahstatic acpi_status 12738e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shahfind_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 12748e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah{ 12758e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int *count = (int *)context; 12768e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah 12778e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah if (is_root_bridge(handle)) { 12788e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 12798e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah handle_hotplug_event_bridge, NULL); 12808e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah (*count)++; 12818e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah } 12828e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah return AE_OK ; 12838e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah} 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_pci_driver acpi_pci_hp_driver = { 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .add = add_bridge, 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = remove_bridge, 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_glue_init(void) 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12968e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah int num = 0; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12988e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 12998e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah ACPI_UINT32_MAX, find_root_bridges, &num, NULL); 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num <= 0) 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 13038e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah else 13048e7561cfbdf00fb1cee694cef0e825d0548aedbcRajesh Shah acpi_pci_register_driver(&acpi_pci_hp_driver); 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function frees all data allocated in acpiphp_glue_init() 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit acpiphp_glue_exit(void) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_pci_unregister_driver(&acpi_pci_hp_driver); 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_get_num_slots - count number of slots in a system 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init acpiphp_get_num_slots(void) 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *node; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_slots; 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_slots = 0; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (node, &bridge_list) { 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = (struct acpiphp_bridge *)node; 133442f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Bus %04x:%02x has %d slot%s\n", 133542f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah pci_domain_nr(bridge->pci_bus), 133642f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->pci_bus->number, bridge->nr_slots, 133742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah bridge->nr_slots == 1 ? "" : "s"); 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_slots += bridge->nr_slots; 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 134142f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah dbg("Total %d slots\n", num_slots); 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num_slots; 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_for_each_slot - call function for each slot 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @fn: callback function 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @data: context to be passed to callback function 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpiphp_for_each_slot(acpiphp_callback fn, void *data) 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *node; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (node, &bridge_list) { 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = (struct acpiphp_bridge *)node; 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) { 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = fn(slot, data); 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* search matching slot from id */ 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct acpiphp_slot *get_slot_from_id(int id) 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *node; 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_bridge *bridge; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpiphp_slot *slot; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each (node, &bridge_list) { 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bridge = (struct acpiphp_bridge *)node; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = bridge->slots; slot; slot = slot->next) 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->id == id) 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return slot; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* should never happen! */ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: no object for id %d\n", __FUNCTION__, id); 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(1); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_enable_slot - power on slot 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_enable_slot(struct acpiphp_slot *slot) 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&slot->crit_sect); 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake up all functions */ 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_on_slot(slot); 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_slot_status(slot) == ACPI_STA_ALL) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* configure all functions */ 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = enable_device(slot); 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&slot->crit_sect); 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpiphp_disable_slot - power off slot 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint acpiphp_disable_slot(struct acpiphp_slot *slot) 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&slot->crit_sect); 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unconfigure all functions */ 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = disable_device(slot); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* power off all functions */ 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = power_off_slot(slot); 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_exit; 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_exit: 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&slot->crit_sect); 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot enabled: 1 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slot disabled: 0 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_power_status(struct acpiphp_slot *slot) 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14498d50e332c8bd4f4e8cc76e8ed7326aa6f18182aaRajesh Shah return (slot->flags & SLOT_POWEREDON); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * latch closed: 1 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * latch open: 0 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_latch_status(struct acpiphp_slot *slot) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adapter presence : 1 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * absence : 0 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sta; 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sta = get_slot_status(slot); 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (sta == 0) ? 0 : 1; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pci address (seg/bus/dev) 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu32 acpiphp_get_address(struct acpiphp_slot *slot) 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 address; 148742f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah struct pci_bus *pci_bus = slot->bridge->pci_bus; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148942f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah address = (pci_domain_nr(pci_bus) << 16) | 149042f49a6ae5dca90cd0594475502bf1c43ff1dc07Rajesh Shah (pci_bus->number << 8) | 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->device; 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return address; 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1495