diff options
author | Lin Ming <ming.m.lin@intel.com> | 2009-06-23 23:32:04 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-08-27 10:17:18 -0400 |
commit | 6557a49a443a347d24aed58076365432ded30edc (patch) | |
tree | d7ac2ce73b7f55bbcdc74864fd99c2285b879a05 /drivers/acpi | |
parent | 3db20bed579bc4e7fe581c48ad1bde853aa9ff68 (diff) |
ACPICA: ACPI 4.0: Interpreter support for IPMI.
Adds support for IPMI which is similar to SMBus and uses a bi-directional data buffer.
ACPICA BZ 773.
http://acpica.org/bugzilla/show_bug.cgi?id=773
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpica/acconfig.h | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/exfield.c | 82 | ||||
-rw-r--r-- | drivers/acpi/acpica/exfldio.c | 7 |
3 files changed, 61 insertions, 31 deletions
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index 9123d5a11627..8e679ef5b231 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h | |||
@@ -199,9 +199,10 @@ | |||
199 | #define ACPI_RSDP_CHECKSUM_LENGTH 20 | 199 | #define ACPI_RSDP_CHECKSUM_LENGTH 20 |
200 | #define ACPI_RSDP_XCHECKSUM_LENGTH 36 | 200 | #define ACPI_RSDP_XCHECKSUM_LENGTH 36 |
201 | 201 | ||
202 | /* SMBus bidirectional buffer size */ | 202 | /* SMBus and IPMI bidirectional buffer size */ |
203 | 203 | ||
204 | #define ACPI_SMBUS_BUFFER_SIZE 34 | 204 | #define ACPI_SMBUS_BUFFER_SIZE 34 |
205 | #define ACPI_IPMI_BUFFER_SIZE 66 | ||
205 | 206 | ||
206 | /* _sx_d and _sx_w control methods */ | 207 | /* _sx_d and _sx_w control methods */ |
207 | 208 | ||
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 546dcdd86785..0b33d6c887b9 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c | |||
@@ -72,6 +72,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, | |||
72 | union acpi_operand_object *buffer_desc; | 72 | union acpi_operand_object *buffer_desc; |
73 | acpi_size length; | 73 | acpi_size length; |
74 | void *buffer; | 74 | void *buffer; |
75 | u32 function; | ||
75 | 76 | ||
76 | ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); | 77 | ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); |
77 | 78 | ||
@@ -97,13 +98,27 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, | |||
97 | } | 98 | } |
98 | } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | 99 | } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
99 | (obj_desc->field.region_obj->region.space_id == | 100 | (obj_desc->field.region_obj->region.space_id == |
100 | ACPI_ADR_SPACE_SMBUS)) { | 101 | ACPI_ADR_SPACE_SMBUS |
102 | || obj_desc->field.region_obj->region.space_id == | ||
103 | ACPI_ADR_SPACE_IPMI)) { | ||
101 | /* | 104 | /* |
102 | * This is an SMBus read. We must create a buffer to hold the data | 105 | * This is an SMBus or IPMI read. We must create a buffer to hold |
103 | * and directly access the region handler. | 106 | * the data and then directly access the region handler. |
107 | * | ||
108 | * Note: Smbus protocol value is passed in upper 16-bits of Function | ||
104 | */ | 109 | */ |
105 | buffer_desc = | 110 | if (obj_desc->field.region_obj->region.space_id == |
106 | acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); | 111 | ACPI_ADR_SPACE_SMBUS) { |
112 | length = ACPI_SMBUS_BUFFER_SIZE; | ||
113 | function = | ||
114 | ACPI_READ | (obj_desc->field.attribute << 16); | ||
115 | } else { /* IPMI */ | ||
116 | |||
117 | length = ACPI_IPMI_BUFFER_SIZE; | ||
118 | function = ACPI_READ; | ||
119 | } | ||
120 | |||
121 | buffer_desc = acpi_ut_create_buffer_object(length); | ||
107 | if (!buffer_desc) { | 122 | if (!buffer_desc) { |
108 | return_ACPI_STATUS(AE_NO_MEMORY); | 123 | return_ACPI_STATUS(AE_NO_MEMORY); |
109 | } | 124 | } |
@@ -112,16 +127,13 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, | |||
112 | 127 | ||
113 | acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); | 128 | acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); |
114 | 129 | ||
115 | /* | 130 | /* Call the region handler for the read */ |
116 | * Perform the read. | 131 | |
117 | * Note: Smbus protocol value is passed in upper 16-bits of Function | ||
118 | */ | ||
119 | status = acpi_ex_access_region(obj_desc, 0, | 132 | status = acpi_ex_access_region(obj_desc, 0, |
120 | ACPI_CAST_PTR(acpi_integer, | 133 | ACPI_CAST_PTR(acpi_integer, |
121 | buffer_desc-> | 134 | buffer_desc-> |
122 | buffer.pointer), | 135 | buffer.pointer), |
123 | ACPI_READ | (obj_desc->field. | 136 | function); |
124 | attribute << 16)); | ||
125 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | 137 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
126 | goto exit; | 138 | goto exit; |
127 | } | 139 | } |
@@ -212,6 +224,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, | |||
212 | u32 length; | 224 | u32 length; |
213 | void *buffer; | 225 | void *buffer; |
214 | union acpi_operand_object *buffer_desc; | 226 | union acpi_operand_object *buffer_desc; |
227 | u32 function; | ||
215 | 228 | ||
216 | ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); | 229 | ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); |
217 | 230 | ||
@@ -234,39 +247,56 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, | |||
234 | } | 247 | } |
235 | } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | 248 | } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && |
236 | (obj_desc->field.region_obj->region.space_id == | 249 | (obj_desc->field.region_obj->region.space_id == |
237 | ACPI_ADR_SPACE_SMBUS)) { | 250 | ACPI_ADR_SPACE_SMBUS |
251 | || obj_desc->field.region_obj->region.space_id == | ||
252 | ACPI_ADR_SPACE_IPMI)) { | ||
238 | /* | 253 | /* |
239 | * This is an SMBus write. We will bypass the entire field mechanism | 254 | * This is an SMBus or IPMI write. We will bypass the entire field |
240 | * and handoff the buffer directly to the handler. | 255 | * mechanism and handoff the buffer directly to the handler. For |
256 | * these address spaces, the buffer is bi-directional; on a write, | ||
257 | * return data is returned in the same buffer. | ||
258 | * | ||
259 | * Source must be a buffer of sufficient size: | ||
260 | * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE. | ||
241 | * | 261 | * |
242 | * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). | 262 | * Note: SMBus protocol type is passed in upper 16-bits of Function |
243 | */ | 263 | */ |
244 | if (source_desc->common.type != ACPI_TYPE_BUFFER) { | 264 | if (source_desc->common.type != ACPI_TYPE_BUFFER) { |
245 | ACPI_ERROR((AE_INFO, | 265 | ACPI_ERROR((AE_INFO, |
246 | "SMBus write requires Buffer, found type %s", | 266 | "SMBus or IPMI write requires Buffer, found type %s", |
247 | acpi_ut_get_object_type_name(source_desc))); | 267 | acpi_ut_get_object_type_name(source_desc))); |
248 | 268 | ||
249 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | 269 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
250 | } | 270 | } |
251 | 271 | ||
252 | if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { | 272 | if (obj_desc->field.region_obj->region.space_id == |
273 | ACPI_ADR_SPACE_SMBUS) { | ||
274 | length = ACPI_SMBUS_BUFFER_SIZE; | ||
275 | function = | ||
276 | ACPI_WRITE | (obj_desc->field.attribute << 16); | ||
277 | } else { /* IPMI */ | ||
278 | |||
279 | length = ACPI_IPMI_BUFFER_SIZE; | ||
280 | function = ACPI_WRITE; | ||
281 | } | ||
282 | |||
283 | if (source_desc->buffer.length < length) { | ||
253 | ACPI_ERROR((AE_INFO, | 284 | ACPI_ERROR((AE_INFO, |
254 | "SMBus write requires Buffer of length %X, found length %X", | 285 | "SMBus or IPMI write requires Buffer of length %X, found length %X", |
255 | ACPI_SMBUS_BUFFER_SIZE, | 286 | length, source_desc->buffer.length)); |
256 | source_desc->buffer.length)); | ||
257 | 287 | ||
258 | return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); | 288 | return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); |
259 | } | 289 | } |
260 | 290 | ||
261 | buffer_desc = | 291 | /* Create the bi-directional buffer */ |
262 | acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE); | 292 | |
293 | buffer_desc = acpi_ut_create_buffer_object(length); | ||
263 | if (!buffer_desc) { | 294 | if (!buffer_desc) { |
264 | return_ACPI_STATUS(AE_NO_MEMORY); | 295 | return_ACPI_STATUS(AE_NO_MEMORY); |
265 | } | 296 | } |
266 | 297 | ||
267 | buffer = buffer_desc->buffer.pointer; | 298 | buffer = buffer_desc->buffer.pointer; |
268 | ACPI_MEMCPY(buffer, source_desc->buffer.pointer, | 299 | ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); |
269 | ACPI_SMBUS_BUFFER_SIZE); | ||
270 | 300 | ||
271 | /* Lock entire transaction if requested */ | 301 | /* Lock entire transaction if requested */ |
272 | 302 | ||
@@ -275,12 +305,10 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, | |||
275 | /* | 305 | /* |
276 | * Perform the write (returns status and perhaps data in the | 306 | * Perform the write (returns status and perhaps data in the |
277 | * same buffer) | 307 | * same buffer) |
278 | * Note: SMBus protocol type is passed in upper 16-bits of Function. | ||
279 | */ | 308 | */ |
280 | status = acpi_ex_access_region(obj_desc, 0, | 309 | status = acpi_ex_access_region(obj_desc, 0, |
281 | (acpi_integer *) buffer, | 310 | (acpi_integer *) buffer, |
282 | ACPI_WRITE | (obj_desc->field. | 311 | function); |
283 | attribute << 16)); | ||
284 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | 312 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); |
285 | 313 | ||
286 | *result_desc = buffer_desc; | 314 | *result_desc = buffer_desc; |
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 6687be167f5f..d7b3b418fb45 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c | |||
@@ -120,12 +120,13 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, | |||
120 | } | 120 | } |
121 | 121 | ||
122 | /* | 122 | /* |
123 | * Exit now for SMBus address space, it has a non-linear address space | 123 | * Exit now for SMBus or IPMI address space, it has a non-linear address space |
124 | * and the request cannot be directly validated | 124 | * and the request cannot be directly validated |
125 | */ | 125 | */ |
126 | if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { | 126 | if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS || |
127 | rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) { | ||
127 | 128 | ||
128 | /* SMBus has a non-linear address space */ | 129 | /* SMBus or IPMI has a non-linear address space */ |
129 | 130 | ||
130 | return_ACPI_STATUS(AE_OK); | 131 | return_ACPI_STATUS(AE_OK); |
131 | } | 132 | } |