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