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)
 
+               [EMAIL PROTECTED],0 {
+                       device_type = "nvram";
+                       compatible = "simtek,stk14ca8";
+                       reg = <0x3 0x0 0x20000>;
+               };
+
                [EMAIL PROTECTED],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)

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to