Subject: [RFC v6 15/25] powerpc: Implement nvram sync ioctl

From: Finn Thain <[email-masked]>
Date: Sun, 23 Aug 2015 20:41:44 +1000

Add the powerpc-specific sync() method to struct nvram_ops and implement
the corresponding ioctl in the nvram module. This allows the nvram module
to replace the generic_nvram module.

Signed-off-by: Finn Thain <[email-masked]>

---

On PPC32, the IOC_NVRAM_SYNC ioctl call always returns 0, even for those
platforms that don't implement ppc_md.nvram_sync. This patch retains
that quirk. It might be better to return -EINVAL (which is what PPC64 does).

Changed since v1:
- Don't bother acquiring the mutex for unimplemented ioctls.

Changed since v5:
- The IOC_NVRAM_GET_OFFSET ioctl returns -EINVAL on PowerPC platforms
other than Power Mac, and -ENOTTY on architectures other than PowerPC.
This is more consistent with the old generic_nvram module.

---
 arch/powerpc/include/asm/nvram.h |    3 ---
 arch/powerpc/kernel/setup_32.c   |    6 +++---
 drivers/char/generic_nvram.c     |    2 +-
 drivers/char/nvram.c             |   39 +++++++++++++++++++++++++++++++++++++++
 include/linux/nvram.h            |    4 ++++
 5 files changed, 47 insertions(+), 7 deletions(-)

Index: linux/drivers/char/nvram.c
===================================================================
--- linux.orig/drivers/char/nvram.c	2015-08-23 20:41:07.000000000 +1000
+++ linux/drivers/char/nvram.c	2015-08-23 20:41:11.000000000 +1000
@@ -48,6 +48,11 @@
 #include <linux/mutex.h>

+#ifdef CONFIG_PPC
+#include <asm/nvram.h>
+#include <asm/machdep.h>
+#endif
+
 static DEFINE_MUTEX(nvram_mutex);
 static DEFINE_SPINLOCK(nvram_state_lock);
 static int nvram_open_cnt;	/* #times opened */
@@ -338,6 +343,37 @@ static long nvram_misc_ioctl(struct file
 	long ret = -ENOTTY;
 
 	switch (cmd) {
+#ifdef CONFIG_PPC
+	case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
+		pr_warn("nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
+		/* fall through */
+	case IOC_NVRAM_GET_OFFSET:
+		ret = -EINVAL;
+#ifdef CONFIG_PPC_PMAC
+		if (machine_is(powermac)) {
+			int part, offset;
+
+			if (copy_from_user(&part, (void __user *)arg,
+			                   sizeof(part)) != 0)
+				return -EFAULT;
+			if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+				return -EINVAL;
+			offset = pmac_get_partition(part);
+			if (copy_to_user((void __user *)arg,
+			                 &offset, sizeof(offset)) != 0)
+				return -EFAULT;
+			ret = 0;
+		}
+#endif
+		break;
+	case IOC_NVRAM_SYNC:
+		if (arch_nvram_ops.sync != NULL) {
+			mutex_lock(&nvram_mutex);
+			ret = arch_nvram_ops.sync();
+			mutex_unlock(&nvram_mutex);
+		}
+		break;
+#else /* !CONFIG_PPC */
 	case NVRAM_INIT:
 		/* initialize NVRAM contents and checksum */
 		if (!capable(CAP_SYS_ADMIN))
@@ -361,6 +397,7 @@ static long nvram_misc_ioctl(struct file
 			mutex_unlock(&nvram_mutex);
 		}
 		break;
+#endif /* CONFIG_PPC */
 	}
 	return ret;
 }
@@ -376,6 +413,7 @@ static int nvram_misc_open(struct inode
 		return -EBUSY;
 	}
 
+#ifndef CONFIG_PPC
 	/* Prevent multiple writers if the set_checksum ioctl is implemented. */
 	if ((arch_nvram_ops.set_checksum != NULL) &&
 	    (file->f_mode & FMODE_WRITE) &&
@@ -383,6 +421,7 @@ static int nvram_misc_open(struct inode
 		spin_unlock(&nvram_state_lock);
 		return -EBUSY;
 	}
+#endif
 
 	if (file->f_flags & O_EXCL)
 		nvram_open_mode |= NVRAM_EXCL;
Index: linux/include/linux/nvram.h
===================================================================
--- linux.orig/include/linux/nvram.h	2015-08-23 20:41:02.000000000 +1000
+++ linux/include/linux/nvram.h	2015-08-23 20:41:11.000000000 +1000
@@ -17,8 +17,12 @@ struct nvram_ops {
 	unsigned char   (*read_byte)(int);
 	void            (*write_byte)(unsigned char, int);
 	ssize_t         (*get_size)(void);
+#ifdef CONFIG_PPC
+	long            (*sync)(void);
+#else
 	long            (*set_checksum)(void);
 	long            (*initialize)(void);
+#endif
 };
 
 extern const struct nvram_ops arch_nvram_ops;
Index: linux/arch/powerpc/include/asm/nvram.h
===================================================================
--- linux.orig/arch/powerpc/include/asm/nvram.h	2015-08-23 20:41:10.000000000 +1000
+++ linux/arch/powerpc/include/asm/nvram.h	2015-08-23 20:41:11.000000000 +1000
@@ -78,9 +78,6 @@ extern int	pmac_get_partition(int partit
 extern u8	pmac_xpram_read(int xpaddr);
 extern void	pmac_xpram_write(int xpaddr, u8 data);
 
-/* Synchronize NVRAM */
-extern void	nvram_sync(void);
-
 /* Initialize NVRAM OS partition */
 extern int __init nvram_init_os_partition(struct nvram_os_partition *part);
 
Index: linux/arch/powerpc/kernel/setup_32.c
===================================================================
--- linux.orig/arch/powerpc/kernel/setup_32.c	2015-08-23 20:41:10.000000000 +1000
+++ linux/arch/powerpc/kernel/setup_32.c	2015-08-23 20:41:11.000000000 +1000
@@ -170,7 +170,6 @@ __setup("l3cr=", ppc_setup_l3cr);
 
 #ifdef CONFIG_GENERIC_NVRAM
 
-/* Generic nvram hooks used by drivers/char/gen_nvram.c */
 unsigned char nvram_read_byte(int addr)
 {
 	if (ppc_md.nvram_read_val)
@@ -193,15 +192,16 @@ static ssize_t ppc_nvram_get_size(void)
 	return -ENODEV;
 }
 
-void nvram_sync(void)
+static long ppc_nvram_sync(void)
 {
 	if (ppc_md.nvram_sync)
 		ppc_md.nvram_sync();
+	return 0;
 }
-EXPORT_SYMBOL(nvram_sync);
 
 const struct nvram_ops arch_nvram_ops = {
 	.get_size       = ppc_nvram_get_size,
+	.sync           = ppc_nvram_sync,
 };
 EXPORT_SYMBOL(arch_nvram_ops);
 
Index: linux/drivers/char/generic_nvram.c
===================================================================
--- linux.orig/drivers/char/generic_nvram.c	2015-08-23 20:41:10.000000000 +1000
+++ linux/drivers/char/generic_nvram.c	2015-08-23 20:41:11.000000000 +1000
@@ -111,7 +111,7 @@ static int nvram_ioctl(struct file *file
 	}
 #endif /* CONFIG_PPC_PMAC */
 	case IOC_NVRAM_SYNC:
-		nvram_sync();
+		arch_nvram_ops.sync();
 		break;
 	default:
 		return -EINVAL;