Commit d5bbb502 authored by Finn Thain's avatar Finn Thain Committed by Greg Kroah-Hartman

char/nvram: Adopt arch_nvram_ops

NVRAMs on different platforms and architectures have different attributes
and access methods. E.g. some platforms have byte-at-a-time accessor
functions while others have byte-range accessor functions. Some have
checksum functionality while others do not. By calling ops struct methods
via the common wrapper functions, the nvram module and other drivers can
make use of the available NVRAM functionality in a portable way.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a156c7ba
...@@ -52,9 +52,11 @@ static DEFINE_MUTEX(nvram_mutex); ...@@ -52,9 +52,11 @@ static DEFINE_MUTEX(nvram_mutex);
static DEFINE_SPINLOCK(nvram_state_lock); static DEFINE_SPINLOCK(nvram_state_lock);
static int nvram_open_cnt; /* #times opened */ static int nvram_open_cnt; /* #times opened */
static int nvram_open_mode; /* special open modes */ static int nvram_open_mode; /* special open modes */
static ssize_t nvram_size;
#define NVRAM_WRITE 1 /* opened for writing (exclusive) */ #define NVRAM_WRITE 1 /* opened for writing (exclusive) */
#define NVRAM_EXCL 2 /* opened with O_EXCL */ #define NVRAM_EXCL 2 /* opened with O_EXCL */
#ifdef CONFIG_X86
/* /*
* These functions are provided to be called internally or by other parts of * These functions are provided to be called internally or by other parts of
* the kernel. It's up to the caller to ensure correct checksum before reading * the kernel. It's up to the caller to ensure correct checksum before reading
...@@ -145,6 +147,19 @@ void nvram_set_checksum(void) ...@@ -145,6 +147,19 @@ void nvram_set_checksum(void)
} }
#endif /* 0 */ #endif /* 0 */
static ssize_t pc_nvram_get_size(void)
{
return NVRAM_BYTES;
}
const struct nvram_ops arch_nvram_ops = {
.read_byte = pc_nvram_read_byte,
.write_byte = pc_nvram_write_byte,
.get_size = pc_nvram_get_size,
};
EXPORT_SYMBOL(arch_nvram_ops);
#endif /* CONFIG_X86 */
/* /*
* The are the file operation function for user access to /dev/nvram * The are the file operation function for user access to /dev/nvram
*/ */
...@@ -152,7 +167,7 @@ void nvram_set_checksum(void) ...@@ -152,7 +167,7 @@ void nvram_set_checksum(void)
static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin) static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin)
{ {
return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
NVRAM_BYTES); nvram_size);
} }
static ssize_t nvram_misc_read(struct file *file, char __user *buf, static ssize_t nvram_misc_read(struct file *file, char __user *buf,
...@@ -303,8 +318,7 @@ static int nvram_misc_release(struct inode *inode, struct file *file) ...@@ -303,8 +318,7 @@ static int nvram_misc_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
#ifdef CONFIG_PROC_FS #if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
static const char * const floppy_types[] = { static const char * const floppy_types[] = {
"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M",
"3.5'' 2.88M", "3.5'' 2.88M" "3.5'' 2.88M", "3.5'' 2.88M"
...@@ -394,7 +408,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset) ...@@ -394,7 +408,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset)
return 0; return 0;
} }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_X86 && CONFIG_PROC_FS */
static const struct file_operations nvram_misc_fops = { static const struct file_operations nvram_misc_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -416,13 +430,17 @@ static int __init nvram_module_init(void) ...@@ -416,13 +430,17 @@ static int __init nvram_module_init(void)
{ {
int ret; int ret;
nvram_size = nvram_get_size();
if (nvram_size < 0)
return nvram_size;
ret = misc_register(&nvram_misc); ret = misc_register(&nvram_misc);
if (ret) { if (ret) {
pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR); pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
return ret; return ret;
} }
#ifdef CONFIG_PROC_FS #if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) { if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
pr_err("nvram: can't create /proc/driver/nvram\n"); pr_err("nvram: can't create /proc/driver/nvram\n");
misc_deregister(&nvram_misc); misc_deregister(&nvram_misc);
...@@ -436,7 +454,7 @@ static int __init nvram_module_init(void) ...@@ -436,7 +454,7 @@ static int __init nvram_module_init(void)
static void __exit nvram_module_exit(void) static void __exit nvram_module_exit(void)
{ {
#ifdef CONFIG_PROC_FS #if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
remove_proc_entry("driver/nvram", NULL); remove_proc_entry("driver/nvram", NULL);
#endif #endif
misc_deregister(&nvram_misc); misc_deregister(&nvram_misc);
......
...@@ -5,8 +5,30 @@ ...@@ -5,8 +5,30 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <uapi/linux/nvram.h> #include <uapi/linux/nvram.h>
/**
* struct nvram_ops - NVRAM functionality made available to drivers
* @read: validate checksum (if any) then load a range of bytes from NVRAM
* @write: store a range of bytes to NVRAM then update checksum (if any)
* @read_byte: load a single byte from NVRAM
* @write_byte: store a single byte to NVRAM
* @get_size: return the fixed number of bytes in the NVRAM
*
* Architectures which provide an nvram ops struct need not implement all
* of these methods. If the NVRAM hardware can be accessed only one byte
* at a time then it may be sufficient to provide .read_byte and .write_byte.
* If the NVRAM has a checksum (and it is to be checked) the .read and
* .write methods can be used to implement that efficiently.
*
* Portable drivers may use the wrapper functions defined here.
* The nvram_read() and nvram_write() functions call the .read and .write
* methods when available and fall back on the .read_byte and .write_byte
* methods otherwise.
*/
struct nvram_ops { struct nvram_ops {
ssize_t (*get_size)(void); ssize_t (*get_size)(void);
unsigned char (*read_byte)(int);
void (*write_byte)(unsigned char, int);
ssize_t (*read)(char *, size_t, loff_t *); ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *); ssize_t (*write)(char *, size_t, loff_t *);
}; };
...@@ -25,11 +47,21 @@ static inline ssize_t nvram_get_size(void) ...@@ -25,11 +47,21 @@ static inline ssize_t nvram_get_size(void)
static inline unsigned char nvram_read_byte(int addr) static inline unsigned char nvram_read_byte(int addr)
{ {
#ifdef CONFIG_PPC
#else
if (arch_nvram_ops.read_byte)
return arch_nvram_ops.read_byte(addr);
#endif
return 0xFF; return 0xFF;
} }
static inline void nvram_write_byte(unsigned char val, int addr) static inline void nvram_write_byte(unsigned char val, int addr)
{ {
#ifdef CONFIG_PPC
#else
if (arch_nvram_ops.write_byte)
arch_nvram_ops.write_byte(val, addr);
#endif
} }
static inline ssize_t nvram_read(char *buf, size_t count, loff_t *ppos) static inline ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment