]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/acpi/acpica/exfield.c
nvme-tcp: support separate queue maps for read and write
[linux.git] / drivers / acpi / acpica / exfield.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: exfield - AML execution - field_unit read/write
5  *
6  * Copyright (C) 2000 - 2018, Intel Corp.
7  *
8  *****************************************************************************/
9
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acdispat.h"
13 #include "acinterp.h"
14 #include "amlcode.h"
15
16 #define _COMPONENT          ACPI_EXECUTER
17 ACPI_MODULE_NAME("exfield")
18
19 /*
20  * This table maps the various Attrib protocols to the byte transfer
21  * length. Used for the generic serial bus.
22  */
23 #define ACPI_INVALID_PROTOCOL_ID        0x80
24 #define ACPI_MAX_PROTOCOL_ID            0x0F
25 const u8 acpi_protocol_lengths[] = {
26         ACPI_INVALID_PROTOCOL_ID,       /* 0 - reserved */
27         ACPI_INVALID_PROTOCOL_ID,       /* 1 - reserved */
28         0x00,                   /* 2 - ATTRIB_QUICK */
29         ACPI_INVALID_PROTOCOL_ID,       /* 3 - reserved */
30         0x01,                   /* 4 - ATTRIB_SEND_RECEIVE */
31         ACPI_INVALID_PROTOCOL_ID,       /* 5 - reserved */
32         0x01,                   /* 6 - ATTRIB_BYTE */
33         ACPI_INVALID_PROTOCOL_ID,       /* 7 - reserved */
34         0x02,                   /* 8 - ATTRIB_WORD */
35         ACPI_INVALID_PROTOCOL_ID,       /* 9 - reserved */
36         0xFF,                   /* A - ATTRIB_BLOCK  */
37         0xFF,                   /* B - ATTRIB_BYTES */
38         0x02,                   /* C - ATTRIB_PROCESS_CALL */
39         0xFF,                   /* D - ATTRIB_BLOCK_PROCESS_CALL */
40         0xFF,                   /* E - ATTRIB_RAW_BYTES */
41         0xFF                    /* F - ATTRIB_RAW_PROCESS_BYTES */
42 };
43
44 /*******************************************************************************
45  *
46  * FUNCTION:    acpi_ex_get_protocol_buffer_length
47  *
48  * PARAMETERS:  protocol_id     - The type of the protocol indicated by region
49  *                                field access attributes
50  *              return_length   - Where the protocol byte transfer length is
51  *                                returned
52  *
53  * RETURN:      Status and decoded byte transfer length
54  *
55  * DESCRIPTION: This routine returns the length of the generic_serial_bus
56  *              protocol bytes
57  *
58  ******************************************************************************/
59
60 acpi_status
61 acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length)
62 {
63
64         if ((protocol_id > ACPI_MAX_PROTOCOL_ID) ||
65             (acpi_protocol_lengths[protocol_id] == ACPI_INVALID_PROTOCOL_ID)) {
66                 ACPI_ERROR((AE_INFO,
67                             "Invalid Field/AccessAs protocol ID: 0x%4.4X",
68                             protocol_id));
69
70                 return (AE_AML_PROTOCOL);
71         }
72
73         *return_length = acpi_protocol_lengths[protocol_id];
74         return (AE_OK);
75 }
76
77 /*******************************************************************************
78  *
79  * FUNCTION:    acpi_ex_read_data_from_field
80  *
81  * PARAMETERS:  walk_state          - Current execution state
82  *              obj_desc            - The named field
83  *              ret_buffer_desc     - Where the return data object is stored
84  *
85  * RETURN:      Status
86  *
87  * DESCRIPTION: Read from a named field. Returns either an Integer or a
88  *              Buffer, depending on the size of the field.
89  *
90  ******************************************************************************/
91
92 acpi_status
93 acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
94                              union acpi_operand_object *obj_desc,
95                              union acpi_operand_object **ret_buffer_desc)
96 {
97         acpi_status status;
98         union acpi_operand_object *buffer_desc;
99         void *buffer;
100         u32 buffer_length;
101
102         ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
103
104         /* Parameter validation */
105
106         if (!obj_desc) {
107                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
108         }
109         if (!ret_buffer_desc) {
110                 return_ACPI_STATUS(AE_BAD_PARAMETER);
111         }
112
113         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
114                 /*
115                  * If the buffer_field arguments have not been previously evaluated,
116                  * evaluate them now and save the results.
117                  */
118                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
119                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
120                         if (ACPI_FAILURE(status)) {
121                                 return_ACPI_STATUS(status);
122                         }
123                 }
124         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
125                    (obj_desc->field.region_obj->region.space_id ==
126                     ACPI_ADR_SPACE_SMBUS
127                     || obj_desc->field.region_obj->region.space_id ==
128                     ACPI_ADR_SPACE_GSBUS
129                     || obj_desc->field.region_obj->region.space_id ==
130                     ACPI_ADR_SPACE_IPMI)) {
131
132                 /* SMBus, GSBus, IPMI serial */
133
134                 status = acpi_ex_read_serial_bus(obj_desc, ret_buffer_desc);
135                 return_ACPI_STATUS(status);
136         }
137
138         /*
139          * Allocate a buffer for the contents of the field.
140          *
141          * If the field is larger than the current integer width, create
142          * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
143          * the use of arithmetic operators on the returned value if the
144          * field size is equal or smaller than an Integer.
145          *
146          * Note: Field.length is in bits.
147          */
148         buffer_length =
149             (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
150
151         if (buffer_length > acpi_gbl_integer_byte_width) {
152
153                 /* Field is too large for an Integer, create a Buffer instead */
154
155                 buffer_desc = acpi_ut_create_buffer_object(buffer_length);
156                 if (!buffer_desc) {
157                         return_ACPI_STATUS(AE_NO_MEMORY);
158                 }
159                 buffer = buffer_desc->buffer.pointer;
160         } else {
161                 /* Field will fit within an Integer (normal case) */
162
163                 buffer_desc = acpi_ut_create_integer_object((u64) 0);
164                 if (!buffer_desc) {
165                         return_ACPI_STATUS(AE_NO_MEMORY);
166                 }
167
168                 buffer_length = acpi_gbl_integer_byte_width;
169                 buffer = &buffer_desc->integer.value;
170         }
171
172         if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
173             (obj_desc->field.region_obj->region.space_id ==
174              ACPI_ADR_SPACE_GPIO)) {
175
176                 /* General Purpose I/O */
177
178                 status = acpi_ex_read_gpio(obj_desc, buffer);
179                 goto exit;
180         }
181
182         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
183                           "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
184                           obj_desc, obj_desc->common.type, buffer,
185                           buffer_length));
186         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
187                           "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
188                           obj_desc->common_field.bit_length,
189                           obj_desc->common_field.start_field_bit_offset,
190                           obj_desc->common_field.base_byte_offset));
191
192         /* Lock entire transaction if requested */
193
194         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
195
196         /* Read from the field */
197
198         status = acpi_ex_extract_from_field(obj_desc, buffer, buffer_length);
199         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
200
201 exit:
202         if (ACPI_FAILURE(status)) {
203                 acpi_ut_remove_reference(buffer_desc);
204         } else {
205                 *ret_buffer_desc = buffer_desc;
206         }
207
208         return_ACPI_STATUS(status);
209 }
210
211 /*******************************************************************************
212  *
213  * FUNCTION:    acpi_ex_write_data_to_field
214  *
215  * PARAMETERS:  source_desc         - Contains data to write
216  *              obj_desc            - The named field
217  *              result_desc         - Where the return value is returned, if any
218  *
219  * RETURN:      Status
220  *
221  * DESCRIPTION: Write to a named field
222  *
223  ******************************************************************************/
224
225 acpi_status
226 acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
227                             union acpi_operand_object *obj_desc,
228                             union acpi_operand_object **result_desc)
229 {
230         acpi_status status;
231         u32 buffer_length;
232         void *buffer;
233
234         ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
235
236         /* Parameter validation */
237
238         if (!source_desc || !obj_desc) {
239                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
240         }
241
242         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
243                 /*
244                  * If the buffer_field arguments have not been previously evaluated,
245                  * evaluate them now and save the results.
246                  */
247                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
248                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
249                         if (ACPI_FAILURE(status)) {
250                                 return_ACPI_STATUS(status);
251                         }
252                 }
253         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
254                    (obj_desc->field.region_obj->region.space_id ==
255                     ACPI_ADR_SPACE_GPIO)) {
256
257                 /* General Purpose I/O */
258
259                 status = acpi_ex_write_gpio(source_desc, obj_desc, result_desc);
260                 return_ACPI_STATUS(status);
261         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
262                    (obj_desc->field.region_obj->region.space_id ==
263                     ACPI_ADR_SPACE_SMBUS
264                     || obj_desc->field.region_obj->region.space_id ==
265                     ACPI_ADR_SPACE_GSBUS
266                     || obj_desc->field.region_obj->region.space_id ==
267                     ACPI_ADR_SPACE_IPMI)) {
268
269                 /* SMBus, GSBus, IPMI serial */
270
271                 status =
272                     acpi_ex_write_serial_bus(source_desc, obj_desc,
273                                              result_desc);
274                 return_ACPI_STATUS(status);
275         }
276
277         /* Get a pointer to the data to be written */
278
279         switch (source_desc->common.type) {
280         case ACPI_TYPE_INTEGER:
281
282                 buffer = &source_desc->integer.value;
283                 buffer_length = sizeof(source_desc->integer.value);
284                 break;
285
286         case ACPI_TYPE_BUFFER:
287
288                 buffer = source_desc->buffer.pointer;
289                 buffer_length = source_desc->buffer.length;
290                 break;
291
292         case ACPI_TYPE_STRING:
293
294                 buffer = source_desc->string.pointer;
295                 buffer_length = source_desc->string.length;
296                 break;
297
298         default:
299                 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
300         }
301
302         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
303                           "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
304                           source_desc,
305                           acpi_ut_get_type_name(source_desc->common.type),
306                           source_desc->common.type, buffer, buffer_length));
307
308         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
309                           "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
310                           obj_desc,
311                           acpi_ut_get_type_name(obj_desc->common.type),
312                           obj_desc->common.type,
313                           obj_desc->common_field.bit_length,
314                           obj_desc->common_field.start_field_bit_offset,
315                           obj_desc->common_field.base_byte_offset));
316
317         /* Lock entire transaction if requested */
318
319         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
320
321         /* Write to the field */
322
323         status = acpi_ex_insert_into_field(obj_desc, buffer, buffer_length);
324         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
325         return_ACPI_STATUS(status);
326 }