diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efivars.c | 85 |
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 | |||
165 | static void efivar_update_sysfs_entries(struct work_struct *); | ||
166 | static 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 */ |
162 | static unsigned long | 169 | static unsigned long |
163 | utf16_strnlen(efi_char16_t *s, size_t maxlength) | 170 | utf16_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 | ||
1503 | static 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 | |||
1525 | static 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: | |||
1833 | static void __exit | 1906 | static void __exit |
1834 | efivars_exit(void) | 1907 | efivars_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); |