]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
1da177e4 LT |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: exregion - ACPI default op_region (address space) handlers | |
5 | * | |
800ba7c5 | 6 | * Copyright (C) 2000 - 2020, Intel Corp. |
1da177e4 | 7 | * |
95857638 | 8 | *****************************************************************************/ |
1da177e4 | 9 | |
1da177e4 | 10 | #include <acpi/acpi.h> |
e2f7a777 LB |
11 | #include "accommon.h" |
12 | #include "acinterp.h" | |
1da177e4 | 13 | |
1da177e4 | 14 | #define _COMPONENT ACPI_EXECUTER |
4be44fcd | 15 | ACPI_MODULE_NAME("exregion") |
1da177e4 LT |
16 | |
17 | /******************************************************************************* | |
18 | * | |
19 | * FUNCTION: acpi_ex_system_memory_space_handler | |
20 | * | |
ba494bee BM |
21 | * PARAMETERS: function - Read or Write operation |
22 | * address - Where in the space to read or write | |
1da177e4 | 23 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 24 | * value - Pointer to in or out value |
1da177e4 LT |
25 | * handler_context - Pointer to Handler's context |
26 | * region_context - Pointer to context specific to the | |
27 | * accessed region | |
28 | * | |
29 | * RETURN: Status | |
30 | * | |
31 | * DESCRIPTION: Handler for the System Memory address space (Op Region) | |
32 | * | |
33 | ******************************************************************************/ | |
1da177e4 | 34 | acpi_status |
4be44fcd LB |
35 | acpi_ex_system_memory_space_handler(u32 function, |
36 | acpi_physical_address address, | |
37 | u32 bit_width, | |
5df7e6cb | 38 | u64 *value, |
4be44fcd | 39 | void *handler_context, void *region_context) |
1da177e4 | 40 | { |
4be44fcd LB |
41 | acpi_status status = AE_OK; |
42 | void *logical_addr_ptr = NULL; | |
43 | struct acpi_mem_space_context *mem_info = region_context; | |
44 | u32 length; | |
d410ee51 BM |
45 | acpi_size map_length; |
46 | acpi_size page_boundary_map_length; | |
0897831b | 47 | #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED |
4be44fcd | 48 | u32 remainder; |
1da177e4 LT |
49 | #endif |
50 | ||
b229cf92 | 51 | ACPI_FUNCTION_TRACE(ex_system_memory_space_handler); |
1da177e4 LT |
52 | |
53 | /* Validate and translate the bit width */ | |
54 | ||
55 | switch (bit_width) { | |
56 | case 8: | |
1d1ea1b7 | 57 | |
1da177e4 LT |
58 | length = 1; |
59 | break; | |
60 | ||
61 | case 16: | |
1d1ea1b7 | 62 | |
1da177e4 LT |
63 | length = 2; |
64 | break; | |
65 | ||
66 | case 32: | |
1d1ea1b7 | 67 | |
1da177e4 LT |
68 | length = 4; |
69 | break; | |
70 | ||
71 | case 64: | |
1d1ea1b7 | 72 | |
1da177e4 LT |
73 | length = 8; |
74 | break; | |
75 | ||
76 | default: | |
1d1ea1b7 | 77 | |
f6a22b0b | 78 | ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u", |
b8e4d893 | 79 | bit_width)); |
4be44fcd | 80 | return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
1da177e4 LT |
81 | } |
82 | ||
0897831b | 83 | #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED |
1da177e4 LT |
84 | /* |
85 | * Hardware does not support non-aligned data transfers, we must verify | |
86 | * the request. | |
87 | */ | |
5df7e6cb | 88 | (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder); |
1da177e4 | 89 | if (remainder != 0) { |
4be44fcd | 90 | return_ACPI_STATUS(AE_AML_ALIGNMENT); |
1da177e4 LT |
91 | } |
92 | #endif | |
93 | ||
94 | /* | |
95 | * Does the request fit into the cached memory mapping? | |
96 | * Is 1) Address below the current mapping? OR | |
97 | * 2) Address beyond the current mapping? | |
98 | */ | |
99 | if ((address < mem_info->mapped_physical_address) || | |
5df7e6cb BM |
100 | (((u64) address + length) > ((u64) |
101 | mem_info->mapped_physical_address + | |
102 | mem_info->mapped_length))) { | |
1da177e4 LT |
103 | /* |
104 | * The request cannot be resolved by the current memory mapping; | |
105 | * Delete the existing mapping and create a new one. | |
106 | */ | |
107 | if (mem_info->mapped_length) { | |
52fc0b02 | 108 | |
1da177e4 LT |
109 | /* Valid mapping, delete it */ |
110 | ||
4be44fcd LB |
111 | acpi_os_unmap_memory(mem_info->mapped_logical_address, |
112 | mem_info->mapped_length); | |
1da177e4 LT |
113 | } |
114 | ||
115 | /* | |
75c8044f LZ |
116 | * October 2009: Attempt to map from the requested address to the |
117 | * end of the region. However, we will never map more than one | |
118 | * page, nor will we cross a page boundary. | |
1da177e4 | 119 | */ |
d410ee51 | 120 | map_length = (acpi_size) |
4be44fcd | 121 | ((mem_info->address + mem_info->length) - address); |
44f6c012 | 122 | |
d410ee51 BM |
123 | /* |
124 | * If mapping the entire remaining portion of the region will cross | |
125 | * a page boundary, just map up to the page boundary, do not cross. | |
126 | * On some systems, crossing a page boundary while mapping regions | |
127 | * can cause warnings if the pages have different attributes | |
75c8044f LZ |
128 | * due to resource management. |
129 | * | |
130 | * This has the added benefit of constraining a single mapping to | |
131 | * one page, which is similar to the original code that used a 4k | |
132 | * maximum window. | |
d410ee51 | 133 | */ |
938ed102 BM |
134 | page_boundary_map_length = (acpi_size) |
135 | (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address); | |
739dcbb9 | 136 | if (page_boundary_map_length == 0) { |
d410ee51 BM |
137 | page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; |
138 | } | |
139 | ||
140 | if (map_length > page_boundary_map_length) { | |
141 | map_length = page_boundary_map_length; | |
1da177e4 LT |
142 | } |
143 | ||
144 | /* Create a new mapping starting at the address given */ | |
145 | ||
ea284925 LZ |
146 | mem_info->mapped_logical_address = |
147 | acpi_os_map_memory(address, map_length); | |
f3d2e786 | 148 | if (!mem_info->mapped_logical_address) { |
b8e4d893 | 149 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 150 | "Could not map memory at 0x%8.8X%8.8X, size %u", |
1d0a0b2f | 151 | ACPI_FORMAT_UINT64(address), |
18ae9021 | 152 | (u32)map_length)); |
1da177e4 | 153 | mem_info->mapped_length = 0; |
f3d2e786 | 154 | return_ACPI_STATUS(AE_NO_MEMORY); |
1da177e4 LT |
155 | } |
156 | ||
157 | /* Save the physical address and mapping size */ | |
158 | ||
159 | mem_info->mapped_physical_address = address; | |
d410ee51 | 160 | mem_info->mapped_length = map_length; |
1da177e4 LT |
161 | } |
162 | ||
163 | /* | |
164 | * Generate a logical pointer corresponding to the address we want to | |
165 | * access | |
166 | */ | |
167 | logical_addr_ptr = mem_info->mapped_logical_address + | |
5df7e6cb | 168 | ((u64) address - (u64) mem_info->mapped_physical_address); |
4be44fcd LB |
169 | |
170 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
b27d6597 | 171 | "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", |
1d0a0b2f | 172 | bit_width, function, ACPI_FORMAT_UINT64(address))); |
4be44fcd LB |
173 | |
174 | /* | |
175 | * Perform the memory read or write | |
176 | * | |
177 | * Note: For machines that do not support non-aligned transfers, the target | |
73a3090a | 178 | * address was checked for alignment above. We do not attempt to break the |
4be44fcd LB |
179 | * transfer up into smaller (byte-size) chunks because the AML specifically |
180 | * asked for a transfer width that the hardware may require. | |
181 | */ | |
1da177e4 LT |
182 | switch (function) { |
183 | case ACPI_READ: | |
184 | ||
185 | *value = 0; | |
186 | switch (bit_width) { | |
187 | case 8: | |
1d1ea1b7 CG |
188 | |
189 | *value = (u64)ACPI_GET8(logical_addr_ptr); | |
1da177e4 LT |
190 | break; |
191 | ||
192 | case 16: | |
1d1ea1b7 CG |
193 | |
194 | *value = (u64)ACPI_GET16(logical_addr_ptr); | |
1da177e4 LT |
195 | break; |
196 | ||
197 | case 32: | |
1d1ea1b7 CG |
198 | |
199 | *value = (u64)ACPI_GET32(logical_addr_ptr); | |
1da177e4 LT |
200 | break; |
201 | ||
1da177e4 | 202 | case 64: |
1d1ea1b7 CG |
203 | |
204 | *value = (u64)ACPI_GET64(logical_addr_ptr); | |
1da177e4 | 205 | break; |
59fa8505 | 206 | |
1da177e4 | 207 | default: |
1d1ea1b7 | 208 | |
1da177e4 | 209 | /* bit_width was already validated */ |
1d1ea1b7 | 210 | |
1da177e4 LT |
211 | break; |
212 | } | |
213 | break; | |
214 | ||
215 | case ACPI_WRITE: | |
216 | ||
217 | switch (bit_width) { | |
218 | case 8: | |
1d1ea1b7 | 219 | |
57bf6aef | 220 | ACPI_SET8(logical_addr_ptr, *value); |
1da177e4 LT |
221 | break; |
222 | ||
223 | case 16: | |
1d1ea1b7 | 224 | |
57bf6aef | 225 | ACPI_SET16(logical_addr_ptr, *value); |
1da177e4 LT |
226 | break; |
227 | ||
228 | case 32: | |
1d1ea1b7 | 229 | |
57bf6aef | 230 | ACPI_SET32(logical_addr_ptr, *value); |
1da177e4 LT |
231 | break; |
232 | ||
1da177e4 | 233 | case 64: |
1d1ea1b7 | 234 | |
57bf6aef | 235 | ACPI_SET64(logical_addr_ptr, *value); |
1da177e4 | 236 | break; |
1da177e4 LT |
237 | |
238 | default: | |
1d1ea1b7 | 239 | |
1da177e4 | 240 | /* bit_width was already validated */ |
1d1ea1b7 | 241 | |
1da177e4 LT |
242 | break; |
243 | } | |
244 | break; | |
245 | ||
246 | default: | |
1d1ea1b7 | 247 | |
1da177e4 LT |
248 | status = AE_BAD_PARAMETER; |
249 | break; | |
250 | } | |
251 | ||
4be44fcd | 252 | return_ACPI_STATUS(status); |
1da177e4 LT |
253 | } |
254 | ||
1da177e4 LT |
255 | /******************************************************************************* |
256 | * | |
257 | * FUNCTION: acpi_ex_system_io_space_handler | |
258 | * | |
ba494bee BM |
259 | * PARAMETERS: function - Read or Write operation |
260 | * address - Where in the space to read or write | |
1da177e4 | 261 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 262 | * value - Pointer to in or out value |
1da177e4 LT |
263 | * handler_context - Pointer to Handler's context |
264 | * region_context - Pointer to context specific to the | |
265 | * accessed region | |
266 | * | |
267 | * RETURN: Status | |
268 | * | |
269 | * DESCRIPTION: Handler for the System IO address space (Op Region) | |
270 | * | |
271 | ******************************************************************************/ | |
272 | ||
273 | acpi_status | |
4be44fcd LB |
274 | acpi_ex_system_io_space_handler(u32 function, |
275 | acpi_physical_address address, | |
276 | u32 bit_width, | |
5df7e6cb | 277 | u64 *value, |
4be44fcd | 278 | void *handler_context, void *region_context) |
1da177e4 | 279 | { |
4be44fcd LB |
280 | acpi_status status = AE_OK; |
281 | u32 value32; | |
1da177e4 | 282 | |
b229cf92 | 283 | ACPI_FUNCTION_TRACE(ex_system_io_space_handler); |
1da177e4 | 284 | |
4be44fcd | 285 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
b27d6597 | 286 | "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n", |
1d0a0b2f | 287 | bit_width, function, ACPI_FORMAT_UINT64(address))); |
1da177e4 LT |
288 | |
289 | /* Decode the function parameter */ | |
290 | ||
291 | switch (function) { | |
292 | case ACPI_READ: | |
293 | ||
f5c1e1c5 | 294 | status = acpi_hw_read_port((acpi_io_address)address, |
4be44fcd | 295 | &value32, bit_width); |
1da177e4 LT |
296 | *value = value32; |
297 | break; | |
298 | ||
299 | case ACPI_WRITE: | |
300 | ||
f5c1e1c5 LZ |
301 | status = acpi_hw_write_port((acpi_io_address)address, |
302 | (u32)*value, bit_width); | |
1da177e4 LT |
303 | break; |
304 | ||
305 | default: | |
1d1ea1b7 | 306 | |
1da177e4 LT |
307 | status = AE_BAD_PARAMETER; |
308 | break; | |
309 | } | |
310 | ||
4be44fcd | 311 | return_ACPI_STATUS(status); |
1da177e4 LT |
312 | } |
313 | ||
bd23fac3 | 314 | #ifdef ACPI_PCI_CONFIGURED |
1da177e4 LT |
315 | /******************************************************************************* |
316 | * | |
317 | * FUNCTION: acpi_ex_pci_config_space_handler | |
318 | * | |
ba494bee BM |
319 | * PARAMETERS: function - Read or Write operation |
320 | * address - Where in the space to read or write | |
1da177e4 | 321 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 322 | * value - Pointer to in or out value |
1da177e4 LT |
323 | * handler_context - Pointer to Handler's context |
324 | * region_context - Pointer to context specific to the | |
325 | * accessed region | |
326 | * | |
327 | * RETURN: Status | |
328 | * | |
329 | * DESCRIPTION: Handler for the PCI Config address space (Op Region) | |
330 | * | |
331 | ******************************************************************************/ | |
332 | ||
333 | acpi_status | |
4be44fcd LB |
334 | acpi_ex_pci_config_space_handler(u32 function, |
335 | acpi_physical_address address, | |
336 | u32 bit_width, | |
5df7e6cb | 337 | u64 *value, |
4be44fcd | 338 | void *handler_context, void *region_context) |
1da177e4 | 339 | { |
4be44fcd LB |
340 | acpi_status status = AE_OK; |
341 | struct acpi_pci_id *pci_id; | |
342 | u16 pci_register; | |
1da177e4 | 343 | |
b229cf92 | 344 | ACPI_FUNCTION_TRACE(ex_pci_config_space_handler); |
1da177e4 LT |
345 | |
346 | /* | |
347 | * The arguments to acpi_os(Read|Write)pci_configuration are: | |
348 | * | |
349 | * pci_segment is the PCI bus segment range 0-31 | |
350 | * pci_bus is the PCI bus number range 0-255 | |
351 | * pci_device is the PCI device number range 0-31 | |
352 | * pci_function is the PCI device function number | |
353 | * pci_register is the Config space register range 0-255 bytes | |
354 | * | |
ba494bee | 355 | * value - input value for write, output address for read |
1da177e4 LT |
356 | * |
357 | */ | |
4be44fcd | 358 | pci_id = (struct acpi_pci_id *)region_context; |
1da177e4 LT |
359 | pci_register = (u16) (u32) address; |
360 | ||
4be44fcd | 361 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1fad8738 BM |
362 | "Pci-Config %u (%u) Seg(%04x) Bus(%04x) " |
363 | "Dev(%04x) Func(%04x) Reg(%04x)\n", | |
4be44fcd LB |
364 | function, bit_width, pci_id->segment, pci_id->bus, |
365 | pci_id->device, pci_id->function, pci_register)); | |
1da177e4 LT |
366 | |
367 | switch (function) { | |
368 | case ACPI_READ: | |
369 | ||
bb42cc22 | 370 | *value = 0; |
1fad8738 BM |
371 | status = |
372 | acpi_os_read_pci_configuration(pci_id, pci_register, value, | |
373 | bit_width); | |
1da177e4 LT |
374 | break; |
375 | ||
376 | case ACPI_WRITE: | |
377 | ||
1fad8738 BM |
378 | status = |
379 | acpi_os_write_pci_configuration(pci_id, pci_register, | |
380 | *value, bit_width); | |
1da177e4 LT |
381 | break; |
382 | ||
383 | default: | |
384 | ||
385 | status = AE_BAD_PARAMETER; | |
386 | break; | |
387 | } | |
388 | ||
4be44fcd | 389 | return_ACPI_STATUS(status); |
1da177e4 | 390 | } |
bd23fac3 | 391 | #endif |
1da177e4 | 392 | |
1da177e4 LT |
393 | /******************************************************************************* |
394 | * | |
395 | * FUNCTION: acpi_ex_cmos_space_handler | |
396 | * | |
ba494bee BM |
397 | * PARAMETERS: function - Read or Write operation |
398 | * address - Where in the space to read or write | |
1da177e4 | 399 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 400 | * value - Pointer to in or out value |
1da177e4 LT |
401 | * handler_context - Pointer to Handler's context |
402 | * region_context - Pointer to context specific to the | |
403 | * accessed region | |
404 | * | |
405 | * RETURN: Status | |
406 | * | |
407 | * DESCRIPTION: Handler for the CMOS address space (Op Region) | |
408 | * | |
409 | ******************************************************************************/ | |
410 | ||
411 | acpi_status | |
4be44fcd LB |
412 | acpi_ex_cmos_space_handler(u32 function, |
413 | acpi_physical_address address, | |
414 | u32 bit_width, | |
5df7e6cb | 415 | u64 *value, |
4be44fcd | 416 | void *handler_context, void *region_context) |
1da177e4 | 417 | { |
4be44fcd | 418 | acpi_status status = AE_OK; |
1da177e4 | 419 | |
b229cf92 | 420 | ACPI_FUNCTION_TRACE(ex_cmos_space_handler); |
1da177e4 | 421 | |
4be44fcd | 422 | return_ACPI_STATUS(status); |
1da177e4 LT |
423 | } |
424 | ||
bd23fac3 | 425 | #ifdef ACPI_PCI_CONFIGURED |
1da177e4 LT |
426 | /******************************************************************************* |
427 | * | |
428 | * FUNCTION: acpi_ex_pci_bar_space_handler | |
429 | * | |
ba494bee BM |
430 | * PARAMETERS: function - Read or Write operation |
431 | * address - Where in the space to read or write | |
1da177e4 | 432 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 433 | * value - Pointer to in or out value |
1da177e4 LT |
434 | * handler_context - Pointer to Handler's context |
435 | * region_context - Pointer to context specific to the | |
436 | * accessed region | |
437 | * | |
438 | * RETURN: Status | |
439 | * | |
440 | * DESCRIPTION: Handler for the PCI bar_target address space (Op Region) | |
441 | * | |
442 | ******************************************************************************/ | |
443 | ||
444 | acpi_status | |
4be44fcd LB |
445 | acpi_ex_pci_bar_space_handler(u32 function, |
446 | acpi_physical_address address, | |
447 | u32 bit_width, | |
5df7e6cb | 448 | u64 *value, |
4be44fcd | 449 | void *handler_context, void *region_context) |
1da177e4 | 450 | { |
4be44fcd | 451 | acpi_status status = AE_OK; |
1da177e4 | 452 | |
b229cf92 | 453 | ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler); |
1da177e4 | 454 | |
4be44fcd | 455 | return_ACPI_STATUS(status); |
1da177e4 | 456 | } |
bd23fac3 | 457 | #endif |
1da177e4 | 458 | |
1da177e4 LT |
459 | /******************************************************************************* |
460 | * | |
461 | * FUNCTION: acpi_ex_data_table_space_handler | |
462 | * | |
ba494bee BM |
463 | * PARAMETERS: function - Read or Write operation |
464 | * address - Where in the space to read or write | |
1da177e4 | 465 | * bit_width - Field width in bits (8, 16, or 32) |
ba494bee | 466 | * value - Pointer to in or out value |
1da177e4 LT |
467 | * handler_context - Pointer to Handler's context |
468 | * region_context - Pointer to context specific to the | |
469 | * accessed region | |
470 | * | |
471 | * RETURN: Status | |
472 | * | |
473 | * DESCRIPTION: Handler for the Data Table address space (Op Region) | |
474 | * | |
475 | ******************************************************************************/ | |
476 | ||
477 | acpi_status | |
4be44fcd LB |
478 | acpi_ex_data_table_space_handler(u32 function, |
479 | acpi_physical_address address, | |
480 | u32 bit_width, | |
5df7e6cb | 481 | u64 *value, |
4be44fcd | 482 | void *handler_context, void *region_context) |
1da177e4 | 483 | { |
b229cf92 | 484 | ACPI_FUNCTION_TRACE(ex_data_table_space_handler); |
1da177e4 | 485 | |
c1637e9c BM |
486 | /* |
487 | * Perform the memory read or write. The bit_width was already | |
488 | * validated. | |
489 | */ | |
1da177e4 LT |
490 | switch (function) { |
491 | case ACPI_READ: | |
492 | ||
4fa4616e BM |
493 | memcpy(ACPI_CAST_PTR(char, value), |
494 | ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width)); | |
1da177e4 LT |
495 | break; |
496 | ||
497 | case ACPI_WRITE: | |
c1637e9c | 498 | |
4fa4616e BM |
499 | memcpy(ACPI_PHYSADDR_TO_PTR(address), |
500 | ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); | |
c1637e9c BM |
501 | break; |
502 | ||
1da177e4 LT |
503 | default: |
504 | ||
c1637e9c | 505 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
506 | } |
507 | ||
4119532c | 508 | return_ACPI_STATUS(AE_OK); |
1da177e4 | 509 | } |