FILE
order-list-attributes.c
File preview with syntax highlighting.
linux-6.19.14/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Functions corresponding to ordered list type attributes under 4 * BIOS ORDERED LIST GUID for use with hp-bioscfg driver. 5 * 6 * Copyright (c) 2022 HP Development Company, L.P. 7 */ 8 9#include "bioscfg.h" 10 11GET_INSTANCE_ID(ordered_list); 12 13static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 14{ 15 int instance_id = get_ordered_list_instance_id(kobj); 16 17 if (instance_id < 0) 18 return -EIO; 19 20 return sysfs_emit(buf, "%s\n", 21 bioscfg_drv.ordered_list_data[instance_id].current_value); 22} 23 24static int replace_char_str(u8 *buffer, char *repl_char, char *repl_with) 25{ 26 char *src = buffer; 27 int buflen = strlen(buffer); 28 int item; 29 30 if (buflen < 1) 31 return -EINVAL; 32 33 for (item = 0; item < buflen; item++) 34 if (src[item] == *repl_char) 35 src[item] = *repl_with; 36 37 return 0; 38} 39 40/** 41 * validate_ordered_list_input() - 42 * Validate input of current_value against possible values 43 * 44 * @instance: The instance on which input is validated 45 * @buf: Input value 46 */ 47static int validate_ordered_list_input(int instance, char *buf) 48{ 49 /* validation is done by BIOS. This validation function will 50 * convert semicolon to commas. BIOS uses commas as 51 * separators when reporting ordered-list values. 52 */ 53 return replace_char_str(buf, SEMICOLON_SEP, COMMA_SEP); 54} 55 56static void update_ordered_list_value(int instance, char *attr_value) 57{ 58 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance]; 59 60 strscpy(ordered_list_data->current_value, attr_value); 61} 62 63ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, ordered_list); 64static struct kobj_attribute ordered_list_display_name = 65 __ATTR_RO(display_name); 66 67ATTRIBUTE_PROPERTY_STORE(current_value, ordered_list); 68static struct kobj_attribute ordered_list_current_val = 69 __ATTR_RW_MODE(current_value, 0644); 70 71ATTRIBUTE_VALUES_PROPERTY_SHOW(elements, ordered_list, SEMICOLON_SEP); 72static struct kobj_attribute ordered_list_elements_val = 73 __ATTR_RO(elements); 74 75static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, 76 char *buf) 77{ 78 return sysfs_emit(buf, "ordered-list\n"); 79} 80 81static struct kobj_attribute ordered_list_type = 82 __ATTR_RO(type); 83 84static struct attribute *ordered_list_attrs[] = { 85 &common_display_langcode.attr, 86 &ordered_list_display_name.attr, 87 &ordered_list_current_val.attr, 88 &ordered_list_elements_val.attr, 89 &ordered_list_type.attr, 90 NULL 91}; 92 93static const struct attribute_group ordered_list_attr_group = { 94 .attrs = ordered_list_attrs, 95}; 96 97int hp_alloc_ordered_list_data(void) 98{ 99 bioscfg_drv.ordered_list_instances_count = 100 hp_get_instance_count(HP_WMI_BIOS_ORDERED_LIST_GUID); 101 bioscfg_drv.ordered_list_data = kcalloc(bioscfg_drv.ordered_list_instances_count, 102 sizeof(*bioscfg_drv.ordered_list_data), 103 GFP_KERNEL); 104 if (!bioscfg_drv.ordered_list_data) { 105 bioscfg_drv.ordered_list_instances_count = 0; 106 return -ENOMEM; 107 } 108 return 0; 109} 110 111/* Expected Values types associated with each element */ 112static const acpi_object_type expected_order_types[] = { 113 [NAME] = ACPI_TYPE_STRING, 114 [VALUE] = ACPI_TYPE_STRING, 115 [PATH] = ACPI_TYPE_STRING, 116 [IS_READONLY] = ACPI_TYPE_INTEGER, 117 [DISPLAY_IN_UI] = ACPI_TYPE_INTEGER, 118 [REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER, 119 [SEQUENCE] = ACPI_TYPE_INTEGER, 120 [PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER, 121 [PREREQUISITES] = ACPI_TYPE_STRING, 122 [SECURITY_LEVEL] = ACPI_TYPE_INTEGER, 123 [ORD_LIST_SIZE] = ACPI_TYPE_INTEGER, 124 [ORD_LIST_ELEMENTS] = ACPI_TYPE_STRING, 125}; 126 127static int hp_populate_ordered_list_elements_from_package(union acpi_object *order_obj, 128 int order_obj_count, 129 int instance_id) 130{ 131 char *str_value = NULL; 132 int value_len = 0; 133 int ret; 134 u32 size; 135 u32 int_value = 0; 136 int elem; 137 int olist_elem; 138 int reqs; 139 int eloc; 140 char *tmpstr = NULL; 141 char *part_tmp = NULL; 142 int tmp_len = 0; 143 char *part = NULL; 144 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 145 146 if (!order_obj) 147 return -EINVAL; 148 149 for (elem = 1, eloc = 1; eloc < ORD_ELEM_CNT; elem++, eloc++) { 150 151 switch (order_obj[elem].type) { 152 case ACPI_TYPE_STRING: 153 if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS) { 154 ret = hp_convert_hexstr_to_str(order_obj[elem].string.pointer, 155 order_obj[elem].string.length, 156 &str_value, &value_len); 157 if (ret) 158 continue; 159 } 160 break; 161 case ACPI_TYPE_INTEGER: 162 int_value = (u32)order_obj[elem].integer.value; 163 break; 164 default: 165 pr_warn("Unsupported object type [%d]\n", order_obj[elem].type); 166 continue; 167 } 168 169 /* Check that both expected and read object type match */ 170 if (expected_order_types[eloc] != order_obj[elem].type) { 171 pr_err("Error expected type %d for elem %d, but got type %d instead\n", 172 expected_order_types[eloc], elem, order_obj[elem].type); 173 kfree(str_value); 174 return -EIO; 175 } 176 177 /* Assign appropriate element value to corresponding field*/ 178 switch (eloc) { 179 case VALUE: 180 strscpy(ordered_list_data->current_value, str_value); 181 replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP); 182 break; 183 case PATH: 184 strscpy(ordered_list_data->common.path, str_value); 185 break; 186 case IS_READONLY: 187 ordered_list_data->common.is_readonly = int_value; 188 break; 189 case DISPLAY_IN_UI: 190 ordered_list_data->common.display_in_ui = int_value; 191 break; 192 case REQUIRES_PHYSICAL_PRESENCE: 193 ordered_list_data->common.requires_physical_presence = int_value; 194 break; 195 case SEQUENCE: 196 ordered_list_data->common.sequence = int_value; 197 break; 198 case PREREQUISITES_SIZE: 199 if (int_value > MAX_PREREQUISITES_SIZE) { 200 pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); 201 int_value = MAX_PREREQUISITES_SIZE; 202 } 203 ordered_list_data->common.prerequisites_size = int_value; 204 205 /* 206 * This step is needed to keep the expected 207 * element list pointing to the right obj[elem].type 208 * when the size is zero. PREREQUISITES 209 * object is omitted by BIOS when the size is 210 * zero. 211 */ 212 if (int_value == 0) 213 eloc++; 214 break; 215 case PREREQUISITES: 216 size = min_t(u32, ordered_list_data->common.prerequisites_size, 217 MAX_PREREQUISITES_SIZE); 218 for (reqs = 0; reqs < size; reqs++) { 219 if (elem + reqs >= order_obj_count) { 220 pr_err("Error elem-objects package is too small\n"); 221 return -EINVAL; 222 } 223 224 ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer, 225 order_obj[elem + reqs].string.length, 226 &str_value, &value_len); 227 228 if (ret) 229 continue; 230 231 strscpy(ordered_list_data->common.prerequisites[reqs], str_value); 232 233 kfree(str_value); 234 str_value = NULL; 235 } 236 break; 237 238 case SECURITY_LEVEL: 239 ordered_list_data->common.security_level = int_value; 240 break; 241 242 case ORD_LIST_SIZE: 243 if (int_value > MAX_ELEMENTS_SIZE) { 244 pr_warn("Order List size value exceeded the maximum number of elements supported or data may be malformed\n"); 245 int_value = MAX_ELEMENTS_SIZE; 246 } 247 ordered_list_data->elements_size = int_value; 248 249 /* 250 * This step is needed to keep the expected 251 * element list pointing to the right obj[elem].type 252 * when the size is zero. ORD_LIST_ELEMENTS 253 * object is omitted by BIOS when the size is 254 * zero. 255 */ 256 if (int_value == 0) 257 eloc++; 258 break; 259 case ORD_LIST_ELEMENTS: 260 261 /* 262 * Ordered list data is stored in hex and comma separated format 263 * Convert the data and split it to show each element 264 */ 265 ret = hp_convert_hexstr_to_str(str_value, value_len, &tmpstr, &tmp_len); 266 if (ret) 267 goto exit_list; 268 269 part_tmp = tmpstr; 270 part = strsep(&part_tmp, COMMA_SEP); 271 272 for (olist_elem = 0; olist_elem < MAX_ELEMENTS_SIZE && part; olist_elem++) { 273 strscpy(ordered_list_data->elements[olist_elem], part); 274 part = strsep(&part_tmp, COMMA_SEP); 275 } 276 ordered_list_data->elements_size = olist_elem; 277 278 kfree(str_value); 279 str_value = NULL; 280 break; 281 default: 282 pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem); 283 break; 284 } 285 kfree(tmpstr); 286 tmpstr = NULL; 287 kfree(str_value); 288 str_value = NULL; 289 } 290 291exit_list: 292 kfree(tmpstr); 293 kfree(str_value); 294 return 0; 295} 296 297/** 298 * hp_populate_ordered_list_package_data() - 299 * Populate all properties of an instance under ordered_list attribute 300 * 301 * @order_obj: ACPI object with ordered_list data 302 * @instance_id: The instance to enumerate 303 * @attr_name_kobj: The parent kernel object 304 */ 305int hp_populate_ordered_list_package_data(union acpi_object *order_obj, int instance_id, 306 struct kobject *attr_name_kobj) 307{ 308 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 309 310 ordered_list_data->attr_name_kobj = attr_name_kobj; 311 312 hp_populate_ordered_list_elements_from_package(order_obj, 313 order_obj->package.count, 314 instance_id); 315 hp_update_attribute_permissions(ordered_list_data->common.is_readonly, 316 &ordered_list_current_val); 317 hp_friendly_user_name_update(ordered_list_data->common.path, 318 attr_name_kobj->name, 319 ordered_list_data->common.display_name, 320 sizeof(ordered_list_data->common.display_name)); 321 return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group); 322} 323 324static int hp_populate_ordered_list_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size, 325 int instance_id) 326{ 327 int values; 328 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 329 int ret = 0; 330 331 /* 332 * Only data relevant to this driver and its functionality is 333 * read. BIOS defines the order in which each * element is 334 * read. Element 0 data is not relevant to this 335 * driver hence it is ignored. For clarity, all element names 336 * (DISPLAY_IN_UI) which defines the order in which is read 337 * and the name matches the variable where the data is stored. 338 * 339 * In earlier implementation, reported errors were ignored 340 * causing the data to remain uninitialized. It is not 341 * possible to determine if data read from BIOS is valid or 342 * not. It is for this reason functions may return a error 343 * without validating the data itself. 344 */ 345 346 // VALUE: 347 ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->current_value, 348 sizeof(ordered_list_data->current_value)); 349 if (ret < 0) 350 goto buffer_exit; 351 352 replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP); 353 354 // COMMON: 355 ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size, 356 &ordered_list_data->common); 357 if (ret < 0) 358 goto buffer_exit; 359 360 // ORD_LIST_SIZE: 361 ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, 362 &ordered_list_data->elements_size); 363 364 if (ordered_list_data->elements_size > MAX_ELEMENTS_SIZE) { 365 /* Report a message and limit elements size to maximum value */ 366 pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n"); 367 ordered_list_data->elements_size = MAX_ELEMENTS_SIZE; 368 } 369 370 // ORD_LIST_ELEMENTS: 371 for (values = 0; values < ordered_list_data->elements_size; values++) { 372 ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, 373 ordered_list_data->elements[values], 374 sizeof(ordered_list_data->elements[values])); 375 if (ret < 0) 376 break; 377 } 378 379buffer_exit: 380 return ret; 381} 382 383/** 384 * hp_populate_ordered_list_buffer_data() - Populate all properties of an 385 * instance under ordered list attribute 386 * 387 * @buffer_ptr: Buffer pointer 388 * @buffer_size: Buffer size 389 * @instance_id: The instance to enumerate 390 * @attr_name_kobj: The parent kernel object 391 */ 392int hp_populate_ordered_list_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id, 393 struct kobject *attr_name_kobj) 394{ 395 struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; 396 int ret = 0; 397 398 ordered_list_data->attr_name_kobj = attr_name_kobj; 399 400 /* Populate ordered list elements */ 401 ret = hp_populate_ordered_list_elements_from_buffer(buffer_ptr, buffer_size, 402 instance_id); 403 if (ret < 0) 404 return ret; 405 406 hp_update_attribute_permissions(ordered_list_data->common.is_readonly, 407 &ordered_list_current_val); 408 hp_friendly_user_name_update(ordered_list_data->common.path, 409 attr_name_kobj->name, 410 ordered_list_data->common.display_name, 411 sizeof(ordered_list_data->common.display_name)); 412 413 return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group); 414} 415 416/** 417 * hp_exit_ordered_list_attributes() - Clear all attribute data 418 * 419 * Clears all data allocated for this group of attributes 420 */ 421void hp_exit_ordered_list_attributes(void) 422{ 423 int instance_id; 424 425 for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count; 426 instance_id++) { 427 struct kobject *attr_name_kobj = 428 bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj; 429 430 if (attr_name_kobj) 431 sysfs_remove_group(attr_name_kobj, 432 &ordered_list_attr_group); 433 } 434 bioscfg_drv.ordered_list_instances_count = 0; 435 436 kfree(bioscfg_drv.ordered_list_data); 437 bioscfg_drv.ordered_list_data = NULL; 438}
~/
Read-only file preview.