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
- Lines: 758
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
linux-2.4.19/drivers/hotplug/pcihp_acpi_glue.c
- Orig date:
Fri Aug 2 17:39:44 2002
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)