diff options
author | Bjorn Helgaas <bjorn.helgaas@hp.com> | 2006-03-28 17:06:20 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2006-04-06 17:42:38 -0400 |
commit | 03fbaca36a85a8c923e30abfb1a9a630bf1c5a1d (patch) | |
tree | 3b3947a7d3365f674b94901fea68ef92abc7c3bb /arch/ia64/kernel/acpi-ext.c | |
parent | b8cd2af862c3cbd428600e1c4f0d3f97c0da54cc (diff) |
[IA64] update HP CSR space discovery via ACPI
Get rid of the manual search of _CRS, in favor of
acpi_get_vendor_resource() which is now provided by the ACPI CA. And fall
back to searching for a consumer-only address space descriptor if no
vendor-defined resource is found.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/kernel/acpi-ext.c')
-rw-r--r-- | arch/ia64/kernel/acpi-ext.c | 143 |
1 files changed, 71 insertions, 72 deletions
diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index 4a5574ff007b..fff82929d225 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c | |||
@@ -1,105 +1,104 @@ | |||
1 | /* | 1 | /* |
2 | * arch/ia64/kernel/acpi-ext.c | 2 | * (c) Copyright 2003, 2006 Hewlett-Packard Development Company, L.P. |
3 | * Alex Williamson <alex.williamson@hp.com> | ||
4 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
3 | * | 5 | * |
4 | * Copyright (C) 2003 Hewlett-Packard | 6 | * This program is free software; you can redistribute it and/or modify |
5 | * Copyright (C) Alex Williamson | 7 | * it under the terms of the GNU General Public License version 2 as |
6 | * Copyright (C) Bjorn Helgaas | 8 | * published by the Free Software Foundation. |
7 | * | ||
8 | * Vendor specific extensions to ACPI. | ||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/acpi.h> | 14 | #include <linux/acpi.h> |
15 | #include <linux/efi.h> | ||
16 | 15 | ||
17 | #include <asm/acpi-ext.h> | 16 | #include <asm/acpi-ext.h> |
18 | 17 | ||
19 | struct acpi_vendor_descriptor { | 18 | /* |
20 | u8 guid_id; | 19 | * Device CSRs that do not appear in PCI config space should be described |
21 | efi_guid_t guid; | 20 | * via ACPI. This would normally be done with Address Space Descriptors |
22 | }; | 21 | * marked as "consumer-only," but old versions of Windows and Linux ignore |
22 | * the producer/consumer flag, so HP invented a vendor-defined resource to | ||
23 | * describe the location and size of CSR space. | ||
24 | */ | ||
23 | 25 | ||
24 | struct acpi_vendor_info { | 26 | struct acpi_vendor_uuid hp_ccsr_uuid = { |
25 | struct acpi_vendor_descriptor *descriptor; | 27 | .subtype = 2, |
26 | u8 *data; | 28 | .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, |
27 | u32 length; | 29 | 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, |
28 | }; | 30 | }; |
29 | 31 | ||
30 | acpi_status | 32 | static acpi_status hp_ccsr_locate(acpi_handle obj, u64 *base, u64 *length) |
31 | acpi_vendor_resource_match(struct acpi_resource *resource, void *context) | ||
32 | { | 33 | { |
33 | struct acpi_vendor_info *info = (struct acpi_vendor_info *)context; | 34 | acpi_status status; |
34 | struct acpi_resource_vendor *vendor; | 35 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
35 | struct acpi_vendor_descriptor *descriptor; | 36 | struct acpi_resource *resource; |
36 | u32 byte_length; | 37 | struct acpi_resource_vendor_typed *vendor; |
37 | |||
38 | if (resource->type != ACPI_RESOURCE_TYPE_VENDOR) | ||
39 | return AE_OK; | ||
40 | |||
41 | vendor = (struct acpi_resource_vendor *)&resource->data; | ||
42 | descriptor = (struct acpi_vendor_descriptor *)vendor->byte_data; | ||
43 | if (vendor->byte_length <= sizeof(*info->descriptor) || | ||
44 | descriptor->guid_id != info->descriptor->guid_id || | ||
45 | efi_guidcmp(descriptor->guid, info->descriptor->guid)) | ||
46 | return AE_OK; | ||
47 | |||
48 | byte_length = vendor->byte_length - sizeof(struct acpi_vendor_descriptor); | ||
49 | info->data = acpi_os_allocate(byte_length); | ||
50 | if (!info->data) | ||
51 | return AE_NO_MEMORY; | ||
52 | |||
53 | memcpy(info->data, | ||
54 | vendor->byte_data + sizeof(struct acpi_vendor_descriptor), | ||
55 | byte_length); | ||
56 | info->length = byte_length; | ||
57 | return AE_CTRL_TERMINATE; | ||
58 | } | ||
59 | 38 | ||
60 | acpi_status | 39 | status = acpi_get_vendor_resource(obj, METHOD_NAME__CRS, &hp_ccsr_uuid, |
61 | acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor * id, | 40 | &buffer); |
62 | u8 ** data, u32 * byte_length) | ||
63 | { | ||
64 | struct acpi_vendor_info info; | ||
65 | 41 | ||
66 | info.descriptor = id; | 42 | resource = buffer.pointer; |
67 | info.data = NULL; | 43 | vendor = &resource->data.vendor_typed; |
68 | 44 | ||
69 | acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, | 45 | if (ACPI_FAILURE(status) || vendor->byte_length < 16) { |
70 | &info); | 46 | status = AE_NOT_FOUND; |
71 | if (!info.data) | 47 | goto exit; |
72 | return AE_NOT_FOUND; | 48 | } |
73 | 49 | ||
74 | *data = info.data; | 50 | memcpy(base, vendor->byte_data, sizeof(*base)); |
75 | *byte_length = info.length; | 51 | memcpy(length, vendor->byte_data + 8, sizeof(*length)); |
76 | return AE_OK; | 52 | |
53 | exit: | ||
54 | acpi_os_free(buffer.pointer); | ||
55 | return status; | ||
77 | } | 56 | } |
78 | 57 | ||
79 | struct acpi_vendor_descriptor hp_ccsr_descriptor = { | 58 | struct csr_space { |
80 | .guid_id = 2, | 59 | u64 base; |
81 | .guid = | 60 | u64 length; |
82 | EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, | ||
83 | 0x37, 0x0e, 0xad) | ||
84 | }; | 61 | }; |
85 | 62 | ||
86 | acpi_status hp_acpi_csr_space(acpi_handle obj, u64 * csr_base, u64 * csr_length) | 63 | static acpi_status find_csr_space(struct acpi_resource *resource, void *data) |
87 | { | 64 | { |
65 | struct csr_space *space = data; | ||
66 | struct acpi_resource_address64 addr; | ||
88 | acpi_status status; | 67 | acpi_status status; |
89 | u8 *data; | ||
90 | u32 length; | ||
91 | 68 | ||
92 | status = | 69 | status = acpi_resource_to_address64(resource, &addr); |
93 | acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length); | 70 | if (ACPI_SUCCESS(status) && |
71 | addr.resource_type == ACPI_MEMORY_RANGE && | ||
72 | addr.address_length && | ||
73 | addr.producer_consumer == ACPI_CONSUMER) { | ||
74 | space->base = addr.minimum; | ||
75 | space->length = addr.address_length; | ||
76 | return AE_CTRL_TERMINATE; | ||
77 | } | ||
78 | return AE_OK; /* keep looking */ | ||
79 | } | ||
94 | 80 | ||
95 | if (ACPI_FAILURE(status) || length != 16) | 81 | static acpi_status hp_crs_locate(acpi_handle obj, u64 *base, u64 *length) |
96 | return AE_NOT_FOUND; | 82 | { |
83 | struct csr_space space = { 0, 0 }; | ||
97 | 84 | ||
98 | memcpy(csr_base, data, sizeof(*csr_base)); | 85 | acpi_walk_resources(obj, METHOD_NAME__CRS, find_csr_space, &space); |
99 | memcpy(csr_length, data + 8, sizeof(*csr_length)); | 86 | if (!space.length) |
100 | acpi_os_free(data); | 87 | return AE_NOT_FOUND; |
101 | 88 | ||
89 | *base = space.base; | ||
90 | *length = space.length; | ||
102 | return AE_OK; | 91 | return AE_OK; |
103 | } | 92 | } |
104 | 93 | ||
94 | acpi_status hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) | ||
95 | { | ||
96 | acpi_status status; | ||
97 | |||
98 | status = hp_ccsr_locate(obj, csr_base, csr_length); | ||
99 | if (ACPI_SUCCESS(status)) | ||
100 | return status; | ||
101 | |||
102 | return hp_crs_locate(obj, csr_base, csr_length); | ||
103 | } | ||
105 | EXPORT_SYMBOL(hp_acpi_csr_space); | 104 | EXPORT_SYMBOL(hp_acpi_csr_space); |