[Linux-ia64] [PATCH] 2.5 vendor-specific ACPI resource cleanup

Bjorn Helgaas
2003-04-25T18:36:40Z

This is to

- handle _CRS with multiple vendor-specific resources
- use acpi_walk_resources() instead of doing it by hand
- make lookup of vendor resource by GUID generic
- cleanup now-unused helper functions

(This depends on the previous IO port space patches, because
they removed the last of acpi_get_addr_space()).

My hope is that acpi_vendor_resource_match() and
acpi_find_vendor_resource() can someday move into ACPI,
but that probably depends on getting the idea of labelling
vendor resources with a GUID into the spec. HP does this
and I think is working on putting it in the spec.

Bjorn

diff -u -r linux-2.5.67-ia64-030416-io5/arch/ia64/kernel/acpi-ext.c linux-2.5.67-ia64-030416-io6/arch/ia64/kernel/acpi-ext.c
--- linux-2.5.67-ia64-030416-io5/arch/ia64/kernel/acpi-ext.c 2003-04-24 10:10:58.000000000 -0600
+++ linux-2.5.67-ia64-030416-io6/arch/ia64/kernel/acpi-ext.c 2003-04-25 12:13:59.000000000 -0600
@@ -3,9 +3,9 @@
*
* Copyright (C) 2003 Hewlett-Packard
* Copyright (C) Alex Williamson
+ * Copyright (C) Bjorn Helgaas
*
- * Vendor specific extensions to ACPI. These are used by both
- * HP and NEC.
+ * Vendor specific extensions to ACPI.
*/

#include <linux/config.h>
@@ -16,58 +16,85 @@

#include <asm/acpi-ext.h>

-/*
- * Note: Strictly speaking, this is only needed for HP and NEC machines.
- * However, NEC machines identify themselves as DIG-compliant, so there is
- * no easy way to #ifdef this out.
- */
+struct acpi_vendor_descriptor {
+ u8 guid_id;
+ efi_guid_t guid;
+};
+
+struct acpi_vendor_info {
+ struct acpi_vendor_descriptor *descriptor;
+ u8 *data;
+ u32 length;
+};
+
acpi_status
-hp_acpi_csr_space (acpi_handle obj, u64 *csr_base, u64 *csr_length)
+acpi_vendor_resource_match(struct acpi_resource *resource, void *context)
{
- int i, offset = 0;
- acpi_status status;
- struct acpi_buffer buf;
- struct acpi_resource_vendor *res;
- struct acpi_hp_vendor_long *hp_res;
- efi_guid_t vendor_guid;
-
- *csr_base = 0;
- *csr_length = 0;
-
- status = acpi_get_crs(obj, &buf);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
- return status;
- }
-
- res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
- if (!res) {
- printk(KERN_ERR PREFIX "Failed to find config space for device\n");
- acpi_dispose_crs(&buf);
+ struct acpi_vendor_info *info = (struct acpi_vendor_info *) context;
+ struct acpi_resource_vendor *vendor;
+ struct acpi_vendor_descriptor *descriptor;
+ u32 length;
+
+ if (resource->id != ACPI_RSTYPE_VENDOR)
+ return AE_OK;
+
+ vendor = (struct acpi_resource_vendor *) &resource->data;
+ descriptor = (struct acpi_vendor_descriptor *) vendor->reserved;
+ if (vendor->length <= sizeof(*info->descriptor) ||
+ descriptor->guid_id != info->descriptor->guid_id ||
+ efi_guidcmp(descriptor->guid, info->descriptor->guid))
+ return AE_OK;
+
+ length = vendor->length - sizeof(struct acpi_vendor_descriptor);
+ info->data = acpi_os_allocate(length);
+ if (!info->data)
+ return AE_NO_MEMORY;
+
+ memcpy(info->data, vendor->reserved + sizeof(struct acpi_vendor_descriptor), length);
+ info->length = length;
+ return AE_CTRL_TERMINATE;
+}
+
+acpi_status
+acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor *id,
+ u8 **data, u32 *length)
+{
+ struct acpi_vendor_info info;
+
+ info.descriptor = id;
+ info.data = 0;
+
+ acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, &info);
+ if (!info.data)
return AE_NOT_FOUND;
- }

- hp_res = (struct acpi_hp_vendor_long *)(res->reserved);
+ *data = info.data;
+ *length = info.length;
+ return AE_OK;
+}
+
+struct acpi_vendor_descriptor hp_ccsr_descriptor = {
+ .guid_id = 2,
+ .guid = EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
+};
+
+acpi_status
+hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
+{
+ acpi_status status;
+ u8 *data;
+ u32 length;
+ int i;
+
+ status = acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length);
+
+ if (ACPI_FAILURE(status) || length != 16)
+ return AE_NOT_FOUND;

- if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
- printk(KERN_ERR PREFIX "Unknown Vendor data\n");
- acpi_dispose_crs(&buf);
- return AE_TYPE; /* Revisit error? */
- }
-
- memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
- if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
- printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
- acpi_dispose_crs(&buf);
- return AE_TYPE; /* Revisit error? */
- }
-
- for (i = 0 ; i < 8 ; i++) {
- *csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
- *csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
- }
+ memcpy(csr_base, data, sizeof(*csr_base));
+ memcpy(csr_length, data + 8, sizeof(*csr_length));
+ acpi_os_free(data);

- acpi_dispose_crs(&buf);
return AE_OK;
}

diff -u -r linux-2.5.67-ia64-030416-io5/arch/ia64/kernel/acpi.c linux-2.5.67-ia64-030416-io6/arch/ia64/kernel/acpi.c
--- linux-2.5.67-ia64-030416-io5/arch/ia64/kernel/acpi.c 2003-04-24 13:44:09.000000000 -0600
+++ linux-2.5.67-ia64-030416-io6/arch/ia64/kernel/acpi.c 2003-04-25 11:23:32.000000000 -0600
@@ -115,138 +115,6 @@
#endif
}

-#ifdef CONFIG_ACPI
-
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, struct acpi_buffer *buf)
-{
- acpi_status result;
- buf->length = 0;
- buf->pointer = NULL;
-
- result = acpi_get_current_resources(obj, buf);
- if (result != AE_BUFFER_OVERFLOW)
- return result;
- buf->pointer = kmalloc(buf->length, GFP_KERNEL);
- if (!buf->pointer)
- return -ENOMEM;
-
- return acpi_get_current_resources(obj, buf);
-}
-
-struct acpi_resource *
-acpi_get_crs_next (struct acpi_buffer *buf, int *offset)
-{
- struct acpi_resource *res;
-
- if (*offset >= buf->length)
- return NULL;
-
- res = buf->pointer + *offset;
-
- if (res->length <= 0)
- return NULL;
-
- *offset += res->length;
- return res;
-}
-
-union acpi_resource_data *
-acpi_get_crs_type (struct acpi_buffer *buf, int *offset, int type)
-{
- for (;;) {
- struct acpi_resource *res = acpi_get_crs_next(buf, offset);
- if (!res)
- return NULL;
- if (res->id = type)
- return &res->data;
- }
-}
-
-void
-acpi_dispose_crs (struct acpi_buffer *buf)
-{
- kfree(buf->pointer);
-}
-
-void
-acpi_get_crs_addr (struct acpi_buffer *buf, int type, u64 *base, u64 *size, u64 *tra)
-{
- int offset = 0;
- struct acpi_resource_address16 *addr16;
- struct acpi_resource_address32 *addr32;
- struct acpi_resource_address64 *addr64;
-
- for (;;) {
- struct acpi_resource *res = acpi_get_crs_next(buf, &offset);
- if (!res)
- return;
- switch (res->id) {
- case ACPI_RSTYPE_ADDRESS16:
- addr16 = (struct acpi_resource_address16 *) &res->data;
-
- if (type = addr16->resource_type) {
- *base = addr16->min_address_range;
- *size = addr16->address_length;
- *tra = addr16->address_translation_offset;
- return;
- }
- break;
- case ACPI_RSTYPE_ADDRESS32:
- addr32 = (struct acpi_resource_address32 *) &res->data;
- if (type = addr32->resource_type) {
- *base = addr32->min_address_range;
- *size = addr32->address_length;
- *tra = addr32->address_translation_offset;
- return;
- }
- break;
- case ACPI_RSTYPE_ADDRESS64:
- addr64 = (struct acpi_resource_address64 *) &res->data;
- if (type = addr64->resource_type) {
- *base = addr64->min_address_range;
- *size = addr64->address_length;
- *tra = addr64->address_translation_offset;
- return;
- }
- break;
- }
- }
-}
-
-int
-acpi_get_addr_space(void *obj, u8 type, u64 *base, u64 *length, u64 *tra)
-{
- acpi_status status;
- struct acpi_buffer buf;
-
- *base = 0;
- *length = 0;
- *tra = 0;
-
- status = acpi_get_crs((acpi_handle)obj, &buf);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
- return status;
- }
-
- acpi_get_crs_addr(&buf, type, base, length, tra);
-
- acpi_dispose_crs(&buf);
-
- return AE_OK;
-}
-#endif /* CONFIG_ACPI */
-
#ifdef CONFIG_ACPI_BOOT

#define ACPI_MAX_PLATFORM_INTERRUPTS 256
diff -u -r linux-2.5.67-ia64-030416-io5/include/asm-ia64/acpi-ext.h linux-2.5.67-ia64-030416-io6/include/asm-ia64/acpi-ext.h
--- linux-2.5.67-ia64-030416-io5/include/asm-ia64/acpi-ext.h 2003-04-24 10:10:58.000000000 -0600
+++ linux-2.5.67-ia64-030416-io6/include/asm-ia64/acpi-ext.h 2003-04-25 11:40:08.000000000 -0600
@@ -3,30 +3,15 @@
*
* Copyright (C) 2003 Hewlett-Packard
* Copyright (C) Alex Williamson
+ * Copyright (C) Bjorn Helgaas
*
- * Vendor specific extensions to ACPI. The HP-specific extensiosn are also used by NEC.
+ * Vendor specific extensions to ACPI.
*/
#ifndef _ASM_IA64_ACPI_EXT_H
#define _ASM_IA64_ACPI_EXT_H

#include <linux/types.h>

-#define HP_CCSR_LENGTH 0x21
-#define HP_CCSR_TYPE 0x2
-#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \
- 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
-
-struct acpi_hp_vendor_long {
- u8 guid_id;
- u8 guid[16];
- u8 csr_base[8];
- u8 csr_length[8];
-};
-
extern acpi_status hp_acpi_csr_space (acpi_handle, u64 *base, u64 *length);
-extern acpi_status acpi_get_crs (acpi_handle, struct acpi_buffer *);
-extern struct acpi_resource *acpi_get_crs_next (struct acpi_buffer *, int *);
-extern union acpi_resource_data *acpi_get_crs_type (struct acpi_buffer *, int *, int);
-extern void acpi_dispose_crs (struct acpi_buffer *);

#endif /* _ASM_IA64_ACPI_EXT_H */