summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efivars.c80
1 files changed, 46 insertions, 34 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 34c8783a2aa8..eab4ec41c523 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -125,7 +125,6 @@ struct efi_variable {
} __attribute__((packed));
struct efivar_entry {
- struct efivars *efivars;
struct efi_variable var;
struct list_head list;
struct kobject kobj;
@@ -137,8 +136,8 @@ struct efivar_attribute {
ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
};
-static struct efivars __efivars;
-static struct efivar_operations ops;
+/* Private pointer to registered efivars */
+static struct efivars *__efivars;
#define PSTORE_EFI_ATTRIBUTES \
(EFI_VARIABLE_NON_VOLATILE | \
@@ -479,7 +478,7 @@ efivar_attr_read(struct efivar_entry *entry, char *buf)
if (!entry || !buf)
return -EINVAL;
- status = get_var_data(entry->efivars, var);
+ status = get_var_data(__efivars, var);
if (status != EFI_SUCCESS)
return -EIO;
@@ -513,7 +512,7 @@ efivar_size_read(struct efivar_entry *entry, char *buf)
if (!entry || !buf)
return -EINVAL;
- status = get_var_data(entry->efivars, var);
+ status = get_var_data(__efivars, var);
if (status != EFI_SUCCESS)
return -EIO;
@@ -530,7 +529,7 @@ efivar_data_read(struct efivar_entry *entry, char *buf)
if (!entry || !buf)
return -EINVAL;
- status = get_var_data(entry->efivars, var);
+ status = get_var_data(__efivars, var);
if (status != EFI_SUCCESS)
return -EIO;
@@ -545,7 +544,7 @@ static ssize_t
efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
{
struct efi_variable *new_var, *var = &entry->var;
- struct efivars *efivars = entry->efivars;
+ struct efivars *efivars = __efivars;
efi_status_t status = EFI_NOT_FOUND;
if (count != sizeof(struct efi_variable))
@@ -606,7 +605,7 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
if (!entry || !buf)
return 0;
- status = get_var_data(entry->efivars, var);
+ status = get_var_data(__efivars, var);
if (status != EFI_SUCCESS)
return -EIO;
@@ -728,7 +727,7 @@ static ssize_t efivarfs_file_write(struct file *file,
const char __user *userbuf, size_t count, loff_t *ppos)
{
struct efivar_entry *var = file->private_data;
- struct efivars *efivars;
+ struct efivars *efivars = __efivars;
efi_status_t status;
void *data;
u32 attributes;
@@ -746,8 +745,6 @@ static ssize_t efivarfs_file_write(struct file *file,
if (attributes & ~(EFI_VARIABLE_MASK))
return -EINVAL;
- efivars = var->efivars;
-
/*
* Ensure that the user can't allocate arbitrarily large
* amounts of memory. Pick a default size of 64K if
@@ -855,7 +852,7 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct efivar_entry *var = file->private_data;
- struct efivars *efivars = var->efivars;
+ struct efivars *efivars = __efivars;
efi_status_t status;
unsigned long datasize = 0;
u32 attributes;
@@ -1009,7 +1006,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
umode_t mode, bool excl)
{
struct inode *inode;
- struct efivars *efivars = &__efivars;
+ struct efivars *efivars = __efivars;
struct efivar_entry *var;
int namelen, i = 0, err = 0;
@@ -1038,7 +1035,6 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
var->var.VariableName[i] = '\0';
inode->i_private = var;
- var->efivars = efivars;
var->kobj.kset = efivars->kset;
err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s",
@@ -1063,7 +1059,7 @@ out:
static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
{
struct efivar_entry *var = dentry->d_inode->i_private;
- struct efivars *efivars = var->efivars;
+ struct efivars *efivars = __efivars;
efi_status_t status;
spin_lock_irq(&efivars->lock);
@@ -1175,7 +1171,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
struct inode *inode = NULL;
struct dentry *root;
struct efivar_entry *entry, *n;
- struct efivars *efivars = &__efivars;
+ struct efivars *efivars = __efivars;
char *name;
int err = -ENOMEM;
@@ -1302,7 +1298,7 @@ static const struct inode_operations efivarfs_dir_inode_operations = {
static int efi_pstore_open(struct pstore_info *psi)
{
- struct efivars *efivars = psi->data;
+ struct efivars *efivars = __efivars;
spin_lock_irq(&efivars->lock);
efivars->walk_entry = list_first_entry(&efivars->list,
@@ -1312,7 +1308,7 @@ static int efi_pstore_open(struct pstore_info *psi)
static int efi_pstore_close(struct pstore_info *psi)
{
- struct efivars *efivars = psi->data;
+ struct efivars *efivars = __efivars;
spin_unlock_irq(&efivars->lock);
return 0;
@@ -1323,7 +1319,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
char **buf, struct pstore_info *psi)
{
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
+ struct efivars *efivars = __efivars;
char name[DUMP_NAME_LEN];
int i;
int cnt;
@@ -1386,7 +1382,7 @@ static int efi_pstore_write(enum pstore_type_id type,
char name[DUMP_NAME_LEN];
efi_char16_t efi_name[DUMP_NAME_LEN];
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
+ struct efivars *efivars = __efivars;
int i, ret = 0;
efi_status_t status = EFI_NOT_FOUND;
unsigned long flags;
@@ -1443,7 +1439,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
char name_old[DUMP_NAME_LEN];
efi_char16_t efi_name_old[DUMP_NAME_LEN];
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
+ struct efivars *efivars = __efivars;
struct efivar_entry *entry, *found = NULL;
int i;
@@ -1535,7 +1531,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
char *buf, loff_t pos, size_t count)
{
struct efi_variable *new_var = (struct efi_variable *)buf;
- struct efivars *efivars = bin_attr->private;
+ struct efivars *efivars = __efivars;
struct efivar_entry *search_efivar, *n;
unsigned long strsize1, strsize2;
efi_status_t status = EFI_NOT_FOUND;
@@ -1612,7 +1608,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
char *buf, loff_t pos, size_t count)
{
struct efi_variable *del_var = (struct efi_variable *)buf;
- struct efivars *efivars = bin_attr->private;
+ struct efivars *efivars = __efivars;
struct efivar_entry *search_efivar, *n;
unsigned long strsize1, strsize2;
efi_status_t status = EFI_NOT_FOUND;
@@ -1670,7 +1666,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
{
struct efivar_entry *entry, *n;
- struct efivars *efivars = &__efivars;
+ struct efivars *efivars = __efivars;
unsigned long strsize1, strsize2;
bool found = false;
@@ -1716,7 +1712,7 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name,
static void efivar_update_sysfs_entries(struct work_struct *work)
{
- struct efivars *efivars = &__efivars;
+ struct efivars *efivars = __efivars;
efi_guid_t vendor;
efi_char16_t *variable_name;
unsigned long variable_name_size = 1024;
@@ -1843,7 +1839,6 @@ efivar_create_sysfs_entry(struct efivars *efivars,
return 1;
}
- new_efivar->efivars = efivars;
memcpy(new_efivar->var.VariableName, variable_name,
variable_name_size);
memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
@@ -1942,6 +1937,8 @@ void unregister_efivars(struct efivars *efivars)
{
struct efivar_entry *entry, *n;
+ __efivars = NULL;
+
list_for_each_entry_safe(entry, n, &efivars->list, list) {
spin_lock_irq(&efivars->lock);
list_del(&entry->list);
@@ -1998,6 +1995,8 @@ int register_efivars(struct efivars *efivars,
unsigned long variable_name_size = 1024;
int error = 0;
+ __efivars = efivars;
+
variable_name = kzalloc(variable_name_size, GFP_KERNEL);
if (!variable_name) {
printk(KERN_ERR "efivars: Memory allocation failed.\n");
@@ -2085,6 +2084,24 @@ out:
}
EXPORT_SYMBOL_GPL(register_efivars);
+static struct efivars generic_efivars;
+static struct efivar_operations generic_ops;
+
+static int generic_ops_register(void)
+{
+ generic_ops.get_variable = efi.get_variable;
+ generic_ops.set_variable = efi.set_variable;
+ generic_ops.get_next_variable = efi.get_next_variable;
+ generic_ops.query_variable_info = efi.query_variable_info;
+
+ return register_efivars(&generic_efivars, &generic_ops, efi_kobj);
+}
+
+static void generic_ops_unregister(void)
+{
+ unregister_efivars(&generic_efivars);
+}
+
/*
* For now we register the efi subsystem with the firmware subsystem
* and the vars subsystem with the efi subsystem. In the future, it
@@ -2111,12 +2128,7 @@ efivars_init(void)
return -ENOMEM;
}
- ops.get_variable = efi.get_variable;
- ops.set_variable = efi.set_variable;
- ops.get_next_variable = efi.get_next_variable;
- ops.query_variable_info = efi.query_variable_info;
-
- error = register_efivars(&__efivars, &ops, efi_kobj);
+ error = generic_ops_register();
if (error)
goto err_put;
@@ -2132,7 +2144,7 @@ efivars_init(void)
return 0;
err_unregister:
- unregister_efivars(&__efivars);
+ generic_ops_unregister();
err_put:
kobject_put(efi_kobj);
return error;
@@ -2144,7 +2156,7 @@ efivars_exit(void)
cancel_work_sync(&efivar_work);
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
- unregister_efivars(&__efivars);
+ generic_ops_unregister();
kobject_put(efi_kobj);
}
}