Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: exregion - ACPI default op_region (address space) handlers
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acinterp.h"
13 : :
14 : : #define _COMPONENT ACPI_EXECUTER
15 : : ACPI_MODULE_NAME("exregion")
16 : :
17 : : /*******************************************************************************
18 : : *
19 : : * FUNCTION: acpi_ex_system_memory_space_handler
20 : : *
21 : : * PARAMETERS: function - Read or Write operation
22 : : * address - Where in the space to read or write
23 : : * bit_width - Field width in bits (8, 16, or 32)
24 : : * value - Pointer to in or out value
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 : : ******************************************************************************/
34 : : acpi_status
35 : 240 : acpi_ex_system_memory_space_handler(u32 function,
36 : : acpi_physical_address address,
37 : : u32 bit_width,
38 : : u64 *value,
39 : : void *handler_context, void *region_context)
40 : : {
41 : 240 : acpi_status status = AE_OK;
42 : 240 : void *logical_addr_ptr = NULL;
43 : 240 : struct acpi_mem_space_context *mem_info = region_context;
44 : 240 : u32 length;
45 : 240 : acpi_size map_length;
46 : 240 : acpi_size page_boundary_map_length;
47 : : #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
48 : : u32 remainder;
49 : : #endif
50 : :
51 : 240 : ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);
52 : :
53 : : /* Validate and translate the bit width */
54 : :
55 [ - + - - : 240 : switch (bit_width) {
- ]
56 : : case 8:
57 : :
58 : : length = 1;
59 : : break;
60 : :
61 : 0 : case 16:
62 : :
63 : 0 : length = 2;
64 : 0 : break;
65 : :
66 : 240 : case 32:
67 : :
68 : 240 : length = 4;
69 : 240 : break;
70 : :
71 : 0 : case 64:
72 : :
73 : 0 : length = 8;
74 : 0 : break;
75 : :
76 : 0 : default:
77 : :
78 : 0 : ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
79 : : bit_width));
80 : 0 : return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
81 : : }
82 : :
83 : : #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
84 : : /*
85 : : * Hardware does not support non-aligned data transfers, we must verify
86 : : * the request.
87 : : */
88 : : (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder);
89 : : if (remainder != 0) {
90 : : return_ACPI_STATUS(AE_AML_ALIGNMENT);
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 [ + - ]: 240 : if ((address < mem_info->mapped_physical_address) ||
100 : 240 : (((u64) address + length) > ((u64)
101 : 240 : mem_info->mapped_physical_address +
102 [ + + ]: 240 : mem_info->mapped_length))) {
103 : : /*
104 : : * The request cannot be resolved by the current memory mapping;
105 : : * Delete the existing mapping and create a new one.
106 : : */
107 [ - + ]: 30 : if (mem_info->mapped_length) {
108 : :
109 : : /* Valid mapping, delete it */
110 : :
111 : 0 : acpi_os_unmap_memory(mem_info->mapped_logical_address,
112 : : mem_info->mapped_length);
113 : : }
114 : :
115 : : /*
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.
119 : : */
120 : 30 : map_length = (acpi_size)
121 : 30 : ((mem_info->address + mem_info->length) - address);
122 : :
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
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.
133 : : */
134 : 30 : page_boundary_map_length = (acpi_size)
135 : 30 : (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address);
136 [ + - ]: 30 : if (page_boundary_map_length == 0) {
137 : 30 : page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
138 : : }
139 : :
140 : 30 : if (map_length > page_boundary_map_length) {
141 : : map_length = page_boundary_map_length;
142 : : }
143 : :
144 : : /* Create a new mapping starting at the address given */
145 : :
146 : 60 : mem_info->mapped_logical_address =
147 : 30 : acpi_os_map_memory(address, map_length);
148 [ - + ]: 30 : if (!mem_info->mapped_logical_address) {
149 : 0 : ACPI_ERROR((AE_INFO,
150 : : "Could not map memory at 0x%8.8X%8.8X, size %u",
151 : : ACPI_FORMAT_UINT64(address),
152 : : (u32)map_length));
153 : 0 : mem_info->mapped_length = 0;
154 : 0 : return_ACPI_STATUS(AE_NO_MEMORY);
155 : : }
156 : :
157 : : /* Save the physical address and mapping size */
158 : :
159 : 30 : mem_info->mapped_physical_address = address;
160 : 30 : mem_info->mapped_length = map_length;
161 : : }
162 : :
163 : : /*
164 : : * Generate a logical pointer corresponding to the address we want to
165 : : * access
166 : : */
167 : 240 : logical_addr_ptr = mem_info->mapped_logical_address +
168 : 240 : ((u64) address - (u64) mem_info->mapped_physical_address);
169 : :
170 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
171 : : "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
172 : 240 : bit_width, function, ACPI_FORMAT_UINT64(address)));
173 : :
174 : : /*
175 : : * Perform the memory read or write
176 : : *
177 : : * Note: For machines that do not support non-aligned transfers, the target
178 : : * address was checked for alignment above. We do not attempt to break the
179 : : * transfer up into smaller (byte-size) chunks because the AML specifically
180 : : * asked for a transfer width that the hardware may require.
181 : : */
182 [ + - - ]: 240 : switch (function) {
183 : 240 : case ACPI_READ:
184 : :
185 : 240 : *value = 0;
186 [ - - + - : 240 : switch (bit_width) {
- ]
187 : 0 : case 8:
188 : :
189 : 0 : *value = (u64)ACPI_GET8(logical_addr_ptr);
190 : 0 : break;
191 : :
192 : 0 : case 16:
193 : :
194 : 0 : *value = (u64)ACPI_GET16(logical_addr_ptr);
195 : 0 : break;
196 : :
197 : 240 : case 32:
198 : :
199 : 240 : *value = (u64)ACPI_GET32(logical_addr_ptr);
200 : 240 : break;
201 : :
202 : 0 : case 64:
203 : :
204 : 0 : *value = (u64)ACPI_GET64(logical_addr_ptr);
205 : 0 : break;
206 : :
207 : : default:
208 : :
209 : : /* bit_width was already validated */
210 : :
211 : : break;
212 : : }
213 : : break;
214 : :
215 : 0 : case ACPI_WRITE:
216 : :
217 [ # # # # : 0 : switch (bit_width) {
# ]
218 : 0 : case 8:
219 : :
220 : 0 : ACPI_SET8(logical_addr_ptr, *value);
221 : 0 : break;
222 : :
223 : 0 : case 16:
224 : :
225 : 0 : ACPI_SET16(logical_addr_ptr, *value);
226 : 0 : break;
227 : :
228 : 0 : case 32:
229 : :
230 : 0 : ACPI_SET32(logical_addr_ptr, *value);
231 : 0 : break;
232 : :
233 : 0 : case 64:
234 : :
235 : 0 : ACPI_SET64(logical_addr_ptr, *value);
236 : 0 : break;
237 : :
238 : : default:
239 : :
240 : : /* bit_width was already validated */
241 : :
242 : : break;
243 : : }
244 : : break;
245 : :
246 : : default:
247 : :
248 : : status = AE_BAD_PARAMETER;
249 : : break;
250 : : }
251 : :
252 : : return_ACPI_STATUS(status);
253 : : }
254 : :
255 : : /*******************************************************************************
256 : : *
257 : : * FUNCTION: acpi_ex_system_io_space_handler
258 : : *
259 : : * PARAMETERS: function - Read or Write operation
260 : : * address - Where in the space to read or write
261 : : * bit_width - Field width in bits (8, 16, or 32)
262 : : * value - Pointer to in or out value
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
274 : 150 : acpi_ex_system_io_space_handler(u32 function,
275 : : acpi_physical_address address,
276 : : u32 bit_width,
277 : : u64 *value,
278 : : void *handler_context, void *region_context)
279 : : {
280 : 150 : acpi_status status = AE_OK;
281 : 150 : u32 value32;
282 : :
283 : 150 : ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
284 : :
285 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
286 : : "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
287 : 150 : bit_width, function, ACPI_FORMAT_UINT64(address)));
288 : :
289 : : /* Decode the function parameter */
290 : :
291 [ + + - ]: 150 : switch (function) {
292 : 60 : case ACPI_READ:
293 : :
294 : 60 : status = acpi_hw_read_port((acpi_io_address)address,
295 : : &value32, bit_width);
296 : 60 : *value = value32;
297 : 60 : break;
298 : :
299 : 90 : case ACPI_WRITE:
300 : :
301 : 90 : status = acpi_hw_write_port((acpi_io_address)address,
302 : 90 : (u32)*value, bit_width);
303 : 90 : break;
304 : :
305 : : default:
306 : :
307 : : status = AE_BAD_PARAMETER;
308 : : break;
309 : : }
310 : :
311 : 150 : return_ACPI_STATUS(status);
312 : : }
313 : :
314 : : #ifdef ACPI_PCI_CONFIGURED
315 : : /*******************************************************************************
316 : : *
317 : : * FUNCTION: acpi_ex_pci_config_space_handler
318 : : *
319 : : * PARAMETERS: function - Read or Write operation
320 : : * address - Where in the space to read or write
321 : : * bit_width - Field width in bits (8, 16, or 32)
322 : : * value - Pointer to in or out value
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
334 : 1410 : acpi_ex_pci_config_space_handler(u32 function,
335 : : acpi_physical_address address,
336 : : u32 bit_width,
337 : : u64 *value,
338 : : void *handler_context, void *region_context)
339 : : {
340 : 1410 : acpi_status status = AE_OK;
341 : 1410 : struct acpi_pci_id *pci_id;
342 : 1410 : u16 pci_register;
343 : :
344 : 1410 : ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
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 : : *
355 : : * value - input value for write, output address for read
356 : : *
357 : : */
358 : 1410 : pci_id = (struct acpi_pci_id *)region_context;
359 : 1410 : pci_register = (u16) (u32) address;
360 : :
361 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
362 : : "Pci-Config %u (%u) Seg(%04x) Bus(%04x) "
363 : : "Dev(%04x) Func(%04x) Reg(%04x)\n",
364 : : function, bit_width, pci_id->segment, pci_id->bus,
365 : 1410 : pci_id->device, pci_id->function, pci_register));
366 : :
367 [ + + - ]: 1410 : switch (function) {
368 : 1260 : case ACPI_READ:
369 : :
370 : 1260 : *value = 0;
371 : 1260 : status =
372 : 1260 : acpi_os_read_pci_configuration(pci_id, pci_register, value,
373 : : bit_width);
374 : 1260 : break;
375 : :
376 : 150 : case ACPI_WRITE:
377 : :
378 : 150 : status =
379 : 150 : acpi_os_write_pci_configuration(pci_id, pci_register,
380 : : *value, bit_width);
381 : 150 : break;
382 : :
383 : : default:
384 : :
385 : : status = AE_BAD_PARAMETER;
386 : : break;
387 : : }
388 : :
389 : 1410 : return_ACPI_STATUS(status);
390 : : }
391 : : #endif
392 : :
393 : : /*******************************************************************************
394 : : *
395 : : * FUNCTION: acpi_ex_cmos_space_handler
396 : : *
397 : : * PARAMETERS: function - Read or Write operation
398 : : * address - Where in the space to read or write
399 : : * bit_width - Field width in bits (8, 16, or 32)
400 : : * value - Pointer to in or out value
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
412 : 0 : acpi_ex_cmos_space_handler(u32 function,
413 : : acpi_physical_address address,
414 : : u32 bit_width,
415 : : u64 *value,
416 : : void *handler_context, void *region_context)
417 : : {
418 : 0 : acpi_status status = AE_OK;
419 : :
420 : 0 : ACPI_FUNCTION_TRACE(ex_cmos_space_handler);
421 : :
422 : 0 : return_ACPI_STATUS(status);
423 : : }
424 : :
425 : : #ifdef ACPI_PCI_CONFIGURED
426 : : /*******************************************************************************
427 : : *
428 : : * FUNCTION: acpi_ex_pci_bar_space_handler
429 : : *
430 : : * PARAMETERS: function - Read or Write operation
431 : : * address - Where in the space to read or write
432 : : * bit_width - Field width in bits (8, 16, or 32)
433 : : * value - Pointer to in or out value
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
445 : 0 : acpi_ex_pci_bar_space_handler(u32 function,
446 : : acpi_physical_address address,
447 : : u32 bit_width,
448 : : u64 *value,
449 : : void *handler_context, void *region_context)
450 : : {
451 : 0 : acpi_status status = AE_OK;
452 : :
453 : 0 : ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler);
454 : :
455 : 0 : return_ACPI_STATUS(status);
456 : : }
457 : : #endif
458 : :
459 : : /*******************************************************************************
460 : : *
461 : : * FUNCTION: acpi_ex_data_table_space_handler
462 : : *
463 : : * PARAMETERS: function - Read or Write operation
464 : : * address - Where in the space to read or write
465 : : * bit_width - Field width in bits (8, 16, or 32)
466 : : * value - Pointer to in or out value
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
478 : 0 : acpi_ex_data_table_space_handler(u32 function,
479 : : acpi_physical_address address,
480 : : u32 bit_width,
481 : : u64 *value,
482 : : void *handler_context, void *region_context)
483 : : {
484 : 0 : ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
485 : :
486 : : /*
487 : : * Perform the memory read or write. The bit_width was already
488 : : * validated.
489 : : */
490 [ # # # ]: 0 : switch (function) {
491 : 0 : case ACPI_READ:
492 : :
493 : 0 : memcpy(ACPI_CAST_PTR(char, value),
494 : 0 : ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width));
495 : 0 : break;
496 : :
497 : 0 : case ACPI_WRITE:
498 : :
499 : 0 : memcpy(ACPI_PHYSADDR_TO_PTR(address),
500 : 0 : ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width));
501 : 0 : break;
502 : :
503 : : default:
504 : :
505 : : return_ACPI_STATUS(AE_BAD_PARAMETER);
506 : : }
507 : :
508 : : return_ACPI_STATUS(AE_OK);
509 : : }
|