aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2009-06-23 23:32:04 -0400
committerLen Brown <len.brown@intel.com>2009-08-27 10:17:18 -0400
commit6557a49a443a347d24aed58076365432ded30edc (patch)
treed7ac2ce73b7f55bbcdc74864fd99c2285b879a05 /drivers/acpi
parent3db20bed579bc4e7fe581c48ad1bde853aa9ff68 (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.h3
-rw-r--r--drivers/acpi/acpica/exfield.c82
-rw-r--r--drivers/acpi/acpica/exfldio.c7
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 }