aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGeert Uytterhoeven2009-06-10 04:39:06 +0000
committerBenjamin Herrenschmidt2009-06-15 16:47:26 +1000
commita4e623fbc9b201930abcf78df6db5e49aa8e00cb (patch)
tree60017689df8260806cba7c007f9f9d85e3758b31 /arch/powerpc
parent47cb996b059e0e5696b8daa1f62881a6462a251a (diff)
ps3: Replace direct file operations by callback
Currently the FLASH database is updated by the kernel using file operations, meant for userspace only. While this works for us because copy_{from,to}_user() on powerpc can handle kernel pointers, this is unportable and a bad example. Replace the file operations by callbacks, registered by the ps3flash driver. Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/ps3.h7
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c138
2 files changed, 82 insertions, 63 deletions
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index 7660694ab3ca..7f065e178ec4 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
extern u64 ps3_os_area_get_rtc_diff(void);
extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
+struct ps3_os_area_flash_ops {
+ ssize_t (*read)(void *buf, size_t count, loff_t pos);
+ ssize_t (*write)(const void *buf, size_t count, loff_t pos);
+};
+
+extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
+
/* dma routines */
enum ps3_dma_page_size {
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 6e4125d6150f..d6487a9c8019 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
.value = &saved_params.av_multi_out,
};
+
+static DEFINE_MUTEX(os_area_flash_mutex);
+
+static const struct ps3_os_area_flash_ops *os_area_flash_ops;
+
+void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
+{
+ mutex_lock(&os_area_flash_mutex);
+ os_area_flash_ops = ops;
+ mutex_unlock(&os_area_flash_mutex);
+}
+EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
+
+static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
+{
+ ssize_t res = -ENODEV;
+
+ mutex_lock(&os_area_flash_mutex);
+ if (os_area_flash_ops)
+ res = os_area_flash_ops->read(buf, count, pos);
+ mutex_unlock(&os_area_flash_mutex);
+
+ return res;
+}
+
+static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
+{
+ ssize_t res = -ENODEV;
+
+ mutex_lock(&os_area_flash_mutex);
+ if (os_area_flash_ops)
+ res = os_area_flash_ops->write(buf, count, pos);
+ mutex_unlock(&os_area_flash_mutex);
+
+ return res;
+}
+
+
/**
* os_area_set_property - Add or overwrite a saved_params value to the device tree.
*
@@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db)
if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
sizeof(db->magic_num))) {
pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
- return -1;
+ return -EINVAL;
}
if (db->version != 1) {
pr_debug("%s:%d version failed\n", __func__, __LINE__);
- return -1;
+ return -EINVAL;
}
return 0;
@@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db)
*
*/
-static void __maybe_unused update_flash_db(void)
+static int update_flash_db(void)
{
- int result;
- int file;
- off_t offset;
+ const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+ struct os_area_header *header;
ssize_t count;
- static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
- const struct os_area_header *header;
+ int error;
+ loff_t pos;
struct os_area_db* db;
/* Read in header and db from flash. */
- file = sys_open("/dev/ps3flash", O_RDWR, 0);
-
- if (file < 0) {
- pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
- goto fail_open;
- }
-
header = kmalloc(buf_len, GFP_KERNEL);
-
if (!header) {
- pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
- goto fail_malloc;
+ pr_debug("%s: kmalloc failed\n", __func__);
+ return -ENOMEM;
}
- offset = sys_lseek(file, 0, SEEK_SET);
-
- if (offset != 0) {
- pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
- goto fail_header_seek;
+ count = os_area_flash_read(header, buf_len, 0);
+ if (count < 0) {
+ pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
+ count);
+ error = count;
+ goto fail;
}
- count = sys_read(file, (char __user *)header, buf_len);
-
- result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
- || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
-
- if (result) {
- pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
+ pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+ if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
+ count < pos) {
+ pr_debug("%s: verify_header failed\n", __func__);
dump_header(header);
- goto fail_header;
+ error = -EINVAL;
+ goto fail;
}
/* Now got a good db offset and some maybe good db data. */
- db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+ db = (void *)header + pos;
- result = db_verify(db);
-
- if (result) {
- printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
- "formatting.\n", __func__, __LINE__);
+ error = db_verify(db);
+ if (error) {
+ pr_notice("%s: Verify of flash database failed, formatting.\n",
+ __func__);
dump_db(db);
os_area_db_init(db);
}
@@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void)
db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
- offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
- SEEK_SET);
-
- if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
- pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
- goto fail_db_seek;
- }
-
- count = sys_write(file, (const char __user *)db,
- sizeof(struct os_area_db));
-
+ count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
if (count < sizeof(struct os_area_db)) {
- pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
+ pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
+ count);
+ error = count < 0 ? count : -EIO;
}
-fail_db_seek:
-fail_header:
-fail_header_seek:
+fail:
kfree(header);
-fail_malloc:
- sys_close(file);
-fail_open:
- return;
+ return error;
}
/**
@@ -674,11 +688,11 @@ fail_open:
static void os_area_queue_work_handler(struct work_struct *work)
{
struct device_node *node;
+ int error;
pr_debug(" -> %s:%d\n", __func__, __LINE__);
node = of_find_node_by_path("/");
-
if (node) {
os_area_set_property(node, &property_rtc_diff);
of_node_put(node);
@@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work)
pr_debug("%s:%d of_find_node_by_path failed\n",
__func__, __LINE__);
-#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
- update_flash_db();
-#else
- printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
- __func__, __LINE__);
-#endif
+ error = update_flash_db();
+ if (error)
+ pr_warning("%s: Could not update FLASH ROM\n", __func__);
+
pr_debug(" <- %s:%d\n", __func__, __LINE__);
}