brintos

brintos / linux-shallow public Read only

0
0
Text · 13.5 KiB · c49b9f8 Raw
526 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: exregion - ACPI default op_region (address space) handlers5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acinterp.h"13 14#define _COMPONENT          ACPI_EXECUTER15ACPI_MODULE_NAME("exregion")16 17/*******************************************************************************18 *19 * FUNCTION:    acpi_ex_system_memory_space_handler20 *21 * PARAMETERS:  function            - Read or Write operation22 *              address             - Where in the space to read or write23 *              bit_width           - Field width in bits (8, 16, or 32)24 *              value               - Pointer to in or out value25 *              handler_context     - Pointer to Handler's context26 *              region_context      - Pointer to context specific to the27 *                                    accessed region28 *29 * RETURN:      Status30 *31 * DESCRIPTION: Handler for the System Memory address space (Op Region)32 *33 ******************************************************************************/34acpi_status35acpi_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_SUPPORTED48	u32 remainder;49#endif50 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_SUPPORTED84	/*85	 * Hardware does not support non-aligned data transfers, we must verify86	 * 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#endif93 94	/*95	 * Does the request fit into the cached memory mapping?96	 * Is 1) Address below the current mapping? OR97	 *    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 range105		 * at hand.  If found, save it as the current one and carry out106		 * 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 the134		 * end of the region. However, we will never map more than one135		 * 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 the163		 * 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 to174	 * access175	 */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 write185	 *186	 * Note: For machines that do not support non-aligned transfers, the target187	 * address was checked for alignment above. We do not attempt to break the188	 * transfer up into smaller (byte-size) chunks because the AML specifically189	 * 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_handler267 *268 * PARAMETERS:  function            - Read or Write operation269 *              address             - Where in the space to read or write270 *              bit_width           - Field width in bits (8, 16, or 32)271 *              value               - Pointer to in or out value272 *              handler_context     - Pointer to Handler's context273 *              region_context      - Pointer to context specific to the274 *                                    accessed region275 *276 * RETURN:      Status277 *278 * DESCRIPTION: Handler for the System IO address space (Op Region)279 *280 ******************************************************************************/281 282acpi_status283acpi_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_CONFIGURED324/*******************************************************************************325 *326 * FUNCTION:    acpi_ex_pci_config_space_handler327 *328 * PARAMETERS:  function            - Read or Write operation329 *              address             - Where in the space to read or write330 *              bit_width           - Field width in bits (8, 16, or 32)331 *              value               - Pointer to in or out value332 *              handler_context     - Pointer to Handler's context333 *              region_context      - Pointer to context specific to the334 *                                    accessed region335 *336 * RETURN:      Status337 *338 * DESCRIPTION: Handler for the PCI Config address space (Op Region)339 *340 ******************************************************************************/341 342acpi_status343acpi_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-31359	 *  pci_bus     is the PCI bus number range 0-255360	 *  pci_device  is the PCI device number range 0-31361	 *  pci_function is the PCI device function number362	 *  pci_register is the Config space register range 0-255 bytes363	 *364	 *  value - input value for write, output address for read365	 *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#endif401 402/*******************************************************************************403 *404 * FUNCTION:    acpi_ex_cmos_space_handler405 *406 * PARAMETERS:  function            - Read or Write operation407 *              address             - Where in the space to read or write408 *              bit_width           - Field width in bits (8, 16, or 32)409 *              value               - Pointer to in or out value410 *              handler_context     - Pointer to Handler's context411 *              region_context      - Pointer to context specific to the412 *                                    accessed region413 *414 * RETURN:      Status415 *416 * DESCRIPTION: Handler for the CMOS address space (Op Region)417 *418 ******************************************************************************/419 420acpi_status421acpi_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_CONFIGURED435/*******************************************************************************436 *437 * FUNCTION:    acpi_ex_pci_bar_space_handler438 *439 * PARAMETERS:  function            - Read or Write operation440 *              address             - Where in the space to read or write441 *              bit_width           - Field width in bits (8, 16, or 32)442 *              value               - Pointer to in or out value443 *              handler_context     - Pointer to Handler's context444 *              region_context      - Pointer to context specific to the445 *                                    accessed region446 *447 * RETURN:      Status448 *449 * DESCRIPTION: Handler for the PCI bar_target address space (Op Region)450 *451 ******************************************************************************/452 453acpi_status454acpi_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#endif467 468/*******************************************************************************469 *470 * FUNCTION:    acpi_ex_data_table_space_handler471 *472 * PARAMETERS:  function            - Read or Write operation473 *              address             - Where in the space to read or write474 *              bit_width           - Field width in bits (8, 16, or 32)475 *              value               - Pointer to in or out value476 *              handler_context     - Pointer to Handler's context477 *              region_context      - Pointer to context specific to the478 *                                    accessed region479 *480 * RETURN:      Status481 *482 * DESCRIPTION: Handler for the Data Table address space (Op Region)483 *484 ******************************************************************************/485 486acpi_status487acpi_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 already504	 * 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}526