patch-2.4.20 linux-2.4.20/drivers/hotplug/pcihp_acpi_glue.c

Next file: linux-2.4.20/drivers/i2c/i2c-core.c
Previous file: linux-2.4.20/drivers/hotplug/pcihp_acpi_ctrl.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/hotplug/pcihp_acpi_glue.c linux-2.4.20/drivers/hotplug/pcihp_acpi_glue.c
@@ -1,757 +0,0 @@
-/*
- * ACPI PCI HotPlug glue functions to ACPI CA subsystem
- *
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "pcihp_acpi.h"
-
-/*
- * TODO:
- * resource management
- * irq related interface? (_PRT)
- * consider locking
- */
-
-static LIST_HEAD(bridge_list);
-
-static int debug = 1;			/* XXX set 0 after debug */
-#define MY_NAME "pcihp_acpi_glue"
-
-static void handle_hotplug_event (acpi_handle, u32, void *);
-
-/*
- * initialization & terminatation routines
- */
-
-/*
- * Ejectable slot satisfies at least these conditions:
- *  1. has _ADR method
- *  2. has _STA method
- *  3. has _EJ0 method
- *
- * optionally
- *  1. has _PS0 method
- *  2. has _PS3 method
- *  3. TBD...
- */
-
-/* callback routine to check the existence of ejectable slots */
-static acpi_status
-is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
-{
-	acpi_status status;
-	acpi_handle tmp;
-	int *count = (int *)context;
-
-	status = acpi_get_handle(handle, "_ADR", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_STA", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	(*count)++;
-
-	/* only one ejectable slot is enough */
-	return AE_CTRL_TERMINATE;
-}
-
-
-/* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct pcihp_acpi_bridge *bridge = (struct pcihp_acpi_bridge *)context;
-	struct pcihp_acpi_slot *slot, *newslot;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-	static int num_slots = 0;	/* XXX */
-	unsigned long adr, sun, sta;
-
-	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _EJ0");
-		//return AE_OK;
-	}
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _STA");
-		//return AE_OK;
-	}
-
-	newslot = kmalloc(sizeof(struct pcihp_acpi_slot), GFP_KERNEL);
-	if (!newslot) {
-		return AE_NO_MEMORY;
-	}
-
-	memset(newslot, 0, sizeof(struct pcihp_acpi_slot));
-
-	INIT_LIST_HEAD(&newslot->sibling);
-	newslot->bridge = bridge;
-	newslot->handle = handle;
-	newslot->device = (adr >> 16) & 0xffff;
-	newslot->function = adr & 0xffff;
-	newslot->status = sta;
-	newslot->sun = -1;
-	newslot->flags = SLOT_HAS_EJ0;
-	newslot->id = num_slots++;
-	bridge->nr_slots++;
-
-	dbg("new slot id=%d device=0x%d function=0x%x", newslot->id, newslot->device, newslot->function);
-
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_SUCCESS(status)) {
-		newslot->sun = sun;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS0;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS3;
-	}
-
-	/* search for objects that share the same slot */
-	for (slot = bridge->slots; slot; slot = slot->next)
-		if (slot->device == newslot->device) {
-			dbg("found a sibling slot!");
-			list_add(&slot->sibling, &newslot->sibling);
-			newslot->id = slot->id;
-			num_slots --;
-			bridge->nr_slots --;
-			break;
-		}
-
-	/* link myself to bridge's slot list */
-	newslot->next = bridge->slots;
-	bridge->slots = newslot;
-
-	return AE_OK;
-}
-
-/* see if it's worth managing this brige */
-static int
-detect_ejectable_slots (acpi_handle *root)
-{
-	acpi_status status;
-	int count;
-
-	count = 0;
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root, ACPI_UINT32_MAX,
-				     is_ejectable_slot, (void *)&count, NULL);
-
-	dbg("%s: count=%d", __FUNCTION__, count);
-	return count;
-}
-
-
-/*
- * push one resource to resource list
- *
- * TBD: use hotplug_resource_sort_and_combine
- * TBD: 64bit resource handling (is it really used?)
- */
-static void
-push_resource (u32 base, u32 length, struct pci_resource **resource)
-{
-	struct pci_resource *resp, *newres;
-	int coalesced = 0;
-
-	if (length == 0) {
-		dbg("zero sized resource. ignored.");
-		return;
-	}
-
-	for (resp = *resource; resp; resp = resp->next) {
-
-		/* coalesce contiguous region */
-
-		if (resp->base + resp->length == base) {
-			resp->length += length;
-			coalesced = 1;
-			break;
-		}
-	}
-
-	if (!coalesced) {
-		newres = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-		if (!newres) {
-			/* TBD panic? */
-			return;
-		}
-		newres->base = base;
-		newres->length = length;
-		newres->next = (*resource);
-		*resource = newres;
-	}
-}
-
-
-/* decode ACPI _CRS data and convert into our internal resource list */
-static void
-decode_acpi_resource (acpi_resource *resource, struct pcihp_acpi_bridge *bridge)
-{
-	acpi_resource_address16 *address16_data;
-	acpi_resource_address32 *address32_data;
-	//acpi_resource_address64 *address64_data;
-
-	u32 resource_type, producer_consumer, min_address_range, max_address_range, address_length;
-	u16 cache_attribute = 0;
-
-	int done = 0, found;
-
-	/* shut up gcc */
-	resource_type = producer_consumer = min_address_range = max_address_range = address_length = 0;
-
-	while (!done) {
-		found = 0;
-
-		switch (resource->id) {
-		case ACPI_RSTYPE_ADDRESS16:
-			address16_data = (acpi_resource_address16 *)&resource->data;
-			resource_type = address16_data->resource_type;
-			producer_consumer = address16_data->producer_consumer;
-			min_address_range = address16_data->min_address_range;
-			max_address_range = address16_data->max_address_range;
-			address_length = address16_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address16_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-
-		case ACPI_RSTYPE_ADDRESS32:
-			address32_data = (acpi_resource_address32 *)&resource->data;
-			resource_type = address32_data->resource_type;
-			producer_consumer = address32_data->producer_consumer;
-			min_address_range = address32_data->min_address_range;
-			max_address_range = address32_data->max_address_range;
-			address_length = address32_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address32_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-/*
-		case ACPI_RSTYPE_ADDRESS64:
-			address64_data = (acpi_resource_address64 *)&resource->data;
-			resource_type = address64_data->resource_type;
-			break;
-*/
-		case ACPI_RSTYPE_END_TAG:
-			done = 1;
-			break;
-
-		default:
-			/* ignore */
-			break;
-		}
-
-		resource = (acpi_resource *)((char*)resource + resource->length);
-		if (found && producer_consumer == ACPI_PRODUCER) {
-			switch (resource_type) {
-			case ACPI_MEMORY_RANGE:
-				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_prefetch);
-				} else {
-					dbg("resource type: memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_mem);
-				}
-				break;
-			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_io);
-				break;
-			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_bus);
-				break;
-			default:
-				/* invalid type */
-				break;
-			}
-		}
-	}
-}
-
-
-/* allocate and initialize bridge data structure */
-static int add_bridge (acpi_handle *handle)
-{
-	struct pcihp_acpi_bridge *bridge;
- 	acpi_status status;
-	acpi_buffer buffer;
-	unsigned long tmp;
-	acpi_handle dummy_handle;
-	int sta = -1;
-
-	status = acpi_get_handle(handle, "_STA", &dummy_handle);
-	if (ACPI_SUCCESS(status)) {
-		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
-			return 0;
-		}
-		sta = tmp;
-	}
-
-	if (sta >= 0 && !(sta & ACPI_STA_PRESENT))
-		/* don't register this object */
-		return 0;
-
-	dbg("%s: _STA: 0x%x", __FUNCTION__, (unsigned int)sta);
-
-	/* check if this bridge has ejectable slots */
-
-	detect_ejectable_slots(handle);
-	//if (detect_ejectable_slots(handle) == 0)
-	//return 0;
-
-	/* allocate per-bridge data structure and fill in */
-
-	bridge = kmalloc(sizeof(struct pcihp_acpi_bridge), GFP_KERNEL);
-	if (bridge == NULL)
-		return -ENOMEM;
-
-	memset(bridge, 0, sizeof(struct pcihp_acpi_bridge));
-
-	if (sta >= 0)
-		bridge->flags |= BRIDGE_HAS_STA;
-
-	/* get PCI segment number */
-	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->seg = tmp;
-	} else {
-		bridge->seg = 0;
-	}
-
-	/* get PCI bus number */
-	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->bus = tmp;
-	} else {
-		bridge->bus = 0;
-	}
-
-	/* to be overridden when we decode _CRS	*/
-	bridge->sub = bridge->bus;
-
-	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
-				     register_slot, bridge, NULL);
-
-	/* decode resources */
-	buffer.length = 0;
-	buffer.pointer = NULL;
-
-	
-	/* TBD use new ACPI_ALLOCATE_BUFFER */
-	status = acpi_get_current_resources(handle, &buffer);
-	if (status != AE_BUFFER_OVERFLOW) {
-		return -1;
-	}
-
-	buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-	if (!buffer.pointer) {
-		return -1;
-	}
-
-	status = acpi_get_current_resources(handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		return -1;
-	}
-
-	decode_acpi_resource(buffer.pointer, bridge);
-
-	/* TBD decode _HPP (hot plug parameters) */
-	// decode_hpp(bridge);
-
-	kfree(buffer.pointer);
-
-	/* check already allocated resources */
-	/* TBD */
-
-	/* install notify handler */
-	dbg("installing notify handler");
-	status = acpi_install_notify_handler(handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
-	}
-
-	list_add(&bridge->list, &bridge_list);
-
-	return 0;
-}
-
-
-/* callback routine to enumerate all the bridges in ACPI namespace */
-static acpi_status
-check_pci_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	acpi_status status;
-	acpi_device_info info;
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
-		return AE_OK;		/* continue */
-	}
-
-	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
-
-	if (strcmp(info.hardware_id, ACPI_PCI_ROOT_HID) == 0) {
-
-		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("%s: found PCI root bridge[%s]", __FUNCTION__, objname);
-
-		add_bridge(handle);
-	}
-	return AE_OK;
-}
-
-
-/* interrupt handler */
-static void handle_hotplug_event (acpi_handle handle, u32 type, void *data)
-{
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* hot insertion/surprise removal */
-		/* TBD */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* TBD */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* eject button pushed */
-		/* TBD */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x", type);
-		break;
-	}
-}
-
-
-/*
- * external interfaces
- */
-
-int pcihp_acpi_glue_init (void)
-{
-	acpi_status status;
-
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX, check_pci_bridge,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: acpi_walk_namespace() failed", __FUNCTION__);
-	}
-
-	return 0;
-}
-
-static void free_all_resources (struct pcihp_acpi_bridge *bridge)
-{
-	struct pci_resource *res, *next;;
-
-	for (res = bridge->free_io; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_mem; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_prefetch; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_bus; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-}
-
-
-void pcihp_acpi_glue_exit (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot, *next;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		slot = bridge->slots;
-		while (slot) {
-			next = slot->next;
-			kfree(slot);
-			slot = next;
-		}
-		free_all_resources(bridge);
-		kfree(bridge);
-	}
-}
-
-
-int pcihp_acpi_get_num_slots (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	int num_slots;
-
-	num_slots = 0;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		dbg("Bus:%d num_slots:%d", bridge->bus, bridge->nr_slots);
-		num_slots += bridge->nr_slots;
-	}
-
-	dbg("num_slots = %d", num_slots);
-	return num_slots;
-}
-
-
-/*  TBD: improve performance */
-struct pcihp_acpi_slot *get_slot_from_id (int id)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		for (slot = bridge->slots; slot; slot = slot->next)
-			if (slot->id == id)
-				return slot;
-	}
-
-	/* should never happen! */
-	dbg("%s: no object for id %d",__FUNCTION__, id);
-	return 0;
-}
-
-
-/* power on slot */
-int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS0) {
-		dbg("%s: powering on bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: powering on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/* power off slot */
-int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS3) {
-		dbg("%s: powering off bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS3", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _PS3 on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	if (slot->flags & SLOT_HAS_EJ0) {
-		dbg("%s: eject bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_EJ0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _EJ0 bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	/* TBD
-	 * evaluate _STA to check if state is successfully changed
-	 * and update status
-	 */
-
-	return 0;
-}
-
-
-static unsigned int get_slot_status(struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-	unsigned long sta;
-
-	status = acpi_evaluate_integer(slot->handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		err("%s: _STA evaluation failed", __FUNCTION__);
-		return 0;
-	}
-
-	return (int)sta;
-}
-
-
-/*
- * slot enabled:  1
- * slot disabled: 0
- */
-u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * . guarantee check _STA on function# 0
-	 * . check configuration space before _STA?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
-}
-
-
-/* XXX this function is not used */
-/* 
- * attention LED ON: 1
- *              OFF: 0
- */
-u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot)
-{
-	/* TBD
-	 * no direct attention led status information via ACPI
-	 */
-
-	return 0;
-}
-
-
-/*
- * latch closed:  1
- * latch   open:  0
- */
-u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * no direct latch information via ACPI
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
-}
-
-
-/*
- * adapter presence : 2
- *          absence : 0
- */
-u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * is this information correct?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 2;
-}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)