mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Finn Thain <fthain@telegraphics.com.au>
To: Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org, linux-m68k@lists.linux-m68k.org,
	linuxppc-dev@lists.ozlabs.org
Subject: [PATCH v9 09/22] char/nvram: Implement NVRAM read/write methods
Date: Tue, 15 Jan 2019 15:18:56 +1100	[thread overview]
Message-ID: <24c1282d42d7d996cdc5c1a6c4dfd979af5a3ff7.1547525936.git.fthain@telegraphics.com.au> (raw)
In-Reply-To: <cover.1547525936.git.fthain@telegraphics.com.au>

Refactor the RTC "CMOS" NVRAM functions so that they can be used as
arch_nvram_ops methods. Checksumming logic is moved from the misc device
operations to the nvram read/write operations. This makes the misc device
implementation more generic.

This preserves the locking mechanism such that "read if checksum valid"
and "write and update checksum" remain atomic operations.

Some platforms implement byte-range read/write methods which are similar
to file_operations struct methods. Other platforms provide only
byte-at-a-time methods. The former are more efficient but may be
unavailable so fall back on the latter methods when necessary.

Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
Changed since v8:
 - Renamed nvram_* functions to avoid name collisions.
 - Added nvram_read_bytes() and nvram_write_bytes() helpers for use by
those platforms which access NVRAM only one-byte-at-a-time.

Changed since v7:
 - Adopted memdup_user(), like arch/powerpc/kernel/nvram_64.c.
---
 drivers/char/nvram.c  | 120 ++++++++++++++++++++++++++----------------
 include/linux/nvram.h |  32 ++++++++++-
 2 files changed, 104 insertions(+), 48 deletions(-)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index f88ef41d0598..adcc213c331e 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -161,7 +162,46 @@ static ssize_t pc_nvram_get_size(void)
 	return NVRAM_BYTES;
 }
 
+static ssize_t pc_nvram_read(char *buf, size_t count, loff_t *ppos)
+{
+	char *p = buf;
+	loff_t i;
+
+	spin_lock_irq(&rtc_lock);
+	if (!__nvram_check_checksum()) {
+		spin_unlock_irq(&rtc_lock);
+		return -EIO;
+	}
+	for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
+		*p = __nvram_read_byte(i);
+	spin_unlock_irq(&rtc_lock);
+
+	*ppos = i;
+	return p - buf;
+}
+
+static ssize_t pc_nvram_write(char *buf, size_t count, loff_t *ppos)
+{
+	char *p = buf;
+	loff_t i;
+
+	spin_lock_irq(&rtc_lock);
+	if (!__nvram_check_checksum()) {
+		spin_unlock_irq(&rtc_lock);
+		return -EIO;
+	}
+	for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
+		__nvram_write_byte(*p, i);
+	__nvram_set_checksum();
+	spin_unlock_irq(&rtc_lock);
+
+	*ppos = i;
+	return p - buf;
+}
+
 const struct nvram_ops arch_nvram_ops = {
+	.read           = pc_nvram_read,
+	.write          = pc_nvram_write,
 	.read_byte      = pc_nvram_read_byte,
 	.write_byte     = pc_nvram_write_byte,
 	.get_size       = pc_nvram_get_size,
@@ -184,69 +224,57 @@ static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin)
 static ssize_t nvram_misc_read(struct file *file, char __user *buf,
 			       size_t count, loff_t *ppos)
 {
-	unsigned char contents[NVRAM_BYTES];
-	unsigned i = *ppos;
-	unsigned char *tmp;
-
-	spin_lock_irq(&rtc_lock);
+	char *tmp;
+	ssize_t ret;
 
-	if (!__nvram_check_checksum())
-		goto checksum_err;
 
-	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
-		*tmp = __nvram_read_byte(i);
+	if (!access_ok(buf, count))
+		return -EFAULT;
+	if (*ppos >= nvram_size)
+		return 0;
 
-	spin_unlock_irq(&rtc_lock);
+	count = min_t(size_t, count, nvram_size - *ppos);
+	count = min_t(size_t, count, PAGE_SIZE);
 
-	if (copy_to_user(buf, contents, tmp - contents))
-		return -EFAULT;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
 
-	*ppos = i;
+	ret = nvram_read(tmp, count, ppos);
+	if (ret <= 0)
+		goto out;
 
-	return tmp - contents;
+	if (copy_to_user(buf, tmp, ret)) {
+		*ppos -= ret;
+		ret = -EFAULT;
+	}
 
-checksum_err:
-	spin_unlock_irq(&rtc_lock);
-	return -EIO;
+out:
+	kfree(tmp);
+	return ret;
 }
 
 static ssize_t nvram_misc_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned char contents[NVRAM_BYTES];
-	unsigned i = *ppos;
-	unsigned char *tmp;
-
-	if (i >= NVRAM_BYTES)
-		return 0;	/* Past EOF */
-
-	if (count > NVRAM_BYTES - i)
-		count = NVRAM_BYTES - i;
-	if (count > NVRAM_BYTES)
-		return -EFAULT;	/* Can't happen, but prove it to gcc */
+	char *tmp;
+	ssize_t ret;
 
-	if (copy_from_user(contents, buf, count))
+	if (!access_ok(buf, count))
 		return -EFAULT;
+	if (*ppos >= nvram_size)
+		return 0;
 
-	spin_lock_irq(&rtc_lock);
-
-	if (!__nvram_check_checksum())
-		goto checksum_err;
-
-	for (tmp = contents; count--; ++i, ++tmp)
-		__nvram_write_byte(*tmp, i);
+	count = min_t(size_t, count, nvram_size - *ppos);
+	count = min_t(size_t, count, PAGE_SIZE);
 
-	__nvram_set_checksum();
-
-	spin_unlock_irq(&rtc_lock);
+	tmp = memdup_user(buf, count);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
 
-	*ppos = i;
-
-	return tmp - contents;
-
-checksum_err:
-	spin_unlock_irq(&rtc_lock);
-	return -EIO;
+	ret = nvram_write(tmp, count, ppos);
+	kfree(tmp);
+	return ret;
 }
 
 static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index 31c763087746..9df85703735c 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -66,18 +66,46 @@ static inline void nvram_write_byte(unsigned char val, int addr)
 #endif
 }
 
+static inline ssize_t nvram_read_bytes(char *buf, size_t count, loff_t *ppos)
+{
+	ssize_t nvram_size = nvram_get_size();
+	loff_t i;
+	char *p = buf;
+
+	if (nvram_size < 0)
+		return nvram_size;
+	for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count)
+		*p = nvram_read_byte(i);
+	*ppos = i;
+	return p - buf;
+}
+
+static inline ssize_t nvram_write_bytes(char *buf, size_t count, loff_t *ppos)
+{
+	ssize_t nvram_size = nvram_get_size();
+	loff_t i;
+	char *p = buf;
+
+	if (nvram_size < 0)
+		return nvram_size;
+	for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count)
+		nvram_write_byte(*p, i);
+	*ppos = i;
+	return p - buf;
+}
+
 static inline ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
 {
 	if (arch_nvram_ops.read)
 		return arch_nvram_ops.read(buf, count, ppos);
-	return -ENODEV;
+	return nvram_read_bytes(buf, count, ppos);
 }
 
 static inline ssize_t nvram_write(char *buf, size_t count, loff_t *ppos)
 {
 	if (arch_nvram_ops.write)
 		return arch_nvram_ops.write(buf, count, ppos);
-	return -ENODEV;
+	return nvram_write_bytes(buf, count, ppos);
 }
 
 #endif  /* _LINUX_NVRAM_H */
-- 
2.19.2


  parent reply	other threads:[~2019-01-15  4:22 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-15  4:18 [PATCH v9 00/22] Re-use nvram module Finn Thain
2019-01-15  4:18 ` [PATCH v9 02/22] m68k/atari: Move Atari-specific code out of drivers/char/nvram.c Finn Thain
2019-01-15  4:18 ` [PATCH v9 04/22] nvram: Replace nvram_* function exports with static functions Finn Thain
2019-01-15  4:18 ` [PATCH v9 22/22] powerpc: Adopt nvram module for PPC64 Finn Thain
2019-01-15  4:18 ` [PATCH v9 13/22] m68k/mac: Fix PRAM accessors Finn Thain
2019-01-15  4:18 ` Finn Thain [this message]
2019-01-15  4:18 ` [PATCH v9 01/22] scsi/atari_scsi: Don't select CONFIG_NVRAM Finn Thain
2019-01-15  4:18 ` [PATCH v9 18/22] powerpc: Implement nvram ioctls Finn Thain
2019-01-15  4:18 ` [PATCH v9 14/22] macintosh/via-cuda: Don't rely on Cuda to end a transfer Finn Thain
2019-01-15  4:18 ` [PATCH v9 16/22] char/nvram: Add "devname:nvram" module alias Finn Thain
2019-01-15  4:18 ` [PATCH v9 10/22] m68k/atari: Implement arch_nvram_ops methods and enable CONFIG_HAVE_ARCH_NVRAM_OPS Finn Thain
2019-01-15  4:18 ` [PATCH v9 12/22] m68k/mac: Use macros for RTC accesses not magic numbers Finn Thain
2019-01-15  4:18 ` [PATCH v9 05/22] m68k/atari: Implement arch_nvram_ops struct Finn Thain
2019-01-15  4:18 ` [PATCH v9 11/22] m68k/mac: Adopt naming and calling conventions for PRAM routines Finn Thain
2019-01-15  4:18 ` [PATCH v9 20/22] powerpc: Enable HAVE_ARCH_NVRAM_OPS and disable GENERIC_NVRAM Finn Thain
2019-01-15  4:18 ` [PATCH v9 21/22] char/generic_nvram: Remove as unused Finn Thain
2019-01-15  4:18 ` [PATCH v9 03/22] char/nvram: Re-order functions to remove forward declarations and #ifdefs Finn Thain
2019-01-15  4:18 ` [PATCH v9 17/22] powerpc: Define missing ppc_md.nvram_size for CHRP and PowerMac Finn Thain
2019-01-15  4:18 ` [PATCH v9 06/22] powerpc: Replace nvram_* extern declarations with standard header Finn Thain
2019-01-15  4:18 ` [PATCH v9 07/22] char/nvram: Adopt arch_nvram_ops Finn Thain
2019-01-15  4:18 ` [PATCH v9 19/22] powerpc, fbdev: Use NV_CMODE and NV_VMODE only when CONFIG_PPC32 && CONFIG_PPC_PMAC && CONFIG_NVRAM Finn Thain
2019-01-15  4:18 ` [PATCH v9 08/22] char/nvram: Allow the set_checksum and initialize ioctls to be omitted Finn Thain
2019-01-15  4:18 ` [PATCH v9 15/22] m68k: Dispatch nvram_ops calls to Atari or Mac functions Finn Thain
2019-01-22  9:19   ` Greg Kroah-Hartman
2019-01-22  9:22     ` Greg Kroah-Hartman
2019-01-22  9:22 ` [PATCH v9 00/22] Re-use nvram module Greg Kroah-Hartman
2019-01-22 22:06   ` Finn Thain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=24c1282d42d7d996cdc5c1a6c4dfd979af5a3ff7.1547525936.git.fthain@telegraphics.com.au \
    --to=fthain@telegraphics.com.au \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-m68k@lists.linux-m68k.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®