forked from mirrors/linux
		
	ACPI: utils: Dynamically determine acpi_handle_list size
Address a long-standing "TBD" comment in the ACPI headers regarding the number of handles in struct acpi_handle_list. The number 10, which along with the comment dates back to 2.4.23, seems like it may have been arbitrarily chosen and isn't sufficient in all cases [1]. Finally change the code to dynamically determine the size of the handles table in struct acpi_handle_list and allocate it accordingly. Update the users of to struct acpi_handle_list to take the additional dynamic allocation into account. Link: https://lore.kernel.org/linux-acpi/20230809094451.15473-1-ivan.hu@canonical.com # [1] Co-developed-by: Vicki Pfau <vi@endrift.com> Signed-off-by: Vicki Pfau <vi@endrift.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
		
							parent
							
								
									3e7d6f396d
								
							
						
					
					
						commit
						2e57d10a65
					
				
					 6 changed files with 101 additions and 18 deletions
				
			
		|  | @ -578,6 +578,7 @@ static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) | |||
| { | ||||
| 	struct acpi_handle_list dep_devices; | ||||
| 	acpi_status status; | ||||
| 	bool ret = false; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!acpi_has_method(adev->handle, "_DEP")) | ||||
|  | @ -591,11 +592,14 @@ static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) | |||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < dep_devices.count; i++) { | ||||
| 		if (dep_devices.handles[i] == handle) | ||||
| 			return true; | ||||
| 		if (dep_devices.handles[i] == handle) { | ||||
| 			ret = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| 	acpi_handle_list_free(&dep_devices); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void acpi_lpss_link_consumer(struct device *dev1, | ||||
|  |  | |||
|  | @ -2032,6 +2032,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) | |||
| 		mutex_unlock(&acpi_dep_list_lock); | ||||
| 	} | ||||
| 
 | ||||
| 	acpi_handle_list_free(&dep_devices); | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -208,7 +208,7 @@ static bool update_trip_devices(struct acpi_thermal *tz, | |||
| 				struct acpi_thermal_trip *acpi_trip, | ||||
| 				int index, bool compare) | ||||
| { | ||||
| 	struct acpi_handle_list devices; | ||||
| 	struct acpi_handle_list devices = { 0 }; | ||||
| 	char method[] = "_PSL"; | ||||
| 	acpi_status status; | ||||
| 
 | ||||
|  | @ -218,18 +218,21 @@ static bool update_trip_devices(struct acpi_thermal *tz, | |||
| 		method[3] = '0' + index; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&devices, 0, sizeof(devices)); | ||||
| 
 | ||||
| 	status = acpi_evaluate_reference(tz->device->handle, method, NULL, &devices); | ||||
| 	if (ACPI_FAILURE(status)) { | ||||
| 		acpi_handle_info(tz->device->handle, "%s evaluation failure\n", method); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (compare && memcmp(&acpi_trip->devices, &devices, sizeof(devices))) | ||||
| 	if (acpi_handle_list_equal(&acpi_trip->devices, &devices)) { | ||||
| 		acpi_handle_list_free(&devices); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (compare) | ||||
| 		ACPI_THERMAL_TRIPS_EXCEPTION(tz, "device"); | ||||
| 
 | ||||
| 	memcpy(&acpi_trip->devices, &devices, sizeof(devices)); | ||||
| 	acpi_handle_list_replace(&acpi_trip->devices, &devices); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -842,6 +845,17 @@ static void acpi_thermal_check_fn(struct work_struct *work) | |||
| 	mutex_unlock(&tz->thermal_check_lock); | ||||
| } | ||||
| 
 | ||||
| static void acpi_thermal_free_thermal_zone(struct acpi_thermal *tz) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	acpi_handle_list_free(&tz->trips.passive.trip.devices); | ||||
| 	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) | ||||
| 		acpi_handle_list_free(&tz->trips.active[i].trip.devices); | ||||
| 
 | ||||
| 	kfree(tz); | ||||
| } | ||||
| 
 | ||||
| static int acpi_thermal_add(struct acpi_device *device) | ||||
| { | ||||
| 	struct acpi_thermal_trip *acpi_trip; | ||||
|  | @ -968,7 +982,7 @@ static int acpi_thermal_add(struct acpi_device *device) | |||
| free_trips: | ||||
| 	kfree(tz->trip_table); | ||||
| free_memory: | ||||
| 	kfree(tz); | ||||
| 	acpi_thermal_free_thermal_zone(tz); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
|  | @ -988,7 +1002,7 @@ static void acpi_thermal_remove(struct acpi_device *device) | |||
| 	flush_workqueue(acpi_thermal_pm_queue); | ||||
| 	acpi_thermal_unregister_thermal_zone(tz); | ||||
| 
 | ||||
| 	kfree(tz); | ||||
| 	acpi_thermal_free_thermal_zone(tz); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM_SLEEP | ||||
|  |  | |||
|  | @ -370,7 +370,8 @@ acpi_evaluate_reference(acpi_handle handle, | |||
| 		goto end; | ||||
| 	} | ||||
| 
 | ||||
| 	if (package->package.count > ACPI_MAX_HANDLES) { | ||||
| 	list->handles = kcalloc(package->package.count, sizeof(*list->handles), GFP_KERNEL); | ||||
| 	if (!list->handles) { | ||||
| 		kfree(package); | ||||
| 		return AE_NO_MEMORY; | ||||
| 	} | ||||
|  | @ -402,7 +403,8 @@ acpi_evaluate_reference(acpi_handle handle, | |||
|       end: | ||||
| 	if (ACPI_FAILURE(status)) { | ||||
| 		list->count = 0; | ||||
| 		//kfree(list->handles);
 | ||||
| 		kfree(list->handles); | ||||
| 		list->handles = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(buffer.pointer); | ||||
|  | @ -412,6 +414,61 @@ acpi_evaluate_reference(acpi_handle handle, | |||
| 
 | ||||
| EXPORT_SYMBOL(acpi_evaluate_reference); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_handle_list_equal - Check if two ACPI handle lists are the same | ||||
|  * @list1: First list to compare. | ||||
|  * @list2: Second list to compare. | ||||
|  * | ||||
|  * Return true if the given ACPI handle lists are of the same size and | ||||
|  * contain the same ACPI handles in the same order.  Otherwise, return false. | ||||
|  */ | ||||
| bool acpi_handle_list_equal(struct acpi_handle_list *list1, | ||||
| 			    struct acpi_handle_list *list2) | ||||
| { | ||||
| 	return list1->count == list2->count && | ||||
| 		!memcmp(list1->handles, list2->handles, | ||||
| 		        list1->count * sizeof(acpi_handle)); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(acpi_handle_list_equal); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_handle_list_replace - Replace one ACPI handle list with another | ||||
|  * @dst: ACPI handle list to replace. | ||||
|  * @src: Source ACPI handle list. | ||||
|  * | ||||
|  * Free the handles table in @dst, move the handles table from @src to @dst, | ||||
|  * copy count from @src to @dst and clear @src. | ||||
|  */ | ||||
| void acpi_handle_list_replace(struct acpi_handle_list *dst, | ||||
| 			      struct acpi_handle_list *src) | ||||
| { | ||||
| 	if (dst->count) | ||||
| 		kfree(dst->handles); | ||||
| 
 | ||||
| 	dst->count = src->count; | ||||
| 	dst->handles = src->handles; | ||||
| 
 | ||||
| 	src->handles = NULL; | ||||
| 	src->count = 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(acpi_handle_list_replace); | ||||
| 
 | ||||
| /**
 | ||||
|  * acpi_handle_list_free - Free the handles table in an ACPI handle list | ||||
|  * @list: ACPI handle list to free. | ||||
|  * | ||||
|  * Free the handles table in @list and clear its count field. | ||||
|  */ | ||||
| void acpi_handle_list_free(struct acpi_handle_list *list) | ||||
| { | ||||
| 	if (!list->count) | ||||
| 		return; | ||||
| 
 | ||||
| 	kfree(list->handles); | ||||
| 	list->count = 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(acpi_handle_list_free); | ||||
| 
 | ||||
| acpi_status | ||||
| acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld) | ||||
| { | ||||
|  |  | |||
|  | @ -741,6 +741,7 @@ static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle) | |||
| 	struct acpi_handle_list dep_devices; | ||||
| 	acpi_handle supplier = ACPI_HANDLE(&pdev->dev); | ||||
| 	acpi_status status; | ||||
| 	bool ret = false; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!acpi_has_method(handle, "_DEP")) | ||||
|  | @ -753,11 +754,14 @@ static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle) | |||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < dep_devices.count; i++) { | ||||
| 		if (dep_devices.handles[i] == supplier) | ||||
| 			return true; | ||||
| 		if (dep_devices.handles[i] == supplier) { | ||||
| 			ret = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| 	acpi_handle_list_free(&dep_devices); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl, | ||||
|  |  | |||
|  | @ -12,11 +12,9 @@ | |||
| #include <linux/device.h> | ||||
| #include <linux/property.h> | ||||
| 
 | ||||
| /* TBD: Make dynamic */ | ||||
| #define ACPI_MAX_HANDLES	10 | ||||
| struct acpi_handle_list { | ||||
| 	u32 count; | ||||
| 	acpi_handle handles[ACPI_MAX_HANDLES]; | ||||
| 	acpi_handle* handles; | ||||
| }; | ||||
| 
 | ||||
| /* acpi_utils.h */ | ||||
|  | @ -32,6 +30,11 @@ acpi_evaluate_reference(acpi_handle handle, | |||
| 			acpi_string pathname, | ||||
| 			struct acpi_object_list *arguments, | ||||
| 			struct acpi_handle_list *list); | ||||
| bool acpi_handle_list_equal(struct acpi_handle_list *list1, | ||||
| 			    struct acpi_handle_list *list2); | ||||
| void acpi_handle_list_replace(struct acpi_handle_list *dst, | ||||
| 			      struct acpi_handle_list *src); | ||||
| void acpi_handle_list_free(struct acpi_handle_list *list); | ||||
| acpi_status | ||||
| acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, | ||||
| 		  struct acpi_buffer *status_buf); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Rafael J. Wysocki
						Rafael J. Wysocki