Commit 7c19bf64 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by David Mosberger

[PATCH] ia64: vendor-specific ACPI resource cleanup

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.
parent 9819f8eb
......@@ -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;
}
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? */
}
struct acpi_vendor_descriptor hp_ccsr_descriptor = {
.guid_id = 2,
.guid = EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
};
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? */
}
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;
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;
}
......
......@@ -115,138 +115,6 @@ acpi_get_sysname (void)
#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
......
......@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment