|
@@ -102,9 +102,10 @@ static struct kmem_cache *flash_block_cache = NULL;
|
|
|
|
|
|
#define FLASH_BLOCK_LIST_VERSION (1UL)
|
|
|
|
|
|
-/* Local copy of the flash block list.
|
|
|
- * We only allow one open of the flash proc file and create this
|
|
|
- * list as we go. The rtas_firmware_flash_list varable will be
|
|
|
+/*
|
|
|
+ * Local copy of the flash block list.
|
|
|
+ *
|
|
|
+ * The rtas_firmware_flash_list varable will be
|
|
|
* set once the data is fully read.
|
|
|
*
|
|
|
* For convenience as we build the list we use virtual addrs,
|
|
@@ -125,23 +126,23 @@ struct rtas_update_flash_t
|
|
|
struct rtas_manage_flash_t
|
|
|
{
|
|
|
int status; /* Returned status */
|
|
|
- unsigned int op; /* Reject or commit image */
|
|
|
};
|
|
|
|
|
|
/* Status int must be first member of struct */
|
|
|
struct rtas_validate_flash_t
|
|
|
{
|
|
|
int status; /* Returned status */
|
|
|
- char buf[VALIDATE_BUF_SIZE]; /* Candidate image buffer */
|
|
|
+ char *buf; /* Candidate image buffer */
|
|
|
unsigned int buf_size; /* Size of image buf */
|
|
|
unsigned int update_results; /* Update results token */
|
|
|
};
|
|
|
|
|
|
-static DEFINE_SPINLOCK(flash_file_open_lock);
|
|
|
-static struct proc_dir_entry *firmware_flash_pde;
|
|
|
-static struct proc_dir_entry *firmware_update_pde;
|
|
|
-static struct proc_dir_entry *validate_pde;
|
|
|
-static struct proc_dir_entry *manage_pde;
|
|
|
+static struct rtas_update_flash_t rtas_update_flash_data;
|
|
|
+static struct rtas_manage_flash_t rtas_manage_flash_data;
|
|
|
+static struct rtas_validate_flash_t rtas_validate_flash_data;
|
|
|
+static DEFINE_MUTEX(rtas_update_flash_mutex);
|
|
|
+static DEFINE_MUTEX(rtas_manage_flash_mutex);
|
|
|
+static DEFINE_MUTEX(rtas_validate_flash_mutex);
|
|
|
|
|
|
/* Do simple sanity checks on the flash image. */
|
|
|
static int flash_list_valid(struct flash_block_list *flist)
|
|
@@ -191,10 +192,10 @@ static void free_flash_list(struct flash_block_list *f)
|
|
|
|
|
|
static int rtas_flash_release(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_update_flash_t *uf;
|
|
|
-
|
|
|
- uf = (struct rtas_update_flash_t *) dp->data;
|
|
|
+ struct rtas_update_flash_t *const uf = &rtas_update_flash_data;
|
|
|
+
|
|
|
+ mutex_lock(&rtas_update_flash_mutex);
|
|
|
+
|
|
|
if (uf->flist) {
|
|
|
/* File was opened in write mode for a new flash attempt */
|
|
|
/* Clear saved list */
|
|
@@ -214,13 +215,14 @@ static int rtas_flash_release(struct inode *inode, struct file *file)
|
|
|
uf->flist = NULL;
|
|
|
}
|
|
|
|
|
|
- atomic_dec(&dp->count);
|
|
|
+ mutex_unlock(&rtas_update_flash_mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void get_flash_status_msg(int status, char *buf)
|
|
|
+static size_t get_flash_status_msg(int status, char *buf)
|
|
|
{
|
|
|
- char *msg;
|
|
|
+ const char *msg;
|
|
|
+ size_t len;
|
|
|
|
|
|
switch (status) {
|
|
|
case FLASH_AUTH:
|
|
@@ -242,34 +244,51 @@ static void get_flash_status_msg(int status, char *buf)
|
|
|
msg = "ready: firmware image ready for flash on reboot\n";
|
|
|
break;
|
|
|
default:
|
|
|
- sprintf(buf, "error: unexpected status value %d\n", status);
|
|
|
- return;
|
|
|
+ return sprintf(buf, "error: unexpected status value %d\n",
|
|
|
+ status);
|
|
|
}
|
|
|
|
|
|
- strcpy(buf, msg);
|
|
|
+ len = strlen(msg);
|
|
|
+ memcpy(buf, msg, len + 1);
|
|
|
+ return len;
|
|
|
}
|
|
|
|
|
|
/* Reading the proc file will show status (not the firmware contents) */
|
|
|
-static ssize_t rtas_flash_read(struct file *file, char __user *buf,
|
|
|
- size_t count, loff_t *ppos)
|
|
|
+static ssize_t rtas_flash_read_msg(struct file *file, char __user *buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_update_flash_t *uf;
|
|
|
+ struct rtas_update_flash_t *const uf = &rtas_update_flash_data;
|
|
|
char msg[RTAS_MSG_MAXLEN];
|
|
|
+ size_t len;
|
|
|
+ int status;
|
|
|
|
|
|
- uf = dp->data;
|
|
|
+ mutex_lock(&rtas_update_flash_mutex);
|
|
|
+ status = uf->status;
|
|
|
+ mutex_unlock(&rtas_update_flash_mutex);
|
|
|
|
|
|
- if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) {
|
|
|
- get_flash_status_msg(uf->status, msg);
|
|
|
- } else { /* FIRMWARE_UPDATE_NAME */
|
|
|
- sprintf(msg, "%d\n", uf->status);
|
|
|
- }
|
|
|
+ /* Read as text message */
|
|
|
+ len = get_flash_status_msg(status, msg);
|
|
|
+ return simple_read_from_buffer(buf, count, ppos, msg, len);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t rtas_flash_read_num(struct file *file, char __user *buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct rtas_update_flash_t *const uf = &rtas_update_flash_data;
|
|
|
+ char msg[RTAS_MSG_MAXLEN];
|
|
|
+ int status;
|
|
|
|
|
|
+ mutex_lock(&rtas_update_flash_mutex);
|
|
|
+ status = uf->status;
|
|
|
+ mutex_unlock(&rtas_update_flash_mutex);
|
|
|
+
|
|
|
+ /* Read as number */
|
|
|
+ sprintf(msg, "%d\n", status);
|
|
|
return simple_read_from_buffer(buf, count, ppos, msg, strlen(msg));
|
|
|
}
|
|
|
|
|
|
/* constructor for flash_block_cache */
|
|
|
-void rtas_block_ctor(void *ptr)
|
|
|
+static void rtas_block_ctor(void *ptr)
|
|
|
{
|
|
|
memset(ptr, 0, RTAS_BLK_SIZE);
|
|
|
}
|
|
@@ -282,16 +301,15 @@ void rtas_block_ctor(void *ptr)
|
|
|
static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
|
|
|
size_t count, loff_t *off)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_update_flash_t *uf;
|
|
|
+ struct rtas_update_flash_t *const uf = &rtas_update_flash_data;
|
|
|
char *p;
|
|
|
- int next_free;
|
|
|
+ int next_free, rc;
|
|
|
struct flash_block_list *fl;
|
|
|
|
|
|
- uf = (struct rtas_update_flash_t *) dp->data;
|
|
|
+ mutex_lock(&rtas_update_flash_mutex);
|
|
|
|
|
|
if (uf->status == FLASH_AUTH || count == 0)
|
|
|
- return count; /* discard data */
|
|
|
+ goto out; /* discard data */
|
|
|
|
|
|
/* In the case that the image is not ready for flashing, the memory
|
|
|
* allocated for the block list will be freed upon the release of the
|
|
@@ -300,7 +318,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
|
|
|
if (uf->flist == NULL) {
|
|
|
uf->flist = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
|
|
|
if (!uf->flist)
|
|
|
- return -ENOMEM;
|
|
|
+ goto nomem;
|
|
|
}
|
|
|
|
|
|
fl = uf->flist;
|
|
@@ -311,7 +329,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
|
|
|
/* Need to allocate another block_list */
|
|
|
fl->next = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
|
|
|
if (!fl->next)
|
|
|
- return -ENOMEM;
|
|
|
+ goto nomem;
|
|
|
fl = fl->next;
|
|
|
next_free = 0;
|
|
|
}
|
|
@@ -320,52 +338,37 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
|
|
|
count = RTAS_BLK_SIZE;
|
|
|
p = kmem_cache_alloc(flash_block_cache, GFP_KERNEL);
|
|
|
if (!p)
|
|
|
- return -ENOMEM;
|
|
|
+ goto nomem;
|
|
|
|
|
|
if(copy_from_user(p, buffer, count)) {
|
|
|
kmem_cache_free(flash_block_cache, p);
|
|
|
- return -EFAULT;
|
|
|
+ rc = -EFAULT;
|
|
|
+ goto error;
|
|
|
}
|
|
|
fl->blocks[next_free].data = p;
|
|
|
fl->blocks[next_free].length = count;
|
|
|
fl->num_blocks++;
|
|
|
-
|
|
|
+out:
|
|
|
+ mutex_unlock(&rtas_update_flash_mutex);
|
|
|
return count;
|
|
|
-}
|
|
|
-
|
|
|
-static int rtas_excl_open(struct inode *inode, struct file *file)
|
|
|
-{
|
|
|
- struct proc_dir_entry *dp = PDE(inode);
|
|
|
-
|
|
|
- /* Enforce exclusive open with use count of PDE */
|
|
|
- spin_lock(&flash_file_open_lock);
|
|
|
- if (atomic_read(&dp->count) > 2) {
|
|
|
- spin_unlock(&flash_file_open_lock);
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- atomic_inc(&dp->count);
|
|
|
- spin_unlock(&flash_file_open_lock);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int rtas_excl_release(struct inode *inode, struct file *file)
|
|
|
-{
|
|
|
- struct proc_dir_entry *dp = PDE(inode);
|
|
|
|
|
|
- atomic_dec(&dp->count);
|
|
|
-
|
|
|
- return 0;
|
|
|
+nomem:
|
|
|
+ rc = -ENOMEM;
|
|
|
+error:
|
|
|
+ mutex_unlock(&rtas_update_flash_mutex);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
-static void manage_flash(struct rtas_manage_flash_t *args_buf)
|
|
|
+/*
|
|
|
+ * Flash management routines.
|
|
|
+ */
|
|
|
+static void manage_flash(struct rtas_manage_flash_t *args_buf, unsigned int op)
|
|
|
{
|
|
|
s32 rc;
|
|
|
|
|
|
do {
|
|
|
- rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1,
|
|
|
- 1, NULL, args_buf->op);
|
|
|
+ rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1,
|
|
|
+ NULL, op);
|
|
|
} while (rtas_busy_delay(rc));
|
|
|
|
|
|
args_buf->status = rc;
|
|
@@ -374,55 +377,62 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf)
|
|
|
static ssize_t manage_flash_read(struct file *file, char __user *buf,
|
|
|
size_t count, loff_t *ppos)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_manage_flash_t *args_buf;
|
|
|
+ struct rtas_manage_flash_t *const args_buf = &rtas_manage_flash_data;
|
|
|
char msg[RTAS_MSG_MAXLEN];
|
|
|
- int msglen;
|
|
|
+ int msglen, status;
|
|
|
|
|
|
- args_buf = dp->data;
|
|
|
- if (args_buf == NULL)
|
|
|
- return 0;
|
|
|
-
|
|
|
- msglen = sprintf(msg, "%d\n", args_buf->status);
|
|
|
+ mutex_lock(&rtas_manage_flash_mutex);
|
|
|
+ status = args_buf->status;
|
|
|
+ mutex_unlock(&rtas_manage_flash_mutex);
|
|
|
|
|
|
+ msglen = sprintf(msg, "%d\n", status);
|
|
|
return simple_read_from_buffer(buf, count, ppos, msg, msglen);
|
|
|
}
|
|
|
|
|
|
static ssize_t manage_flash_write(struct file *file, const char __user *buf,
|
|
|
size_t count, loff_t *off)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_manage_flash_t *args_buf;
|
|
|
- const char reject_str[] = "0";
|
|
|
- const char commit_str[] = "1";
|
|
|
+ struct rtas_manage_flash_t *const args_buf = &rtas_manage_flash_data;
|
|
|
+ static const char reject_str[] = "0";
|
|
|
+ static const char commit_str[] = "1";
|
|
|
char stkbuf[10];
|
|
|
- int op;
|
|
|
+ int op, rc;
|
|
|
+
|
|
|
+ mutex_lock(&rtas_manage_flash_mutex);
|
|
|
|
|
|
- args_buf = (struct rtas_manage_flash_t *) dp->data;
|
|
|
if ((args_buf->status == MANAGE_AUTH) || (count == 0))
|
|
|
- return count;
|
|
|
+ goto out;
|
|
|
|
|
|
op = -1;
|
|
|
if (buf) {
|
|
|
if (count > 9) count = 9;
|
|
|
- if (copy_from_user (stkbuf, buf, count)) {
|
|
|
- return -EFAULT;
|
|
|
- }
|
|
|
+ rc = -EFAULT;
|
|
|
+ if (copy_from_user (stkbuf, buf, count))
|
|
|
+ goto error;
|
|
|
if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0)
|
|
|
op = RTAS_REJECT_TMP_IMG;
|
|
|
else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0)
|
|
|
op = RTAS_COMMIT_TMP_IMG;
|
|
|
}
|
|
|
|
|
|
- if (op == -1) /* buf is empty, or contains invalid string */
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- args_buf->op = op;
|
|
|
- manage_flash(args_buf);
|
|
|
+ if (op == -1) { /* buf is empty, or contains invalid string */
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
|
|
|
+ manage_flash(args_buf, op);
|
|
|
+out:
|
|
|
+ mutex_unlock(&rtas_manage_flash_mutex);
|
|
|
return count;
|
|
|
+
|
|
|
+error:
|
|
|
+ mutex_unlock(&rtas_manage_flash_mutex);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Validation routines.
|
|
|
+ */
|
|
|
static void validate_flash(struct rtas_validate_flash_t *args_buf)
|
|
|
{
|
|
|
int token = rtas_token("ibm,validate-flash-image");
|
|
@@ -462,14 +472,14 @@ static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf,
|
|
|
static ssize_t validate_flash_read(struct file *file, char __user *buf,
|
|
|
size_t count, loff_t *ppos)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_validate_flash_t *args_buf;
|
|
|
+ struct rtas_validate_flash_t *const args_buf =
|
|
|
+ &rtas_validate_flash_data;
|
|
|
char msg[RTAS_MSG_MAXLEN];
|
|
|
int msglen;
|
|
|
|
|
|
- args_buf = dp->data;
|
|
|
-
|
|
|
+ mutex_lock(&rtas_validate_flash_mutex);
|
|
|
msglen = get_validate_flash_msg(args_buf, msg);
|
|
|
+ mutex_unlock(&rtas_validate_flash_mutex);
|
|
|
|
|
|
return simple_read_from_buffer(buf, count, ppos, msg, msglen);
|
|
|
}
|
|
@@ -477,24 +487,18 @@ static ssize_t validate_flash_read(struct file *file, char __user *buf,
|
|
|
static ssize_t validate_flash_write(struct file *file, const char __user *buf,
|
|
|
size_t count, loff_t *off)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_validate_flash_t *args_buf;
|
|
|
+ struct rtas_validate_flash_t *const args_buf =
|
|
|
+ &rtas_validate_flash_data;
|
|
|
int rc;
|
|
|
|
|
|
- args_buf = (struct rtas_validate_flash_t *) dp->data;
|
|
|
-
|
|
|
- if (dp->data == NULL) {
|
|
|
- dp->data = kmalloc(sizeof(struct rtas_validate_flash_t),
|
|
|
- GFP_KERNEL);
|
|
|
- if (dp->data == NULL)
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
+ mutex_lock(&rtas_validate_flash_mutex);
|
|
|
|
|
|
/* We are only interested in the first 4K of the
|
|
|
* candidate image */
|
|
|
if ((*off >= VALIDATE_BUF_SIZE) ||
|
|
|
(args_buf->status == VALIDATE_AUTH)) {
|
|
|
*off += count;
|
|
|
+ mutex_unlock(&rtas_validate_flash_mutex);
|
|
|
return count;
|
|
|
}
|
|
|
|
|
@@ -517,31 +521,29 @@ static ssize_t validate_flash_write(struct file *file, const char __user *buf,
|
|
|
*off += count;
|
|
|
rc = count;
|
|
|
done:
|
|
|
- if (rc < 0) {
|
|
|
- kfree(dp->data);
|
|
|
- dp->data = NULL;
|
|
|
- }
|
|
|
+ mutex_unlock(&rtas_validate_flash_mutex);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
static int validate_flash_release(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
- struct proc_dir_entry *dp = PDE(file_inode(file));
|
|
|
- struct rtas_validate_flash_t *args_buf;
|
|
|
+ struct rtas_validate_flash_t *const args_buf =
|
|
|
+ &rtas_validate_flash_data;
|
|
|
|
|
|
- args_buf = (struct rtas_validate_flash_t *) dp->data;
|
|
|
+ mutex_lock(&rtas_validate_flash_mutex);
|
|
|
|
|
|
if (args_buf->status == VALIDATE_READY) {
|
|
|
args_buf->buf_size = VALIDATE_BUF_SIZE;
|
|
|
validate_flash(args_buf);
|
|
|
}
|
|
|
|
|
|
- /* The matching atomic_inc was in rtas_excl_open() */
|
|
|
- atomic_dec(&dp->count);
|
|
|
-
|
|
|
+ mutex_unlock(&rtas_validate_flash_mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * On-reboot flash update applicator.
|
|
|
+ */
|
|
|
static void rtas_flash_firmware(int reboot_type)
|
|
|
{
|
|
|
unsigned long image_size;
|
|
@@ -634,75 +636,57 @@ static void rtas_flash_firmware(int reboot_type)
|
|
|
spin_unlock(&rtas_data_buf_lock);
|
|
|
}
|
|
|
|
|
|
-static void remove_flash_pde(struct proc_dir_entry *dp)
|
|
|
-{
|
|
|
- if (dp) {
|
|
|
- kfree(dp->data);
|
|
|
- remove_proc_entry(dp->name, dp->parent);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int initialize_flash_pde_data(const char *rtas_call_name,
|
|
|
- size_t buf_size,
|
|
|
- struct proc_dir_entry *dp)
|
|
|
-{
|
|
|
+/*
|
|
|
+ * Manifest of proc files to create
|
|
|
+ */
|
|
|
+struct rtas_flash_file {
|
|
|
+ const char *filename;
|
|
|
+ const char *rtas_call_name;
|
|
|
int *status;
|
|
|
- int token;
|
|
|
-
|
|
|
- dp->data = kzalloc(buf_size, GFP_KERNEL);
|
|
|
- if (dp->data == NULL)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- /*
|
|
|
- * This code assumes that the status int is the first member of the
|
|
|
- * struct
|
|
|
- */
|
|
|
- status = (int *) dp->data;
|
|
|
- token = rtas_token(rtas_call_name);
|
|
|
- if (token == RTAS_UNKNOWN_SERVICE)
|
|
|
- *status = FLASH_AUTH;
|
|
|
- else
|
|
|
- *status = FLASH_NO_OP;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static struct proc_dir_entry *create_flash_pde(const char *filename,
|
|
|
- const struct file_operations *fops)
|
|
|
-{
|
|
|
- return proc_create(filename, S_IRUSR | S_IWUSR, NULL, fops);
|
|
|
-}
|
|
|
-
|
|
|
-static const struct file_operations rtas_flash_operations = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .read = rtas_flash_read,
|
|
|
- .write = rtas_flash_write,
|
|
|
- .open = rtas_excl_open,
|
|
|
- .release = rtas_flash_release,
|
|
|
- .llseek = default_llseek,
|
|
|
-};
|
|
|
-
|
|
|
-static const struct file_operations manage_flash_operations = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .read = manage_flash_read,
|
|
|
- .write = manage_flash_write,
|
|
|
- .open = rtas_excl_open,
|
|
|
- .release = rtas_excl_release,
|
|
|
- .llseek = default_llseek,
|
|
|
+ const struct file_operations fops;
|
|
|
};
|
|
|
|
|
|
-static const struct file_operations validate_flash_operations = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .read = validate_flash_read,
|
|
|
- .write = validate_flash_write,
|
|
|
- .open = rtas_excl_open,
|
|
|
- .release = validate_flash_release,
|
|
|
- .llseek = default_llseek,
|
|
|
+static const struct rtas_flash_file rtas_flash_files[] = {
|
|
|
+ {
|
|
|
+ .filename = "powerpc/rtas/" FIRMWARE_FLASH_NAME,
|
|
|
+ .rtas_call_name = "ibm,update-flash-64-and-reboot",
|
|
|
+ .status = &rtas_update_flash_data.status,
|
|
|
+ .fops.read = rtas_flash_read_msg,
|
|
|
+ .fops.write = rtas_flash_write,
|
|
|
+ .fops.release = rtas_flash_release,
|
|
|
+ .fops.llseek = default_llseek,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .filename = "powerpc/rtas/" FIRMWARE_UPDATE_NAME,
|
|
|
+ .rtas_call_name = "ibm,update-flash-64-and-reboot",
|
|
|
+ .status = &rtas_update_flash_data.status,
|
|
|
+ .fops.read = rtas_flash_read_num,
|
|
|
+ .fops.write = rtas_flash_write,
|
|
|
+ .fops.release = rtas_flash_release,
|
|
|
+ .fops.llseek = default_llseek,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .filename = "powerpc/rtas/" VALIDATE_FLASH_NAME,
|
|
|
+ .rtas_call_name = "ibm,validate-flash-image",
|
|
|
+ .status = &rtas_validate_flash_data.status,
|
|
|
+ .fops.read = validate_flash_read,
|
|
|
+ .fops.write = validate_flash_write,
|
|
|
+ .fops.release = validate_flash_release,
|
|
|
+ .fops.llseek = default_llseek,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .filename = "powerpc/rtas/" MANAGE_FLASH_NAME,
|
|
|
+ .rtas_call_name = "ibm,manage-flash-image",
|
|
|
+ .status = &rtas_manage_flash_data.status,
|
|
|
+ .fops.read = manage_flash_read,
|
|
|
+ .fops.write = manage_flash_write,
|
|
|
+ .fops.llseek = default_llseek,
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
static int __init rtas_flash_init(void)
|
|
|
{
|
|
|
- int rc;
|
|
|
+ int i;
|
|
|
|
|
|
if (rtas_token("ibm,update-flash-64-and-reboot") ==
|
|
|
RTAS_UNKNOWN_SERVICE) {
|
|
@@ -710,93 +694,65 @@ static int __init rtas_flash_init(void)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- firmware_flash_pde = create_flash_pde("powerpc/rtas/"
|
|
|
- FIRMWARE_FLASH_NAME,
|
|
|
- &rtas_flash_operations);
|
|
|
- if (firmware_flash_pde == NULL) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
- }
|
|
|
+ rtas_validate_flash_data.buf = kzalloc(VALIDATE_BUF_SIZE, GFP_KERNEL);
|
|
|
+ if (!rtas_validate_flash_data.buf)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
|
|
|
- sizeof(struct rtas_update_flash_t),
|
|
|
- firmware_flash_pde);
|
|
|
- if (rc != 0)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
- firmware_update_pde = create_flash_pde("powerpc/rtas/"
|
|
|
- FIRMWARE_UPDATE_NAME,
|
|
|
- &rtas_flash_operations);
|
|
|
- if (firmware_update_pde == NULL) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
+ flash_block_cache = kmem_cache_create("rtas_flash_cache",
|
|
|
+ RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
|
|
|
+ rtas_block_ctor);
|
|
|
+ if (!flash_block_cache) {
|
|
|
+ printk(KERN_ERR "%s: failed to create block cache\n",
|
|
|
+ __func__);
|
|
|
+ goto enomem_buf;
|
|
|
}
|
|
|
|
|
|
- rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
|
|
|
- sizeof(struct rtas_update_flash_t),
|
|
|
- firmware_update_pde);
|
|
|
- if (rc != 0)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
- validate_pde = create_flash_pde("powerpc/rtas/" VALIDATE_FLASH_NAME,
|
|
|
- &validate_flash_operations);
|
|
|
- if (validate_pde == NULL) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
- }
|
|
|
+ for (i = 0; i < ARRAY_SIZE(rtas_flash_files); i++) {
|
|
|
+ const struct rtas_flash_file *f = &rtas_flash_files[i];
|
|
|
+ int token;
|
|
|
|
|
|
- rc = initialize_flash_pde_data("ibm,validate-flash-image",
|
|
|
- sizeof(struct rtas_validate_flash_t),
|
|
|
- validate_pde);
|
|
|
- if (rc != 0)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
- manage_pde = create_flash_pde("powerpc/rtas/" MANAGE_FLASH_NAME,
|
|
|
- &manage_flash_operations);
|
|
|
- if (manage_pde == NULL) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
- }
|
|
|
+ if (!proc_create(f->filename, S_IRUSR | S_IWUSR, NULL, &f->fops))
|
|
|
+ goto enomem;
|
|
|
|
|
|
- rc = initialize_flash_pde_data("ibm,manage-flash-image",
|
|
|
- sizeof(struct rtas_manage_flash_t),
|
|
|
- manage_pde);
|
|
|
- if (rc != 0)
|
|
|
- goto cleanup;
|
|
|
+ /*
|
|
|
+ * This code assumes that the status int is the first member of the
|
|
|
+ * struct
|
|
|
+ */
|
|
|
+ token = rtas_token(f->rtas_call_name);
|
|
|
+ if (token == RTAS_UNKNOWN_SERVICE)
|
|
|
+ *f->status = FLASH_AUTH;
|
|
|
+ else
|
|
|
+ *f->status = FLASH_NO_OP;
|
|
|
+ }
|
|
|
|
|
|
rtas_flash_term_hook = rtas_flash_firmware;
|
|
|
-
|
|
|
- flash_block_cache = kmem_cache_create("rtas_flash_cache",
|
|
|
- RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
|
|
|
- rtas_block_ctor);
|
|
|
- if (!flash_block_cache) {
|
|
|
- printk(KERN_ERR "%s: failed to create block cache\n",
|
|
|
- __func__);
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
- }
|
|
|
return 0;
|
|
|
|
|
|
-cleanup:
|
|
|
- remove_flash_pde(firmware_flash_pde);
|
|
|
- remove_flash_pde(firmware_update_pde);
|
|
|
- remove_flash_pde(validate_pde);
|
|
|
- remove_flash_pde(manage_pde);
|
|
|
+enomem:
|
|
|
+ while (--i >= 0) {
|
|
|
+ const struct rtas_flash_file *f = &rtas_flash_files[i];
|
|
|
+ remove_proc_entry(f->filename, NULL);
|
|
|
+ }
|
|
|
|
|
|
- return rc;
|
|
|
+ kmem_cache_destroy(flash_block_cache);
|
|
|
+enomem_buf:
|
|
|
+ kfree(rtas_validate_flash_data.buf);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
static void __exit rtas_flash_cleanup(void)
|
|
|
{
|
|
|
+ int i;
|
|
|
+
|
|
|
rtas_flash_term_hook = NULL;
|
|
|
|
|
|
- if (flash_block_cache)
|
|
|
- kmem_cache_destroy(flash_block_cache);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(rtas_flash_files); i++) {
|
|
|
+ const struct rtas_flash_file *f = &rtas_flash_files[i];
|
|
|
+ remove_proc_entry(f->filename, NULL);
|
|
|
+ }
|
|
|
|
|
|
- remove_flash_pde(firmware_flash_pde);
|
|
|
- remove_flash_pde(firmware_update_pde);
|
|
|
- remove_flash_pde(validate_pde);
|
|
|
- remove_flash_pde(manage_pde);
|
|
|
+ kmem_cache_destroy(flash_block_cache);
|
|
|
+ kfree(rtas_validate_flash_data.buf);
|
|
|
}
|
|
|
|
|
|
module_init(rtas_flash_init);
|