File Index
Files and directories
Sign in
FILE

exregion.c

File preview with syntax highlighting.

linux-6.19.14/drivers/acpi/acpica/exregion.c C
  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 - 2025, Intel Corp.
  7 *
  8 *****************************************************************************/
  9
 10#include <acpi/acpi.h>
 11#include "accommon.h"
 12#include "acinterp.h"
 13
 14#define _COMPONENT          ACPI_EXECUTER
 15ACPI_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 ******************************************************************************/
 34acpi_status
 35acpi_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	acpi_status status = AE_OK;
 42	void *logical_addr_ptr = NULL;
 43	struct acpi_mem_space_context *mem_info = region_context;
 44	struct acpi_mem_mapping *mm = mem_info->cur_mm;
 45	u32 length;
 46	acpi_size map_length;
 47#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
 48	u32 remainder;
 49#endif
 50
 51	ACPI_FUNCTION_TRACE(ex_system_memory_space_handler);
 52
 53	/* Validate and translate the bit width */
 54
 55	switch (bit_width) {
 56	case 8:
 57
 58		length = 1;
 59		break;
 60
 61	case 16:
 62
 63		length = 2;
 64		break;
 65
 66	case 32:
 67
 68		length = 4;
 69		break;
 70
 71	case 64:
 72
 73		length = 8;
 74		break;
 75
 76	default:
 77
 78		ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
 79			    bit_width));
 80		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	if (!mm || (address < mm->physical_address) ||
100	    ((u64) address + length > (u64) mm->physical_address + mm->length)) {
101		/*
102		 * The request cannot be resolved by the current memory mapping.
103		 *
104		 * Look for an existing saved mapping covering the address range
105		 * at hand.  If found, save it as the current one and carry out
106		 * the access.
107		 */
108		for (mm = mem_info->first_mm; mm; mm = mm->next_mm) {
109			if (mm == mem_info->cur_mm)
110				continue;
111
112			if (address < mm->physical_address)
113				continue;
114
115			if ((u64) address + length >
116					(u64) mm->physical_address + mm->length)
117				continue;
118
119			mem_info->cur_mm = mm;
120			goto access;
121		}
122
123		/* Create a new mappings list entry */
124		mm = ACPI_ALLOCATE_ZEROED(sizeof(*mm));
125		if (!mm) {
126			ACPI_ERROR((AE_INFO,
127				    "Unable to save memory mapping at 0x%8.8X%8.8X, size %u",
128				    ACPI_FORMAT_UINT64(address), length));
129			return_ACPI_STATUS(AE_NO_MEMORY);
130		}
131
132		/*
133		 * October 2009: Attempt to map from the requested address to the
134		 * end of the region. However, we will never map more than one
135		 * page, nor will we cross a page boundary.
136		 */
137		map_length = (acpi_size)
138		    ((mem_info->address + mem_info->length) - address);
139
140		if (map_length > ACPI_DEFAULT_PAGE_SIZE)
141			map_length = ACPI_DEFAULT_PAGE_SIZE;
142
143		/* Create a new mapping starting at the address given */
144
145		logical_addr_ptr = acpi_os_map_memory(address, map_length);
146		if (!logical_addr_ptr) {
147			ACPI_ERROR((AE_INFO,
148				    "Could not map memory at 0x%8.8X%8.8X, size %u",
149				    ACPI_FORMAT_UINT64(address),
150				    (u32)map_length));
151			ACPI_FREE(mm);
152			return_ACPI_STATUS(AE_NO_MEMORY);
153		}
154
155		/* Save the physical address and mapping size */
156
157		mm->logical_address = logical_addr_ptr;
158		mm->physical_address = address;
159		mm->length = map_length;
160
161		/*
162		 * Add the new entry to the mappigs list and save it as the
163		 * current mapping.
164		 */
165		mm->next_mm = mem_info->first_mm;
166		mem_info->first_mm = mm;
167
168		mem_info->cur_mm = mm;
169	}
170
171access:
172	/*
173	 * Generate a logical pointer corresponding to the address we want to
174	 * access
175	 */
176	logical_addr_ptr = mm->logical_address +
177		((u64) address - (u64) mm->physical_address);
178
179	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
180			  "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
181			  bit_width, function, ACPI_FORMAT_UINT64(address)));
182
183	/*
184	 * Perform the memory read or write
185	 *
186	 * Note: For machines that do not support non-aligned transfers, the target
187	 * address was checked for alignment above. We do not attempt to break the
188	 * transfer up into smaller (byte-size) chunks because the AML specifically
189	 * asked for a transfer width that the hardware may require.
190	 */
191	switch (function) {
192	case ACPI_READ:
193
194		*value = 0;
195		switch (bit_width) {
196		case 8:
197
198			*value = (u64)ACPI_GET8(logical_addr_ptr);
199			break;
200
201		case 16:
202
203			*value = (u64)ACPI_GET16(logical_addr_ptr);
204			break;
205
206		case 32:
207
208			*value = (u64)ACPI_GET32(logical_addr_ptr);
209			break;
210
211		case 64:
212
213			*value = (u64)ACPI_GET64(logical_addr_ptr);
214			break;
215
216		default:
217
218			/* bit_width was already validated */
219
220			break;
221		}
222		break;
223
224	case ACPI_WRITE:
225
226		switch (bit_width) {
227		case 8:
228
229			ACPI_SET8(logical_addr_ptr, *value);
230			break;
231
232		case 16:
233
234			ACPI_SET16(logical_addr_ptr, *value);
235			break;
236
237		case 32:
238
239			ACPI_SET32(logical_addr_ptr, *value);
240			break;
241
242		case 64:
243
244			ACPI_SET64(logical_addr_ptr, *value);
245			break;
246
247		default:
248
249			/* bit_width was already validated */
250
251			break;
252		}
253		break;
254
255	default:
256
257		status = AE_BAD_PARAMETER;
258		break;
259	}
260
261	return_ACPI_STATUS(status);
262}
263
264/*******************************************************************************
265 *
266 * FUNCTION:    acpi_ex_system_io_space_handler
267 *
268 * PARAMETERS:  function            - Read or Write operation
269 *              address             - Where in the space to read or write
270 *              bit_width           - Field width in bits (8, 16, or 32)
271 *              value               - Pointer to in or out value
272 *              handler_context     - Pointer to Handler's context
273 *              region_context      - Pointer to context specific to the
274 *                                    accessed region
275 *
276 * RETURN:      Status
277 *
278 * DESCRIPTION: Handler for the System IO address space (Op Region)
279 *
280 ******************************************************************************/
281
282acpi_status
283acpi_ex_system_io_space_handler(u32 function,
284				acpi_physical_address address,
285				u32 bit_width,
286				u64 *value,
287				void *handler_context, void *region_context)
288{
289	acpi_status status = AE_OK;
290	u32 value32;
291
292	ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
293
294	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
295			  "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
296			  bit_width, function, ACPI_FORMAT_UINT64(address)));
297
298	/* Decode the function parameter */
299
300	switch (function) {
301	case ACPI_READ:
302
303		status = acpi_hw_read_port((acpi_io_address)address,
304					   &value32, bit_width);
305		*value = value32;
306		break;
307
308	case ACPI_WRITE:
309
310		status = acpi_hw_write_port((acpi_io_address)address,
311					    (u32)*value, bit_width);
312		break;
313
314	default:
315
316		status = AE_BAD_PARAMETER;
317		break;
318	}
319
320	return_ACPI_STATUS(status);
321}
322
323#ifdef ACPI_PCI_CONFIGURED
324/*******************************************************************************
325 *
326 * FUNCTION:    acpi_ex_pci_config_space_handler
327 *
328 * PARAMETERS:  function            - Read or Write operation
329 *              address             - Where in the space to read or write
330 *              bit_width           - Field width in bits (8, 16, or 32)
331 *              value               - Pointer to in or out value
332 *              handler_context     - Pointer to Handler's context
333 *              region_context      - Pointer to context specific to the
334 *                                    accessed region
335 *
336 * RETURN:      Status
337 *
338 * DESCRIPTION: Handler for the PCI Config address space (Op Region)
339 *
340 ******************************************************************************/
341
342acpi_status
343acpi_ex_pci_config_space_handler(u32 function,
344				 acpi_physical_address address,
345				 u32 bit_width,
346				 u64 *value,
347				 void *handler_context, void *region_context)
348{
349	acpi_status status = AE_OK;
350	struct acpi_pci_id *pci_id;
351	u16 pci_register;
352
353	ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
354
355	/*
356	 *  The arguments to acpi_os(Read|Write)pci_configuration are:
357	 *
358	 *  pci_segment is the PCI bus segment range 0-31
359	 *  pci_bus     is the PCI bus number range 0-255
360	 *  pci_device  is the PCI device number range 0-31
361	 *  pci_function is the PCI device function number
362	 *  pci_register is the Config space register range 0-255 bytes
363	 *
364	 *  value - input value for write, output address for read
365	 *
366	 */
367	pci_id = (struct acpi_pci_id *)region_context;
368	pci_register = (u16) (u32) address;
369
370	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
371			  "Pci-Config %u (%u) Seg(%04x) Bus(%04x) "
372			  "Dev(%04x) Func(%04x) Reg(%04x)\n",
373			  function, bit_width, pci_id->segment, pci_id->bus,
374			  pci_id->device, pci_id->function, pci_register));
375
376	switch (function) {
377	case ACPI_READ:
378
379		*value = 0;
380		status =
381		    acpi_os_read_pci_configuration(pci_id, pci_register, value,
382						   bit_width);
383		break;
384
385	case ACPI_WRITE:
386
387		status =
388		    acpi_os_write_pci_configuration(pci_id, pci_register,
389						    *value, bit_width);
390		break;
391
392	default:
393
394		status = AE_BAD_PARAMETER;
395		break;
396	}
397
398	return_ACPI_STATUS(status);
399}
400#endif
401
402/*******************************************************************************
403 *
404 * FUNCTION:    acpi_ex_cmos_space_handler
405 *
406 * PARAMETERS:  function            - Read or Write operation
407 *              address             - Where in the space to read or write
408 *              bit_width           - Field width in bits (8, 16, or 32)
409 *              value               - Pointer to in or out value
410 *              handler_context     - Pointer to Handler's context
411 *              region_context      - Pointer to context specific to the
412 *                                    accessed region
413 *
414 * RETURN:      Status
415 *
416 * DESCRIPTION: Handler for the CMOS address space (Op Region)
417 *
418 ******************************************************************************/
419
420acpi_status
421acpi_ex_cmos_space_handler(u32 function,
422			   acpi_physical_address address,
423			   u32 bit_width,
424			   u64 *value,
425			   void *handler_context, void *region_context)
426{
427	acpi_status status = AE_OK;
428
429	ACPI_FUNCTION_TRACE(ex_cmos_space_handler);
430
431	return_ACPI_STATUS(status);
432}
433
434#ifdef ACPI_PCI_CONFIGURED
435/*******************************************************************************
436 *
437 * FUNCTION:    acpi_ex_pci_bar_space_handler
438 *
439 * PARAMETERS:  function            - Read or Write operation
440 *              address             - Where in the space to read or write
441 *              bit_width           - Field width in bits (8, 16, or 32)
442 *              value               - Pointer to in or out value
443 *              handler_context     - Pointer to Handler's context
444 *              region_context      - Pointer to context specific to the
445 *                                    accessed region
446 *
447 * RETURN:      Status
448 *
449 * DESCRIPTION: Handler for the PCI bar_target address space (Op Region)
450 *
451 ******************************************************************************/
452
453acpi_status
454acpi_ex_pci_bar_space_handler(u32 function,
455			      acpi_physical_address address,
456			      u32 bit_width,
457			      u64 *value,
458			      void *handler_context, void *region_context)
459{
460	acpi_status status = AE_OK;
461
462	ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler);
463
464	return_ACPI_STATUS(status);
465}
466#endif
467
468/*******************************************************************************
469 *
470 * FUNCTION:    acpi_ex_data_table_space_handler
471 *
472 * PARAMETERS:  function            - Read or Write operation
473 *              address             - Where in the space to read or write
474 *              bit_width           - Field width in bits (8, 16, or 32)
475 *              value               - Pointer to in or out value
476 *              handler_context     - Pointer to Handler's context
477 *              region_context      - Pointer to context specific to the
478 *                                    accessed region
479 *
480 * RETURN:      Status
481 *
482 * DESCRIPTION: Handler for the Data Table address space (Op Region)
483 *
484 ******************************************************************************/
485
486acpi_status
487acpi_ex_data_table_space_handler(u32 function,
488				 acpi_physical_address address,
489				 u32 bit_width,
490				 u64 *value,
491				 void *handler_context, void *region_context)
492{
493	struct acpi_data_table_mapping *mapping;
494	char *pointer;
495
496	ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
497
498	mapping = (struct acpi_data_table_mapping *) region_context;
499	pointer = ACPI_CAST_PTR(char, mapping->pointer) +
500	    (address - ACPI_PTR_TO_PHYSADDR(mapping->pointer));
501
502	/*
503	 * Perform the memory read or write. The bit_width was already
504	 * validated.
505	 */
506	switch (function) {
507	case ACPI_READ:
508
509		memcpy(ACPI_CAST_PTR(char, value), pointer,
510		       ACPI_DIV_8(bit_width));
511		break;
512
513	case ACPI_WRITE:
514
515		memcpy(pointer, ACPI_CAST_PTR(char, value),
516		       ACPI_DIV_8(bit_width));
517		break;
518
519	default:
520
521		return_ACPI_STATUS(AE_BAD_PARAMETER);
522	}
523
524	return_ACPI_STATUS(AE_OK);
525}
~/ Read-only file preview.