aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efivars.c85
1 files changed, 80 insertions, 5 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index a64fb7bda365..69225115304d 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -158,6 +158,13 @@ efivar_create_sysfs_entry(struct efivars *efivars,
158 efi_char16_t *variable_name, 158 efi_char16_t *variable_name,
159 efi_guid_t *vendor_guid); 159 efi_guid_t *vendor_guid);
160 160
161/*
162 * Prototype for workqueue functions updating sysfs entry
163 */
164
165static void efivar_update_sysfs_entries(struct work_struct *);
166static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
167
161/* Return the number of unicode characters in data */ 168/* Return the number of unicode characters in data */
162static unsigned long 169static unsigned long
163utf16_strnlen(efi_char16_t *s, size_t maxlength) 170utf16_strnlen(efi_char16_t *s, size_t maxlength)
@@ -1248,11 +1255,8 @@ static int efi_pstore_write(enum pstore_type_id type,
1248 1255
1249 spin_unlock_irqrestore(&efivars->lock, flags); 1256 spin_unlock_irqrestore(&efivars->lock, flags);
1250 1257
1251 if (size) 1258 if (reason == KMSG_DUMP_OOPS)
1252 ret = efivar_create_sysfs_entry(efivars, 1259 schedule_work(&efivar_work);
1253 utf16_strsize(efi_name,
1254 DUMP_NAME_LEN * 2),
1255 efi_name, &vendor);
1256 1260
1257 *id = part; 1261 *id = part;
1258 return ret; 1262 return ret;
@@ -1496,6 +1500,75 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
1496 return count; 1500 return count;
1497} 1501}
1498 1502
1503static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
1504{
1505 struct efivar_entry *entry, *n;
1506 struct efivars *efivars = &__efivars;
1507 unsigned long strsize1, strsize2;
1508 bool found = false;
1509
1510 strsize1 = utf16_strsize(variable_name, 1024);
1511 list_for_each_entry_safe(entry, n, &efivars->list, list) {
1512 strsize2 = utf16_strsize(entry->var.VariableName, 1024);
1513 if (strsize1 == strsize2 &&
1514 !memcmp(variable_name, &(entry->var.VariableName),
1515 strsize2) &&
1516 !efi_guidcmp(entry->var.VendorGuid,
1517 *vendor)) {
1518 found = true;
1519 break;
1520 }
1521 }
1522 return found;
1523}
1524
1525static void efivar_update_sysfs_entries(struct work_struct *work)
1526{
1527 struct efivars *efivars = &__efivars;
1528 efi_guid_t vendor;
1529 efi_char16_t *variable_name;
1530 unsigned long variable_name_size = 1024;
1531 efi_status_t status = EFI_NOT_FOUND;
1532 bool found;
1533
1534 /* Add new sysfs entries */
1535 while (1) {
1536 variable_name = kzalloc(variable_name_size, GFP_KERNEL);
1537 if (!variable_name) {
1538 pr_err("efivars: Memory allocation failed.\n");
1539 return;
1540 }
1541
1542 spin_lock_irq(&efivars->lock);
1543 found = false;
1544 while (1) {
1545 variable_name_size = 1024;
1546 status = efivars->ops->get_next_variable(
1547 &variable_name_size,
1548 variable_name,
1549 &vendor);
1550 if (status != EFI_SUCCESS) {
1551 break;
1552 } else {
1553 if (!variable_is_present(variable_name,
1554 &vendor)) {
1555 found = true;
1556 break;
1557 }
1558 }
1559 }
1560 spin_unlock_irq(&efivars->lock);
1561
1562 if (!found) {
1563 kfree(variable_name);
1564 break;
1565 } else
1566 efivar_create_sysfs_entry(efivars,
1567 variable_name_size,
1568 variable_name, &vendor);
1569 }
1570}
1571
1499/* 1572/*
1500 * Let's not leave out systab information that snuck into 1573 * Let's not leave out systab information that snuck into
1501 * the efivars driver 1574 * the efivars driver
@@ -1833,6 +1906,8 @@ err_put:
1833static void __exit 1906static void __exit
1834efivars_exit(void) 1907efivars_exit(void)
1835{ 1908{
1909 cancel_work_sync(&efivar_work);
1910
1836 if (efi_enabled) { 1911 if (efi_enabled) {
1837 unregister_efivars(&__efivars); 1912 unregister_efivars(&__efivars);
1838 kobject_put(efi_kobj); 1913 kobject_put(efi_kobj);