[PATCH] [RFC] Exposing mmio nvrams greater than 8MB using generic_nvram
Martyn Welch
martyn.welch at gefanuc.com
Wed Nov 12 20:26:56 EST 2008
I have been looking for a way to access the nvram on our board and expose it
to userspace. The board has a 128kB nvram, the mmio_nvram driver seemed to be
a capable of mapping this device.
generic_nvram seemed initially to be the correct way of exposing the driver
to userspace, however it was hard-coded to assume an nvram of 8kB. The
mmio_nvram driver also didn't provide the functions expected by
generic_nvram.
The patch below extends generic_nvram and mmio_nvram. I realise this is
really not ready yet (I dread to think how this patch could break other's
builds), however I am interested in knowing if this is the correct approach
to take or whether I am missing a much more suitable one.
Martyn
---
arch/powerpc/boot/dts/gef_sbc610.dts | 6 +++++
arch/powerpc/configs/86xx/gef_sbc610_defconfig | 4 ++-
arch/powerpc/include/asm/nvram.h | 3 ++
arch/powerpc/kernel/setup_32.c | 8 ++++++
arch/powerpc/platforms/86xx/Kconfig | 1 +
arch/powerpc/platforms/86xx/gef_sbc610.c | 5 ++++
arch/powerpc/sysdev/mmio_nvram.c | 32 ++++++++++++++++++++++++
drivers/char/generic_nvram.c | 24 ++++++++++++++----
8 files changed, 75 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts
index e78c355..ed230bf 100644
--- a/arch/powerpc/boot/dts/gef_sbc610.dts
+++ b/arch/powerpc/boot/dts/gef_sbc610.dts
@@ -84,6 +84,12 @@
6 0 0xfd000000 0x00800000 // IO FPGA (8-bit)
7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit)
+ nvram at 3,0 {
+ device_type = "nvram";
+ compatible = "simtek,stk14ca8";
+ reg = <0x3 0x0 0x20000>;
+ };
+
fpga at 4,0 {
compatible = "gef,fpga-regs";
reg = <0x4 0x0 0x40>;
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index b539433..3dfd252 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -178,7 +178,7 @@ CONFIG_MPIC=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
# CONFIG_PPC_RTAS is not set
-# CONFIG_MMIO_NVRAM is not set
+CONFIG_MMIO_NVRAM=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
# CONFIG_PPC_INDIRECT_IO is not set
@@ -991,7 +991,7 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_RAW_DRIVER is not set
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index efde5ac..71df8b2 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -107,6 +107,9 @@ extern void pmac_xpram_write(int xpaddr, u8 data);
/* Synchronize NVRAM */
extern void nvram_sync(void);
+/* Determine NVRAM size */
+extern ssize_t nvram_size(void);
+
/* Normal access to NVRAM */
extern unsigned char nvram_read_byte(int i);
extern void nvram_write_byte(unsigned char c, int i);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index c1a2762..8130b9b 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -200,6 +200,14 @@ void nvram_write_byte(unsigned char val, int addr)
}
EXPORT_SYMBOL(nvram_write_byte);
+ssize_t nvram_size(void)
+{
+ if (ppc_md.nvram_size)
+ return ppc_md.nvram_size();
+ return 0;
+}
+EXPORT_SYMBOL(nvram_size);
+
void nvram_sync(void)
{
if (ppc_md.nvram_sync)
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 8e56939..be4e9f9 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -34,6 +34,7 @@ config MPC8610_HPCD
config GEF_SBC610
bool "GE Fanuc SBC610"
select DEFAULT_UIMAGE
+ select MMIO_NVRAM
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
select HAS_RAPIDIO
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
index fb371f5..2daec46 100644
--- a/arch/powerpc/platforms/86xx/gef_sbc610.c
+++ b/arch/powerpc/platforms/86xx/gef_sbc610.c
@@ -34,6 +34,7 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
+#include <asm/nvram.h>
#include <sysdev/fsl_pci.h>
#include <sysdev/fsl_soc.h>
@@ -96,6 +97,10 @@ static void __init gef_sbc610_setup_arch(void)
printk(KERN_WARNING "Unable to map board registers\n");
of_node_put(regs);
}
+
+#if defined(CONFIG_MMIO_NVRAM)
+ mmio_nvram_init();
+#endif
}
/* Return the PCB revision */
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
index 7b49633..2073242 100644
--- a/arch/powerpc/sysdev/mmio_nvram.c
+++ b/arch/powerpc/sysdev/mmio_nvram.c
@@ -53,6 +53,23 @@ static ssize_t mmio_nvram_read(char *buf, size_t count, loff_t *index)
return count;
}
+static unsigned char mmio_nvram_read_val(int addr)
+{
+ unsigned long flags;
+ unsigned char val;
+
+ if (addr >= mmio_nvram_len)
+ return 0xff;
+
+ spin_lock_irqsave(&mmio_nvram_lock, flags);
+
+ val = ioread8(mmio_nvram_start + addr);
+
+ spin_unlock_irqrestore(&mmio_nvram_lock, flags);
+
+ return val;
+}
+
static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
{
unsigned long flags;
@@ -72,6 +89,19 @@ static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
return count;
}
+void mmio_nvram_write_val(int addr, unsigned char val)
+{
+ unsigned long flags;
+
+ if (addr < mmio_nvram_len) {
+ spin_lock_irqsave(&mmio_nvram_lock, flags);
+
+ iowrite8(val, mmio_nvram_start + addr);
+
+ spin_unlock_irqrestore(&mmio_nvram_lock, flags);
+ }
+}
+
static ssize_t mmio_nvram_get_size(void)
{
return mmio_nvram_len;
@@ -114,6 +144,8 @@ int __init mmio_nvram_init(void)
printk(KERN_INFO "mmio NVRAM, %luk at 0x%lx mapped to %p\n",
mmio_nvram_len >> 10, nvram_addr, mmio_nvram_start);
+ ppc_md.nvram_read_val = mmio_nvram_read_val;
+ ppc_md.nvram_write_val = mmio_nvram_write_val;
ppc_md.nvram_read = mmio_nvram_read;
ppc_md.nvram_write = mmio_nvram_write;
ppc_md.nvram_size = mmio_nvram_get_size;
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index a00869c..904d2b4 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -28,6 +28,8 @@
#define NVRAM_SIZE 8192
+static ssize_t nvram_len;
+
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
lock_kernel();
@@ -36,7 +38,7 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
offset += file->f_pos;
break;
case 2:
- offset += NVRAM_SIZE;
+ offset += nvram_len;
break;
}
if (offset < 0) {
@@ -56,9 +58,9 @@ static ssize_t read_nvram(struct file *file, char __user *buf,
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
- if (*ppos >= NVRAM_SIZE)
+ if (*ppos >= nvram_len)
return 0;
- for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+ for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
if (__put_user(nvram_read_byte(i), p))
return -EFAULT;
*ppos = i;
@@ -74,9 +76,9 @@ static ssize_t write_nvram(struct file *file, const char __user *buf,
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- if (*ppos >= NVRAM_SIZE)
+ if (*ppos >= nvram_len)
return 0;
- for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+ for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
if (__get_user(c, p))
return -EFAULT;
nvram_write_byte(c, i);
@@ -133,9 +135,19 @@ static struct miscdevice nvram_dev = {
int __init nvram_init(void)
{
+ int ret = 0;
+
printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
NVRAM_VERSION);
- return misc_register(&nvram_dev);
+ if ((ret = misc_register(&nvram_dev)) != 0)
+ goto out;
+
+ nvram_len = nvram_size();
+ if (nvram_len == 0)
+ nvram_len = NVRAM_SIZE;
+
+out:
+ return ret;
}
void __exit nvram_cleanup(void)
More information about the Linuxppc-dev
mailing list