exserial.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /******************************************************************************
  3. *
  4. * Module Name: exserial - field_unit support for serial address spaces
  5. *
  6. * Copyright (C) 2000 - 2022, Intel Corp.
  7. *
  8. *****************************************************************************/
  9. #include <acpi/acpi.h>
  10. #include "accommon.h"
  11. #include "acdispat.h"
  12. #include "acinterp.h"
  13. #include "amlcode.h"
  14. #define _COMPONENT ACPI_EXECUTER
  15. ACPI_MODULE_NAME("exserial")
  16. /*******************************************************************************
  17. *
  18. * FUNCTION: acpi_ex_read_gpio
  19. *
  20. * PARAMETERS: obj_desc - The named field to read
  21. * buffer - Where the return data is returned
  22. *
  23. * RETURN: Status
  24. *
  25. * DESCRIPTION: Read from a named field that references a Generic Serial Bus
  26. * field
  27. *
  28. ******************************************************************************/
  29. acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer)
  30. {
  31. acpi_status status;
  32. ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc);
  33. /*
  34. * For GPIO (general_purpose_io), the Address will be the bit offset
  35. * from the previous Connection() operator, making it effectively a
  36. * pin number index. The bit_length is the length of the field, which
  37. * is thus the number of pins.
  38. */
  39. ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  40. "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
  41. obj_desc->field.pin_number_index,
  42. obj_desc->field.bit_length));
  43. /* Lock entire transaction if requested */
  44. acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  45. /* Perform the read */
  46. status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ);
  47. acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  48. return_ACPI_STATUS(status);
  49. }
  50. /*******************************************************************************
  51. *
  52. * FUNCTION: acpi_ex_write_gpio
  53. *
  54. * PARAMETERS: source_desc - Contains data to write. Expect to be
  55. * an Integer object.
  56. * obj_desc - The named field
  57. * result_desc - Where the return value is returned, if any
  58. *
  59. * RETURN: Status
  60. *
  61. * DESCRIPTION: Write to a named field that references a General Purpose I/O
  62. * field.
  63. *
  64. ******************************************************************************/
  65. acpi_status
  66. acpi_ex_write_gpio(union acpi_operand_object *source_desc,
  67. union acpi_operand_object *obj_desc,
  68. union acpi_operand_object **return_buffer)
  69. {
  70. acpi_status status;
  71. void *buffer;
  72. ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc);
  73. /*
  74. * For GPIO (general_purpose_io), we will bypass the entire field
  75. * mechanism and handoff the bit address and bit width directly to
  76. * the handler. The Address will be the bit offset
  77. * from the previous Connection() operator, making it effectively a
  78. * pin number index. The bit_length is the length of the field, which
  79. * is thus the number of pins.
  80. */
  81. if (source_desc->common.type != ACPI_TYPE_INTEGER) {
  82. return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  83. }
  84. ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
  85. "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X [TO]: Pin %u Bits %u\n",
  86. acpi_ut_get_type_name(source_desc->common.type),
  87. source_desc->common.type,
  88. (u32)source_desc->integer.value,
  89. obj_desc->field.pin_number_index,
  90. obj_desc->field.bit_length));
  91. buffer = &source_desc->integer.value;
  92. /* Lock entire transaction if requested */
  93. acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  94. /* Perform the write */
  95. status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE);
  96. acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  97. return_ACPI_STATUS(status);
  98. }
  99. /*******************************************************************************
  100. *
  101. * FUNCTION: acpi_ex_read_serial_bus
  102. *
  103. * PARAMETERS: obj_desc - The named field to read
  104. * return_buffer - Where the return value is returned, if any
  105. *
  106. * RETURN: Status
  107. *
  108. * DESCRIPTION: Read from a named field that references a serial bus
  109. * (SMBus, IPMI, or GSBus).
  110. *
  111. ******************************************************************************/
  112. acpi_status
  113. acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
  114. union acpi_operand_object **return_buffer)
  115. {
  116. acpi_status status;
  117. u32 buffer_length;
  118. union acpi_operand_object *buffer_desc;
  119. u32 function;
  120. u16 accessor_type;
  121. ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc);
  122. /*
  123. * This is an SMBus, GSBus or IPMI read. We must create a buffer to
  124. * hold the data and then directly access the region handler.
  125. *
  126. * Note: SMBus and GSBus protocol value is passed in upper 16-bits
  127. * of Function
  128. *
  129. * Common buffer format:
  130. * Status; (Byte 0 of the data buffer)
  131. * Length; (Byte 1 of the data buffer)
  132. * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
  133. */
  134. switch (obj_desc->field.region_obj->region.space_id) {
  135. case ACPI_ADR_SPACE_SMBUS:
  136. buffer_length = ACPI_SMBUS_BUFFER_SIZE;
  137. function = ACPI_READ | (obj_desc->field.attribute << 16);
  138. break;
  139. case ACPI_ADR_SPACE_IPMI:
  140. buffer_length = ACPI_IPMI_BUFFER_SIZE;
  141. function = ACPI_READ;
  142. break;
  143. case ACPI_ADR_SPACE_GSBUS:
  144. accessor_type = obj_desc->field.attribute;
  145. if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) {
  146. ACPI_ERROR((AE_INFO,
  147. "Invalid direct read using bidirectional write-then-read protocol"));
  148. return_ACPI_STATUS(AE_AML_PROTOCOL);
  149. }
  150. status =
  151. acpi_ex_get_protocol_buffer_length(accessor_type,
  152. &buffer_length);
  153. if (ACPI_FAILURE(status)) {
  154. ACPI_ERROR((AE_INFO,
  155. "Invalid protocol ID for GSBus: 0x%4.4X",
  156. accessor_type));
  157. return_ACPI_STATUS(status);
  158. }
  159. /* Add header length to get the full size of the buffer */
  160. buffer_length += ACPI_SERIAL_HEADER_SIZE;
  161. function = ACPI_READ | (accessor_type << 16);
  162. break;
  163. case ACPI_ADR_SPACE_PLATFORM_RT:
  164. buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
  165. function = ACPI_READ;
  166. break;
  167. default:
  168. return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
  169. }
  170. /* Create the local transfer buffer that is returned to the caller */
  171. buffer_desc = acpi_ut_create_buffer_object(buffer_length);
  172. if (!buffer_desc) {
  173. return_ACPI_STATUS(AE_NO_MEMORY);
  174. }
  175. /* Lock entire transaction if requested */
  176. acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  177. /* Call the region handler for the write-then-read */
  178. status = acpi_ex_access_region(obj_desc, 0,
  179. ACPI_CAST_PTR(u64,
  180. buffer_desc->buffer.
  181. pointer), function);
  182. acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  183. *return_buffer = buffer_desc;
  184. return_ACPI_STATUS(status);
  185. }
  186. /*******************************************************************************
  187. *
  188. * FUNCTION: acpi_ex_write_serial_bus
  189. *
  190. * PARAMETERS: source_desc - Contains data to write
  191. * obj_desc - The named field
  192. * return_buffer - Where the return value is returned, if any
  193. *
  194. * RETURN: Status
  195. *
  196. * DESCRIPTION: Write to a named field that references a serial bus
  197. * (SMBus, IPMI, GSBus).
  198. *
  199. ******************************************************************************/
  200. acpi_status
  201. acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
  202. union acpi_operand_object *obj_desc,
  203. union acpi_operand_object **return_buffer)
  204. {
  205. acpi_status status;
  206. u32 buffer_length;
  207. u32 data_length;
  208. void *buffer;
  209. union acpi_operand_object *buffer_desc;
  210. u32 function;
  211. u16 accessor_type;
  212. ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc);
  213. /*
  214. * This is an SMBus, GSBus or IPMI write. We will bypass the entire
  215. * field mechanism and handoff the buffer directly to the handler.
  216. * For these address spaces, the buffer is bidirectional; on a
  217. * write, return data is returned in the same buffer.
  218. *
  219. * Source must be a buffer of sufficient size, these are fixed size:
  220. * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
  221. *
  222. * Note: SMBus and GSBus protocol type is passed in upper 16-bits
  223. * of Function
  224. *
  225. * Common buffer format:
  226. * Status; (Byte 0 of the data buffer)
  227. * Length; (Byte 1 of the data buffer)
  228. * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
  229. */
  230. if (source_desc->common.type != ACPI_TYPE_BUFFER) {
  231. ACPI_ERROR((AE_INFO,
  232. "SMBus/IPMI/GenericSerialBus write requires "
  233. "Buffer, found type %s",
  234. acpi_ut_get_object_type_name(source_desc)));
  235. return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  236. }
  237. switch (obj_desc->field.region_obj->region.space_id) {
  238. case ACPI_ADR_SPACE_SMBUS:
  239. buffer_length = ACPI_SMBUS_BUFFER_SIZE;
  240. function = ACPI_WRITE | (obj_desc->field.attribute << 16);
  241. break;
  242. case ACPI_ADR_SPACE_IPMI:
  243. buffer_length = ACPI_IPMI_BUFFER_SIZE;
  244. function = ACPI_WRITE;
  245. break;
  246. case ACPI_ADR_SPACE_GSBUS:
  247. accessor_type = obj_desc->field.attribute;
  248. status =
  249. acpi_ex_get_protocol_buffer_length(accessor_type,
  250. &buffer_length);
  251. if (ACPI_FAILURE(status)) {
  252. ACPI_ERROR((AE_INFO,
  253. "Invalid protocol ID for GSBus: 0x%4.4X",
  254. accessor_type));
  255. return_ACPI_STATUS(status);
  256. }
  257. /* Add header length to get the full size of the buffer */
  258. buffer_length += ACPI_SERIAL_HEADER_SIZE;
  259. function = ACPI_WRITE | (accessor_type << 16);
  260. break;
  261. case ACPI_ADR_SPACE_PLATFORM_RT:
  262. buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
  263. function = ACPI_WRITE;
  264. break;
  265. default:
  266. return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
  267. }
  268. /* Create the transfer/bidirectional/return buffer */
  269. buffer_desc = acpi_ut_create_buffer_object(buffer_length);
  270. if (!buffer_desc) {
  271. return_ACPI_STATUS(AE_NO_MEMORY);
  272. }
  273. /* Copy the input buffer data to the transfer buffer */
  274. buffer = buffer_desc->buffer.pointer;
  275. data_length = (buffer_length < source_desc->buffer.length ?
  276. buffer_length : source_desc->buffer.length);
  277. memcpy(buffer, source_desc->buffer.pointer, data_length);
  278. /* Lock entire transaction if requested */
  279. acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
  280. /*
  281. * Perform the write (returns status and perhaps data in the
  282. * same buffer)
  283. */
  284. status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
  285. acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
  286. *return_buffer = buffer_desc;
  287. return_ACPI_STATUS(status);
  288. }