2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 00/25] Re-use nvram module

The generic NVRAM module, drivers/char/generic_nvram.c, implements a
/dev/nvram misc device. This module is used only by 32-bit PowerPC
platforms. Unfortunately, it isn't generic enough to be more widely used.

The RTC "CMOS" NVRAM module, drivers/char/nvram.c, also implements a
/dev/nvram misc device. This module is now used only by x86 and m68k
thanks to commit 3ba9faedc180 ("char: nvram: disable on ARM").

The "generic" module cannot be used by x86 or m68k platforms because it
cannot co-exist with the "CMOS" module. One reason for that is the
CONFIG_GENERIC_NVRAM kludge in drivers/char/Makefile. Another reason is
that automatically loading the appropriate module would be impossible
because only one module can provide the 'char-major-10-144' alias.

A multi-platform kernel binary needs a single generic module. With this
patch series, drivers/char/nvram.c becomes more generic and some
arch-specific code gets moved under arch/. The 'nvram' module is then
usable by all m68k, powerpc and x86 platforms.

This allows for removal of drivers/char/generic_nvram.c as well as some
duplicated code in arch/powerpc/kernel/nvram_64.c. By reducing the number
of /dev/nvram char misc device implementations, the number of bugs and
inconsistencies is also reduced.

This patch series reduces inconsistencies between PPC32 and PPC64, and
between PPC_PMAC and MAC. A uniform API has benefits for userspace.
For example, some error codes for some ioctl calls become consistent
across PowerPC platforms. The uniform API can potentially benefit
bootloaders that work across different platforms which all have XPRAM
(e.g. Emile).

I think there are two reasonable merge strategies for this patch series.
The char misc maintainer could take the entire series. Alternatively the
m68k maintainer could take patches 1 thru 14, and after those patches
reach mainline the powerpc maintainer could take 15 thru 25 (even though
patch 21 is not powerpc-related).

This patch series has been tested on m68k, powerpc32, powerpc64 and x86.
The nvram and thinkpad_acpi modules were regression tested on a ThinkPad
T43. The /dev/nvram functionality was also regression tested on a G3
PowerMac. The nvram module was also tested on a variety of m68k Macs
and an Atari Falcon. The PPC64 changes were tested on a G5 PowerMac.
AFAIK, there's been no testing on pSeries or CHRP as yet.

Changed since v7:
- Rebased.
- Dropped patch 9/26, "char/nvram: Use generic fixed_size_llseek()"
because generic_file_llseek_size() was adopted in commit b808b1d632f6.
- Reordered the m68k and powerpc patches to simplify the merge strategy.
- Addressed some trivial checkpatch.pl complaints.
- Improved some commit log entries.
- Changed the CONFIG_NVRAM default to better approximate the present code.
In particular, the CONFIG_GENERIC_NVRAM default and use of "select NVRAM".
- Added more tested-by tags.

For older change logs, please refer to,
https://lore.kernel.org/lkml/[email protected]/


Finn Thain (25):
scsi/atari_scsi: Don't select CONFIG_NVRAM
m68k/atari: Move Atari-specific code out of drivers/char/nvram.c
m68k/atari: Replace nvram_{read,write}_byte with arch_nvram_ops
char/nvram: Re-order functions to remove forward declarations and
#ifdefs
char/nvram: Adopt arch_nvram_ops
x86/thinkpad_acpi: Use arch_nvram_ops methods instead of
nvram_read_byte() and nvram_write_byte()
char/nvram: Allow the set_checksum and initialize ioctls to be omitted
char/nvram: Implement NVRAM read/write methods
m68k/atari: Implement arch_nvram_ops methods and enable
CONFIG_HAVE_ARCH_NVRAM_OPS
m68k/mac: Adopt naming and calling conventions for PRAM routines
m68k/mac: Use macros for RTC accesses not magic numbers
m68k/mac: Fix PRAM accessors
m68k: Dispatch nvram_ops calls to Atari or Mac functions
char/nvram: Add "devname:nvram" module alias
powerpc: Clean up nvram includes
powerpc: Add missing ppc_md.nvram_size for CHRP and PowerMac
powerpc: Implement arch_nvram_ops.get_size() and remove old nvram_*
exports
powerpc: Implement nvram sync ioctl
powerpc, fbdev: Use NV_CMODE and NV_VMODE only when CONFIG_PPC32 &&
CONFIG_PPC_PMAC && CONFIG_NVRAM
powerpc, fbdev: Use arch_nvram_ops methods instead of
nvram_read_byte() and nvram_write_byte()
nvram: Drop nvram_* symbol exports and prototypes
powerpc: Remove CONFIG_GENERIC_NVRAM and adopt
CONFIG_HAVE_ARCH_NVRAM_OPS
char/generic_nvram: Remove as unused
powerpc: Adopt nvram module for PPC64
powerpc: Remove pmac_xpram_{read,write} functions

arch/m68k/Kconfig | 3 +
arch/m68k/Kconfig.machine | 2 +
arch/m68k/atari/Makefile | 2 +
arch/m68k/atari/nvram.c | 279 ++++++++
arch/m68k/include/asm/atarihw.h | 6 +
arch/m68k/include/asm/macintosh.h | 4 +
arch/m68k/kernel/setup_mm.c | 100 ++-
arch/m68k/mac/misc.c | 174 +++--
arch/powerpc/Kconfig | 5 +-
arch/powerpc/include/asm/nvram.h | 13 -
arch/powerpc/kernel/nvram_64.c | 188 ++----
arch/powerpc/kernel/setup_32.c | 30 +-
arch/powerpc/platforms/chrp/Makefile | 2 +-
arch/powerpc/platforms/chrp/nvram.c | 14 +-
arch/powerpc/platforms/chrp/setup.c | 2 +-
arch/powerpc/platforms/powermac/Makefile | 2 -
arch/powerpc/platforms/powermac/nvram.c | 37 +-
arch/powerpc/platforms/powermac/setup.c | 3 +-
arch/powerpc/platforms/powermac/time.c | 19 +-
arch/powerpc/platforms/pseries/nvram.c | 2 -
drivers/char/Kconfig | 19 +-
drivers/char/Makefile | 6 +-
drivers/char/generic_nvram.c | 159 -----
drivers/char/nvram.c | 701 +++++++++------------
drivers/platform/x86/thinkpad_acpi.c | 20 +-
drivers/scsi/Kconfig | 6 +-
drivers/scsi/atari_scsi.c | 15 +-
drivers/video/fbdev/Kconfig | 2 +-
drivers/video/fbdev/controlfb.c | 4 +-
drivers/video/fbdev/imsttfb.c | 16 +-
drivers/video/fbdev/matrox/matroxfb_base.c | 6 +-
drivers/video/fbdev/platinumfb.c | 4 +-
drivers/video/fbdev/valkyriefb.c | 18 +-
include/linux/nvram.h | 24 +-
include/uapi/linux/pmu.h | 2 +
35 files changed, 964 insertions(+), 925 deletions(-)
create mode 100644 arch/m68k/atari/nvram.c
delete mode 100644 drivers/char/generic_nvram.c

--
2.19.2



2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 12/25] m68k/mac: Fix PRAM accessors

PMU-based m68k Macs pre-date PowerMac-style NVRAM. Use the appropriate
PMU commands. Also implement the missing XPRAM accessors for VIA-based
Macs.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
Changed since v7:
- Updated PMU response decoding due to via-pmu68k driver replacement.
---
arch/m68k/mac/misc.c | 43 ++++++++++++++++++++++++++++++----------
include/uapi/linux/pmu.h | 2 ++
2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 475c93e4048c..0009efebb264 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -66,23 +66,22 @@ static unsigned char pmu_pram_read_byte(int offset)
{
struct adb_request req;

- if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
- (offset >> 8) & 0xFF, offset & 0xFF) < 0)
+ if (pmu_request(&req, NULL, 3, PMU_READ_XPRAM,
+ offset & 0xFF, 1) < 0)
return 0;
- while (!req.complete)
- pmu_poll();
- return req.reply[3];
+ pmu_wait_complete(&req);
+
+ return req.reply[0];
}

static void pmu_pram_write_byte(unsigned char data, int offset)
{
struct adb_request req;

- if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
- (offset >> 8) & 0xFF, offset & 0xFF, data) < 0)
+ if (pmu_request(&req, NULL, 4, PMU_WRITE_XPRAM,
+ offset & 0xFF, 1, data) < 0)
return;
- while (!req.complete)
- pmu_poll();
+ pmu_wait_complete(&req);
}
#endif /* CONFIG_ADB_PMU */

@@ -151,6 +150,16 @@ static void via_rtc_send(__u8 data)
#define RTC_REG_SECONDS_3 3
#define RTC_REG_WRITE_PROTECT 13

+/*
+ * Inside Mac has no information about two-byte RTC commands but
+ * the MAME/MESS source code has the essentials.
+ */
+
+#define RTC_REG_XPRAM 14
+#define RTC_CMD_XPRAM_READ (RTC_CMD_READ(RTC_REG_XPRAM) << 8)
+#define RTC_CMD_XPRAM_WRITE (RTC_CMD_WRITE(RTC_REG_XPRAM) << 8)
+#define RTC_CMD_XPRAM_ARG(a) (((a & 0xE0) << 3) | ((a & 0x1F) << 2))
+
/*
* Execute a VIA PRAM/RTC command. For read commands
* data should point to a one-byte buffer for the
@@ -198,11 +207,25 @@ static void via_rtc_command(int command, __u8 *data)

static unsigned char via_pram_read_byte(int offset)
{
- return 0;
+ unsigned char temp;
+
+ via_rtc_command(RTC_CMD_XPRAM_READ | RTC_CMD_XPRAM_ARG(offset), &temp);
+
+ return temp;
}

static void via_pram_write_byte(unsigned char data, int offset)
{
+ unsigned char temp;
+
+ temp = 0x55;
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_WRITE_PROTECT), &temp);
+
+ temp = data;
+ via_rtc_command(RTC_CMD_XPRAM_WRITE | RTC_CMD_XPRAM_ARG(offset), &temp);
+
+ temp = 0x55 | RTC_FLG_WRITE_PROTECT;
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_WRITE_PROTECT), &temp);
}

/*
diff --git a/include/uapi/linux/pmu.h b/include/uapi/linux/pmu.h
index 97256f90e6df..f2fc1bd80017 100644
--- a/include/uapi/linux/pmu.h
+++ b/include/uapi/linux/pmu.h
@@ -19,7 +19,9 @@
#define PMU_POWER_CTRL 0x11 /* control power of some devices */
#define PMU_ADB_CMD 0x20 /* send ADB packet */
#define PMU_ADB_POLL_OFF 0x21 /* disable ADB auto-poll */
+#define PMU_WRITE_XPRAM 0x32 /* write eXtended Parameter RAM */
#define PMU_WRITE_NVRAM 0x33 /* write non-volatile RAM */
+#define PMU_READ_XPRAM 0x3a /* read eXtended Parameter RAM */
#define PMU_READ_NVRAM 0x3b /* read non-volatile RAM */
#define PMU_SET_RTC 0x30 /* set real-time clock */
#define PMU_READ_RTC 0x38 /* read real-time clock */
--
2.19.2


2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 07/25] char/nvram: Allow the set_checksum and initialize ioctls to be omitted

The drivers/char/nvram module has previously only supported RTC "CMOS"
NVRAM, for which it provides appropriate checksum ioctls. Make these
ioctls optional so the module can be re-used with other kinds of NVRAM.

The ops struct methods that implement the ioctls now return error
codes so that a multi-platform kernel binary can do the right thing when
running on hardware without suitable NVRAM.

Signed-off-by: Finn Thain <[email protected]>
---
drivers/char/nvram.c | 70 ++++++++++++++++++++++++-------------------
include/linux/nvram.h | 2 ++
2 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 00897daa0643..33ef3b02d365 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -153,16 +153,25 @@ static void __nvram_set_checksum(void)
__nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
}

-#if 0
-void nvram_set_checksum(void)
+static long nvram_set_checksum(void)
{
- unsigned long flags;
+ spin_lock_irq(&rtc_lock);
+ __nvram_set_checksum();
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+}

- spin_lock_irqsave(&rtc_lock, flags);
+static long nvram_initialize(void)
+{
+ ssize_t i;
+
+ spin_lock_irq(&rtc_lock);
+ for (i = 0; i < NVRAM_BYTES; ++i)
+ __nvram_write_byte(0, i);
__nvram_set_checksum();
- spin_unlock_irqrestore(&rtc_lock, flags);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
}
-#endif /* 0 */

static ssize_t nvram_get_size(void)
{
@@ -173,6 +182,8 @@ const struct nvram_ops arch_nvram_ops = {
.read_byte = nvram_read_byte,
.write_byte = nvram_write_byte,
.get_size = nvram_get_size,
+ .set_checksum = nvram_set_checksum,
+ .initialize = nvram_initialize,
};
EXPORT_SYMBOL(arch_nvram_ops);
#endif /* CONFIG_X86 */
@@ -258,51 +269,50 @@ static ssize_t nvram_misc_write(struct file *file, const char __user *buf,
static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- int i;
+ long ret = -ENOTTY;

switch (cmd) {
-
case NVRAM_INIT:
/* initialize NVRAM contents and checksum */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

- mutex_lock(&nvram_mutex);
- spin_lock_irq(&rtc_lock);
-
- for (i = 0; i < NVRAM_BYTES; ++i)
- __nvram_write_byte(0, i);
- __nvram_set_checksum();
-
- spin_unlock_irq(&rtc_lock);
- mutex_unlock(&nvram_mutex);
- return 0;
-
+ if (arch_nvram_ops.initialize != NULL) {
+ mutex_lock(&nvram_mutex);
+ ret = arch_nvram_ops.initialize();
+ mutex_unlock(&nvram_mutex);
+ }
+ break;
case NVRAM_SETCKS:
/* just set checksum, contents unchanged (maybe useful after
* checksum garbaged somehow...) */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

- mutex_lock(&nvram_mutex);
- spin_lock_irq(&rtc_lock);
- __nvram_set_checksum();
- spin_unlock_irq(&rtc_lock);
- mutex_unlock(&nvram_mutex);
- return 0;
-
- default:
- return -ENOTTY;
+ if (arch_nvram_ops.set_checksum != NULL) {
+ mutex_lock(&nvram_mutex);
+ ret = arch_nvram_ops.set_checksum();
+ mutex_unlock(&nvram_mutex);
+ }
+ break;
}
+ return ret;
}

static int nvram_misc_open(struct inode *inode, struct file *file)
{
spin_lock(&nvram_state_lock);

+ /* Prevent multiple readers/writers if desired. */
if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
- (nvram_open_mode & NVRAM_EXCL) ||
- ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
+ (nvram_open_mode & NVRAM_EXCL)) {
+ spin_unlock(&nvram_state_lock);
+ return -EBUSY;
+ }
+
+ /* Prevent multiple writers if the set_checksum ioctl is implemented. */
+ if ((arch_nvram_ops.set_checksum != NULL) &&
+ (file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) {
spin_unlock(&nvram_state_lock);
return -EBUSY;
}
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index d1bdee50d6a8..b7bfaec60a43 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -18,6 +18,8 @@ struct nvram_ops {
unsigned char (*read_byte)(int);
void (*write_byte)(unsigned char, int);
ssize_t (*get_size)(void);
+ long (*set_checksum)(void);
+ long (*initialize)(void);
};

extern const struct nvram_ops arch_nvram_ops;
--
2.19.2


2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

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 protected]>
Tested-by: Stan Johnson <[email protected]>
---
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).
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 6 ++---
drivers/char/generic_nvram.c | 2 +-
drivers/char/nvram.c | 38 ++++++++++++++++++++++++++++++++
include/linux/nvram.h | 4 ++++
5 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 56a388da9c4f..629a5cdcc865 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -78,9 +78,6 @@ extern int pmac_get_partition(int partition);
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);

diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index ee91bba0805d..e0d045677472 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -152,7 +152,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)
@@ -175,15 +174,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);

diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index a7dfde734897..f32d5663de95 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -96,7 +96,7 @@ static int nvram_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#endif /* CONFIG_PPC_PMAC */
case IOC_NVRAM_SYNC:
- nvram_sync();
+ arch_nvram_ops.sync();
break;
default:
return -EINVAL;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index b77c27d68762..466e1fb02052 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -48,6 +48,10 @@
#include <linux/mutex.h>
#include <linux/pagemap.h>

+#ifdef CONFIG_PPC
+#include <asm/nvram.h>
+#include <asm/machdep.h>
+#endif

static DEFINE_MUTEX(nvram_mutex);
static DEFINE_SPINLOCK(nvram_state_lock);
@@ -331,6 +335,37 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
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))
@@ -354,6 +389,7 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
mutex_unlock(&nvram_mutex);
}
break;
+#endif /* CONFIG_PPC */
}
return ret;
}
@@ -369,12 +405,14 @@ static int nvram_misc_open(struct inode *inode, struct file *file)
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) && (nvram_open_mode & NVRAM_WRITE)) {
spin_unlock(&nvram_state_lock);
return -EBUSY;
}
+#endif

if (file->f_flags & O_EXCL)
nvram_open_mode |= NVRAM_EXCL;
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index b7bfaec60a43..24a57675dba1 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -18,8 +18,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;
--
2.19.2


2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 19/25] powerpc, fbdev: Use NV_CMODE and NV_VMODE only when CONFIG_PPC32 && CONFIG_PPC_PMAC && CONFIG_NVRAM

This patch addresses inconsistencies in Mac framebuffer drivers and their
use of Kconfig symbols relating to NVRAM, so PPC64 can use CONFIG_NVRAM.

Macintosh framebuffer drivers use default settings for color mode and
video mode that are found in NVRAM. On PCI Macs, MacOS stores display
settings in the Name Registry (NR) partition in NVRAM*. On NuBus Macs,
there is no NR partition and MacOS stores display mode settings in PRAM**.

Early-model Macs are the ones most likely to benefit from these settings,
since they are more likely to have a fixed-frequency monitor connected to
the built-in framebuffer device. Moreover, a single NV_CMODE value and
a single NV_VMODE value provide for only one display.

The NV_CMODE and NV_VMODE constants are apparently offsets into the NR
partition for Old World machines. This also suggests that these defaults
are not useful on later models. The NR partition seems to be optional on
New World machines. CONFIG_NVRAM cannot be enabled on PPC64 at present.

It is safe to say that NVRAM support in PowerMac fbdev drivers is only
applicable to CONFIG_PPC32 so make this condition explicit. This means
matroxfb driver won't crash on PPC64 when CONFIG_NVRAM becomes available
there.

For imsttfb, add the missing CONFIG_NVRAM test to prevent a build failure,
since PPC64 does not implement nvram_read_byte(). Also add a missing
machine_is(powermac) check. Change the inconsistent dependency on
CONFIG_PPC and the matching #ifdef tests to CONFIG_PPC_PMAC.

For valkyriefb, to improve clarity and consistency with the other PowerMac
fbdev drivers, test for CONFIG_PPC_PMAC instead of !CONFIG_MAC. Remove a
bogus comment regarding PRAM.

* See GetPreferredConfiguration and SavePreferredConfiguration in
"Designing PCI Cards and Drivers for Power Macintosh Computers".

** See SetDefaultMode and GetDefaultMode in "Designing Cards and Drivers
for the Macintosh Family".

Signed-off-by: Finn Thain <[email protected]>
---
drivers/video/fbdev/Kconfig | 2 +-
drivers/video/fbdev/imsttfb.c | 12 +++++-------
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
drivers/video/fbdev/valkyriefb.c | 14 ++++++--------
4 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index e413f54208f4..52453ce3040a 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -536,7 +536,7 @@ config FB_IMSTT
bool "IMS Twin Turbo display support"
depends on (FB = y) && PCI
select FB_CFB_IMAGEBLIT
- select FB_MACMODES if PPC
+ select FB_MACMODES if PPC_PMAC
help
The IMS Twin Turbo is a PCI-based frame buffer card bundled with
many Macintosh and compatible computers.
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 901ca4ed10e9..8d231591ff0e 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -30,9 +30,8 @@
#include <asm/io.h>
#include <linux/uaccess.h>

-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
#include <linux/nvram.h>
-#include <asm/prom.h>
#include "macmodes.h"
#endif

@@ -327,14 +326,13 @@ enum {
TVP = 1
};

-#define USE_NV_MODES 1
#define INIT_BPP 8
#define INIT_XRES 640
#define INIT_YRES 480

static int inverse = 0;
static char fontname[40] __initdata = { 0 };
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
static signed char init_vmode = -1, init_cmode = -1;
#endif

@@ -1390,8 +1388,8 @@ static void init_imstt(struct fb_info *info)
}
}

-#if USE_NV_MODES && defined(CONFIG_PPC32)
- {
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
+ if (machine_is(powermac)) {
int vmode = init_vmode, cmode = init_cmode;

if (vmode == -1) {
@@ -1565,7 +1563,7 @@ imsttfb_setup(char *options)
inverse = 1;
fb_invert_cmaps();
}
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC_PMAC)
else if (!strncmp(this_opt, "vmode:", 6)) {
int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c
index 0a4e5bad33f4..cac5865d461c 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.c
+++ b/drivers/video/fbdev/matrox/matroxfb_base.c
@@ -1874,7 +1874,7 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
struct fb_var_screeninfo var;
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
-#ifdef CONFIG_NVRAM
+#if defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
diff --git a/drivers/video/fbdev/valkyriefb.c b/drivers/video/fbdev/valkyriefb.c
index d51c3a8009cb..8022316ee9c9 100644
--- a/drivers/video/fbdev/valkyriefb.c
+++ b/drivers/video/fbdev/valkyriefb.c
@@ -63,14 +63,12 @@
#include "macmodes.h"
#include "valkyriefb.h"

-#ifdef CONFIG_MAC
-/* We don't yet have functions to read the PRAM... perhaps we can
- adapt them from the PPC code? */
-static int default_vmode = VMODE_CHOOSE;
-static int default_cmode = CMODE_8;
-#else
+#ifdef CONFIG_PPC_PMAC
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
+#else
+static int default_vmode = VMODE_CHOOSE;
+static int default_cmode = CMODE_8;
#endif

struct fb_par_valkyrie {
@@ -283,7 +281,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);

/* Try to pick a video mode out of NVRAM if we have one. */
-#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_vmode == VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0
@@ -296,7 +294,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
default_vmode = mac_map_monitor_sense(p->sense);
if (!valkyrie_reg_init[default_vmode - 1])
default_vmode = VMODE_640_480_67;
-#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
--
2.19.2


2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 02/25] m68k/atari: Move Atari-specific code out of drivers/char/nvram.c

Move the m68k-specific code out of the driver to make the driver generic.

I've used 'SPDX-License-Identifier: GPL-2.0+' for the new file because the
old file is covered by MODULE_LICENSE("GPL").

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Christian T. Steigies <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
---
Changed since v7:
- Added SPDX-License-Identifier.
---
arch/m68k/atari/Makefile | 2 +
arch/m68k/atari/nvram.c | 243 +++++++++++++++++++++++++++++++++
drivers/char/nvram.c | 280 +++++----------------------------------
3 files changed, 280 insertions(+), 245 deletions(-)
create mode 100644 arch/m68k/atari/nvram.c

diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 0cac723306f9..0b86bb6cfa87 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -6,3 +6,5 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \
atasound.o stram.o

obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
+
+obj-$(CONFIG_NVRAM:m=y) += nvram.o
diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
new file mode 100644
index 000000000000..3e620ee955ba
--- /dev/null
+++ b/arch/m68k/atari/nvram.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CMOS/NV-RAM driver for Atari. Adapted from drivers/char/nvram.c.
+ * Copyright (C) 1997 Roman Hodek <[email protected]>
+ * idea by and with help from Richard Jelinek <[email protected]>
+ * Portions copyright (c) 2001,2002 Sun Microsystems ([email protected])
+ * Further contributions from Cesar Barros, Erik Gilling, Tim Hockin and
+ * Wim Van Sebroeck.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/nvram.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+
+#define NVRAM_BYTES 50
+
+/* It is worth noting that these functions all access bytes of general
+ * purpose memory in the NVRAM - that is to say, they all add the
+ * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not
+ * know about the RTC cruft.
+ */
+
+/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
+ * rtc_lock held. Due to the index-port/data-port design of the RTC, we
+ * don't want two different things trying to get to it at once. (e.g. the
+ * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
+ */
+
+unsigned char __nvram_read_byte(int i)
+{
+ return CMOS_READ(NVRAM_FIRST_BYTE + i);
+}
+
+unsigned char nvram_read_byte(int i)
+{
+ unsigned long flags;
+ unsigned char c;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ c = __nvram_read_byte(i);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return c;
+}
+EXPORT_SYMBOL(nvram_read_byte);
+
+/* This races nicely with trying to read with checksum checking */
+void __nvram_write_byte(unsigned char c, int i)
+{
+ CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
+}
+
+void nvram_write_byte(unsigned char c, int i)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ __nvram_write_byte(c, i);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+}
+
+/* On Ataris, the checksum is over all bytes except the checksum bytes
+ * themselves; these are at the very end.
+ */
+#define ATARI_CKS_RANGE_START 0
+#define ATARI_CKS_RANGE_END 47
+#define ATARI_CKS_LOC 48
+
+int __nvram_check_checksum(void)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+ return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
+ (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
+}
+
+int nvram_check_checksum(void)
+{
+ unsigned long flags;
+ int rv;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ rv = __nvram_check_checksum();
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return rv;
+}
+EXPORT_SYMBOL(nvram_check_checksum);
+
+static void __nvram_set_checksum(void)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+ __nvram_write_byte(~sum, ATARI_CKS_LOC);
+ __nvram_write_byte(sum, ATARI_CKS_LOC + 1);
+}
+
+#ifdef CONFIG_PROC_FS
+static struct {
+ unsigned char val;
+ const char *name;
+} boot_prefs[] = {
+ { 0x80, "TOS" },
+ { 0x40, "ASV" },
+ { 0x20, "NetBSD (?)" },
+ { 0x10, "Linux" },
+ { 0x00, "unspecified" },
+};
+
+static const char * const languages[] = {
+ "English (US)",
+ "German",
+ "French",
+ "English (UK)",
+ "Spanish",
+ "Italian",
+ "6 (undefined)",
+ "Swiss (French)",
+ "Swiss (German)",
+};
+
+static const char * const dateformat[] = {
+ "MM%cDD%cYY",
+ "DD%cMM%cYY",
+ "YY%cMM%cDD",
+ "YY%cDD%cMM",
+ "4 (undefined)",
+ "5 (undefined)",
+ "6 (undefined)",
+ "7 (undefined)",
+};
+
+static const char * const colors[] = {
+ "2", "4", "16", "256", "65536", "??", "??", "??"
+};
+
+static void atari_nvram_proc_read(unsigned char *nvram, struct seq_file *seq,
+ void *offset)
+{
+ int checksum;
+ int i;
+ unsigned int vmode;
+
+ spin_lock_irq(&rtc_lock);
+ checksum = __nvram_check_checksum();
+ spin_unlock_irq(&rtc_lock);
+
+ seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not ");
+
+ seq_puts(seq, "Boot preference : ");
+ for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i)
+ if (nvram[1] == boot_prefs[i].val) {
+ seq_printf(seq, "%s\n", boot_prefs[i].name);
+ break;
+ }
+ if (i < 0)
+ seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
+
+ seq_printf(seq, "SCSI arbitration : %s\n",
+ (nvram[16] & 0x80) ? "on" : "off");
+ seq_puts(seq, "SCSI host ID : ");
+ if (nvram[16] & 0x80)
+ seq_printf(seq, "%d\n", nvram[16] & 7);
+ else
+ seq_puts(seq, "n/a\n");
+
+ if (!MACH_IS_FALCON)
+ return;
+
+ seq_puts(seq, "OS language : ");
+ if (nvram[6] < ARRAY_SIZE(languages))
+ seq_printf(seq, "%s\n", languages[nvram[6]]);
+ else
+ seq_printf(seq, "%u (undefined)\n", nvram[6]);
+ seq_puts(seq, "Keyboard language: ");
+ if (nvram[7] < ARRAY_SIZE(languages))
+ seq_printf(seq, "%s\n", languages[nvram[7]]);
+ else
+ seq_printf(seq, "%u (undefined)\n", nvram[7]);
+ seq_puts(seq, "Date format : ");
+ seq_printf(seq, dateformat[nvram[8] & 7],
+ nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
+ seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
+ seq_puts(seq, "Boot delay : ");
+ if (nvram[10] == 0)
+ seq_puts(seq, "default");
+ else
+ seq_printf(seq, "%ds%s\n", nvram[10],
+ nvram[10] < 8 ? ", no memory test" : "");
+
+ vmode = (nvram[14] << 8) | nvram[15];
+ seq_printf(seq,
+ "Video mode : %s colors, %d columns, %s %s monitor\n",
+ colors[vmode & 7], vmode & 8 ? 80 : 40,
+ vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
+ seq_printf(seq,
+ " %soverscan, compat. mode %s%s\n",
+ vmode & 64 ? "" : "no ", vmode & 128 ? "on" : "off",
+ vmode & 256 ?
+ (vmode & 16 ? ", line doubling" : ", half screen") : "");
+}
+
+static int nvram_proc_read(struct seq_file *seq, void *offset)
+{
+ unsigned char contents[NVRAM_BYTES];
+ int i;
+
+ spin_lock_irq(&rtc_lock);
+ for (i = 0; i < NVRAM_BYTES; ++i)
+ contents[i] = __nvram_read_byte(i);
+ spin_unlock_irq(&rtc_lock);
+
+ atari_nvram_proc_read(contents, seq, offset);
+
+ return 0;
+}
+
+static int __init atari_nvram_init(void)
+{
+ if (!(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)))
+ return -ENODEV;
+
+ if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
+ pr_err("nvram: can't create /proc/driver/nvram\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+device_initcall(atari_nvram_init);
+#endif /* CONFIG_PROC_FS */
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 25264d65e716..a9d4652f9e90 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -21,13 +21,6 @@
* ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
* again; use with care!)
*
- * This file also provides some functions for other parts of the kernel that
- * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
- * Obviously this can be used only if this driver is always configured into
- * the kernel and is not a module. Since the functions are used by some Atari
- * drivers, this is the case on the Atari.
- *
- *
* 1.1 Cesar Barros: SMP locking fixes
* added changelog
* 1.2 Erik Gilling: Cobalt Networks support
@@ -39,64 +32,6 @@

#include <linux/module.h>
#include <linux/nvram.h>
-
-#define PC 1
-#define ATARI 2
-
-/* select machine configuration */
-#if defined(CONFIG_ATARI)
-# define MACH ATARI
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and ?? */
-# define MACH PC
-#else
-# error Cannot build nvram driver for this machine configuration.
-#endif
-
-#if MACH == PC
-
-/* RTC in a PC */
-#define CHECK_DRIVER_INIT() 1
-
-/* On PCs, the checksum is built only over bytes 2..31 */
-#define PC_CKS_RANGE_START 2
-#define PC_CKS_RANGE_END 31
-#define PC_CKS_LOC 32
-#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
-
-#define mach_check_checksum pc_check_checksum
-#define mach_set_checksum pc_set_checksum
-#define mach_proc_infos pc_proc_infos
-
-#endif
-
-#if MACH == ATARI
-
-/* Special parameters for RTC in Atari machines */
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#define RTC_PORT(x) (TT_RTC_BAS + 2*(x))
-#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
-
-#define NVRAM_BYTES 50
-
-/* On Ataris, the checksum is over all bytes except the checksum bytes
- * themselves; these are at the very end */
-#define ATARI_CKS_RANGE_START 0
-#define ATARI_CKS_RANGE_END 47
-#define ATARI_CKS_LOC 48
-
-#define mach_check_checksum atari_check_checksum
-#define mach_set_checksum atari_set_checksum
-#define mach_proc_infos atari_proc_infos
-
-#endif
-
-/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
- * rtc_lock held. Due to the index-port/data-port design of the RTC, we
- * don't want two different things trying to get to it at once. (e.g. the
- * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
- */
-
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -120,12 +55,9 @@ static int nvram_open_mode; /* special open modes */
#define NVRAM_WRITE 1 /* opened for writing (exclusive) */
#define NVRAM_EXCL 2 /* opened with O_EXCL */

-static int mach_check_checksum(void);
-static void mach_set_checksum(void);
-
#ifdef CONFIG_PROC_FS
-static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
- void *offset);
+static void pc_nvram_proc_read(unsigned char *contents, struct seq_file *seq,
+ void *offset);
#endif

/*
@@ -139,6 +71,14 @@ static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
* know about the RTC cruft.
*/

+#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE)
+
+/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
+ * rtc_lock held. Due to the index-port/data-port design of the RTC, we
+ * don't want two different things trying to get to it at once. (e.g. the
+ * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
+ */
+
unsigned char __nvram_read_byte(int i)
{
return CMOS_READ(NVRAM_FIRST_BYTE + i);
@@ -174,9 +114,22 @@ void nvram_write_byte(unsigned char c, int i)
}
EXPORT_SYMBOL(nvram_write_byte);

+/* On PCs, the checksum is built only over bytes 2..31 */
+#define PC_CKS_RANGE_START 2
+#define PC_CKS_RANGE_END 31
+#define PC_CKS_LOC 32
+
int __nvram_check_checksum(void)
{
- return mach_check_checksum();
+ int i;
+ unsigned short sum = 0;
+ unsigned short expect;
+
+ for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+ expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
+ __nvram_read_byte(PC_CKS_LOC+1);
+ return (sum & 0xffff) == expect;
}
EXPORT_SYMBOL(__nvram_check_checksum);

@@ -194,7 +147,13 @@ EXPORT_SYMBOL(nvram_check_checksum);

static void __nvram_set_checksum(void)
{
- mach_set_checksum();
+ int i;
+ unsigned short sum = 0;
+
+ for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+ __nvram_write_byte(sum >> 8, PC_CKS_LOC);
+ __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
}

#if 0
@@ -384,7 +343,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset)
contents[i] = __nvram_read_byte(i);
spin_unlock_irq(&rtc_lock);

- mach_proc_infos(contents, seq, offset);
+ pc_nvram_proc_read(contents, seq, offset);

return 0;
}
@@ -418,10 +377,6 @@ static int __init nvram_init(void)
{
int ret;

- /* First test whether the driver should init at all */
- if (!CHECK_DRIVER_INIT())
- return -ENODEV;
-
ret = misc_register(&nvram_dev);
if (ret) {
printk(KERN_ERR "nvram: can't misc_register on minor=%d\n",
@@ -451,36 +406,6 @@ static void __exit nvram_cleanup_module(void)
module_init(nvram_init);
module_exit(nvram_cleanup_module);

-/*
- * Machine specific functions
- */
-
-#if MACH == PC
-
-static int pc_check_checksum(void)
-{
- int i;
- unsigned short sum = 0;
- unsigned short expect;
-
- for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
- sum += __nvram_read_byte(i);
- expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
- __nvram_read_byte(PC_CKS_LOC+1);
- return (sum & 0xffff) == expect;
-}
-
-static void pc_set_checksum(void)
-{
- int i;
- unsigned short sum = 0;
-
- for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
- sum += __nvram_read_byte(i);
- __nvram_write_byte(sum >> 8, PC_CKS_LOC);
- __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
-}
-
#ifdef CONFIG_PROC_FS

static const char * const floppy_types[] = {
@@ -495,8 +420,8 @@ static const char * const gfx_types[] = {
"monochrome",
};

-static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq,
- void *offset)
+static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq,
+ void *offset)
{
int checksum;
int type;
@@ -557,143 +482,8 @@ static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq,

return;
}
-#endif
-
-#endif /* MACH == PC */
-
-#if MACH == ATARI
-
-static int atari_check_checksum(void)
-{
- int i;
- unsigned char sum = 0;
-
- for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
- sum += __nvram_read_byte(i);
- return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
- (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
-}
-
-static void atari_set_checksum(void)
-{
- int i;
- unsigned char sum = 0;
-
- for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
- sum += __nvram_read_byte(i);
- __nvram_write_byte(~sum, ATARI_CKS_LOC);
- __nvram_write_byte(sum, ATARI_CKS_LOC + 1);
-}
-
-#ifdef CONFIG_PROC_FS
-
-static struct {
- unsigned char val;
- const char *name;
-} boot_prefs[] = {
- { 0x80, "TOS" },
- { 0x40, "ASV" },
- { 0x20, "NetBSD (?)" },
- { 0x10, "Linux" },
- { 0x00, "unspecified" }
-};
-
-static const char * const languages[] = {
- "English (US)",
- "German",
- "French",
- "English (UK)",
- "Spanish",
- "Italian",
- "6 (undefined)",
- "Swiss (French)",
- "Swiss (German)"
-};
-
-static const char * const dateformat[] = {
- "MM%cDD%cYY",
- "DD%cMM%cYY",
- "YY%cMM%cDD",
- "YY%cDD%cMM",
- "4 (undefined)",
- "5 (undefined)",
- "6 (undefined)",
- "7 (undefined)"
-};
-
-static const char * const colors[] = {
- "2", "4", "16", "256", "65536", "??", "??", "??"
-};
-
-static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq,
- void *offset)
-{
- int checksum = nvram_check_checksum();
- int i;
- unsigned vmode;
-
- seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not ");
-
- seq_printf(seq, "Boot preference : ");
- for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) {
- if (nvram[1] == boot_prefs[i].val) {
- seq_printf(seq, "%s\n", boot_prefs[i].name);
- break;
- }
- }
- if (i < 0)
- seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
-
- seq_printf(seq, "SCSI arbitration : %s\n",
- (nvram[16] & 0x80) ? "on" : "off");
- seq_printf(seq, "SCSI host ID : ");
- if (nvram[16] & 0x80)
- seq_printf(seq, "%d\n", nvram[16] & 7);
- else
- seq_printf(seq, "n/a\n");
-
- /* the following entries are defined only for the Falcon */
- if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
- return;
-
- seq_printf(seq, "OS language : ");
- if (nvram[6] < ARRAY_SIZE(languages))
- seq_printf(seq, "%s\n", languages[nvram[6]]);
- else
- seq_printf(seq, "%u (undefined)\n", nvram[6]);
- seq_printf(seq, "Keyboard language: ");
- if (nvram[7] < ARRAY_SIZE(languages))
- seq_printf(seq, "%s\n", languages[nvram[7]]);
- else
- seq_printf(seq, "%u (undefined)\n", nvram[7]);
- seq_printf(seq, "Date format : ");
- seq_printf(seq, dateformat[nvram[8] & 7],
- nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
- seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
- seq_printf(seq, "Boot delay : ");
- if (nvram[10] == 0)
- seq_printf(seq, "default");
- else
- seq_printf(seq, "%ds%s\n", nvram[10],
- nvram[10] < 8 ? ", no memory test" : "");
-
- vmode = (nvram[14] << 8) | nvram[15];
- seq_printf(seq,
- "Video mode : %s colors, %d columns, %s %s monitor\n",
- colors[vmode & 7],
- vmode & 8 ? 80 : 40,
- vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
- seq_printf(seq, " %soverscan, compat. mode %s%s\n",
- vmode & 64 ? "" : "no ",
- vmode & 128 ? "on" : "off",
- vmode & 256 ?
- (vmode & 16 ? ", line doubling" : ", half screen") : "");
-
- return;
-}
-#endif

-#endif /* MACH == ATARI */
+#endif /* CONFIG_PROC_FS */

MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
--
2.19.2


2018-12-26 00:46:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

Make use of arch_nvram_ops in device drivers so that the nvram_* function
exports can be removed.

Since they are no longer global symbols, rename the PPC32 nvram_* functions
appropriately.

Signed-off-by: Finn Thain <[email protected]>
---
arch/powerpc/kernel/setup_32.c | 8 ++++----
drivers/char/generic_nvram.c | 4 ++--
drivers/video/fbdev/controlfb.c | 4 ++--
drivers/video/fbdev/imsttfb.c | 4 ++--
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
drivers/video/fbdev/platinumfb.c | 4 ++--
drivers/video/fbdev/valkyriefb.c | 4 ++--
7 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index e0d045677472..bdbe6acbef11 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -152,20 +152,18 @@ __setup("l3cr=", ppc_setup_l3cr);

#ifdef CONFIG_GENERIC_NVRAM

-unsigned char nvram_read_byte(int addr)
+static unsigned char ppc_nvram_read_byte(int addr)
{
if (ppc_md.nvram_read_val)
return ppc_md.nvram_read_val(addr);
return 0xff;
}
-EXPORT_SYMBOL(nvram_read_byte);

-void nvram_write_byte(unsigned char val, int addr)
+static void ppc_nvram_write_byte(unsigned char val, int addr)
{
if (ppc_md.nvram_write_val)
ppc_md.nvram_write_val(addr, val);
}
-EXPORT_SYMBOL(nvram_write_byte);

static ssize_t ppc_nvram_get_size(void)
{
@@ -182,6 +180,8 @@ static long ppc_nvram_sync(void)
}

const struct nvram_ops arch_nvram_ops = {
+ .read_byte = ppc_nvram_read_byte,
+ .write_byte = ppc_nvram_write_byte,
.get_size = ppc_nvram_get_size,
.sync = ppc_nvram_sync,
};
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index f32d5663de95..41b76bf9614e 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -48,7 +48,7 @@ static ssize_t read_nvram(struct file *file, char __user *buf,
if (*ppos >= nvram_len)
return 0;
for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
- if (__put_user(nvram_read_byte(i), p))
+ if (__put_user(arch_nvram_ops.read_byte(i), p))
return -EFAULT;
*ppos = i;
return p - buf;
@@ -68,7 +68,7 @@ static ssize_t write_nvram(struct file *file, const char __user *buf,
for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
if (__get_user(c, p))
return -EFAULT;
- nvram_write_byte(c, i);
+ arch_nvram_ops.write_byte(c, i);
}
*ppos = i;
return p - buf;
diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c
index 9cb0ef7ac29e..27ff33ccafcb 100644
--- a/drivers/video/fbdev/controlfb.c
+++ b/drivers/video/fbdev/controlfb.c
@@ -413,7 +413,7 @@ static int __init init_control(struct fb_info_control *p)
/* Try to pick a video mode out of NVRAM if we have one. */
#ifdef CONFIG_NVRAM
if (default_cmode == CMODE_NVRAM) {
- cmode = nvram_read_byte(NV_CMODE);
+ cmode = arch_nvram_ops.read_byte(NV_CMODE);
if(cmode < CMODE_8 || cmode > CMODE_32)
cmode = CMODE_8;
} else
@@ -421,7 +421,7 @@ static int __init init_control(struct fb_info_control *p)
cmode=default_cmode;
#ifdef CONFIG_NVRAM
if (default_vmode == VMODE_NVRAM) {
- vmode = nvram_read_byte(NV_VMODE);
+ vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (vmode < 1 || vmode > VMODE_MAX ||
control_mac_modes[vmode - 1].m[full] < cmode) {
sense = read_control_sense(p);
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 8d231591ff0e..e9f3b8914145 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1393,12 +1393,12 @@ static void init_imstt(struct fb_info *info)
int vmode = init_vmode, cmode = init_cmode;

if (vmode == -1) {
- vmode = nvram_read_byte(NV_VMODE);
+ vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (vmode <= 0 || vmode > VMODE_MAX)
vmode = VMODE_640_480_67;
}
if (cmode == -1) {
- cmode = nvram_read_byte(NV_CMODE);
+ cmode = arch_nvram_ops.read_byte(NV_CMODE);
if (cmode < CMODE_8 || cmode > CMODE_32)
cmode = CMODE_8;
}
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c
index cac5865d461c..3fecc628752c 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.c
+++ b/drivers/video/fbdev/matrox/matroxfb_base.c
@@ -1876,7 +1876,7 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
default_vmode = VMODE_640_480_60;
#if defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
if (default_cmode == CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c
index bf6b7fb83cf4..3efceaf38f98 100644
--- a/drivers/video/fbdev/platinumfb.c
+++ b/drivers/video/fbdev/platinumfb.c
@@ -347,7 +347,7 @@ static int platinum_init_fb(struct fb_info *info)
printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
if (default_vmode == VMODE_NVRAM) {
#ifdef CONFIG_NVRAM
- default_vmode = nvram_read_byte(NV_VMODE);
+ default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
!platinum_reg_init[default_vmode-1])
#endif
@@ -360,7 +360,7 @@ static int platinum_init_fb(struct fb_info *info)
default_vmode = VMODE_640_480_60;
#ifdef CONFIG_NVRAM
if (default_cmode == CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
diff --git a/drivers/video/fbdev/valkyriefb.c b/drivers/video/fbdev/valkyriefb.c
index 8022316ee9c9..81f66d69d9dd 100644
--- a/drivers/video/fbdev/valkyriefb.c
+++ b/drivers/video/fbdev/valkyriefb.c
@@ -283,7 +283,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
/* Try to pick a video mode out of NVRAM if we have one. */
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_vmode == VMODE_NVRAM) {
- default_vmode = nvram_read_byte(NV_VMODE);
+ default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
if (default_vmode <= 0
|| default_vmode > VMODE_MAX
|| !valkyrie_reg_init[default_vmode - 1])
@@ -296,7 +296,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
default_vmode = VMODE_640_480_67;
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
if (default_cmode == CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
+ default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
#endif

/*
--
2.19.2


2018-12-26 00:46:58

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

A multi-platform kernel binary has to decide at run-time how to dispatch
the arch_nvram_ops calls. Add a platform-independent arch_nvram_ops
struct for this, to replace the atari-specific one.

Enable CONFIG_HAVE_ARCH_NVRAM_OPS for Macs.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Christian T. Steigies <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/m68k/Kconfig.machine | 1 +
arch/m68k/atari/nvram.c | 21 ++-----
arch/m68k/include/asm/atarihw.h | 6 ++
arch/m68k/include/asm/macintosh.h | 4 ++
arch/m68k/kernel/setup_mm.c | 100 +++++++++++++++++++++++++++++-
arch/m68k/mac/misc.c | 11 ++++
6 files changed, 126 insertions(+), 17 deletions(-)

diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine
index 0c8c4c7982c1..da21783136c7 100644
--- a/arch/m68k/Kconfig.machine
+++ b/arch/m68k/Kconfig.machine
@@ -27,6 +27,7 @@ config MAC
bool "Macintosh support"
depends on MMU
select MMU_MOTOROLA if MMU
+ select HAVE_ARCH_NVRAM_OPS
help
This option enables support for the Apple Macintosh series of
computers (yes, there is experimental support now, at least for part
diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
index 4b27f1683a37..0a6fe59c95e8 100644
--- a/arch/m68k/atari/nvram.c
+++ b/arch/m68k/atari/nvram.c
@@ -74,7 +74,7 @@ static void __nvram_set_checksum(void)
__nvram_write_byte(sum, ATARI_CKS_LOC + 1);
}

-static long nvram_set_checksum(void)
+long atari_nvram_set_checksum(void)
{
spin_lock_irq(&rtc_lock);
__nvram_set_checksum();
@@ -82,7 +82,7 @@ static long nvram_set_checksum(void)
return 0;
}

-static long nvram_initialize(void)
+long atari_nvram_initialize(void)
{
loff_t i;

@@ -94,7 +94,7 @@ static long nvram_initialize(void)
return 0;
}

-static ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
+ssize_t atari_nvram_read(char *buf, size_t count, loff_t *ppos)
{
char *p = buf;
loff_t i;
@@ -115,7 +115,7 @@ static ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
return p - buf;
}

-static ssize_t nvram_write(char *buf, size_t count, loff_t *ppos)
+ssize_t atari_nvram_write(char *buf, size_t count, loff_t *ppos)
{
char *p = buf;
loff_t i;
@@ -138,22 +138,11 @@ static ssize_t nvram_write(char *buf, size_t count, loff_t *ppos)
return p - buf;
}

-static ssize_t nvram_get_size(void)
+ssize_t atari_nvram_get_size(void)
{
- if (!MACH_IS_ATARI)
- return -ENODEV;
return NVRAM_BYTES;
}

-const struct nvram_ops arch_nvram_ops = {
- .read = nvram_read,
- .write = nvram_write,
- .get_size = nvram_get_size,
- .set_checksum = nvram_set_checksum,
- .initialize = nvram_initialize,
-};
-EXPORT_SYMBOL(arch_nvram_ops);
-
#ifdef CONFIG_PROC_FS
static struct {
unsigned char val;
diff --git a/arch/m68k/include/asm/atarihw.h b/arch/m68k/include/asm/atarihw.h
index 9000b249d225..533008262b69 100644
--- a/arch/m68k/include/asm/atarihw.h
+++ b/arch/m68k/include/asm/atarihw.h
@@ -33,6 +33,12 @@ extern int atari_dont_touch_floppy_select;

extern int atari_SCC_reset_done;

+extern ssize_t atari_nvram_read(char *, size_t, loff_t *);
+extern ssize_t atari_nvram_write(char *, size_t, loff_t *);
+extern ssize_t atari_nvram_get_size(void);
+extern long atari_nvram_set_checksum(void);
+extern long atari_nvram_initialize(void);
+
/* convenience macros for testing machine type */
#define MACH_IS_ST ((atari_mch_cookie >> 16) == ATARI_MCH_ST)
#define MACH_IS_STE ((atari_mch_cookie >> 16) == ATARI_MCH_STE && \
diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h
index 08cee11180e6..d9a08bed4b12 100644
--- a/arch/m68k/include/asm/macintosh.h
+++ b/arch/m68k/include/asm/macintosh.h
@@ -19,6 +19,10 @@ extern void mac_init_IRQ(void);
extern void mac_irq_enable(struct irq_data *data);
extern void mac_irq_disable(struct irq_data *data);

+extern unsigned char mac_pram_read_byte(int);
+extern void mac_pram_write_byte(unsigned char, int);
+extern ssize_t mac_pram_get_size(void);
+
/*
* Macintosh Table
*/
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index ad0195cbe042..4dd80bb8a283 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -24,6 +24,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/module.h>
+#include <linux/nvram.h>
#include <linux/initrd.h>

#include <asm/bootinfo.h>
@@ -37,13 +38,14 @@
#ifdef CONFIG_AMIGA
#include <asm/amigahw.h>
#endif
-#ifdef CONFIG_ATARI
#include <asm/atarihw.h>
+#ifdef CONFIG_ATARI
#include <asm/atari_stram.h>
#endif
#ifdef CONFIG_SUN3X
#include <asm/dvma.h>
#endif
+#include <asm/macintosh.h>
#include <asm/natfeat.h>

#if !FPSTATESIZE || !NR_IRQS
@@ -547,3 +549,99 @@ static int __init adb_probe_sync_enable (char *str) {

__setup("adb_sync", adb_probe_sync_enable);
#endif /* CONFIG_ADB */
+
+#if IS_ENABLED(CONFIG_NVRAM)
+#ifdef CONFIG_MAC
+static unsigned char m68k_nvram_read_byte(int addr)
+{
+ if (MACH_IS_MAC)
+ return mac_pram_read_byte(addr);
+ return 0xff;
+}
+
+static void m68k_nvram_write_byte(unsigned char val, int addr)
+{
+ if (MACH_IS_MAC)
+ mac_pram_write_byte(val, addr);
+}
+#endif /* CONFIG_MAC */
+
+#ifdef CONFIG_ATARI
+static ssize_t m68k_nvram_read(char *buf, size_t count, loff_t *ppos)
+{
+ if (MACH_IS_ATARI)
+ return atari_nvram_read(buf, count, ppos);
+ else if (MACH_IS_MAC) {
+ ssize_t size = mac_pram_get_size();
+ char *p = buf;
+ loff_t i;
+
+ for (i = *ppos; count > 0 && i < size; --count, ++i, ++p)
+ *p = mac_pram_read_byte(i);
+
+ *ppos = i;
+ return p - buf;
+ }
+ return -EINVAL;
+}
+
+static ssize_t m68k_nvram_write(char *buf, size_t count, loff_t *ppos)
+{
+ if (MACH_IS_ATARI)
+ return atari_nvram_write(buf, count, ppos);
+ else if (MACH_IS_MAC) {
+ ssize_t size = mac_pram_get_size();
+ char *p = buf;
+ loff_t i;
+
+ for (i = *ppos; count > 0 && i < size; --count, ++i, ++p)
+ mac_pram_write_byte(*p, i);
+
+ *ppos = i;
+ return p - buf;
+ }
+ return -EINVAL;
+}
+
+static long m68k_nvram_set_checksum(void)
+{
+ if (MACH_IS_ATARI)
+ return atari_nvram_set_checksum();
+ return -EINVAL;
+}
+
+static long m68k_nvram_initialize(void)
+{
+ if (MACH_IS_ATARI)
+ return atari_nvram_initialize();
+ return -EINVAL;
+}
+#endif /* CONFIG_ATARI */
+
+static ssize_t m68k_nvram_get_size(void)
+{
+ if (MACH_IS_ATARI)
+ return atari_nvram_get_size();
+ else if (MACH_IS_MAC)
+ return mac_pram_get_size();
+ return -ENODEV;
+}
+
+/* Atari device drivers call .read (to get checksum validation) whereas
+ * Mac and PowerMac device drivers just use .read_byte.
+ */
+const struct nvram_ops arch_nvram_ops = {
+#ifdef CONFIG_MAC
+ .read_byte = m68k_nvram_read_byte,
+ .write_byte = m68k_nvram_write_byte,
+#endif
+#ifdef CONFIG_ATARI
+ .read = m68k_nvram_read,
+ .write = m68k_nvram_write,
+ .set_checksum = m68k_nvram_set_checksum,
+ .initialize = m68k_nvram_initialize,
+#endif
+ .get_size = m68k_nvram_get_size,
+};
+EXPORT_SYMBOL(arch_nvram_ops);
+#endif /* CONFIG_NVRAM */
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 0009efebb264..b7e6bc037fc4 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -36,6 +36,7 @@

static void (*rom_reset)(void);

+#if IS_ENABLED(CONFIG_NVRAM)
#ifdef CONFIG_ADB_CUDA
static unsigned char cuda_pram_read_byte(int offset)
{
@@ -84,6 +85,7 @@ static void pmu_pram_write_byte(unsigned char data, int offset)
pmu_wait_complete(&req);
}
#endif /* CONFIG_ADB_PMU */
+#endif /* CONFIG_NVRAM */

/*
* VIA PRAM/RTC access routines
@@ -205,6 +207,7 @@ static void via_rtc_command(int command, __u8 *data)
local_irq_restore(flags);
}

+#if IS_ENABLED(CONFIG_NVRAM)
static unsigned char via_pram_read_byte(int offset)
{
unsigned char temp;
@@ -227,6 +230,7 @@ static void via_pram_write_byte(unsigned char data, int offset)
temp = 0x55 | RTC_FLG_WRITE_PROTECT;
via_rtc_command(RTC_CMD_WRITE(RTC_REG_WRITE_PROTECT), &temp);
}
+#endif /* CONFIG_NVRAM */

/*
* Return the current time in seconds since January 1, 1904.
@@ -372,6 +376,7 @@ static void cuda_shutdown(void)
*-------------------------------------------------------------------
*/

+#if IS_ENABLED(CONFIG_NVRAM)
unsigned char mac_pram_read_byte(int addr)
{
switch (macintosh_config->adb_type) {
@@ -417,6 +422,12 @@ void mac_pram_write_byte(unsigned char val, int addr)
}
}

+ssize_t mac_pram_get_size(void)
+{
+ return 256;
+}
+#endif /* CONFIG_NVRAM */
+
void mac_poweroff(void)
{
if (oss_present) {
--
2.19.2


2018-12-26 00:47:40

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 16/25] powerpc: Add missing ppc_md.nvram_size for CHRP and PowerMac

Add the nvram_size() function to those PowerPC platforms that don't already
have one: CHRP and PowerMac. This means that the ppc_md.nvram_size()
function can be used to implement arch_nvram_ops.get_size()

Since we are addressing inconsistencies here, also rename chrp_nvram_read
and chrp_nvram_write, which break the naming convention used across
PowerPC platforms for NVRAM accessor functions.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/powerpc/platforms/chrp/nvram.c | 14 ++++++++++----
arch/powerpc/platforms/powermac/nvram.c | 9 +++++++++
2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c
index 791b86398e1d..6ec2901d2aa4 100644
--- a/arch/powerpc/platforms/chrp/nvram.c
+++ b/arch/powerpc/platforms/chrp/nvram.c
@@ -24,7 +24,7 @@ static unsigned int nvram_size;
static unsigned char nvram_buf[4];
static DEFINE_SPINLOCK(nvram_lock);

-static unsigned char chrp_nvram_read(int addr)
+static unsigned char chrp_nvram_read_byte(int addr)
{
unsigned int done;
unsigned long flags;
@@ -46,7 +46,7 @@ static unsigned char chrp_nvram_read(int addr)
return ret;
}

-static void chrp_nvram_write(int addr, unsigned char val)
+static void chrp_nvram_write_byte(int addr, unsigned char val)
{
unsigned int done;
unsigned long flags;
@@ -64,6 +64,11 @@ static void chrp_nvram_write(int addr, unsigned char val)
spin_unlock_irqrestore(&nvram_lock, flags);
}

+static ssize_t chrp_nvram_size(void)
+{
+ return nvram_size;
+}
+
void __init chrp_nvram_init(void)
{
struct device_node *nvram;
@@ -85,8 +90,9 @@ void __init chrp_nvram_init(void)
printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size);
of_node_put(nvram);

- ppc_md.nvram_read_val = chrp_nvram_read;
- ppc_md.nvram_write_val = chrp_nvram_write;
+ ppc_md.nvram_read_val = chrp_nvram_read_byte;
+ ppc_md.nvram_write_val = chrp_nvram_write_byte;
+ ppc_md.nvram_size = chrp_nvram_size;

return;
}
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index ae54d7fe68f3..9360cdc408c1 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -147,6 +147,11 @@ static ssize_t core99_nvram_size(void)
static volatile unsigned char __iomem *nvram_addr;
static int nvram_mult;

+static ssize_t ppc32_nvram_size(void)
+{
+ return NVRAM_SIZE;
+}
+
static unsigned char direct_nvram_read_byte(int addr)
{
return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
@@ -590,21 +595,25 @@ int __init pmac_nvram_init(void)
nvram_mult = 1;
ppc_md.nvram_read_val = direct_nvram_read_byte;
ppc_md.nvram_write_val = direct_nvram_write_byte;
+ ppc_md.nvram_size = ppc32_nvram_size;
} else if (nvram_naddrs == 1) {
nvram_data = ioremap(r1.start, s1);
nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE;
ppc_md.nvram_read_val = direct_nvram_read_byte;
ppc_md.nvram_write_val = direct_nvram_write_byte;
+ ppc_md.nvram_size = ppc32_nvram_size;
} else if (nvram_naddrs == 2) {
nvram_addr = ioremap(r1.start, s1);
nvram_data = ioremap(r2.start, s2);
ppc_md.nvram_read_val = indirect_nvram_read_byte;
ppc_md.nvram_write_val = indirect_nvram_write_byte;
+ ppc_md.nvram_size = ppc32_nvram_size;
} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
#ifdef CONFIG_ADB_PMU
nvram_naddrs = -1;
ppc_md.nvram_read_val = pmu_nvram_read_byte;
ppc_md.nvram_write_val = pmu_nvram_write_byte;
+ ppc_md.nvram_size = ppc32_nvram_size;
#endif /* CONFIG_ADB_PMU */
} else {
printk(KERN_ERR "Incompatible type of NVRAM\n");
--
2.19.2


2018-12-26 00:47:42

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 17/25] powerpc: Implement arch_nvram_ops.get_size() and remove old nvram_* exports

Implement arch_nvram_ops for PPC32 and make use of it in the generic_nvram
misc device module so that the nvram_* function exports can be removed.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 10 +++++++---
drivers/char/generic_nvram.c | 24 ++++++++++++------------
3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 1443b40f44b9..56a388da9c4f 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -98,7 +98,4 @@ extern int nvram_write_os_partition(struct nvram_os_partition *part,
unsigned int err_type,
unsigned int error_log_cnt);

-/* Determine NVRAM size */
-extern ssize_t nvram_get_size(void);
-
#endif /* _ASM_POWERPC_NVRAM_H */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 04c0315cfe46..ee91bba0805d 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -168,13 +168,12 @@ void nvram_write_byte(unsigned char val, int addr)
}
EXPORT_SYMBOL(nvram_write_byte);

-ssize_t nvram_get_size(void)
+static ssize_t ppc_nvram_get_size(void)
{
if (ppc_md.nvram_size)
return ppc_md.nvram_size();
- return -1;
+ return -ENODEV;
}
-EXPORT_SYMBOL(nvram_get_size);

void nvram_sync(void)
{
@@ -183,6 +182,11 @@ void nvram_sync(void)
}
EXPORT_SYMBOL(nvram_sync);

+const struct nvram_ops arch_nvram_ops = {
+ .get_size = ppc_nvram_get_size,
+};
+EXPORT_SYMBOL(arch_nvram_ops);
+
#endif /* CONFIG_NVRAM */

static int __init ppc_init(void)
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 0381af638fe3..a7dfde734897 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -28,8 +28,6 @@
#include <asm/machdep.h>
#endif

-#define NVRAM_SIZE 8192
-
static DEFINE_MUTEX(nvram_mutex);
static ssize_t nvram_len;

@@ -134,20 +132,22 @@ static struct miscdevice nvram_dev = {

int __init nvram_init(void)
{
- int ret = 0;
+ int ret;

- printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
- NVRAM_VERSION);
- ret = misc_register(&nvram_dev);
- if (ret != 0)
- goto out;
+ if (arch_nvram_ops.get_size == NULL)
+ return -ENODEV;

- nvram_len = nvram_get_size();
+ nvram_len = arch_nvram_ops.get_size();
if (nvram_len < 0)
- nvram_len = NVRAM_SIZE;
+ return nvram_len;

-out:
- return ret;
+ ret = misc_register(&nvram_dev);
+ if (ret)
+ return ret;
+
+ pr_info("Generic non-volatile memory driver v%s\n", NVRAM_VERSION);
+
+ return 0;
}

void __exit nvram_cleanup(void)
--
2.19.2


2018-12-26 00:47:50

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 06/25] x86/thinkpad_acpi: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

Make use of arch_nvram_ops in the thinkpad_acpi driver so that the
nvram_* function exports can be removed.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Henrique de Moraes Holschuh <[email protected]>
Reviewed-by: Darren Hart <[email protected]>
---
I've tested this on a ThinkPad T43.
---
drivers/platform/x86/thinkpad_acpi.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index fde08a997557..fbbf7b452e51 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2435,30 +2435,30 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m)
u8 d;

if (m & TP_NVRAM_HKEY_GROUP_HK2) {
- d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
+ d = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_HK2);
n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
}
if (m & TP_ACPI_HKEY_KBD_LIGHT_MASK) {
- d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
+ d = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_THINKLIGHT);
n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
}
if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
- d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
+ d = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_VIDEO);
n->displayexp_toggle =
!!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
}
if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
- d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
+ d = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
n->brightness_toggle =
!!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
}
if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
- d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
+ d = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_MIXER);
n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
>> TP_NVRAM_POS_LEVEL_VOLUME;
n->mute = !!(d & TP_NVRAM_MASK_MUTE);
@@ -6605,7 +6605,7 @@ static unsigned int tpacpi_brightness_nvram_get(void)
{
u8 lnvram;

- lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+ lnvram = (arch_nvram_ops.read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
lnvram &= bright_maxlvl;
@@ -6630,7 +6630,7 @@ static void tpacpi_brightness_checkpoint_nvram(void)
if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec)))
goto unlock;
lec &= TP_EC_BACKLIGHT_LVLMSK;
- b_nvram = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
+ b_nvram = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_BRIGHTNESS);

if (lec != ((b_nvram & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS)) {
@@ -6638,7 +6638,7 @@ static void tpacpi_brightness_checkpoint_nvram(void)
b_nvram &= ~(TP_NVRAM_MASK_LEVEL_BRIGHTNESS <<
TP_NVRAM_POS_LEVEL_BRIGHTNESS);
b_nvram |= lec;
- nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS);
+ arch_nvram_ops.write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS);
dbg_printk(TPACPI_DBG_BRGHT,
"updated NVRAM backlight level to %u (0x%02x)\n",
(unsigned int) lec, (unsigned int) b_nvram);
@@ -7236,13 +7236,13 @@ static void tpacpi_volume_checkpoint_nvram(void)
if (unlikely(!acpi_ec_read(TP_EC_AUDIO, &lec)))
goto unlock;
lec &= ec_mask;
- b_nvram = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
+ b_nvram = arch_nvram_ops.read_byte(TP_NVRAM_ADDR_MIXER);

if (lec != (b_nvram & ec_mask)) {
/* NVRAM needs update */
b_nvram &= ~ec_mask;
b_nvram |= lec;
- nvram_write_byte(b_nvram, TP_NVRAM_ADDR_MIXER);
+ arch_nvram_ops.write_byte(b_nvram, TP_NVRAM_ADDR_MIXER);
dbg_printk(TPACPI_DBG_MIXER,
"updated NVRAM mixer status to 0x%02x (0x%02x)\n",
(unsigned int) lec, (unsigned int) b_nvram);
--
2.19.2


2018-12-26 00:47:51

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 10/25] m68k/mac: Adopt naming and calling conventions for PRAM routines

Adopt the existing *_read_byte and *_write_byte naming convention.
Rename via_pram_readbyte and via_pram_writebyte to avoid confusion.
Adjust calling conventions of mac_pram_* functions to match the
arch_nvram_ops struct methods.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
Changed since v7:
- Removed some gratuitous function pointers.
---
arch/m68k/mac/misc.c | 61 +++++++++++++++++---------------------------
1 file changed, 23 insertions(+), 38 deletions(-)

diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index ebb3b6d169ea..9f6849deecea 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -37,7 +37,7 @@
static void (*rom_reset)(void);

#ifdef CONFIG_ADB_CUDA
-static __u8 cuda_read_pram(int offset)
+static unsigned char cuda_pram_read_byte(int offset)
{
struct adb_request req;

@@ -49,7 +49,7 @@ static __u8 cuda_read_pram(int offset)
return req.reply[3];
}

-static void cuda_write_pram(int offset, __u8 data)
+static void cuda_pram_write_byte(unsigned char data, int offset)
{
struct adb_request req;

@@ -62,7 +62,7 @@ static void cuda_write_pram(int offset, __u8 data)
#endif /* CONFIG_ADB_CUDA */

#ifdef CONFIG_ADB_PMU
-static __u8 pmu_read_pram(int offset)
+static unsigned char pmu_pram_read_byte(int offset)
{
struct adb_request req;

@@ -74,7 +74,7 @@ static __u8 pmu_read_pram(int offset)
return req.reply[3];
}

-static void pmu_write_pram(int offset, __u8 data)
+static void pmu_pram_write_byte(unsigned char data, int offset)
{
struct adb_request req;

@@ -93,7 +93,7 @@ static void pmu_write_pram(int offset, __u8 data)
* the RTC should be enabled.
*/

-static __u8 via_pram_readbyte(void)
+static __u8 via_rtc_recv(void)
{
int i, reg;
__u8 data;
@@ -120,7 +120,7 @@ static __u8 via_pram_readbyte(void)
return data;
}

-static void via_pram_writebyte(__u8 data)
+static void via_rtc_send(__u8 data)
{
int i, reg, bit;

@@ -157,17 +157,17 @@ static void via_pram_command(int command, __u8 *data)
via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;

if (command & 0xFF00) { /* extended (two-byte) command */
- via_pram_writebyte((command & 0xFF00) >> 8);
- via_pram_writebyte(command & 0xFF);
+ via_rtc_send((command & 0xFF00) >> 8);
+ via_rtc_send(command & 0xFF);
is_read = command & 0x8000;
} else { /* one-byte command */
- via_pram_writebyte(command);
+ via_rtc_send(command);
is_read = command & 0x80;
}
if (is_read) {
- *data = via_pram_readbyte();
+ *data = via_rtc_recv();
} else {
- via_pram_writebyte(*data);
+ via_rtc_send(*data);
}

/* All done, disable the RTC */
@@ -177,12 +177,12 @@ static void via_pram_command(int command, __u8 *data)
local_irq_restore(flags);
}

-static __u8 via_read_pram(int offset)
+static unsigned char via_pram_read_byte(int offset)
{
return 0;
}

-static void via_write_pram(int offset, __u8 data)
+static void via_pram_write_byte(unsigned char data, int offset)
{
}

@@ -326,63 +326,48 @@ static void cuda_shutdown(void)
*-------------------------------------------------------------------
*/

-void mac_pram_read(int offset, __u8 *buffer, int len)
+unsigned char mac_pram_read_byte(int addr)
{
- __u8 (*func)(int);
- int i;
-
switch (macintosh_config->adb_type) {
case MAC_ADB_IOP:
case MAC_ADB_II:
case MAC_ADB_PB1:
- func = via_read_pram;
- break;
+ return via_pram_read_byte(addr);
#ifdef CONFIG_ADB_CUDA
case MAC_ADB_EGRET:
case MAC_ADB_CUDA:
- func = cuda_read_pram;
- break;
+ return cuda_pram_read_byte(addr);
#endif
#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
- func = pmu_read_pram;
- break;
+ return pmu_pram_read_byte(addr);
#endif
default:
- return;
- }
- for (i = 0 ; i < len ; i++) {
- buffer[i] = (*func)(offset++);
+ return 0xFF;
}
}

-void mac_pram_write(int offset, __u8 *buffer, int len)
+void mac_pram_write_byte(unsigned char val, int addr)
{
- void (*func)(int, __u8);
- int i;
-
switch (macintosh_config->adb_type) {
case MAC_ADB_IOP:
case MAC_ADB_II:
case MAC_ADB_PB1:
- func = via_write_pram;
+ via_pram_write_byte(val, addr);
break;
#ifdef CONFIG_ADB_CUDA
case MAC_ADB_EGRET:
case MAC_ADB_CUDA:
- func = cuda_write_pram;
+ cuda_pram_write_byte(val, addr);
break;
#endif
#ifdef CONFIG_ADB_PMU
case MAC_ADB_PB2:
- func = pmu_write_pram;
+ pmu_pram_write_byte(val, addr);
break;
#endif
default:
- return;
- }
- for (i = 0 ; i < len ; i++) {
- (*func)(offset++, buffer[i]);
+ break;
}
}

--
2.19.2


2018-12-26 00:48:03

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 14/25] char/nvram: Add "devname:nvram" module alias

Signed-off-by: Finn Thain <[email protected]>
---
drivers/char/nvram.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 889123ddace4..b77c27d68762 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -554,3 +554,4 @@ module_exit(nvram_module_exit);

MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
+MODULE_ALIAS("devname:nvram");
--
2.19.2


2018-12-26 00:48:34

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 09/25] m68k/atari: Implement arch_nvram_ops methods and enable CONFIG_HAVE_ARCH_NVRAM_OPS

Atari RTC NVRAM has a checksum so implement the remaining arch_nvram_ops
methods for the set_checksum and initialize ioctls. Enable
CONFIG_HAVE_ARCH_NVRAM_OPS.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
---
Changed since v7:
- Changed the default for CONFIG_NVRAM, because "select NVRAM" was
removed from ATARI_SCSI in patch 1.
---
arch/m68k/Kconfig | 3 +++
arch/m68k/Kconfig.machine | 1 +
arch/m68k/atari/nvram.c | 24 ++++++++++++++++++++++++
drivers/char/Kconfig | 3 ++-
4 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 1bc9f1ba759a..79e545f2520a 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -70,6 +70,9 @@ config ZONE_DMA
bool
default y

+config HAVE_ARCH_NVRAM_OPS
+ bool
+
config HZ
int
default 1000 if CLEOPATRA
diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine
index 64a641467736..0c8c4c7982c1 100644
--- a/arch/m68k/Kconfig.machine
+++ b/arch/m68k/Kconfig.machine
@@ -16,6 +16,7 @@ config ATARI
bool "Atari support"
depends on MMU
select MMU_MOTOROLA if MMU
+ select HAVE_ARCH_NVRAM_OPS
help
This option enables support for the 68000-based Atari series of
computers (including the TT, Falcon and Medusa). If you plan to use
diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
index bafc9dc32830..4b27f1683a37 100644
--- a/arch/m68k/atari/nvram.c
+++ b/arch/m68k/atari/nvram.c
@@ -74,6 +74,26 @@ static void __nvram_set_checksum(void)
__nvram_write_byte(sum, ATARI_CKS_LOC + 1);
}

+static long nvram_set_checksum(void)
+{
+ spin_lock_irq(&rtc_lock);
+ __nvram_set_checksum();
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+}
+
+static long nvram_initialize(void)
+{
+ loff_t i;
+
+ spin_lock_irq(&rtc_lock);
+ for (i = 0; i < NVRAM_BYTES; ++i)
+ __nvram_write_byte(0, i);
+ __nvram_set_checksum();
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+}
+
static ssize_t nvram_read(char *buf, size_t count, loff_t *ppos)
{
char *p = buf;
@@ -120,6 +140,8 @@ static ssize_t nvram_write(char *buf, size_t count, loff_t *ppos)

static ssize_t nvram_get_size(void)
{
+ if (!MACH_IS_ATARI)
+ return -ENODEV;
return NVRAM_BYTES;
}

@@ -127,6 +149,8 @@ const struct nvram_ops arch_nvram_ops = {
.read = nvram_read,
.write = nvram_write,
.get_size = nvram_get_size,
+ .set_checksum = nvram_set_checksum,
+ .initialize = nvram_initialize,
};
EXPORT_SYMBOL(arch_nvram_ops);

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 5b54595dfe30..f9960bd65481 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -236,7 +236,8 @@ source "drivers/char/hw_random/Kconfig"

config NVRAM
tristate "/dev/nvram support"
- depends on X86 || GENERIC_NVRAM
+ depends on X86 || GENERIC_NVRAM || HAVE_ARCH_NVRAM_OPS
+ default M68K
---help---
If you say Y here and create a character special file /dev/nvram
with major number 10 and minor number 144 using mknod ("man mknod"),
--
2.19.2


2018-12-26 00:52:03

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 05/25] char/nvram: Adopt arch_nvram_ops

Different platforms and architectures offer different NVRAM sizes and
access methods. E.g. PPC32 has byte-at-a-time accessor functions whereas
PPC64 has byte-range accessor functions. Adopt the nvram_ops struct so
the nvram module can call such functions as are defined by the various
platforms and architectures.

Signed-off-by: Finn Thain <[email protected]>
---
The procfs code here could be moved to arch/x86 (like the earlier patch
did for m68k code that was here). The nvram_ops struct could be
implemented and exported by the rtc-cmos driver instead, to eliminate
the remaining #ifdefs.
---
drivers/char/nvram.c | 33 +++++++++++++++++++++++++++------
include/linux/nvram.h | 2 ++
2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index c660cff9faf4..00897daa0643 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -52,9 +52,11 @@ static DEFINE_MUTEX(nvram_mutex);
static DEFINE_SPINLOCK(nvram_state_lock);
static int nvram_open_cnt; /* #times opened */
static int nvram_open_mode; /* special open modes */
+static ssize_t nvram_size;
#define NVRAM_WRITE 1 /* opened for writing (exclusive) */
#define NVRAM_EXCL 2 /* opened with O_EXCL */

+#ifdef CONFIG_X86
/*
* 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
@@ -162,6 +164,19 @@ void nvram_set_checksum(void)
}
#endif /* 0 */

+static ssize_t nvram_get_size(void)
+{
+ return NVRAM_BYTES;
+}
+
+const struct nvram_ops arch_nvram_ops = {
+ .read_byte = nvram_read_byte,
+ .write_byte = nvram_write_byte,
+ .get_size = nvram_get_size,
+};
+EXPORT_SYMBOL(arch_nvram_ops);
+#endif /* CONFIG_X86 */
+
/*
* The are the file operation function for user access to /dev/nvram
*/
@@ -169,7 +184,7 @@ void nvram_set_checksum(void)
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,
- NVRAM_BYTES);
+ nvram_size);
}

static ssize_t nvram_misc_read(struct file *file, char __user *buf,
@@ -320,8 +335,7 @@ static int nvram_misc_release(struct inode *inode, struct file *file)
return 0;
}

-#ifdef CONFIG_PROC_FS
-
+#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
static const char * const floppy_types[] = {
"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M",
"3.5'' 2.88M", "3.5'' 2.88M"
@@ -411,7 +425,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset)

return 0;
}
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_X86 && CONFIG_PROC_FS */

static const struct file_operations nvram_misc_fops = {
.owner = THIS_MODULE,
@@ -433,13 +447,20 @@ static int __init nvram_module_init(void)
{
int ret;

+ if (arch_nvram_ops.get_size == NULL)
+ return -ENODEV;
+
+ nvram_size = arch_nvram_ops.get_size();
+ if (nvram_size < 0)
+ return nvram_size;
+
ret = misc_register(&nvram_misc);
if (ret) {
pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
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)) {
pr_err("nvram: can't create /proc/driver/nvram\n");
misc_deregister(&nvram_misc);
@@ -453,7 +474,7 @@ static int __init nvram_module_init(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);
#endif
misc_deregister(&nvram_misc);
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index 4f78147e74d9..d1bdee50d6a8 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -15,6 +15,8 @@ extern int nvram_check_checksum(void);
struct nvram_ops {
ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *);
+ unsigned char (*read_byte)(int);
+ void (*write_byte)(unsigned char, int);
ssize_t (*get_size)(void);
};

--
2.19.2


2018-12-26 00:53:03

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 23/25] char/generic_nvram: Remove as unused

Thereby eliminating some twisted CONFIG_NVRAM logic.

Signed-off-by: Finn Thain <[email protected]>
---
drivers/char/Makefile | 6 +-
drivers/char/generic_nvram.c | 160 -----------------------------------
2 files changed, 1 insertion(+), 165 deletions(-)
delete mode 100644 drivers/char/generic_nvram.c

diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b8d42b4e979b..fbea7dd12932 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -26,11 +26,7 @@ obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_HPET) += hpet.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
-ifeq ($(CONFIG_GENERIC_NVRAM),y)
- obj-$(CONFIG_NVRAM) += generic_nvram.o
-else
- obj-$(CONFIG_NVRAM) += nvram.o
-endif
+obj-$(CONFIG_NVRAM) += nvram.o
obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random/
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
deleted file mode 100644
index 41b76bf9614e..000000000000
--- a/drivers/char/generic_nvram.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Generic /dev/nvram driver for architectures providing some
- * "generic" hooks, that is :
- *
- * nvram_read_byte, nvram_write_byte, nvram_sync, nvram_get_size
- *
- * Note that an additional hook is supported for PowerMac only
- * for getting the nvram "partition" informations
- *
- */
-
-#define NVRAM_VERSION "1.1"
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/nvram.h>
-#include <linux/pagemap.h>
-#include <linux/uaccess.h>
-#include <asm/nvram.h>
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#endif
-
-static DEFINE_MUTEX(nvram_mutex);
-static ssize_t nvram_len;
-
-static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
-{
- return generic_file_llseek_size(file, offset, origin,
- MAX_LFS_FILESIZE, nvram_len);
-}
-
-static ssize_t read_nvram(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int i;
- char __user *p = buf;
-
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
- if (*ppos >= nvram_len)
- return 0;
- for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
- if (__put_user(arch_nvram_ops.read_byte(i), p))
- return -EFAULT;
- *ppos = i;
- return p - buf;
-}
-
-static ssize_t write_nvram(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned int i;
- const char __user *p = buf;
- char c;
-
- if (!access_ok(VERIFY_READ, buf, count))
- return -EFAULT;
- if (*ppos >= nvram_len)
- return 0;
- for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
- if (__get_user(c, p))
- return -EFAULT;
- arch_nvram_ops.write_byte(c, i);
- }
- *ppos = i;
- return p - buf;
-}
-
-static int nvram_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- switch(cmd) {
-#ifdef CONFIG_PPC_PMAC
- case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
- printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
- case IOC_NVRAM_GET_OFFSET: {
- int part, offset;
-
- if (!machine_is(powermac))
- return -EINVAL;
- 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;
- break;
- }
-#endif /* CONFIG_PPC_PMAC */
- case IOC_NVRAM_SYNC:
- arch_nvram_ops.sync();
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static long nvram_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&nvram_mutex);
- ret = nvram_ioctl(file, cmd, arg);
- mutex_unlock(&nvram_mutex);
-
- return ret;
-}
-
-const struct file_operations nvram_fops = {
- .owner = THIS_MODULE,
- .llseek = nvram_llseek,
- .read = read_nvram,
- .write = write_nvram,
- .unlocked_ioctl = nvram_unlocked_ioctl,
-};
-
-static struct miscdevice nvram_dev = {
- NVRAM_MINOR,
- "nvram",
- &nvram_fops
-};
-
-int __init nvram_init(void)
-{
- int ret;
-
- if (arch_nvram_ops.get_size == NULL)
- return -ENODEV;
-
- nvram_len = arch_nvram_ops.get_size();
- if (nvram_len < 0)
- return nvram_len;
-
- ret = misc_register(&nvram_dev);
- if (ret)
- return ret;
-
- pr_info("Generic non-volatile memory driver v%s\n", NVRAM_VERSION);
-
- return 0;
-}
-
-void __exit nvram_cleanup(void)
-{
- misc_deregister( &nvram_dev );
-}
-
-module_init(nvram_init);
-module_exit(nvram_cleanup);
-MODULE_LICENSE("GPL");
--
2.19.2


2018-12-26 00:53:12

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 15/25] powerpc: Clean up nvram includes

The nvram_read_byte() and nvram_write_byte() definitions in asm/nvram.h
duplicate those in linux/nvram.h. Get rid of the former to prepare for
adoption of struct arch_nvram_ops (which is defined in linux/nvram.h for
general use).

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 1 +
drivers/char/generic_nvram.c | 1 +
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
4 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 09a518bb7c03..1443b40f44b9 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -101,7 +101,4 @@ extern int nvram_write_os_partition(struct nvram_os_partition *part,
/* Determine NVRAM size */
extern ssize_t nvram_get_size(void);

-/* Normal access to NVRAM */
-extern unsigned char nvram_read_byte(int i);
-extern void nvram_write_byte(unsigned char c, int i);
#endif /* _ASM_POWERPC_NVRAM_H */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 81909600013a..04c0315cfe46 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -17,6 +17,7 @@
#include <linux/console.h>
#include <linux/memblock.h>
#include <linux/export.h>
+#include <linux/nvram.h>

#include <asm/io.h>
#include <asm/prom.h>
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 14e728fbb8a0..0381af638fe3 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -20,6 +20,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/nvram.h>
#include <linux/pagemap.h>
#include <linux/uaccess.h>
#include <asm/nvram.h>
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c
index 838869c6490c..0a4e5bad33f4 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.c
+++ b/drivers/video/fbdev/matrox/matroxfb_base.c
@@ -111,12 +111,12 @@
#include "matroxfb_g450.h"
#include <linux/matroxfb.h>
#include <linux/interrupt.h>
+#include <linux/nvram.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
-unsigned char nvram_read_byte(int);
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
#endif
--
2.19.2


2018-12-26 00:53:37

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 21/25] nvram: Drop nvram_* symbol exports and prototypes

Drivers now use the arch_nvram_ops calls so remove the function exports and
prototypes. nvram_check_checksum() is unused so remove it.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
---
arch/m68k/atari/nvram.c | 6 +++---
drivers/char/nvram.c | 27 +++++----------------------
include/linux/nvram.h | 8 --------
3 files changed, 8 insertions(+), 33 deletions(-)

diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
index 0a6fe59c95e8..2906743f0da3 100644
--- a/arch/m68k/atari/nvram.c
+++ b/arch/m68k/atari/nvram.c
@@ -34,13 +34,13 @@
* periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
*/

-unsigned char __nvram_read_byte(int i)
+static unsigned char __nvram_read_byte(int i)
{
return CMOS_READ(NVRAM_FIRST_BYTE + i);
}

/* This races nicely with trying to read with checksum checking */
-void __nvram_write_byte(unsigned char c, int i)
+static void __nvram_write_byte(unsigned char c, int i)
{
CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
}
@@ -52,7 +52,7 @@ void __nvram_write_byte(unsigned char c, int i)
#define ATARI_CKS_RANGE_END 47
#define ATARI_CKS_LOC 48

-int __nvram_check_checksum(void)
+static int __nvram_check_checksum(void)
{
int i;
unsigned char sum = 0;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 466e1fb02052..8339885e8e9b 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -81,13 +81,12 @@ static ssize_t nvram_size;
* periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
*/

-unsigned char __nvram_read_byte(int i)
+static unsigned char __nvram_read_byte(int i)
{
return CMOS_READ(NVRAM_FIRST_BYTE + i);
}
-EXPORT_SYMBOL(__nvram_read_byte);

-unsigned char nvram_read_byte(int i)
+static unsigned char nvram_read_byte(int i)
{
unsigned long flags;
unsigned char c;
@@ -97,16 +96,14 @@ unsigned char nvram_read_byte(int i)
spin_unlock_irqrestore(&rtc_lock, flags);
return c;
}
-EXPORT_SYMBOL(nvram_read_byte);

/* This races nicely with trying to read with checksum checking (nvram_read) */
-void __nvram_write_byte(unsigned char c, int i)
+static void __nvram_write_byte(unsigned char c, int i)
{
CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
}
-EXPORT_SYMBOL(__nvram_write_byte);

-void nvram_write_byte(unsigned char c, int i)
+static void nvram_write_byte(unsigned char c, int i)
{
unsigned long flags;

@@ -114,14 +111,13 @@ void nvram_write_byte(unsigned char c, int i)
__nvram_write_byte(c, i);
spin_unlock_irqrestore(&rtc_lock, flags);
}
-EXPORT_SYMBOL(nvram_write_byte);

/* On PCs, the checksum is built only over bytes 2..31 */
#define PC_CKS_RANGE_START 2
#define PC_CKS_RANGE_END 31
#define PC_CKS_LOC 32

-int __nvram_check_checksum(void)
+static int __nvram_check_checksum(void)
{
int i;
unsigned short sum = 0;
@@ -133,19 +129,6 @@ int __nvram_check_checksum(void)
__nvram_read_byte(PC_CKS_LOC+1);
return (sum & 0xffff) == expect;
}
-EXPORT_SYMBOL(__nvram_check_checksum);
-
-int nvram_check_checksum(void)
-{
- unsigned long flags;
- int rv;
-
- spin_lock_irqsave(&rtc_lock, flags);
- rv = __nvram_check_checksum();
- spin_unlock_irqrestore(&rtc_lock, flags);
- return rv;
-}
-EXPORT_SYMBOL(nvram_check_checksum);

static void __nvram_set_checksum(void)
{
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index 24a57675dba1..251472f1b2bd 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -4,14 +4,6 @@

#include <uapi/linux/nvram.h>

-/* __foo is foo without grabbing the rtc_lock - get it yourself */
-extern unsigned char __nvram_read_byte(int i);
-extern unsigned char nvram_read_byte(int i);
-extern void __nvram_write_byte(unsigned char c, int i);
-extern void nvram_write_byte(unsigned char c, int i);
-extern int __nvram_check_checksum(void);
-extern int nvram_check_checksum(void);
-
struct nvram_ops {
ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *);
--
2.19.2


2018-12-26 00:53:57

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 11/25] m68k/mac: Use macros for RTC accesses not magic numbers

This is intended to improve code style and not affect code behaviour.

Signed-off-by: Finn Thain <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/m68k/mac/misc.c | 59 ++++++++++++++++++++++++++++++--------------
1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 9f6849deecea..475c93e4048c 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -136,6 +136,21 @@ static void via_rtc_send(__u8 data)
}
}

+/*
+ * These values can be found in Inside Macintosh vol. III ch. 2
+ * which has a description of the RTC chip in the original Mac.
+ */
+
+#define RTC_FLG_READ BIT(7)
+#define RTC_FLG_WRITE_PROTECT BIT(7)
+#define RTC_CMD_READ(r) (RTC_FLG_READ | (r << 2))
+#define RTC_CMD_WRITE(r) (r << 2)
+#define RTC_REG_SECONDS_0 0
+#define RTC_REG_SECONDS_1 1
+#define RTC_REG_SECONDS_2 2
+#define RTC_REG_SECONDS_3 3
+#define RTC_REG_WRITE_PROTECT 13
+
/*
* Execute a VIA PRAM/RTC command. For read commands
* data should point to a one-byte buffer for the
@@ -145,13 +160,17 @@ static void via_rtc_send(__u8 data)
* This function disables all interrupts while running.
*/

-static void via_pram_command(int command, __u8 *data)
+static void via_rtc_command(int command, __u8 *data)
{
unsigned long flags;
int is_read;

local_irq_save(flags);

+ /* The least significant bits must be 0b01 according to Inside Mac */
+
+ command = (command & ~3) | 1;
+
/* Enable the RTC and make sure the strobe line is high */

via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
@@ -159,10 +178,10 @@ static void via_pram_command(int command, __u8 *data)
if (command & 0xFF00) { /* extended (two-byte) command */
via_rtc_send((command & 0xFF00) >> 8);
via_rtc_send(command & 0xFF);
- is_read = command & 0x8000;
+ is_read = command & (RTC_FLG_READ << 8);
} else { /* one-byte command */
via_rtc_send(command);
- is_read = command & 0x80;
+ is_read = command & RTC_FLG_READ;
}
if (is_read) {
*data = via_rtc_recv();
@@ -201,10 +220,10 @@ static time64_t via_read_time(void)
} result, last_result;
int count = 1;

- via_pram_command(0x81, &last_result.cdata[3]);
- via_pram_command(0x85, &last_result.cdata[2]);
- via_pram_command(0x89, &last_result.cdata[1]);
- via_pram_command(0x8D, &last_result.cdata[0]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_0), &last_result.cdata[3]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_1), &last_result.cdata[2]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_2), &last_result.cdata[1]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_3), &last_result.cdata[0]);

/*
* The NetBSD guys say to loop until you get the same reading
@@ -212,10 +231,14 @@ static time64_t via_read_time(void)
*/

while (1) {
- via_pram_command(0x81, &result.cdata[3]);
- via_pram_command(0x85, &result.cdata[2]);
- via_pram_command(0x89, &result.cdata[1]);
- via_pram_command(0x8D, &result.cdata[0]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_0),
+ &result.cdata[3]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_1),
+ &result.cdata[2]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_2),
+ &result.cdata[1]);
+ via_rtc_command(RTC_CMD_READ(RTC_REG_SECONDS_3),
+ &result.cdata[0]);

if (result.idata == last_result.idata)
return (time64_t)result.idata - RTC_OFFSET;
@@ -254,18 +277,18 @@ static void via_set_rtc_time(struct rtc_time *tm)
/* Clear the write protect bit */

temp = 0x55;
- via_pram_command(0x35, &temp);
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_WRITE_PROTECT), &temp);

data.idata = lower_32_bits(time + RTC_OFFSET);
- via_pram_command(0x01, &data.cdata[3]);
- via_pram_command(0x05, &data.cdata[2]);
- via_pram_command(0x09, &data.cdata[1]);
- via_pram_command(0x0D, &data.cdata[0]);
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_SECONDS_0), &data.cdata[3]);
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_SECONDS_1), &data.cdata[2]);
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_SECONDS_2), &data.cdata[1]);
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_SECONDS_3), &data.cdata[0]);

/* Set the write protect bit */

- temp = 0xD5;
- via_pram_command(0x35, &temp);
+ temp = 0x55 | RTC_FLG_WRITE_PROTECT;
+ via_rtc_command(RTC_CMD_WRITE(RTC_REG_WRITE_PROTECT), &temp);
}

static void via_shutdown(void)
--
2.19.2


2018-12-26 00:54:20

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On powerpc, setting CONFIG_NVRAM=n builds a kernel with no NVRAM support.
Setting CONFIG_NVRAM=m enables the /dev/nvram misc device module without
enabling NVRAM support in drivers. Setting CONFIG_NVRAM=y enables the
misc device (built-in) and also enables NVRAM support in drivers.

m68k shares the valkyriefb driver with powerpc, and since that driver uses
NVRAM, it is affected by CONFIG_ATARI_SCSI, because of the use of
"select NVRAM".

Adopt the powerpc convention on m68k to avoid surprises.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Christian T. Steigies <[email protected]>
---
This patch temporarily disables CONFIG_NVRAM on Atari, to prevent build
failures when bisecting the rest of this patch series. It gets enabled
again with the introduction of CONFIG_HAVE_ARCH_NVRAM_OPS, once the
nvram_* global functions have been moved to an ops struct.
---
drivers/char/Kconfig | 5 +----
drivers/scsi/Kconfig | 6 +++---
drivers/scsi/atari_scsi.c | 7 ++++---
3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9d03b2ff5df6..5b54595dfe30 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -236,7 +236,7 @@ source "drivers/char/hw_random/Kconfig"

config NVRAM
tristate "/dev/nvram support"
- depends on ATARI || X86 || GENERIC_NVRAM
+ depends on X86 || GENERIC_NVRAM
---help---
If you say Y here and create a character special file /dev/nvram
with major number 10 and minor number 144 using mknod ("man mknod"),
@@ -254,9 +254,6 @@ config NVRAM
should NEVER idly tamper with it. See Ralf Brown's interrupt list
for a guide to the use of CMOS bytes by your BIOS.

- On Atari machines, /dev/nvram is always configured and does not need
- to be selected.
-
To compile this driver as a module, choose M here: the
module will be called nvram.

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 640cd1b31a18..924eb69e7fc4 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1381,14 +1381,14 @@ config ATARI_SCSI
tristate "Atari native SCSI support"
depends on ATARI && SCSI
select SCSI_SPI_ATTRS
- select NVRAM
---help---
If you have an Atari with built-in NCR5380 SCSI controller (TT,
Falcon, ...) say Y to get it supported. Of course also, if you have
a compatible SCSI controller (e.g. for Medusa).

- To compile this driver as a module, choose M here: the
- module will be called atari_scsi.
+ To compile this driver as a module, choose M here: the module will
+ be called atari_scsi. If you also enable NVRAM support, the SCSI
+ host's ID is taken from the setting in TT RTC NVRAM.

This driver supports both styles of NCR integration into the
system: the TT style (separate DMA), and the Falcon style (via
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 89f5154c40b6..99e5729d910d 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
atari_scsi_template.sg_tablesize = setup_sg_tablesize;

- if (setup_hostid >= 0) {
+ if (setup_hostid >= 0)
atari_scsi_template.this_id = setup_hostid & 7;
- } else {
+#ifdef CONFIG_NVRAM
+ else
/* Test if a host id is set in the NVRam */
if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
unsigned char b = nvram_read_byte(16);
@@ -768,7 +769,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
if (b & 0x80)
atari_scsi_template.this_id = b & 7;
}
- }
+#endif

/* If running on a Falcon and if there's TT-Ram (i.e., more than one
* memory block, since there's always ST-Ram in a Falcon), then
--
2.19.2


2018-12-26 01:06:04

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 04/25] char/nvram: Re-order functions to remove forward declarations and #ifdefs

Also give functions more sensible names: nvram_misc_* for misc device ops,
nvram_proc_* for proc file ops and nvram_module_* for init and exit
functions. This helps to distinguish them from struct nvram_ops methods.

Signed-off-by: Finn Thain <[email protected]>
---
drivers/char/nvram.c | 167 +++++++++++++++++++------------------------
1 file changed, 72 insertions(+), 95 deletions(-)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index a9d4652f9e90..c660cff9faf4 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -55,11 +55,6 @@ static int nvram_open_mode; /* special open modes */
#define NVRAM_WRITE 1 /* opened for writing (exclusive) */
#define NVRAM_EXCL 2 /* opened with O_EXCL */

-#ifdef CONFIG_PROC_FS
-static void pc_nvram_proc_read(unsigned char *contents, struct seq_file *seq,
- void *offset);
-#endif
-
/*
* 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
@@ -171,14 +166,14 @@ void nvram_set_checksum(void)
* The are the file operation function for user access to /dev/nvram
*/

-static loff_t nvram_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,
NVRAM_BYTES);
}

-static ssize_t nvram_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+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;
@@ -206,8 +201,8 @@ static ssize_t nvram_read(struct file *file, char __user *buf,
return -EIO;
}

-static ssize_t nvram_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+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;
@@ -245,8 +240,8 @@ static ssize_t nvram_write(struct file *file, const char __user *buf,
return -EIO;
}

-static long nvram_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
int i;

@@ -286,7 +281,7 @@ static long nvram_ioctl(struct file *file, unsigned int cmd,
}
}

-static int nvram_open(struct inode *inode, struct file *file)
+static int nvram_misc_open(struct inode *inode, struct file *file)
{
spin_lock(&nvram_state_lock);

@@ -308,7 +303,7 @@ static int nvram_open(struct inode *inode, struct file *file)
return 0;
}

-static int nvram_release(struct inode *inode, struct file *file)
+static int nvram_misc_release(struct inode *inode, struct file *file)
{
spin_lock(&nvram_state_lock);

@@ -325,87 +320,6 @@ static int nvram_release(struct inode *inode, struct file *file)
return 0;
}

-#ifndef CONFIG_PROC_FS
-static int nvram_add_proc_fs(void)
-{
- return 0;
-}
-
-#else
-
-static int nvram_proc_read(struct seq_file *seq, void *offset)
-{
- unsigned char contents[NVRAM_BYTES];
- int i = 0;
-
- spin_lock_irq(&rtc_lock);
- for (i = 0; i < NVRAM_BYTES; ++i)
- contents[i] = __nvram_read_byte(i);
- spin_unlock_irq(&rtc_lock);
-
- pc_nvram_proc_read(contents, seq, offset);
-
- return 0;
-}
-
-static int nvram_add_proc_fs(void)
-{
- if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read))
- return -ENOMEM;
- return 0;
-}
-
-#endif /* CONFIG_PROC_FS */
-
-static const struct file_operations nvram_fops = {
- .owner = THIS_MODULE,
- .llseek = nvram_llseek,
- .read = nvram_read,
- .write = nvram_write,
- .unlocked_ioctl = nvram_ioctl,
- .open = nvram_open,
- .release = nvram_release,
-};
-
-static struct miscdevice nvram_dev = {
- NVRAM_MINOR,
- "nvram",
- &nvram_fops
-};
-
-static int __init nvram_init(void)
-{
- int ret;
-
- ret = misc_register(&nvram_dev);
- if (ret) {
- printk(KERN_ERR "nvram: can't misc_register on minor=%d\n",
- NVRAM_MINOR);
- goto out;
- }
- ret = nvram_add_proc_fs();
- if (ret) {
- printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n");
- goto outmisc;
- }
- ret = 0;
- printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n");
-out:
- return ret;
-outmisc:
- misc_deregister(&nvram_dev);
- goto out;
-}
-
-static void __exit nvram_cleanup_module(void)
-{
- remove_proc_entry("driver/nvram", NULL);
- misc_deregister(&nvram_dev);
-}
-
-module_init(nvram_init);
-module_exit(nvram_cleanup_module);
-
#ifdef CONFIG_PROC_FS

static const char * const floppy_types[] = {
@@ -483,7 +397,70 @@ static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq,
return;
}

+static int nvram_proc_read(struct seq_file *seq, void *offset)
+{
+ unsigned char contents[NVRAM_BYTES];
+ int i = 0;
+
+ spin_lock_irq(&rtc_lock);
+ for (i = 0; i < NVRAM_BYTES; ++i)
+ contents[i] = __nvram_read_byte(i);
+ spin_unlock_irq(&rtc_lock);
+
+ pc_nvram_proc_read(contents, seq, offset);
+
+ return 0;
+}
#endif /* CONFIG_PROC_FS */

+static const struct file_operations nvram_misc_fops = {
+ .owner = THIS_MODULE,
+ .llseek = nvram_misc_llseek,
+ .read = nvram_misc_read,
+ .write = nvram_misc_write,
+ .unlocked_ioctl = nvram_misc_ioctl,
+ .open = nvram_misc_open,
+ .release = nvram_misc_release,
+};
+
+static struct miscdevice nvram_misc = {
+ NVRAM_MINOR,
+ "nvram",
+ &nvram_misc_fops,
+};
+
+static int __init nvram_module_init(void)
+{
+ int ret;
+
+ ret = misc_register(&nvram_misc);
+ if (ret) {
+ pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
+ return ret;
+ }
+
+#ifdef CONFIG_PROC_FS
+ if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
+ pr_err("nvram: can't create /proc/driver/nvram\n");
+ misc_deregister(&nvram_misc);
+ return -ENOMEM;
+ }
+#endif
+
+ pr_info("Non-volatile memory driver v" NVRAM_VERSION "\n");
+ return 0;
+}
+
+static void __exit nvram_module_exit(void)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("driver/nvram", NULL);
+#endif
+ misc_deregister(&nvram_misc);
+}
+
+module_init(nvram_module_init);
+module_exit(nvram_module_exit);
+
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
--
2.19.2


2018-12-26 01:06:04

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 03/25] m68k/atari: Replace nvram_{read,write}_byte with arch_nvram_ops

By implementing an arch_nvram_ops struct, any platform can re-use the
drivers/char/nvram.c module without needing any arch-specific code
in that module. Atari does so here.

Atari has one user of nvram_check_checksum() whereas the other "CMOS"
platforms don't use that function at all. Replace this
validate-checksum-and-read-byte sequence with the equivalent
rtc_nvram_ops.read() call and remove the now unused functions.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Christian T. Steigies <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
---
The advantage of the new ops struct over the old global nvram_* functions
is that the misc device module can be shared by different platforms
without requiring every platform to implement every nvram_* function.
E.g. only RTC "CMOS" NVRAMs have a checksum for the entire NVRAM
and only PowerPC platforms have a "sync" ioctl.
---
arch/m68k/atari/nvram.c | 89 ++++++++++++++++++++++++---------------
drivers/scsi/atari_scsi.c | 8 ++--
include/linux/nvram.h | 9 ++++
3 files changed, 70 insertions(+), 36 deletions(-)

diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
index 3e620ee955ba..bafc9dc32830 100644
--- a/arch/m68k/atari/nvram.c
+++ b/arch/m68k/atari/nvram.c
@@ -39,33 +39,12 @@ unsigned char __nvram_read_byte(int i)
return CMOS_READ(NVRAM_FIRST_BYTE + i);
}

-unsigned char nvram_read_byte(int i)
-{
- unsigned long flags;
- unsigned char c;
-
- spin_lock_irqsave(&rtc_lock, flags);
- c = __nvram_read_byte(i);
- spin_unlock_irqrestore(&rtc_lock, flags);
- return c;
-}
-EXPORT_SYMBOL(nvram_read_byte);
-
/* This races nicely with trying to read with checksum checking */
void __nvram_write_byte(unsigned char c, int i)
{
CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
}

-void nvram_write_byte(unsigned char c, int i)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- __nvram_write_byte(c, i);
- spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
/* On Ataris, the checksum is over all bytes except the checksum bytes
* themselves; these are at the very end.
*/
@@ -84,18 +63,6 @@ int __nvram_check_checksum(void)
(__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
}

-int nvram_check_checksum(void)
-{
- unsigned long flags;
- int rv;
-
- spin_lock_irqsave(&rtc_lock, flags);
- rv = __nvram_check_checksum();
- spin_unlock_irqrestore(&rtc_lock, flags);
- return rv;
-}
-EXPORT_SYMBOL(nvram_check_checksum);
-
static void __nvram_set_checksum(void)
{
int i;
@@ -107,6 +74,62 @@ static void __nvram_set_checksum(void)
__nvram_write_byte(sum, ATARI_CKS_LOC + 1);
}

+static ssize_t 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 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;
+}
+
+static ssize_t nvram_get_size(void)
+{
+ return NVRAM_BYTES;
+}
+
+const struct nvram_ops arch_nvram_ops = {
+ .read = nvram_read,
+ .write = nvram_write,
+ .get_size = nvram_get_size,
+};
+EXPORT_SYMBOL(arch_nvram_ops);
+
#ifdef CONFIG_PROC_FS
static struct {
unsigned char val;
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 99e5729d910d..f55d13e400da 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -760,13 +760,15 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
#ifdef CONFIG_NVRAM
else
/* Test if a host id is set in the NVRam */
- if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
- unsigned char b = nvram_read_byte(16);
+ if (ATARIHW_PRESENT(TT_CLK)) {
+ unsigned char b;
+ loff_t offset = 16;
+ ssize_t count = arch_nvram_ops.read(&b, 1, &offset);

/* Arbitration enabled? (for TOS)
* If yes, use configured host ID
*/
- if (b & 0x80)
+ if ((count == 1) && (b & 0x80))
atari_scsi_template.this_id = b & 7;
}
#endif
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index 28bfb9ab94ca..4f78147e74d9 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -11,4 +11,13 @@ extern void __nvram_write_byte(unsigned char c, int i);
extern void nvram_write_byte(unsigned char c, int i);
extern int __nvram_check_checksum(void);
extern int nvram_check_checksum(void);
+
+struct nvram_ops {
+ ssize_t (*read)(char *, size_t, loff_t *);
+ ssize_t (*write)(char *, size_t, loff_t *);
+ ssize_t (*get_size)(void);
+};
+
+extern const struct nvram_ops arch_nvram_ops;
+
#endif /* _LINUX_NVRAM_H */
--
2.19.2


2018-12-26 01:08:22

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 25/25] powerpc: Remove pmac_xpram_{read,write} functions

The arch_nvram_ops methods provide a uniform API to replace the
nvram_{read,write}_byte exports and pmac_xpram_{read,write} functions.

The latter API gets removed in this patch. To make that possible, add
a get_partition() method to the nvram_ops struct and call it from
pmac_time_init().

pmac_xpram_read() becomes unused as pmac_time_init() is converted to the
arch_nvram_ops API. pmac_xpram_write() was already unused.

As a bonus, drivers/char/nvram.c benefits from the API conversion by the
removal of an #ifdef.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
arch/powerpc/include/asm/nvram.h | 4 ----
arch/powerpc/kernel/nvram_64.c | 3 +++
arch/powerpc/kernel/setup_32.c | 3 +++
arch/powerpc/platforms/powermac/nvram.c | 28 +++----------------------
arch/powerpc/platforms/powermac/time.c | 17 +++++++++++----
drivers/char/nvram.c | 6 ++----
include/linux/nvram.h | 1 +
7 files changed, 25 insertions(+), 37 deletions(-)

diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 629a5cdcc865..a7916b1c3f3a 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -74,10 +74,6 @@ extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
/* Return partition offset in nvram */
extern int pmac_get_partition(int partition);

-/* Direct access to XPRAM on PowerMacs */
-extern u8 pmac_xpram_read(int xpaddr);
-extern void pmac_xpram_write(int xpaddr, u8 data);
-
/* Initialize NVRAM OS partition */
extern int __init nvram_init_os_partition(struct nvram_os_partition *part);

diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 6d0461c02e0f..2190ce75467d 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -1093,6 +1093,9 @@ const struct nvram_ops arch_nvram_ops = {
.write = ppc_nvram_write,
.get_size = ppc_nvram_get_size,
.sync = ppc_nvram_sync,
+#ifdef CONFIG_PPC_PMAC
+ .get_partition = pmac_get_partition,
+#endif
};
EXPORT_SYMBOL(arch_nvram_ops);

diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 96782abb0c41..a76cfb125eb1 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -184,6 +184,9 @@ const struct nvram_ops arch_nvram_ops = {
.write_byte = ppc_nvram_write_byte,
.get_size = ppc_nvram_get_size,
.sync = ppc_nvram_sync,
+#ifdef CONFIG_PPC_PMAC
+ .get_partition = pmac_get_partition,
+#endif
};
EXPORT_SYMBOL(arch_nvram_ops);

diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 9360cdc408c1..38c5cdd44d7b 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -629,29 +629,7 @@ int __init pmac_nvram_init(void)

int pmac_get_partition(int partition)
{
- return nvram_partitions[partition];
+ if (machine_is(powermac))
+ return nvram_partitions[partition];
+ return -1;
}
-
-u8 pmac_xpram_read(int xpaddr)
-{
- int offset = pmac_get_partition(pmac_nvram_XPRAM);
-
- if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
- return 0xff;
-
- return ppc_md.nvram_read_val(xpaddr + offset);
-}
-
-void pmac_xpram_write(int xpaddr, u8 data)
-{
- int offset = pmac_get_partition(pmac_nvram_XPRAM);
-
- if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
- return;
-
- ppc_md.nvram_write_val(xpaddr + offset, data);
-}
-
-EXPORT_SYMBOL(pmac_get_partition);
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index b36ddee17c87..7df08c7d348f 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/hardirq.h>
#include <linux/rtc.h>
+#include <linux/nvram.h>

#include <asm/sections.h>
#include <asm/prom.h>
@@ -70,13 +71,21 @@ long __init pmac_time_init(void)
s32 delta = 0;
#if defined(CONFIG_NVRAM) && defined(CONFIG_PPC32)
int dst;
+ int offset = arch_nvram_ops.get_partition(pmac_nvram_XPRAM);

- delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
- delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
- delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+ if (offset < 0)
+ return 0;
+
+ delta = arch_nvram_ops.read_byte(offset + PMAC_XPRAM_MACHINE_LOC + 9);
+ delta <<= 8;
+ delta |= arch_nvram_ops.read_byte(offset + PMAC_XPRAM_MACHINE_LOC + 10);
+ delta <<= 8;
+ delta |= arch_nvram_ops.read_byte(offset + PMAC_XPRAM_MACHINE_LOC + 11);
+
if (delta & 0x00800000UL)
delta |= 0xFF000000UL;
- dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+ dst = arch_nvram_ops.read_byte(offset + PMAC_XPRAM_MACHINE_LOC + 8);
+ dst &= 0x80;
printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
dst ? "on" : "off");
#endif
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 8cbfed86ec8d..e19d9be214cf 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -324,8 +324,7 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
/* fall through */
case IOC_NVRAM_GET_OFFSET:
ret = -EINVAL;
-#ifdef CONFIG_PPC_PMAC
- if (machine_is(powermac)) {
+ if (arch_nvram_ops.get_partition != NULL) {
int part, offset;

if (copy_from_user(&part, (void __user *)arg,
@@ -333,7 +332,7 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
if (part < pmac_nvram_OF || part > pmac_nvram_NR)
return -EINVAL;
- offset = pmac_get_partition(part);
+ offset = arch_nvram_ops.get_partition(part);
if (offset < 0)
return -EINVAL;
if (copy_to_user((void __user *)arg,
@@ -341,7 +340,6 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
ret = 0;
}
-#endif
break;
case IOC_NVRAM_SYNC:
if (arch_nvram_ops.sync != NULL) {
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index 251472f1b2bd..4ccb491d9871 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -12,6 +12,7 @@ struct nvram_ops {
ssize_t (*get_size)(void);
#ifdef CONFIG_PPC
long (*sync)(void);
+ int (*get_partition)(int);
#else
long (*set_checksum)(void);
long (*initialize)(void);
--
2.19.2


2018-12-26 01:09:32

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

Adopt nvram module to reduce code duplication. This means CONFIG_NVRAM
becomes available to CONFIG_PPC64 builds (until now it was only PPC32).

The IOC_NVRAM_GET_OFFSET ioctl as implemented on PPC64 validates the offset
returned by pmac_get_partition(). Add this test to the nvram module.

Note that the old PPC32 generic_nvram module lacked this test.
So when CONFIG_PPC32 && CONFIG_PPC_PMAC, the IOC_NVRAM_GET_OFFSET ioctl
would have returned 0 (always). But when CONFIG_PPC64 && CONFIG_PPC_PMAC,
the IOC_NVRAM_GET_OFFSET ioctl would have returned -1 (which is -EPERM)
when the requested partition was not found.

With this patch, the result is now -EINVAL on both PPC32 and PPC64 when
the requested PowerMac NVRAM partition is not found. This is a userspace-
visible change, in the non-existent partition case, which would be in
an error path for an IOC_NVRAM_GET_OFFSET ioctl syscall.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Laurent Vivier <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
BTW, the IOC_NVRAM_SYNC ioctl call returns -EINVAL on PPC64. This patch
retains this behaviour though it might be better to actually perform a sync.
Both PPC64 and PPC32 kernels implement ppc_md.nvram_sync() for Core99,
but on PPC64 the ioctl is unimplemented (unlike PPC32).

Changed since v7:
- Drop pointless comment edit.
---
arch/powerpc/Kconfig | 3 +-
arch/powerpc/kernel/nvram_64.c | 185 +++++------------------
arch/powerpc/platforms/powermac/Makefile | 2 -
arch/powerpc/platforms/powermac/setup.c | 2 +-
arch/powerpc/platforms/powermac/time.c | 2 +-
arch/powerpc/platforms/pseries/nvram.c | 2 -
drivers/char/nvram.c | 2 +
7 files changed, 40 insertions(+), 158 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 5b859b7f6599..940de2d62fb5 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -271,10 +271,9 @@ config SYSVIPC_COMPAT
depends on COMPAT && SYSVIPC
default y

-# All PPC32s use generic nvram driver through ppc_md
config HAVE_ARCH_NVRAM_OPS
bool
- default y if PPC32
+ default y

config SCHED_OMIT_FRAME_POINTER
bool
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 22e9d281324d..6d0461c02e0f 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -7,12 +7,6 @@
* 2 of the License, or (at your option) any later version.
*
* /dev/nvram driver for PPC64
- *
- * This perhaps should live in drivers/char
- *
- * TODO: Split the /dev/nvram part (that one can use
- * drivers/char/generic_nvram.c) from the arch & partition
- * parsing code.
*/

#include <linux/types.h>
@@ -716,136 +710,6 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
spin_unlock_irqrestore(&lock, flags);
}

-static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
-{
- if (ppc_md.nvram_size == NULL)
- return -ENODEV;
- return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
- ppc_md.nvram_size());
-}
-
-
-static ssize_t dev_nvram_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- ssize_t ret;
- char *tmp = NULL;
- ssize_t size;
-
- if (!ppc_md.nvram_size) {
- ret = -ENODEV;
- goto out;
- }
-
- size = ppc_md.nvram_size();
- if (size < 0) {
- ret = size;
- goto out;
- }
-
- if (*ppos >= size) {
- ret = 0;
- goto out;
- }
-
- count = min_t(size_t, count, size - *ppos);
- count = min(count, PAGE_SIZE);
-
- tmp = kmalloc(count, GFP_KERNEL);
- if (!tmp) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = ppc_md.nvram_read(tmp, count, ppos);
- if (ret <= 0)
- goto out;
-
- if (copy_to_user(buf, tmp, ret))
- ret = -EFAULT;
-
-out:
- kfree(tmp);
- return ret;
-
-}
-
-static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- ssize_t ret;
- char *tmp = NULL;
- ssize_t size;
-
- ret = -ENODEV;
- if (!ppc_md.nvram_size)
- goto out;
-
- ret = 0;
- size = ppc_md.nvram_size();
- if (*ppos >= size || size < 0)
- goto out;
-
- count = min_t(size_t, count, size - *ppos);
- count = min(count, PAGE_SIZE);
-
- tmp = memdup_user(buf, count);
- if (IS_ERR(tmp)) {
- ret = PTR_ERR(tmp);
- goto out;
- }
-
- ret = ppc_md.nvram_write(tmp, count, ppos);
-
- kfree(tmp);
-out:
- return ret;
-}
-
-static long dev_nvram_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- switch(cmd) {
-#ifdef CONFIG_PPC_PMAC
- case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
- printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
- case IOC_NVRAM_GET_OFFSET: {
- int part, offset;
-
- if (!machine_is(powermac))
- return -EINVAL;
- 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 (offset < 0)
- return offset;
- if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
- return -EFAULT;
- return 0;
- }
-#endif /* CONFIG_PPC_PMAC */
- default:
- return -EINVAL;
- }
-}
-
-static const struct file_operations nvram_fops = {
- .owner = THIS_MODULE,
- .llseek = dev_nvram_llseek,
- .read = dev_nvram_read,
- .write = dev_nvram_write,
- .unlocked_ioctl = dev_nvram_ioctl,
-};
-
-static struct miscdevice nvram_dev = {
- NVRAM_MINOR,
- "nvram",
- &nvram_fops
-};
-
-
#ifdef DEBUG_NVRAM
static void __init nvram_print_partitions(char * label)
{
@@ -993,6 +857,8 @@ loff_t __init nvram_create_partition(const char *name, int sig,
long size = 0;
int rc;

+ BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16);
+
/* Convert sizes from bytes to blocks */
req_size = _ALIGN_UP(req_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN;
min_size = _ALIGN_UP(min_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN;
@@ -1194,21 +1060,40 @@ int __init nvram_scan_partitions(void)
return err;
}

-static int __init nvram_init(void)
+#if IS_ENABLED(CONFIG_NVRAM)
+
+static ssize_t ppc_nvram_read(char *buf, size_t count, loff_t *index)
{
- int rc;
-
- BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16);
+ if (ppc_md.nvram_read)
+ return ppc_md.nvram_read(buf, count, index);
+ return -EINVAL;
+}

- if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
- return -ENODEV;
+static ssize_t ppc_nvram_write(char *buf, size_t count, loff_t *index)
+{
+ if (ppc_md.nvram_write)
+ return ppc_md.nvram_write(buf, count, index);
+ return -EINVAL;
+}

- rc = misc_register(&nvram_dev);
- if (rc != 0) {
- printk(KERN_ERR "nvram_init: failed to register device\n");
- return rc;
- }
-
- return rc;
+static ssize_t ppc_nvram_get_size(void)
+{
+ if (ppc_md.nvram_size)
+ return ppc_md.nvram_size();
+ return -ENODEV;
+}
+
+static long ppc_nvram_sync(void)
+{
+ return -EINVAL;
}
-device_initcall(nvram_init);
+
+const struct nvram_ops arch_nvram_ops = {
+ .read = ppc_nvram_read,
+ .write = ppc_nvram_write,
+ .get_size = ppc_nvram_get_size,
+ .sync = ppc_nvram_sync,
+};
+EXPORT_SYMBOL(arch_nvram_ops);
+
+#endif /* CONFIG_NVRAM */
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index 923bfb340433..20ebf35d7913 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -15,7 +15,5 @@ obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
# need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really
# CONFIG_NVRAM=y
obj-$(CONFIG_NVRAM:m=y) += nvram.o
-# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
-obj-$(CONFIG_PPC64) += nvram.o
obj-$(CONFIG_PPC32) += bootx_init.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index ce340ae4ee38..dc56ae23118a 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -316,7 +316,7 @@ static void __init pmac_setup_arch(void)
find_via_pmu();
smu_init();

-#if IS_ENABLED(CONFIG_NVRAM) || defined(CONFIG_PPC64)
+#if IS_ENABLED(CONFIG_NVRAM)
pmac_nvram_init();
#endif
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index f157e3d071f2..b36ddee17c87 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -68,7 +68,7 @@
long __init pmac_time_init(void)
{
s32 delta = 0;
-#ifdef CONFIG_NVRAM
+#if defined(CONFIG_NVRAM) && defined(CONFIG_PPC32)
int dst;

delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 69cedc1b3b8a..1136a38ff039 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -7,8 +7,6 @@
* 2 of the License, or (at your option) any later version.
*
* /dev/nvram driver for PPC64
- *
- * This perhaps should live in drivers/char
*/


diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 8339885e8e9b..8cbfed86ec8d 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -334,6 +334,8 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
if (part < pmac_nvram_OF || part > pmac_nvram_NR)
return -EINVAL;
offset = pmac_get_partition(part);
+ if (offset < 0)
+ return -EINVAL;
if (copy_to_user((void __user *)arg,
&offset, sizeof(offset)) != 0)
return -EFAULT;
--
2.19.2


2018-12-26 01:23:55

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 08/25] char/nvram: Implement NVRAM read/write methods

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 also
preserves the locking semantics 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 functions. The misc device driver prefers to use the
former but will fall back on the latter.

Signed-off-by: Finn Thain <[email protected]>
---
Changed since v7:
- Use memdup_user(), like arch/powerpc/kernel/nvram_64.c.
---
drivers/char/nvram.c | 149 ++++++++++++++++++++++++++++++-------------
1 file changed, 104 insertions(+), 45 deletions(-)

diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 33ef3b02d365..889123ddace4 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>
@@ -178,9 +179,48 @@ static ssize_t nvram_get_size(void)
return NVRAM_BYTES;
}

+static ssize_t 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 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_byte = nvram_read_byte,
.write_byte = nvram_write_byte,
+ .read = nvram_read,
+ .write = nvram_write,
.get_size = nvram_get_size,
.set_checksum = nvram_set_checksum,
.initialize = nvram_initialize,
@@ -201,69 +241,88 @@ 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);
-
- if (!__nvram_check_checksum())
- goto checksum_err;
+ loff_t i;
+ char __user *p = buf;

- for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
- *tmp = __nvram_read_byte(i);
-
- spin_unlock_irq(&rtc_lock);
-
- if (copy_to_user(buf, contents, tmp - contents))
+ if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
+ if (*ppos >= nvram_size)
+ return 0;
+
+ /* If the arch provided a byte range read op, use it. Otherwise
+ * fall back on the byte-at-a-time accessor.
+ */
+ if (arch_nvram_ops.read != NULL) {
+ char *tmp;
+ ssize_t ret;
+
+ count = min_t(size_t, count, nvram_size - *ppos);
+ count = min_t(size_t, count, PAGE_SIZE);
+
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = arch_nvram_ops.read(tmp, count, ppos);
+ if (ret <= 0)
+ goto out;
+
+ if (copy_to_user(buf, tmp, ret)) {
+ *ppos -= ret;
+ ret = -EFAULT;
+ }

- *ppos = i;
-
- return tmp - contents;
+out:
+ kfree(tmp);
+ return ret;
+ }

-checksum_err:
- spin_unlock_irq(&rtc_lock);
- return -EIO;
+ for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count)
+ if (__put_user(arch_nvram_ops.read_byte(i), p))
+ return -EFAULT;
+ *ppos = i;
+ return p - buf;
}

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;
+ loff_t i;
+ const char __user *p = buf;

- 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 */
-
- if (copy_from_user(contents, buf, count))
+ if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
+ if (*ppos >= nvram_size)
+ return 0;

- spin_lock_irq(&rtc_lock);
+ /* If the arch provided a byte range write op, use it. Otherwise
+ * fall back on the byte-at-a-time accessor.
+ */
+ if (arch_nvram_ops.write != NULL) {
+ char *tmp;
+ ssize_t ret;

- if (!__nvram_check_checksum())
- goto checksum_err;
+ count = min_t(size_t, count, nvram_size - *ppos);
+ count = min_t(size_t, count, PAGE_SIZE);

- for (tmp = contents; count--; ++i, ++tmp)
- __nvram_write_byte(*tmp, i);
+ tmp = memdup_user(buf, count);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);

- __nvram_set_checksum();
+ ret = arch_nvram_ops.write(tmp, count, ppos);
+ kfree(tmp);
+ return ret;
+ }

- spin_unlock_irq(&rtc_lock);
+ for (i = *ppos; count > 0 && i < nvram_size; ++i, ++p, --count) {
+ char c;

+ if (__get_user(c, p))
+ return -EFAULT;
+ arch_nvram_ops.write_byte(c, i);
+ }
*ppos = i;
-
- return tmp - contents;
-
-checksum_err:
- spin_unlock_irq(&rtc_lock);
- return -EIO;
+ return p - buf;
}

static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
--
2.19.2


2018-12-26 01:46:23

by Finn Thain

[permalink] [raw]
Subject: [PATCH v8 22/25] powerpc: Remove CONFIG_GENERIC_NVRAM and adopt CONFIG_HAVE_ARCH_NVRAM_OPS

Switch PPC32 kernels from the generic_nvram module to the nvram module.

Also fix a theoretical bug where CHRP omits the chrp_nvram_init()
call when CONFIG_NVRAM_MODULE=m.

Signed-off-by: Finn Thain <[email protected]>
Tested-by: Laurent Vivier <[email protected]>
Tested-by: Stan Johnson <[email protected]>
---
The change in the name of the module is visible to userspace. The module
that implements /dev/nvram on PowerPC now has suitable aliases, i.e.
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
MODULE_ALIAS("devname:nvram");
so that the device special file can be automatically created and the
module automatically loaded when needed. Previously this was not the case.

Changed since v7:
- Improved Kconfig help text for CONFIG_NVRAM.
- Changed the default for CONFIG_NVRAM, which used to be "n". This is to
reduce the risk that CONFIG_GENERIC_NVRAM=y accidentally gets changed to
CONFIG_NVRAM=n.
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/platforms/chrp/Makefile | 2 +-
arch/powerpc/platforms/chrp/setup.c | 2 +-
arch/powerpc/platforms/powermac/setup.c | 3 +--
drivers/char/Kconfig | 19 +++++++++----------
6 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8be31261aec8..5b859b7f6599 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -272,7 +272,7 @@ config SYSVIPC_COMPAT
default y

# All PPC32s use generic nvram driver through ppc_md
-config GENERIC_NVRAM
+config HAVE_ARCH_NVRAM_OPS
bool
default y if PPC32

diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index bdbe6acbef11..96782abb0c41 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -150,7 +150,7 @@ static int __init ppc_setup_l3cr(char *str)
}
__setup("l3cr=", ppc_setup_l3cr);

-#ifdef CONFIG_GENERIC_NVRAM
+#if IS_ENABLED(CONFIG_NVRAM)

static unsigned char ppc_nvram_read_byte(int addr)
{
diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile
index 4b3bfadc70fa..dc3465cc8bc6 100644
--- a/arch/powerpc/platforms/chrp/Makefile
+++ b/arch/powerpc/platforms/chrp/Makefile
@@ -1,3 +1,3 @@
obj-y += setup.o time.o pegasos_eth.o pci.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_NVRAM) += nvram.o
+obj-$(CONFIG_NVRAM:m=y) += nvram.o
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index d6d8ffc0271e..ba216aef964a 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -556,7 +556,7 @@ static void __init chrp_init_IRQ(void)
static void __init
chrp_init2(void)
{
-#ifdef CONFIG_NVRAM
+#if IS_ENABLED(CONFIG_NVRAM)
chrp_nvram_init();
#endif

diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 2f00e3daafb0..ce340ae4ee38 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -316,8 +316,7 @@ static void __init pmac_setup_arch(void)
find_via_pmu();
smu_init();

-#if defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) || \
- defined(CONFIG_PPC64)
+#if IS_ENABLED(CONFIG_NVRAM) || defined(CONFIG_PPC64)
pmac_nvram_init();
#endif
#ifdef CONFIG_PPC32
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index f9960bd65481..2a193b298d27 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -236,25 +236,24 @@ source "drivers/char/hw_random/Kconfig"

config NVRAM
tristate "/dev/nvram support"
- depends on X86 || GENERIC_NVRAM || HAVE_ARCH_NVRAM_OPS
- default M68K
+ depends on X86 || HAVE_ARCH_NVRAM_OPS
+ default M68K || PPC
---help---
If you say Y here and create a character special file /dev/nvram
with major number 10 and minor number 144 using mknod ("man mknod"),
- you get read and write access to the extra bytes of non-volatile
- memory in the real time clock (RTC), which is contained in every PC
- and most Ataris. The actual number of bytes varies, depending on the
- nvram in the system, but is usually 114 (128-14 for the RTC).
-
- This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
- on Ataris. /dev/nvram may be used to view settings there, or to
- change them (with some utility). It could also be used to frequently
+ you get read and write access to the non-volatile memory.
+
+ /dev/nvram may be used to view settings in NVRAM or to change them
+ (with some utility). It could also be used to frequently
save a few bits of very important data that may not be lost over
power-off and for which writing to disk is too insecure. Note
however that most NVRAM space in a PC belongs to the BIOS and you
should NEVER idly tamper with it. See Ralf Brown's interrupt list
for a guide to the use of CMOS bytes by your BIOS.

+ This memory is conventionally called "NVRAM" on PowerPC machines,
+ "CMOS RAM" on PCs, "NVRAM" on Ataris and "PRAM" on Macintoshes.
+
To compile this driver as a module, choose M here: the
module will be called nvram.

--
2.19.2


2018-12-29 01:34:41

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Finn Thain <[email protected]> a écrit :

> On powerpc, setting CONFIG_NVRAM=n builds a kernel with no NVRAM support.
> Setting CONFIG_NVRAM=m enables the /dev/nvram misc device module without
> enabling NVRAM support in drivers. Setting CONFIG_NVRAM=y enables the
> misc device (built-in) and also enables NVRAM support in drivers.
>
> m68k shares the valkyriefb driver with powerpc, and since that driver uses
> NVRAM, it is affected by CONFIG_ATARI_SCSI, because of the use of
> "select NVRAM".
>
> Adopt the powerpc convention on m68k to avoid surprises.
>
> Signed-off-by: Finn Thain <[email protected]>
> Tested-by: Christian T. Steigies <[email protected]>
> ---
> This patch temporarily disables CONFIG_NVRAM on Atari, to prevent build
> failures when bisecting the rest of this patch series. It gets enabled
> again with the introduction of CONFIG_HAVE_ARCH_NVRAM_OPS, once the
> nvram_* global functions have been moved to an ops struct.
> ---
> drivers/char/Kconfig | 5 +----
> drivers/scsi/Kconfig | 6 +++---
> drivers/scsi/atari_scsi.c | 7 ++++---
> 3 files changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 9d03b2ff5df6..5b54595dfe30 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -236,7 +236,7 @@ source "drivers/char/hw_random/Kconfig"
>
> config NVRAM
> tristate "/dev/nvram support"
> - depends on ATARI || X86 || GENERIC_NVRAM
> + depends on X86 || GENERIC_NVRAM
> ---help---
> If you say Y here and create a character special file /dev/nvram
> with major number 10 and minor number 144 using mknod ("man mknod"),
> @@ -254,9 +254,6 @@ config NVRAM
> should NEVER idly tamper with it. See Ralf Brown's interrupt list
> for a guide to the use of CMOS bytes by your BIOS.
>
> - On Atari machines, /dev/nvram is always configured and does not need
> - to be selected.
> -
> To compile this driver as a module, choose M here: the
> module will be called nvram.
>
> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
> index 640cd1b31a18..924eb69e7fc4 100644
> --- a/drivers/scsi/Kconfig
> +++ b/drivers/scsi/Kconfig
> @@ -1381,14 +1381,14 @@ config ATARI_SCSI
> tristate "Atari native SCSI support"
> depends on ATARI && SCSI
> select SCSI_SPI_ATTRS
> - select NVRAM
> ---help---
> If you have an Atari with built-in NCR5380 SCSI controller (TT,
> Falcon, ...) say Y to get it supported. Of course also, if you have
> a compatible SCSI controller (e.g. for Medusa).
>
> - To compile this driver as a module, choose M here: the
> - module will be called atari_scsi.
> + To compile this driver as a module, choose M here: the module will
> + be called atari_scsi. If you also enable NVRAM support, the SCSI
> + host's ID is taken from the setting in TT RTC NVRAM.
>
> This driver supports both styles of NCR integration into the
> system: the TT style (separate DMA), and the Falcon style (via
> diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
> index 89f5154c40b6..99e5729d910d 100644
> --- a/drivers/scsi/atari_scsi.c
> +++ b/drivers/scsi/atari_scsi.c
> @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct
> platform_device *pdev)
> if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
> atari_scsi_template.sg_tablesize = setup_sg_tablesize;
>
> - if (setup_hostid >= 0) {
> + if (setup_hostid >= 0)
> atari_scsi_template.this_id = setup_hostid & 7;
> - } else {
> +#ifdef CONFIG_NVRAM
> + else

Such ifdefs should be avoided in C files.
It would be better to use

} else if (IS_ENABLED(CONFIG_NVRAM)) {

> /* Test if a host id is set in the NVRam */
> if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
> unsigned char b = nvram_read_byte(16);
> @@ -768,7 +769,7 @@ static int __init atari_scsi_probe(struct
> platform_device *pdev)
> if (b & 0x80)
> atari_scsi_template.this_id = b & 7;
> }
> - }
> +#endif
>
> /* If running on a Falcon and if there's TT-Ram (i.e., more than one
> * memory block, since there's always ST-Ram in a Falcon), then
> --
> 2.19.2



2018-12-29 05:35:53

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 02/25] m68k/atari: Move Atari-specific code out of drivers/char/nvram.c

Finn Thain <[email protected]> a écrit :

> Move the m68k-specific code out of the driver to make the driver generic.
>
> I've used 'SPDX-License-Identifier: GPL-2.0+' for the new file because the
> old file is covered by MODULE_LICENSE("GPL").
>
> Signed-off-by: Finn Thain <[email protected]>
> Tested-by: Christian T. Steigies <[email protected]>
> Acked-by: Geert Uytterhoeven <[email protected]>
> ---
> Changed since v7:
> - Added SPDX-License-Identifier.
> ---
> arch/m68k/atari/Makefile | 2 +
> arch/m68k/atari/nvram.c | 243 +++++++++++++++++++++++++++++++++
> drivers/char/nvram.c | 280 +++++----------------------------------
> 3 files changed, 280 insertions(+), 245 deletions(-)
> create mode 100644 arch/m68k/atari/nvram.c
>
> diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
> index 0cac723306f9..0b86bb6cfa87 100644
> --- a/arch/m68k/atari/Makefile
> +++ b/arch/m68k/atari/Makefile
> @@ -6,3 +6,5 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \
> atasound.o stram.o
>
> obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
> +
> +obj-$(CONFIG_NVRAM:m=y) += nvram.o
> diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
> new file mode 100644
> index 000000000000..3e620ee955ba
> --- /dev/null
> +++ b/arch/m68k/atari/nvram.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * CMOS/NV-RAM driver for Atari. Adapted from drivers/char/nvram.c.
> + * Copyright (C) 1997 Roman Hodek <[email protected]>
> + * idea by and with help from Richard Jelinek <[email protected]>
> + * Portions copyright (c) 2001,2002 Sun Microsystems ([email protected])
> + * Further contributions from Cesar Barros, Erik Gilling, Tim Hockin and
> + * Wim Van Sebroeck.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/mc146818rtc.h>
> +#include <linux/module.h>
> +#include <linux/nvram.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <asm/atarihw.h>
> +#include <asm/atariints.h>
> +
> +#define NVRAM_BYTES 50
> +
> +/* It is worth noting that these functions all access bytes of general
> + * purpose memory in the NVRAM - that is to say, they all add the
> + * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not
> + * know about the RTC cruft.
> + */
> +
> +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> + * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> + * don't want two different things trying to get to it at once. (e.g. the
> + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> + */
> +
> +unsigned char __nvram_read_byte(int i)
> +{
> + return CMOS_READ(NVRAM_FIRST_BYTE + i);
> +}
> +
> +unsigned char nvram_read_byte(int i)
> +{
> + unsigned long flags;
> + unsigned char c;
> +
> + spin_lock_irqsave(&rtc_lock, flags);
> + c = __nvram_read_byte(i);
> + spin_unlock_irqrestore(&rtc_lock, flags);
> + return c;
> +}
> +EXPORT_SYMBOL(nvram_read_byte);
> +
> +/* This races nicely with trying to read with checksum checking */
> +void __nvram_write_byte(unsigned char c, int i)
> +{
> + CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
> +}
> +
> +void nvram_write_byte(unsigned char c, int i)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&rtc_lock, flags);
> + __nvram_write_byte(c, i);
> + spin_unlock_irqrestore(&rtc_lock, flags);
> +}
> +
> +/* On Ataris, the checksum is over all bytes except the checksum bytes
> + * themselves; these are at the very end.
> + */
> +#define ATARI_CKS_RANGE_START 0
> +#define ATARI_CKS_RANGE_END 47
> +#define ATARI_CKS_LOC 48
> +
> +int __nvram_check_checksum(void)
> +{
> + int i;
> + unsigned char sum = 0;
> +
> + for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> + sum += __nvram_read_byte(i);
> + return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
> + (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
> +}
> +
> +int nvram_check_checksum(void)
> +{
> + unsigned long flags;
> + int rv;
> +
> + spin_lock_irqsave(&rtc_lock, flags);
> + rv = __nvram_check_checksum();
> + spin_unlock_irqrestore(&rtc_lock, flags);
> + return rv;
> +}
> +EXPORT_SYMBOL(nvram_check_checksum);
> +
> +static void __nvram_set_checksum(void)
> +{
> + int i;
> + unsigned char sum = 0;
> +
> + for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> + sum += __nvram_read_byte(i);
> + __nvram_write_byte(~sum, ATARI_CKS_LOC);
> + __nvram_write_byte(sum, ATARI_CKS_LOC + 1);
> +}
> +
> +#ifdef CONFIG_PROC_FS
> +static struct {
> + unsigned char val;
> + const char *name;
> +} boot_prefs[] = {
> + { 0x80, "TOS" },
> + { 0x40, "ASV" },
> + { 0x20, "NetBSD (?)" },
> + { 0x10, "Linux" },
> + { 0x00, "unspecified" },
> +};
> +
> +static const char * const languages[] = {
> + "English (US)",
> + "German",
> + "French",
> + "English (UK)",
> + "Spanish",
> + "Italian",
> + "6 (undefined)",
> + "Swiss (French)",
> + "Swiss (German)",
> +};
> +
> +static const char * const dateformat[] = {
> + "MM%cDD%cYY",
> + "DD%cMM%cYY",
> + "YY%cMM%cDD",
> + "YY%cDD%cMM",
> + "4 (undefined)",
> + "5 (undefined)",
> + "6 (undefined)",
> + "7 (undefined)",
> +};
> +
> +static const char * const colors[] = {
> + "2", "4", "16", "256", "65536", "??", "??", "??"
> +};
> +
> +static void atari_nvram_proc_read(unsigned char *nvram, struct
> seq_file *seq,
> + void *offset)
> +{
> + int checksum;
> + int i;
> + unsigned int vmode;
> +
> + spin_lock_irq(&rtc_lock);
> + checksum = __nvram_check_checksum();
> + spin_unlock_irq(&rtc_lock);
> +
> + seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not ");
> +
> + seq_puts(seq, "Boot preference : ");
> + for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i)
> + if (nvram[1] == boot_prefs[i].val) {
> + seq_printf(seq, "%s\n", boot_prefs[i].name);
> + break;
> + }
> + if (i < 0)
> + seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
> +
> + seq_printf(seq, "SCSI arbitration : %s\n",
> + (nvram[16] & 0x80) ? "on" : "off");
> + seq_puts(seq, "SCSI host ID : ");
> + if (nvram[16] & 0x80)
> + seq_printf(seq, "%d\n", nvram[16] & 7);
> + else
> + seq_puts(seq, "n/a\n");
> +
> + if (!MACH_IS_FALCON)
> + return;
> +
> + seq_puts(seq, "OS language : ");
> + if (nvram[6] < ARRAY_SIZE(languages))
> + seq_printf(seq, "%s\n", languages[nvram[6]]);
> + else
> + seq_printf(seq, "%u (undefined)\n", nvram[6]);
> + seq_puts(seq, "Keyboard language: ");
> + if (nvram[7] < ARRAY_SIZE(languages))
> + seq_printf(seq, "%s\n", languages[nvram[7]]);
> + else
> + seq_printf(seq, "%u (undefined)\n", nvram[7]);
> + seq_puts(seq, "Date format : ");
> + seq_printf(seq, dateformat[nvram[8] & 7],
> + nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
> + seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
> + seq_puts(seq, "Boot delay : ");
> + if (nvram[10] == 0)
> + seq_puts(seq, "default");
> + else
> + seq_printf(seq, "%ds%s\n", nvram[10],
> + nvram[10] < 8 ? ", no memory test" : "");
> +
> + vmode = (nvram[14] << 8) | nvram[15];
> + seq_printf(seq,
> + "Video mode : %s colors, %d columns, %s %s monitor\n",
> + colors[vmode & 7], vmode & 8 ? 80 : 40,
> + vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
> + seq_printf(seq,
> + " %soverscan, compat. mode %s%s\n",
> + vmode & 64 ? "" : "no ", vmode & 128 ? "on" : "off",
> + vmode & 256 ?
> + (vmode & 16 ? ", line doubling" : ", half screen") : "");
> +}
> +
> +static int nvram_proc_read(struct seq_file *seq, void *offset)
> +{
> + unsigned char contents[NVRAM_BYTES];
> + int i;
> +
> + spin_lock_irq(&rtc_lock);
> + for (i = 0; i < NVRAM_BYTES; ++i)
> + contents[i] = __nvram_read_byte(i);
> + spin_unlock_irq(&rtc_lock);
> +
> + atari_nvram_proc_read(contents, seq, offset);
> +
> + return 0;
> +}
> +
> +static int __init atari_nvram_init(void)
> +{
> + if (!(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)))
> + return -ENODEV;
> +
> + if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
> + pr_err("nvram: can't create /proc/driver/nvram\n");
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +device_initcall(atari_nvram_init);
> +#endif /* CONFIG_PROC_FS */
> diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
> index 25264d65e716..a9d4652f9e90 100644
> --- a/drivers/char/nvram.c
> +++ b/drivers/char/nvram.c
> @@ -21,13 +21,6 @@
> * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
> * again; use with care!)
> *
> - * This file also provides some functions for other parts of the kernel that
> - * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
> - * Obviously this can be used only if this driver is always configured into
> - * the kernel and is not a module. Since the functions are used by
> some Atari
> - * drivers, this is the case on the Atari.
> - *
> - *
> * 1.1 Cesar Barros: SMP locking fixes
> * added changelog
> * 1.2 Erik Gilling: Cobalt Networks support
> @@ -39,64 +32,6 @@
>
> #include <linux/module.h>
> #include <linux/nvram.h>
> -
> -#define PC 1
> -#define ATARI 2
> -
> -/* select machine configuration */
> -#if defined(CONFIG_ATARI)
> -# define MACH ATARI
> -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
> /* and ?? */
> -# define MACH PC
> -#else
> -# error Cannot build nvram driver for this machine configuration.
> -#endif
> -
> -#if MACH == PC
> -
> -/* RTC in a PC */
> -#define CHECK_DRIVER_INIT() 1
> -
> -/* On PCs, the checksum is built only over bytes 2..31 */
> -#define PC_CKS_RANGE_START 2
> -#define PC_CKS_RANGE_END 31
> -#define PC_CKS_LOC 32
> -#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
> -
> -#define mach_check_checksum pc_check_checksum
> -#define mach_set_checksum pc_set_checksum
> -#define mach_proc_infos pc_proc_infos
> -
> -#endif
> -
> -#if MACH == ATARI
> -
> -/* Special parameters for RTC in Atari machines */
> -#include <asm/atarihw.h>
> -#include <asm/atariints.h>
> -#define RTC_PORT(x) (TT_RTC_BAS + 2*(x))
> -#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
> -
> -#define NVRAM_BYTES 50
> -
> -/* On Ataris, the checksum is over all bytes except the checksum bytes
> - * themselves; these are at the very end */
> -#define ATARI_CKS_RANGE_START 0
> -#define ATARI_CKS_RANGE_END 47
> -#define ATARI_CKS_LOC 48
> -
> -#define mach_check_checksum atari_check_checksum
> -#define mach_set_checksum atari_set_checksum
> -#define mach_proc_infos atari_proc_infos
> -
> -#endif
> -
> -/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> - * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> - * don't want two different things trying to get to it at once. (e.g. the
> - * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> - */
> -
> #include <linux/types.h>
> #include <linux/errno.h>
> #include <linux/miscdevice.h>
> @@ -120,12 +55,9 @@ static int nvram_open_mode; /* special open modes */
> #define NVRAM_WRITE 1 /* opened for writing (exclusive) */
> #define NVRAM_EXCL 2 /* opened with O_EXCL */
>
> -static int mach_check_checksum(void);
> -static void mach_set_checksum(void);
> -
> #ifdef CONFIG_PROC_FS
> -static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
> - void *offset);
> +static void pc_nvram_proc_read(unsigned char *contents, struct
> seq_file *seq,
> + void *offset);
> #endif
>
> /*
> @@ -139,6 +71,14 @@ static void mach_proc_infos(unsigned char
> *contents, struct seq_file *seq,
> * know about the RTC cruft.
> */
>
> +#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE)
> +
> +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> + * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> + * don't want two different things trying to get to it at once. (e.g. the
> + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> + */
> +
> unsigned char __nvram_read_byte(int i)
> {
> return CMOS_READ(NVRAM_FIRST_BYTE + i);
> @@ -174,9 +114,22 @@ void nvram_write_byte(unsigned char c, int i)
> }
> EXPORT_SYMBOL(nvram_write_byte);
>
> +/* On PCs, the checksum is built only over bytes 2..31 */
> +#define PC_CKS_RANGE_START 2
> +#define PC_CKS_RANGE_END 31
> +#define PC_CKS_LOC 32
> +
> int __nvram_check_checksum(void)
> {
> - return mach_check_checksum();
> + int i;
> + unsigned short sum = 0;
> + unsigned short expect;
> +
> + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> + sum += __nvram_read_byte(i);
> + expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
> + __nvram_read_byte(PC_CKS_LOC+1);
> + return (sum & 0xffff) == expect;
> }


I don't understand how this is part of the code move.
Does the pc specific checksum becomes the generic one ?

Christophe

> EXPORT_SYMBOL(__nvram_check_checksum);
>
> @@ -194,7 +147,13 @@ EXPORT_SYMBOL(nvram_check_checksum);
>
> static void __nvram_set_checksum(void)
> {
> - mach_set_checksum();
> + int i;
> + unsigned short sum = 0;
> +
> + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> + sum += __nvram_read_byte(i);
> + __nvram_write_byte(sum >> 8, PC_CKS_LOC);
> + __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
> }
>
> #if 0
> @@ -384,7 +343,7 @@ static int nvram_proc_read(struct seq_file *seq,
> void *offset)
> contents[i] = __nvram_read_byte(i);
> spin_unlock_irq(&rtc_lock);
>
> - mach_proc_infos(contents, seq, offset);
> + pc_nvram_proc_read(contents, seq, offset);
>
> return 0;
> }
> @@ -418,10 +377,6 @@ static int __init nvram_init(void)
> {
> int ret;
>
> - /* First test whether the driver should init at all */
> - if (!CHECK_DRIVER_INIT())
> - return -ENODEV;
> -
> ret = misc_register(&nvram_dev);
> if (ret) {
> printk(KERN_ERR "nvram: can't misc_register on minor=%d\n",
> @@ -451,36 +406,6 @@ static void __exit nvram_cleanup_module(void)
> module_init(nvram_init);
> module_exit(nvram_cleanup_module);
>
> -/*
> - * Machine specific functions
> - */
> -
> -#if MACH == PC
> -
> -static int pc_check_checksum(void)
> -{
> - int i;
> - unsigned short sum = 0;
> - unsigned short expect;
> -
> - for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> - sum += __nvram_read_byte(i);
> - expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
> - __nvram_read_byte(PC_CKS_LOC+1);
> - return (sum & 0xffff) == expect;
> -}
> -
> -static void pc_set_checksum(void)
> -{
> - int i;
> - unsigned short sum = 0;
> -
> - for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> - sum += __nvram_read_byte(i);
> - __nvram_write_byte(sum >> 8, PC_CKS_LOC);
> - __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
> -}
> -
> #ifdef CONFIG_PROC_FS
>
> static const char * const floppy_types[] = {
> @@ -495,8 +420,8 @@ static const char * const gfx_types[] = {
> "monochrome",
> };
>
> -static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq,
> - void *offset)
> +static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq,
> + void *offset)
> {
> int checksum;
> int type;
> @@ -557,143 +482,8 @@ static void pc_proc_infos(unsigned char
> *nvram, struct seq_file *seq,
>
> return;
> }
> -#endif
> -
> -#endif /* MACH == PC */
> -
> -#if MACH == ATARI
> -
> -static int atari_check_checksum(void)
> -{
> - int i;
> - unsigned char sum = 0;
> -
> - for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> - sum += __nvram_read_byte(i);
> - return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
> - (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
> -}
> -
> -static void atari_set_checksum(void)
> -{
> - int i;
> - unsigned char sum = 0;
> -
> - for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> - sum += __nvram_read_byte(i);
> - __nvram_write_byte(~sum, ATARI_CKS_LOC);
> - __nvram_write_byte(sum, ATARI_CKS_LOC + 1);
> -}
> -
> -#ifdef CONFIG_PROC_FS
> -
> -static struct {
> - unsigned char val;
> - const char *name;
> -} boot_prefs[] = {
> - { 0x80, "TOS" },
> - { 0x40, "ASV" },
> - { 0x20, "NetBSD (?)" },
> - { 0x10, "Linux" },
> - { 0x00, "unspecified" }
> -};
> -
> -static const char * const languages[] = {
> - "English (US)",
> - "German",
> - "French",
> - "English (UK)",
> - "Spanish",
> - "Italian",
> - "6 (undefined)",
> - "Swiss (French)",
> - "Swiss (German)"
> -};
> -
> -static const char * const dateformat[] = {
> - "MM%cDD%cYY",
> - "DD%cMM%cYY",
> - "YY%cMM%cDD",
> - "YY%cDD%cMM",
> - "4 (undefined)",
> - "5 (undefined)",
> - "6 (undefined)",
> - "7 (undefined)"
> -};
> -
> -static const char * const colors[] = {
> - "2", "4", "16", "256", "65536", "??", "??", "??"
> -};
> -
> -static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq,
> - void *offset)
> -{
> - int checksum = nvram_check_checksum();
> - int i;
> - unsigned vmode;
> -
> - seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not ");
> -
> - seq_printf(seq, "Boot preference : ");
> - for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) {
> - if (nvram[1] == boot_prefs[i].val) {
> - seq_printf(seq, "%s\n", boot_prefs[i].name);
> - break;
> - }
> - }
> - if (i < 0)
> - seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
> -
> - seq_printf(seq, "SCSI arbitration : %s\n",
> - (nvram[16] & 0x80) ? "on" : "off");
> - seq_printf(seq, "SCSI host ID : ");
> - if (nvram[16] & 0x80)
> - seq_printf(seq, "%d\n", nvram[16] & 7);
> - else
> - seq_printf(seq, "n/a\n");
> -
> - /* the following entries are defined only for the Falcon */
> - if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
> - return;
> -
> - seq_printf(seq, "OS language : ");
> - if (nvram[6] < ARRAY_SIZE(languages))
> - seq_printf(seq, "%s\n", languages[nvram[6]]);
> - else
> - seq_printf(seq, "%u (undefined)\n", nvram[6]);
> - seq_printf(seq, "Keyboard language: ");
> - if (nvram[7] < ARRAY_SIZE(languages))
> - seq_printf(seq, "%s\n", languages[nvram[7]]);
> - else
> - seq_printf(seq, "%u (undefined)\n", nvram[7]);
> - seq_printf(seq, "Date format : ");
> - seq_printf(seq, dateformat[nvram[8] & 7],
> - nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
> - seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
> - seq_printf(seq, "Boot delay : ");
> - if (nvram[10] == 0)
> - seq_printf(seq, "default");
> - else
> - seq_printf(seq, "%ds%s\n", nvram[10],
> - nvram[10] < 8 ? ", no memory test" : "");
> -
> - vmode = (nvram[14] << 8) | nvram[15];
> - seq_printf(seq,
> - "Video mode : %s colors, %d columns, %s %s monitor\n",
> - colors[vmode & 7],
> - vmode & 8 ? 80 : 40,
> - vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
> - seq_printf(seq, " %soverscan, compat. mode %s%s\n",
> - vmode & 64 ? "" : "no ",
> - vmode & 128 ? "on" : "off",
> - vmode & 256 ?
> - (vmode & 16 ? ", line doubling" : ", half screen") : "");
> -
> - return;
> -}
> -#endif
>
> -#endif /* MACH == ATARI */
> +#endif /* CONFIG_PROC_FS */
>
> MODULE_LICENSE("GPL");
> MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
> --
> 2.19.2



2018-12-29 11:51:42

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Fri, 28 Dec 2018, LEROY Christophe wrote:

> Finn Thain <[email protected]> a ?crit?:
>
> > On powerpc, setting CONFIG_NVRAM=n builds a kernel with no NVRAM support.
> > Setting CONFIG_NVRAM=m enables the /dev/nvram misc device module without
> > enabling NVRAM support in drivers. Setting CONFIG_NVRAM=y enables the
> > misc device (built-in) and also enables NVRAM support in drivers.
> >
> > m68k shares the valkyriefb driver with powerpc, and since that driver uses
> > NVRAM, it is affected by CONFIG_ATARI_SCSI, because of the use of
> > "select NVRAM".
> >
> > Adopt the powerpc convention on m68k to avoid surprises.
> >
> > Signed-off-by: Finn Thain <[email protected]>
> > Tested-by: Christian T. Steigies <[email protected]>
> > ---
> > This patch temporarily disables CONFIG_NVRAM on Atari, to prevent build
> > failures when bisecting the rest of this patch series. It gets enabled
> > again with the introduction of CONFIG_HAVE_ARCH_NVRAM_OPS, once the
> > nvram_* global functions have been moved to an ops struct.
> > ---
> > drivers/char/Kconfig | 5 +----
> > drivers/scsi/Kconfig | 6 +++---
> > drivers/scsi/atari_scsi.c | 7 ++++---
> > 3 files changed, 8 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> > index 9d03b2ff5df6..5b54595dfe30 100644
> > --- a/drivers/char/Kconfig
> > +++ b/drivers/char/Kconfig
> > @@ -236,7 +236,7 @@ source "drivers/char/hw_random/Kconfig"
> >
> > config NVRAM
> > tristate "/dev/nvram support"
> > - depends on ATARI || X86 || GENERIC_NVRAM
> > + depends on X86 || GENERIC_NVRAM
> > ---help---
> > If you say Y here and create a character special file /dev/nvram
> > with major number 10 and minor number 144 using mknod ("man mknod"),
> > @@ -254,9 +254,6 @@ config NVRAM
> > should NEVER idly tamper with it. See Ralf Brown's interrupt list
> > for a guide to the use of CMOS bytes by your BIOS.
> >
> > - On Atari machines, /dev/nvram is always configured and does not need
> > - to be selected.
> > -
> > To compile this driver as a module, choose M here: the
> > module will be called nvram.
> >
> > diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
> > index 640cd1b31a18..924eb69e7fc4 100644
> > --- a/drivers/scsi/Kconfig
> > +++ b/drivers/scsi/Kconfig
> > @@ -1381,14 +1381,14 @@ config ATARI_SCSI
> > tristate "Atari native SCSI support"
> > depends on ATARI && SCSI
> > select SCSI_SPI_ATTRS
> > - select NVRAM
> > ---help---
> > If you have an Atari with built-in NCR5380 SCSI controller (TT,
> > Falcon, ...) say Y to get it supported. Of course also, if you have
> > a compatible SCSI controller (e.g. for Medusa).
> >
> > - To compile this driver as a module, choose M here: the
> > - module will be called atari_scsi.
> > + To compile this driver as a module, choose M here: the module will
> > + be called atari_scsi. If you also enable NVRAM support, the SCSI
> > + host's ID is taken from the setting in TT RTC NVRAM.
> >
> > This driver supports both styles of NCR integration into the
> > system: the TT style (separate DMA), and the Falcon style (via
> > diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
> > index 89f5154c40b6..99e5729d910d 100644
> > --- a/drivers/scsi/atari_scsi.c
> > +++ b/drivers/scsi/atari_scsi.c
> > @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct
> > platform_device *pdev)
> > if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
> > atari_scsi_template.sg_tablesize = setup_sg_tablesize;
> >
> > - if (setup_hostid >= 0) {
> > + if (setup_hostid >= 0)
> > atari_scsi_template.this_id = setup_hostid & 7;
> > - } else {
> > +#ifdef CONFIG_NVRAM
> > + else
>
> Such ifdefs should be avoided in C files.
> It would be better to use
>
> } else if (IS_ENABLED(CONFIG_NVRAM)) {
>

I don't like #ifdefs either. However, as the maintainer of this file, I am
okay with this one.

The old #ifdef CONFIG_NVRAM conditional compilation convention that gets
used here and under drivers/video/fbdev could probably be improved upon
but I consider this to be out-of-scope for this series, which is
complicated enough.

And as explained in the commit log, CONFIG_NVRAM=y and CONFIG_NVRAM=m are
treaded differently by drivers. Therefore, IS_ENABLED would be incorrect.

--

> > /* Test if a host id is set in the NVRam */
> > if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
> > unsigned char b = nvram_read_byte(16);
> > @@ -768,7 +769,7 @@ static int __init atari_scsi_probe(struct
> > platform_device *pdev)
> > if (b & 0x80)
> > atari_scsi_template.this_id = b & 7;
> > }
> > - }
> > +#endif
> >
> > /* If running on a Falcon and if there's TT-Ram (i.e., more than one
> > * memory block, since there's always ST-Ram in a Falcon), then
> > --
> > 2.19.2
>
>
>

2018-12-29 12:42:55

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 02/25] m68k/atari: Move Atari-specific code out of drivers/char/nvram.c

On Fri, 28 Dec 2018, LEROY Christophe wrote:

> Finn Thain <[email protected]> a ?crit?:
>
> > Move the m68k-specific code out of the driver to make the driver generic.
> >
> > I've used 'SPDX-License-Identifier: GPL-2.0+' for the new file because the
> > old file is covered by MODULE_LICENSE("GPL").
> >
> > Signed-off-by: Finn Thain <[email protected]>
> > Tested-by: Christian T. Steigies <[email protected]>
> > Acked-by: Geert Uytterhoeven <[email protected]>
> > ---
> > Changed since v7:
> > - Added SPDX-License-Identifier.
> > ---
> > arch/m68k/atari/Makefile | 2 +
> > arch/m68k/atari/nvram.c | 243 +++++++++++++++++++++++++++++++++
> > drivers/char/nvram.c | 280 +++++----------------------------------
> > 3 files changed, 280 insertions(+), 245 deletions(-)
> > create mode 100644 arch/m68k/atari/nvram.c
> >
> > diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
> > index 0cac723306f9..0b86bb6cfa87 100644
> > --- a/arch/m68k/atari/Makefile
> > +++ b/arch/m68k/atari/Makefile
> > @@ -6,3 +6,5 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \
> > atasound.o stram.o
> >
> > obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
> > +
> > +obj-$(CONFIG_NVRAM:m=y) += nvram.o
> > diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c
> > new file mode 100644
> > index 000000000000..3e620ee955ba
> > --- /dev/null
> > +++ b/arch/m68k/atari/nvram.c
> > @@ -0,0 +1,243 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * CMOS/NV-RAM driver for Atari. Adapted from drivers/char/nvram.c.
> > + * Copyright (C) 1997 Roman Hodek <[email protected]>
> > + * idea by and with help from Richard Jelinek <[email protected]>
> > + * Portions copyright (c) 2001,2002 Sun Microsystems ([email protected])
> > + * Further contributions from Cesar Barros, Erik Gilling, Tim Hockin and
> > + * Wim Van Sebroeck.
> > + */
> > +
> > +#include <linux/errno.h>
> > +#include <linux/init.h>
> > +#include <linux/mc146818rtc.h>
> > +#include <linux/module.h>
> > +#include <linux/nvram.h>
> > +#include <linux/proc_fs.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/types.h>
> > +#include <asm/atarihw.h>
> > +#include <asm/atariints.h>
> > +
> > +#define NVRAM_BYTES 50
> > +
> > +/* It is worth noting that these functions all access bytes of general
> > + * purpose memory in the NVRAM - that is to say, they all add the
> > + * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not
> > + * know about the RTC cruft.
> > + */
> > +
> > +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> > + * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> > + * don't want two different things trying to get to it at once. (e.g. the
> > + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> > + */
> > +
> > +unsigned char __nvram_read_byte(int i)
> > +{
> > + return CMOS_READ(NVRAM_FIRST_BYTE + i);
> > +}
> > +
> > +unsigned char nvram_read_byte(int i)
> > +{
> > + unsigned long flags;
> > + unsigned char c;
> > +
> > + spin_lock_irqsave(&rtc_lock, flags);
> > + c = __nvram_read_byte(i);
> > + spin_unlock_irqrestore(&rtc_lock, flags);
> > + return c;
> > +}
> > +EXPORT_SYMBOL(nvram_read_byte);
> > +
> > +/* This races nicely with trying to read with checksum checking */
> > +void __nvram_write_byte(unsigned char c, int i)
> > +{
> > + CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
> > +}
> > +
> > +void nvram_write_byte(unsigned char c, int i)
> > +{
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&rtc_lock, flags);
> > + __nvram_write_byte(c, i);
> > + spin_unlock_irqrestore(&rtc_lock, flags);
> > +}
> > +
> > +/* On Ataris, the checksum is over all bytes except the checksum bytes
> > + * themselves; these are at the very end.
> > + */
> > +#define ATARI_CKS_RANGE_START 0
> > +#define ATARI_CKS_RANGE_END 47
> > +#define ATARI_CKS_LOC 48
> > +
> > +int __nvram_check_checksum(void)
> > +{
> > + int i;
> > + unsigned char sum = 0;
> > +
> > + for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> > + sum += __nvram_read_byte(i);
> > + return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
> > + (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
> > +}
> > +
> > +int nvram_check_checksum(void)
> > +{
> > + unsigned long flags;
> > + int rv;
> > +
> > + spin_lock_irqsave(&rtc_lock, flags);
> > + rv = __nvram_check_checksum();
> > + spin_unlock_irqrestore(&rtc_lock, flags);
> > + return rv;
> > +}
> > +EXPORT_SYMBOL(nvram_check_checksum);
> > +
> > +static void __nvram_set_checksum(void)
> > +{
> > + int i;
> > + unsigned char sum = 0;
> > +
> > + for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
> > + sum += __nvram_read_byte(i);
> > + __nvram_write_byte(~sum, ATARI_CKS_LOC);
> > + __nvram_write_byte(sum, ATARI_CKS_LOC + 1);
> > +}
> > +
> > +#ifdef CONFIG_PROC_FS
> > +static struct {
> > + unsigned char val;
> > + const char *name;
> > +} boot_prefs[] = {
> > + { 0x80, "TOS" },
> > + { 0x40, "ASV" },
> > + { 0x20, "NetBSD (?)" },
> > + { 0x10, "Linux" },
> > + { 0x00, "unspecified" },
> > +};
> > +
> > +static const char * const languages[] = {
> > + "English (US)",
> > + "German",
> > + "French",
> > + "English (UK)",
> > + "Spanish",
> > + "Italian",
> > + "6 (undefined)",
> > + "Swiss (French)",
> > + "Swiss (German)",
> > +};
> > +
> > +static const char * const dateformat[] = {
> > + "MM%cDD%cYY",
> > + "DD%cMM%cYY",
> > + "YY%cMM%cDD",
> > + "YY%cDD%cMM",
> > + "4 (undefined)",
> > + "5 (undefined)",
> > + "6 (undefined)",
> > + "7 (undefined)",
> > +};
> > +
> > +static const char * const colors[] = {
> > + "2", "4", "16", "256", "65536", "??", "??", "??"
> > +};
> > +
> > +static void atari_nvram_proc_read(unsigned char *nvram, struct
> > seq_file *seq,
> > + void *offset)
> > +{
> > + int checksum;
> > + int i;
> > + unsigned int vmode;
> > +
> > + spin_lock_irq(&rtc_lock);
> > + checksum = __nvram_check_checksum();
> > + spin_unlock_irq(&rtc_lock);
> > +
> > + seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not ");
> > +
> > + seq_puts(seq, "Boot preference : ");
> > + for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i)
> > + if (nvram[1] == boot_prefs[i].val) {
> > + seq_printf(seq, "%s\n", boot_prefs[i].name);
> > + break;
> > + }
> > + if (i < 0)
> > + seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
> > +
> > + seq_printf(seq, "SCSI arbitration : %s\n",
> > + (nvram[16] & 0x80) ? "on" : "off");
> > + seq_puts(seq, "SCSI host ID : ");
> > + if (nvram[16] & 0x80)
> > + seq_printf(seq, "%d\n", nvram[16] & 7);
> > + else
> > + seq_puts(seq, "n/a\n");
> > +
> > + if (!MACH_IS_FALCON)
> > + return;
> > +
> > + seq_puts(seq, "OS language : ");
> > + if (nvram[6] < ARRAY_SIZE(languages))
> > + seq_printf(seq, "%s\n", languages[nvram[6]]);
> > + else
> > + seq_printf(seq, "%u (undefined)\n", nvram[6]);
> > + seq_puts(seq, "Keyboard language: ");
> > + if (nvram[7] < ARRAY_SIZE(languages))
> > + seq_printf(seq, "%s\n", languages[nvram[7]]);
> > + else
> > + seq_printf(seq, "%u (undefined)\n", nvram[7]);
> > + seq_puts(seq, "Date format : ");
> > + seq_printf(seq, dateformat[nvram[8] & 7],
> > + nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
> > + seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
> > + seq_puts(seq, "Boot delay : ");
> > + if (nvram[10] == 0)
> > + seq_puts(seq, "default");
> > + else
> > + seq_printf(seq, "%ds%s\n", nvram[10],
> > + nvram[10] < 8 ? ", no memory test" : "");
> > +
> > + vmode = (nvram[14] << 8) | nvram[15];
> > + seq_printf(seq,
> > + "Video mode : %s colors, %d columns, %s %s monitor\n",
> > + colors[vmode & 7], vmode & 8 ? 80 : 40,
> > + vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
> > + seq_printf(seq,
> > + " %soverscan, compat. mode %s%s\n",
> > + vmode & 64 ? "" : "no ", vmode & 128 ? "on" : "off",
> > + vmode & 256 ?
> > + (vmode & 16 ? ", line doubling" : ", half screen") : "");
> > +}
> > +
> > +static int nvram_proc_read(struct seq_file *seq, void *offset)
> > +{
> > + unsigned char contents[NVRAM_BYTES];
> > + int i;
> > +
> > + spin_lock_irq(&rtc_lock);
> > + for (i = 0; i < NVRAM_BYTES; ++i)
> > + contents[i] = __nvram_read_byte(i);
> > + spin_unlock_irq(&rtc_lock);
> > +
> > + atari_nvram_proc_read(contents, seq, offset);
> > +
> > + return 0;
> > +}
> > +
> > +static int __init atari_nvram_init(void)
> > +{
> > + if (!(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)))
> > + return -ENODEV;
> > +
> > + if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
> > + pr_err("nvram: can't create /proc/driver/nvram\n");
> > + return -ENOMEM;
> > + }
> > +
> > + return 0;
> > +}
> > +device_initcall(atari_nvram_init);
> > +#endif /* CONFIG_PROC_FS */
> > diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
> > index 25264d65e716..a9d4652f9e90 100644
> > --- a/drivers/char/nvram.c
> > +++ b/drivers/char/nvram.c
> > @@ -21,13 +21,6 @@
> > * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
> > * again; use with care!)
> > *
> > - * This file also provides some functions for other parts of the kernel that
> > - * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
> > - * Obviously this can be used only if this driver is always configured into
> > - * the kernel and is not a module. Since the functions are used by
> > some Atari
> > - * drivers, this is the case on the Atari.
> > - *
> > - *
> > * 1.1 Cesar Barros: SMP locking fixes
> > * added changelog
> > * 1.2 Erik Gilling: Cobalt Networks support
> > @@ -39,64 +32,6 @@
> >
> > #include <linux/module.h>
> > #include <linux/nvram.h>
> > -
> > -#define PC 1
> > -#define ATARI 2
> > -
> > -/* select machine configuration */
> > -#if defined(CONFIG_ATARI)
> > -# define MACH ATARI
> > -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
> > /* and ?? */
> > -# define MACH PC
> > -#else
> > -# error Cannot build nvram driver for this machine configuration.
> > -#endif
> > -
> > -#if MACH == PC
> > -
> > -/* RTC in a PC */
> > -#define CHECK_DRIVER_INIT() 1
> > -
> > -/* On PCs, the checksum is built only over bytes 2..31 */
> > -#define PC_CKS_RANGE_START 2
> > -#define PC_CKS_RANGE_END 31
> > -#define PC_CKS_LOC 32
> > -#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
> > -
> > -#define mach_check_checksum pc_check_checksum
> > -#define mach_set_checksum pc_set_checksum
> > -#define mach_proc_infos pc_proc_infos
> > -
> > -#endif
> > -
> > -#if MACH == ATARI
> > -
> > -/* Special parameters for RTC in Atari machines */
> > -#include <asm/atarihw.h>
> > -#include <asm/atariints.h>
> > -#define RTC_PORT(x) (TT_RTC_BAS + 2*(x))
> > -#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
> > -
> > -#define NVRAM_BYTES 50
> > -
> > -/* On Ataris, the checksum is over all bytes except the checksum bytes
> > - * themselves; these are at the very end */
> > -#define ATARI_CKS_RANGE_START 0
> > -#define ATARI_CKS_RANGE_END 47
> > -#define ATARI_CKS_LOC 48
> > -
> > -#define mach_check_checksum atari_check_checksum
> > -#define mach_set_checksum atari_set_checksum
> > -#define mach_proc_infos atari_proc_infos
> > -
> > -#endif
> > -
> > -/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> > - * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> > - * don't want two different things trying to get to it at once. (e.g. the
> > - * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> > - */
> > -
> > #include <linux/types.h>
> > #include <linux/errno.h>
> > #include <linux/miscdevice.h>
> > @@ -120,12 +55,9 @@ static int nvram_open_mode; /* special open modes */
> > #define NVRAM_WRITE 1 /* opened for writing (exclusive) */
> > #define NVRAM_EXCL 2 /* opened with O_EXCL */
> >
> > -static int mach_check_checksum(void);
> > -static void mach_set_checksum(void);
> > -
> > #ifdef CONFIG_PROC_FS
> > -static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
> > - void *offset);
> > +static void pc_nvram_proc_read(unsigned char *contents, struct
> > seq_file *seq,
> > + void *offset);
> > #endif
> >
> > /*
> > @@ -139,6 +71,14 @@ static void mach_proc_infos(unsigned char
> > *contents, struct seq_file *seq,
> > * know about the RTC cruft.
> > */
> >
> > +#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE)
> > +
> > +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> > + * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> > + * don't want two different things trying to get to it at once. (e.g. the
> > + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> > + */
> > +
> > unsigned char __nvram_read_byte(int i)
> > {
> > return CMOS_READ(NVRAM_FIRST_BYTE + i);
> > @@ -174,9 +114,22 @@ void nvram_write_byte(unsigned char c, int i)
> > }
> > EXPORT_SYMBOL(nvram_write_byte);
> >
> > +/* On PCs, the checksum is built only over bytes 2..31 */
> > +#define PC_CKS_RANGE_START 2
> > +#define PC_CKS_RANGE_END 31
> > +#define PC_CKS_LOC 32
> > +
> > int __nvram_check_checksum(void)
> > {
> > - return mach_check_checksum();
> > + int i;
> > + unsigned short sum = 0;
> > + unsigned short expect;
> > +
> > + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> > + sum += __nvram_read_byte(i);
> > + expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
> > + __nvram_read_byte(PC_CKS_LOC+1);
> > + return (sum & 0xffff) == expect;
> > }
>
>
> I don't understand how this is part of the code move.
> Does the pc specific checksum becomes the generic one ?
>

This is not generic code, of course. Please refer to the two patches that
follow this one, in which all of the x86-specific code gets wrapped with
#ifdef CONFIG_X86.

This code gets moved because the MACH macro is made redundant. You might
defer this code motion to patch 4 or patch 5 but I don't see that as being
an improvement.

You may want to take a look at the final generic implementation of
drivers/char/nvram.c, which can be seen here:
https://github.com/fthain/linux/blob/0949c1b7bd8b9d0034e77601a9af73c712d26d4a/drivers/char/nvram.c

You may also find it helpful to look at this whole series in the form of a
single diff, to reveal the effect on this file. I think you'll agree that
the overall effect on this file is a dramatic improvement.

You may argue that there should be no CONFIG_X86 code in drivers/char.
Sure, that would be nice. However, if you grep for CMOS_READ|CMOS_WRITE
you'll see that the problem is much bigger than drivers/char/nvram.c.
Perhaps the next best place for the x86-specific code here is
drivers/rtc/rtc-cmos.c where you can already find #ifdef CONFIG_X86.

Anyway, I consider the CMOS_READ|CMOS_WRITE issue to be out-of-scope,
though hopefully this patch series does untangle it a little.

--

2018-12-29 12:48:12

by Michael Schmitz

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Hi Finn,

Am 29.12.2018 um 14:06 schrieb Finn Thain:
> On Fri, 28 Dec 2018, LEROY Christophe wrote:
>>> diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
>>> index 89f5154c40b6..99e5729d910d 100644
>>> --- a/drivers/scsi/atari_scsi.c
>>> +++ b/drivers/scsi/atari_scsi.c
>>> @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct
>>> platform_device *pdev)
>>> if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
>>> atari_scsi_template.sg_tablesize = setup_sg_tablesize;
>>>
>>> - if (setup_hostid >= 0) {
>>> + if (setup_hostid >= 0)
>>> atari_scsi_template.this_id = setup_hostid & 7;
>>> - } else {
>>> +#ifdef CONFIG_NVRAM
>>> + else
>>
>> Such ifdefs should be avoided in C files.
>> It would be better to use
>>
>> } else if (IS_ENABLED(CONFIG_NVRAM)) {
>>
>
> I don't like #ifdefs either. However, as the maintainer of this file, I am
> okay with this one.
>
> The old #ifdef CONFIG_NVRAM conditional compilation convention that gets
> used here and under drivers/video/fbdev could probably be improved upon
> but I consider this to be out-of-scope for this series, which is
> complicated enough.
>
> And as explained in the commit log, CONFIG_NVRAM=y and CONFIG_NVRAM=m are
> treaded differently by drivers. Therefore, IS_ENABLED would be incorrect.

IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to
suggest.

Or (really going out on a limb here):

IS_BUILTIN(CONFIG_NVRAM) ||
( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )

Not that I'd advocate that, for this series.

Cheers,

Michael




2018-12-29 12:48:56

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Sat, 29 Dec 2018, Michael Schmitz wrote:

>
> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to suggest.
>
> Or (really going out on a limb here):
>
> IS_BUILTIN(CONFIG_NVRAM) ||
> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
>
> Not that I'd advocate that, for this series.
>

Well, you are a maintainer for atari_scsi.c.

Are you saying that you want IS_BUILTIN(CONFIG_NVRAM) used here instead of
ifdef?

OTOH, if you approve of the existing patch, please send your acked-by.

--

> Cheers,
>
> Michael
>
>
>
>

2018-12-29 12:49:56

by Michael Schmitz

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Hi Finn,

Am 29.12.2018 um 15:34 schrieb Finn Thain:
> On Sat, 29 Dec 2018, Michael Schmitz wrote:
>
>>
>> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to suggest.
>>
>> Or (really going out on a limb here):
>>
>> IS_BUILTIN(CONFIG_NVRAM) ||
>> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
>>
>> Not that I'd advocate that, for this series.
>>
>
> Well, you are a maintainer for atari_scsi.c.
>
> Are you saying that you want IS_BUILTIN(CONFIG_NVRAM) used here instead of
> ifdef?

No, just pointing out that there would be a way to avoid the ifdef
without messing up driver behaviour. I'm fine with the ifdef - not least
because it clearly eliminates code that would be unreachable.

(On second thought - I don't want to speculate whether there's weird
compiler options that could result in the nvram_check_checksum and
nvram_read_bytes symbols to still be referenced in the final link, even
though IS_BUILTIN(CONFIG_NVRAM) always evaluates to false. Best leave
this as-is.)

> OTOH, if you approve of the existing patch, please send your acked-by.

Of course - I'd seen Geert's acked-by on some of the patches and forgot
to check which still required acks.

Cheers,

Michael



2018-12-29 12:50:08

by Michael Schmitz

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Hi Finn,

Am 26.12.2018 um 13:37 schrieb Finn Thain:
> On powerpc, setting CONFIG_NVRAM=n builds a kernel with no NVRAM support.
> Setting CONFIG_NVRAM=m enables the /dev/nvram misc device module without
> enabling NVRAM support in drivers. Setting CONFIG_NVRAM=y enables the
> misc device (built-in) and also enables NVRAM support in drivers.
>
> m68k shares the valkyriefb driver with powerpc, and since that driver uses
> NVRAM, it is affected by CONFIG_ATARI_SCSI, because of the use of
> "select NVRAM".
>
> Adopt the powerpc convention on m68k to avoid surprises.
>
> Signed-off-by: Finn Thain <[email protected]>
> Tested-by: Christian T. Steigies <[email protected]>

Acked-by: Michael Schmitz <[email protected]>

> ---
> This patch temporarily disables CONFIG_NVRAM on Atari, to prevent build
> failures when bisecting the rest of this patch series. It gets enabled
> again with the introduction of CONFIG_HAVE_ARCH_NVRAM_OPS, once the
> nvram_* global functions have been moved to an ops struct.
> ---
> drivers/char/Kconfig | 5 +----
> drivers/scsi/Kconfig | 6 +++---
> drivers/scsi/atari_scsi.c | 7 ++++---
> 3 files changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 9d03b2ff5df6..5b54595dfe30 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -236,7 +236,7 @@ source "drivers/char/hw_random/Kconfig"
>
> config NVRAM
> tristate "/dev/nvram support"
> - depends on ATARI || X86 || GENERIC_NVRAM
> + depends on X86 || GENERIC_NVRAM
> ---help---
> If you say Y here and create a character special file /dev/nvram
> with major number 10 and minor number 144 using mknod ("man mknod"),
> @@ -254,9 +254,6 @@ config NVRAM
> should NEVER idly tamper with it. See Ralf Brown's interrupt list
> for a guide to the use of CMOS bytes by your BIOS.
>
> - On Atari machines, /dev/nvram is always configured and does not need
> - to be selected.
> -
> To compile this driver as a module, choose M here: the
> module will be called nvram.
>
> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
> index 640cd1b31a18..924eb69e7fc4 100644
> --- a/drivers/scsi/Kconfig
> +++ b/drivers/scsi/Kconfig
> @@ -1381,14 +1381,14 @@ config ATARI_SCSI
> tristate "Atari native SCSI support"
> depends on ATARI && SCSI
> select SCSI_SPI_ATTRS
> - select NVRAM
> ---help---
> If you have an Atari with built-in NCR5380 SCSI controller (TT,
> Falcon, ...) say Y to get it supported. Of course also, if you have
> a compatible SCSI controller (e.g. for Medusa).
>
> - To compile this driver as a module, choose M here: the
> - module will be called atari_scsi.
> + To compile this driver as a module, choose M here: the module will
> + be called atari_scsi. If you also enable NVRAM support, the SCSI
> + host's ID is taken from the setting in TT RTC NVRAM.
>
> This driver supports both styles of NCR integration into the
> system: the TT style (separate DMA), and the Falcon style (via
> diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
> index 89f5154c40b6..99e5729d910d 100644
> --- a/drivers/scsi/atari_scsi.c
> +++ b/drivers/scsi/atari_scsi.c
> @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
> if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
> atari_scsi_template.sg_tablesize = setup_sg_tablesize;
>
> - if (setup_hostid >= 0) {
> + if (setup_hostid >= 0)
> atari_scsi_template.this_id = setup_hostid & 7;
> - } else {
> +#ifdef CONFIG_NVRAM
> + else
> /* Test if a host id is set in the NVRam */
> if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
> unsigned char b = nvram_read_byte(16);
> @@ -768,7 +769,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
> if (b & 0x80)
> atari_scsi_template.this_id = b & 7;
> }
> - }
> +#endif
>
> /* If running on a Falcon and if there's TT-Ram (i.e., more than one
> * memory block, since there's always ST-Ram in a Falcon), then
>

2018-12-30 00:23:56

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Michael Schmitz <[email protected]> a écrit :

> Hi Finn,
>
> Am 29.12.2018 um 14:06 schrieb Finn Thain:
>> On Fri, 28 Dec 2018, LEROY Christophe wrote:
>>>> diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
>>>> index 89f5154c40b6..99e5729d910d 100644
>>>> --- a/drivers/scsi/atari_scsi.c
>>>> +++ b/drivers/scsi/atari_scsi.c
>>>> @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct
>>>> platform_device *pdev)
>>>> if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
>>>> atari_scsi_template.sg_tablesize = setup_sg_tablesize;
>>>>
>>>> - if (setup_hostid >= 0) {
>>>> + if (setup_hostid >= 0)
>>>> atari_scsi_template.this_id = setup_hostid & 7;
>>>> - } else {
>>>> +#ifdef CONFIG_NVRAM
>>>> + else
>>>
>>> Such ifdefs should be avoided in C files.
>>> It would be better to use
>>>
>>> } else if (IS_ENABLED(CONFIG_NVRAM)) {
>>>
>>
>> I don't like #ifdefs either. However, as the maintainer of this file, I am
>> okay with this one.
>>
>> The old #ifdef CONFIG_NVRAM conditional compilation convention that gets
>> used here and under drivers/video/fbdev could probably be improved upon
>> but I consider this to be out-of-scope for this series, which is
>> complicated enough.
>>
>> And as explained in the commit log, CONFIG_NVRAM=y and CONFIG_NVRAM=m are
>> treaded differently by drivers. Therefore, IS_ENABLED would be incorrect.
>
> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to suggest.

Doesn't #ifdef means either y or m ? So the same as IS_ENABLED() ?

Christophe

>
> Or (really going out on a limb here):
>
> IS_BUILTIN(CONFIG_NVRAM) ||
> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
>
> Not that I'd advocate that, for this series.
>
> Cheers,
>
> Michael



2018-12-30 00:23:56

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

Finn Thain <[email protected]> a écrit :

> Make use of arch_nvram_ops in device drivers so that the nvram_* function
> exports can be removed.
>
> Since they are no longer global symbols, rename the PPC32 nvram_* functions
> appropriately.
>
> Signed-off-by: Finn Thain <[email protected]>
> ---
> arch/powerpc/kernel/setup_32.c | 8 ++++----
> drivers/char/generic_nvram.c | 4 ++--
> drivers/video/fbdev/controlfb.c | 4 ++--
> drivers/video/fbdev/imsttfb.c | 4 ++--
> drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
> drivers/video/fbdev/platinumfb.c | 4 ++--
> drivers/video/fbdev/valkyriefb.c | 4 ++--
> 7 files changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
> index e0d045677472..bdbe6acbef11 100644
> --- a/arch/powerpc/kernel/setup_32.c
> +++ b/arch/powerpc/kernel/setup_32.c
> @@ -152,20 +152,18 @@ __setup("l3cr=", ppc_setup_l3cr);
>
> #ifdef CONFIG_GENERIC_NVRAM
>
> -unsigned char nvram_read_byte(int addr)
> +static unsigned char ppc_nvram_read_byte(int addr)
> {
> if (ppc_md.nvram_read_val)
> return ppc_md.nvram_read_val(addr);
> return 0xff;
> }
> -EXPORT_SYMBOL(nvram_read_byte);
>
> -void nvram_write_byte(unsigned char val, int addr)
> +static void ppc_nvram_write_byte(unsigned char val, int addr)
> {
> if (ppc_md.nvram_write_val)
> ppc_md.nvram_write_val(addr, val);
> }
> -EXPORT_SYMBOL(nvram_write_byte);
>
> static ssize_t ppc_nvram_get_size(void)
> {
> @@ -182,6 +180,8 @@ static long ppc_nvram_sync(void)
> }
>
> const struct nvram_ops arch_nvram_ops = {
> + .read_byte = ppc_nvram_read_byte,
> + .write_byte = ppc_nvram_write_byte,
> .get_size = ppc_nvram_get_size,
> .sync = ppc_nvram_sync,
> };
> diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
> index f32d5663de95..41b76bf9614e 100644
> --- a/drivers/char/generic_nvram.c
> +++ b/drivers/char/generic_nvram.c
> @@ -48,7 +48,7 @@ static ssize_t read_nvram(struct file *file, char
> __user *buf,
> if (*ppos >= nvram_len)
> return 0;
> for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
> - if (__put_user(nvram_read_byte(i), p))
> + if (__put_user(arch_nvram_ops.read_byte(i), p))

Instead of modifying all drivers (in this patch and previous ones
related to other arches), wouldn't it be better to add helpers like
the following in nvram.h:

Static inline unsigned char nvram_read_byte(int addr)
{
return arch_nvram_ops.read_byte(addr);
}

Christophe

> return -EFAULT;
> *ppos = i;
> return p - buf;
> @@ -68,7 +68,7 @@ static ssize_t write_nvram(struct file *file,
> const char __user *buf,
> for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
> if (__get_user(c, p))
> return -EFAULT;
> - nvram_write_byte(c, i);
> + arch_nvram_ops.write_byte(c, i);
> }
> *ppos = i;
> return p - buf;
> diff --git a/drivers/video/fbdev/controlfb.c
> b/drivers/video/fbdev/controlfb.c
> index 9cb0ef7ac29e..27ff33ccafcb 100644
> --- a/drivers/video/fbdev/controlfb.c
> +++ b/drivers/video/fbdev/controlfb.c
> @@ -413,7 +413,7 @@ static int __init init_control(struct fb_info_control *p)
> /* Try to pick a video mode out of NVRAM if we have one. */
> #ifdef CONFIG_NVRAM
> if (default_cmode == CMODE_NVRAM) {
> - cmode = nvram_read_byte(NV_CMODE);
> + cmode = arch_nvram_ops.read_byte(NV_CMODE);
> if(cmode < CMODE_8 || cmode > CMODE_32)
> cmode = CMODE_8;
> } else
> @@ -421,7 +421,7 @@ static int __init init_control(struct fb_info_control *p)
> cmode=default_cmode;
> #ifdef CONFIG_NVRAM
> if (default_vmode == VMODE_NVRAM) {
> - vmode = nvram_read_byte(NV_VMODE);
> + vmode = arch_nvram_ops.read_byte(NV_VMODE);
> if (vmode < 1 || vmode > VMODE_MAX ||
> control_mac_modes[vmode - 1].m[full] < cmode) {
> sense = read_control_sense(p);
> diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
> index 8d231591ff0e..e9f3b8914145 100644
> --- a/drivers/video/fbdev/imsttfb.c
> +++ b/drivers/video/fbdev/imsttfb.c
> @@ -1393,12 +1393,12 @@ static void init_imstt(struct fb_info *info)
> int vmode = init_vmode, cmode = init_cmode;
>
> if (vmode == -1) {
> - vmode = nvram_read_byte(NV_VMODE);
> + vmode = arch_nvram_ops.read_byte(NV_VMODE);
> if (vmode <= 0 || vmode > VMODE_MAX)
> vmode = VMODE_640_480_67;
> }
> if (cmode == -1) {
> - cmode = nvram_read_byte(NV_CMODE);
> + cmode = arch_nvram_ops.read_byte(NV_CMODE);
> if (cmode < CMODE_8 || cmode > CMODE_32)
> cmode = CMODE_8;
> }
> diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c
> b/drivers/video/fbdev/matrox/matroxfb_base.c
> index cac5865d461c..3fecc628752c 100644
> --- a/drivers/video/fbdev/matrox/matroxfb_base.c
> +++ b/drivers/video/fbdev/matrox/matroxfb_base.c
> @@ -1876,7 +1876,7 @@ static int initMatrox2(struct matrox_fb_info
> *minfo, struct board *b)
> default_vmode = VMODE_640_480_60;
> #if defined(CONFIG_PPC32) && defined(CONFIG_NVRAM)
> if (default_cmode == CMODE_NVRAM)
> - default_cmode = nvram_read_byte(NV_CMODE);
> + default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
> #endif
> if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
> default_cmode = CMODE_8;
> diff --git a/drivers/video/fbdev/platinumfb.c
> b/drivers/video/fbdev/platinumfb.c
> index bf6b7fb83cf4..3efceaf38f98 100644
> --- a/drivers/video/fbdev/platinumfb.c
> +++ b/drivers/video/fbdev/platinumfb.c
> @@ -347,7 +347,7 @@ static int platinum_init_fb(struct fb_info *info)
> printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
> if (default_vmode == VMODE_NVRAM) {
> #ifdef CONFIG_NVRAM
> - default_vmode = nvram_read_byte(NV_VMODE);
> + default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
> if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
> !platinum_reg_init[default_vmode-1])
> #endif
> @@ -360,7 +360,7 @@ static int platinum_init_fb(struct fb_info *info)
> default_vmode = VMODE_640_480_60;
> #ifdef CONFIG_NVRAM
> if (default_cmode == CMODE_NVRAM)
> - default_cmode = nvram_read_byte(NV_CMODE);
> + default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
> #endif
> if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
> default_cmode = CMODE_8;
> diff --git a/drivers/video/fbdev/valkyriefb.c
> b/drivers/video/fbdev/valkyriefb.c
> index 8022316ee9c9..81f66d69d9dd 100644
> --- a/drivers/video/fbdev/valkyriefb.c
> +++ b/drivers/video/fbdev/valkyriefb.c
> @@ -283,7 +283,7 @@ static void __init valkyrie_choose_mode(struct
> fb_info_valkyrie *p)
> /* Try to pick a video mode out of NVRAM if we have one. */
> #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
> if (default_vmode == VMODE_NVRAM) {
> - default_vmode = nvram_read_byte(NV_VMODE);
> + default_vmode = arch_nvram_ops.read_byte(NV_VMODE);
> if (default_vmode <= 0
> || default_vmode > VMODE_MAX
> || !valkyrie_reg_init[default_vmode - 1])
> @@ -296,7 +296,7 @@ static void __init valkyrie_choose_mode(struct
> fb_info_valkyrie *p)
> default_vmode = VMODE_640_480_67;
> #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_NVRAM)
> if (default_cmode == CMODE_NVRAM)
> - default_cmode = nvram_read_byte(NV_CMODE);
> + default_cmode = arch_nvram_ops.read_byte(NV_CMODE);
> #endif
>
> /*
> --
> 2.19.2



2018-12-30 00:27:20

by Michael Schmitz

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Christophe,

Am 30.12.2018 um 05:55 schrieb LEROY Christophe:
> Michael Schmitz <[email protected]> a écrit :
>
>> Hi Finn,
>>
>> Am 29.12.2018 um 14:06 schrieb Finn Thain:
>>> On Fri, 28 Dec 2018, LEROY Christophe wrote:
>>>>> diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
>>>>> index 89f5154c40b6..99e5729d910d 100644
>>>>> --- a/drivers/scsi/atari_scsi.c
>>>>> +++ b/drivers/scsi/atari_scsi.c
>>>>> @@ -755,9 +755,10 @@ static int __init atari_scsi_probe(struct
>>>>> platform_device *pdev)
>>>>> if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
>>>>> atari_scsi_template.sg_tablesize = setup_sg_tablesize;
>>>>>
>>>>> - if (setup_hostid >= 0) {
>>>>> + if (setup_hostid >= 0)
>>>>> atari_scsi_template.this_id = setup_hostid & 7;
>>>>> - } else {
>>>>> +#ifdef CONFIG_NVRAM
>>>>> + else
>>>>
>>>> Such ifdefs should be avoided in C files.
>>>> It would be better to use
>>>>
>>>> } else if (IS_ENABLED(CONFIG_NVRAM)) {
>>>>
>>>
>>> I don't like #ifdefs either. However, as the maintainer of this file,
>>> I am
>>> okay with this one.
>>>
>>> The old #ifdef CONFIG_NVRAM conditional compilation convention that gets
>>> used here and under drivers/video/fbdev could probably be improved upon
>>> but I consider this to be out-of-scope for this series, which is
>>> complicated enough.
>>>
>>> And as explained in the commit log, CONFIG_NVRAM=y and CONFIG_NVRAM=m
>>> are
>>> treaded differently by drivers. Therefore, IS_ENABLED would be
>>> incorrect.
>>
>> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to
>> suggest.
>
> Doesn't #ifdef means either y or m ? So the same as IS_ENABLED() ?

#ifdef CONFIG_NVRAM is used if you want to match CONFIG_NVRAM=y. For
CONFIG_NVRAM=m, you'd use #ifdef CONFIG_NVRAM_MODULE.

Cheers,

Michael


>
> Christophe
>
>>
>> Or (really going out on a limb here):
>>
>> IS_BUILTIN(CONFIG_NVRAM) ||
>> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
>>
>> Not that I'd advocate that, for this series.
>>
>> Cheers,
>>
>> Michael
>
>

2018-12-30 00:35:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Sat, Dec 29, 2018 at 3:51 AM Michael Schmitz <[email protected]> wrote:
>
> Hi Finn,
>
> Am 29.12.2018 um 15:34 schrieb Finn Thain:
> > On Sat, 29 Dec 2018, Michael Schmitz wrote:
> >
> >>
> >> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really meant to suggest.
> >>
> >> Or (really going out on a limb here):
> >>
> >> IS_BUILTIN(CONFIG_NVRAM) ||
> >> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
> >>
> >> Not that I'd advocate that, for this series.
> >>
> >
> > Well, you are a maintainer for atari_scsi.c.
> >
> > Are you saying that you want IS_BUILTIN(CONFIG_NVRAM) used here instead of
> > ifdef?
>
> No, just pointing out that there would be a way to avoid the ifdef
> without messing up driver behaviour. I'm fine with the ifdef - not least
> because it clearly eliminates code that would be unreachable.
>
> (On second thought - I don't want to speculate whether there's weird
> compiler options that could result in the nvram_check_checksum and
> nvram_read_bytes symbols to still be referenced in the final link, even
> though IS_BUILTIN(CONFIG_NVRAM) always evaluates to false. Best leave
> this as-is.)

As far as I know, it's totally reliable with the supported compilers (gcc-4.6+).
In the older compilers (e.g. 4.1), there was a corner case, where it could
have failed to eliminate a function that was only referenced through a pointer
from a discarded variable, but a plain IS_ENABLED() check like the one here
was still ok, and lots of code relies on that.

Other than that, I agree either way is totally fine here, so no objections
to using the #ifdef.

Arnd

2018-12-30 00:38:50

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

> --- a/drivers/char/nvram.c
> +++ b/drivers/char/nvram.c
> @@ -48,6 +48,10 @@
> #include <linux/mutex.h>
> #include <linux/pagemap.h>
>
> +#ifdef CONFIG_PPC
> +#include <asm/nvram.h>
> +#include <asm/machdep.h>
> +#endif
>
> static DEFINE_MUTEX(nvram_mutex);
> static DEFINE_SPINLOCK(nvram_state_lock);
> @@ -331,6 +335,37 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
> 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

I think it would make be nicer here to keep the ppc bits in arch/ppc,
and instead add a .ioctl() callback to nvram_ops.

> @@ -369,12 +405,14 @@ static int nvram_misc_open(struct inode *inode, struct file *file)
> 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) && (nvram_open_mode & NVRAM_WRITE)) {
> spin_unlock(&nvram_state_lock);
> return -EBUSY;
> }
> +#endif
>
> diff --git a/include/linux/nvram.h b/include/linux/nvram.h
> index b7bfaec60a43..24a57675dba1 100644
> --- a/include/linux/nvram.h
> +++ b/include/linux/nvram.h
> @@ -18,8 +18,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
> };

Maybe just leave all entries visible here, and avoid the above #ifdef checks.

Arnd

2018-12-30 00:39:19

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:

> +
> +static ssize_t m68k_nvram_get_size(void)
> +{
> + if (MACH_IS_ATARI)
> + return atari_nvram_get_size();
> + else if (MACH_IS_MAC)
> + return mac_pram_get_size();
> + return -ENODEV;
> +}
> +
> +/* Atari device drivers call .read (to get checksum validation) whereas
> + * Mac and PowerMac device drivers just use .read_byte.
> + */
> +const struct nvram_ops arch_nvram_ops = {
> +#ifdef CONFIG_MAC
> + .read_byte = m68k_nvram_read_byte,
> + .write_byte = m68k_nvram_write_byte,
> +#endif
> +#ifdef CONFIG_ATARI
> + .read = m68k_nvram_read,
> + .write = m68k_nvram_write,
> + .set_checksum = m68k_nvram_set_checksum,
> + .initialize = m68k_nvram_initialize,
> +#endif
> + .get_size = m68k_nvram_get_size,
> +};
> +EXPORT_SYMBOL(arch_nvram_ops);

Since the operations are almost entirely distinct, why not have two
separate 'nvram_ops' instances here that each refer to just
the set they actually need?

I was actually expecting one more patch here that would make the
arch_nvram_ops a pointer to one of multiple structures, which would
be easier to do with multiple copies, but I suppose there is no need
for that here (there might be on ppc, I have to look again).

Arnd

2018-12-30 00:41:05

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:

> +static ssize_t ppc_nvram_get_size(void)
> +{
> + if (ppc_md.nvram_size)
> + return ppc_md.nvram_size();
> + return -ENODEV;
> +}

> +const struct nvram_ops arch_nvram_ops = {
> + .read = ppc_nvram_read,
> + .write = ppc_nvram_write,
> + .get_size = ppc_nvram_get_size,
> + .sync = ppc_nvram_sync,
> +};

Coming back to this after my comment on the m68k side, I notice that
there is now a double indirection through function pointers. Have you
considered completely removing the operations from ppc_md instead
by having multiple copies of nvram_ops?

With the current method, it does seem odd to have a single
per-architecture instance of the exported structure containing
function pointers. This doesn't give us the flexibility of having
multiple copies in the kernel the way that ppc_md does, but it adds
overhead compared to simply exporting the functions directly.

Arnd

2018-12-30 00:42:38

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 00/25] Re-use nvram module

On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:

> This allows for removal of drivers/char/generic_nvram.c as well as some
> duplicated code in arch/powerpc/kernel/nvram_64.c. By reducing the number
> of /dev/nvram char misc device implementations, the number of bugs and
> inconsistencies is also reduced.
>
> This patch series reduces inconsistencies between PPC32 and PPC64, and
> between PPC_PMAC and MAC. A uniform API has benefits for userspace.
> For example, some error codes for some ioctl calls become consistent
> across PowerPC platforms. The uniform API can potentially benefit
> bootloaders that work across different platforms which all have XPRAM
> (e.g. Emile).
>
> I think there are two reasonable merge strategies for this patch series.
> The char misc maintainer could take the entire series. Alternatively the
> m68k maintainer could take patches 1 thru 14, and after those patches
> reach mainline the powerpc maintainer could take 15 thru 25 (even though
> patch 21 is not powerpc-related).

I had a look at the complete series now, and I think this is a great cleanup.
I replied with a couple of minor comments that you may or may not want
to address first.

The one thing I would like to see resolved (I hope this doesn't bring
back an old discussion you had already concluded) is regarding
the use of a global exported structure of function pointers, as opposed
to using either directly exported functions (with a consistent interface)
or a boot-time selectable structure like dma_map_ops or ppc_md.

Arnd

2018-12-30 00:44:02

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

On Sat, 29 Dec 2018, LEROY Christophe wrote:

> Finn Thain <[email protected]> a ?crit?:
>
> > Make use of arch_nvram_ops in device drivers so that the nvram_* function
> > exports can be removed.
> >
> > Since they are no longer global symbols, rename the PPC32 nvram_* functions
> > appropriately.
> >
> > Signed-off-by: Finn Thain <[email protected]>
> > ---
> > arch/powerpc/kernel/setup_32.c | 8 ++++----
> > drivers/char/generic_nvram.c | 4 ++--
> > drivers/video/fbdev/controlfb.c | 4 ++--
> > drivers/video/fbdev/imsttfb.c | 4 ++--
> > drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
> > drivers/video/fbdev/platinumfb.c | 4 ++--
> > drivers/video/fbdev/valkyriefb.c | 4 ++--
> > 7 files changed, 15 insertions(+), 15 deletions(-)
> >
> > diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
> > index e0d045677472..bdbe6acbef11 100644
> > --- a/arch/powerpc/kernel/setup_32.c
> > +++ b/arch/powerpc/kernel/setup_32.c
> > @@ -152,20 +152,18 @@ __setup("l3cr=", ppc_setup_l3cr);
> >
> > #ifdef CONFIG_GENERIC_NVRAM
> >
> > -unsigned char nvram_read_byte(int addr)
> > +static unsigned char ppc_nvram_read_byte(int addr)
> > {
> > if (ppc_md.nvram_read_val)
> > return ppc_md.nvram_read_val(addr);
> > return 0xff;
> > }
> > -EXPORT_SYMBOL(nvram_read_byte);
> >
> > -void nvram_write_byte(unsigned char val, int addr)
> > +static void ppc_nvram_write_byte(unsigned char val, int addr)
> > {
> > if (ppc_md.nvram_write_val)
> > ppc_md.nvram_write_val(addr, val);
> > }
> > -EXPORT_SYMBOL(nvram_write_byte);
> >
> > static ssize_t ppc_nvram_get_size(void)
> > {
> > @@ -182,6 +180,8 @@ static long ppc_nvram_sync(void)
> > }
> >
> > const struct nvram_ops arch_nvram_ops = {
> > + .read_byte = ppc_nvram_read_byte,
> > + .write_byte = ppc_nvram_write_byte,
> > .get_size = ppc_nvram_get_size,
> > .sync = ppc_nvram_sync,
> > };
> > diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
> > index f32d5663de95..41b76bf9614e 100644
> > --- a/drivers/char/generic_nvram.c
> > +++ b/drivers/char/generic_nvram.c
> > @@ -48,7 +48,7 @@ static ssize_t read_nvram(struct file *file, char __user
> > *buf,
> > if (*ppos >= nvram_len)
> > return 0;
> > for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
> > - if (__put_user(nvram_read_byte(i), p))
> > + if (__put_user(arch_nvram_ops.read_byte(i), p))
>
> Instead of modifying all drivers (in this patch and previous ones related to
> other arches), wouldn't it be better to add helpers like the following in
> nvram.h:
>
> Static inline unsigned char nvram_read_byte(int addr)
> {
> return arch_nvram_ops.read_byte(addr);
> }
>

Is there some benefit, or is that just personal taste?

Avoiding changes to call sites avoids code review, but I think 1) the
thinkpad_acpi changes have already been reviewed and 2) the fbdev changes
need review anyway.

Your suggesion would add several new entities and one extra layer of
indirection.

I think indirection harms readability because now the reader now has to go
and look up the meaning of the new entities.

It's not the case that we need to choose between definitions of
nvram_read_byte() at compile time, or stub them out:

#ifdef CONFIG_FOO
static inline unsigned char nvram_read_byte(int addr)
{
return arch_nvram_ops.read_byte(addr);
}
#else
static inline unsigned char nvram_read_byte(int addr) { }
#endif

And I don't anticipate a need for a macro here either:

#define nvram_read_byte(a) random_nvram_read_byte_impl(a)

I think I've used the simplest solution.

--

> Christophe
>

2018-12-30 00:44:49

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 00/25] Re-use nvram module

On Sat, 29 Dec 2018, Arnd Bergmann wrote:

> I had a look at the complete series now, and I think this is a great
> cleanup. I replied with a couple of minor comments that you may or may
> not want to address first.
>

Thanks for reviewing this.

> The one thing I would like to see resolved (I hope this doesn't bring
> back an old discussion you had already concluded) is regarding the use
> of a global exported structure of function pointers, as opposed to using
> either directly exported functions (with a consistent interface) or a
> boot-time selectable structure like dma_map_ops or ppc_md.
>

If I understand correctly, /dev/nvram was made obsolete by the nvmem
subsystem (?). If so, there won't be new /dev/nvram users, and the
refactoring here only has to be sufficiently flexible to meet the needs of
existing users.

I'm not opposed to exported functions in place of a singleton ops struct.
Other things being equal I'm inclined toward the ops struct, perhaps
because I like encapsulation or perhaps because I don't like excess
generality. (That design decision was made years ago and I don't remember
the reasoning.)

All the arch_nvram_ops structs that I've defined in these patches have the
'const' properly:

const struct nvram_ops arch_nvram_ops = {
.read_byte = nvram_read_byte,
.write_byte = nvram_write_byte,
.read = nvram_read,
.write = nvram_write,
.get_size = nvram_get_size,
.set_checksum = nvram_set_checksum,
.initialize = nvram_initialize,
};
EXPORT_SYMBOL(arch_nvram_ops);

This is because there's no need to do any run-time reconfiguration.

Is a collection of exported functions a better fit here?

--

> Arnd
>

2018-12-30 03:30:17

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Sat, 29 Dec 2018, Arnd Bergmann wrote:

> On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
>
> > +static ssize_t ppc_nvram_get_size(void)
> > +{
> > + if (ppc_md.nvram_size)
> > + return ppc_md.nvram_size();
> > + return -ENODEV;
> > +}
>
> > +const struct nvram_ops arch_nvram_ops = {
> > + .read = ppc_nvram_read,
> > + .write = ppc_nvram_write,
> > + .get_size = ppc_nvram_get_size,
> > + .sync = ppc_nvram_sync,
> > +};
>
> Coming back to this after my comment on the m68k side, I notice that
> there is now a double indirection through function pointers. Have you
> considered completely removing the operations from ppc_md instead by
> having multiple copies of nvram_ops?
>

I considered a few alternatives. I figured that it was refactoring that
could be deferred, as it would be confined to arch/powerpc. I was more
interested in the cross-platform API.

> With the current method, it does seem odd to have a single
> per-architecture instance of the exported structure containing function
> pointers. This doesn't give us the flexibility of having multiple copies
> in the kernel the way that ppc_md does, but it adds overhead compared to
> simply exporting the functions directly.
>

You're right, there is overhead here.

With a bit of auditing, wrappers like the one you quoted (which merely
checks whether or not a ppc_md method is implemented) could surely be
avoided.

The arch_nvram_ops methods are supposed to optional (that is, they are
allowed to be NULL).

We could call exactly the same function pointers though either ppc_md or
arch_nvram_ops. That would avoid the double indirection.

--

> Arnd
>

2018-12-30 04:07:03

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 00/25] Re-use nvram module

On Sun, 30 Dec 2018, I wrote:

>
> I'm not opposed to exported functions in place of a singleton ops
> struct. Other things being equal I'm inclined toward the ops struct,
> perhaps because I like encapsulation or perhaps because I don't like
> excess generality. (That design decision was made years ago and I don't
> remember the reasoning.)

The rationale for the ops struct was that it offers introspection.

It turns out that PPC64 device drivers don't care about byte-at-a-time
accessors and X86 device drivers don't care about checksum validation.
But that only gets us so far.

We still needed a way to find out whether the arch has provided
byte-at-a-time accessors (i.e. PPC32 and M68K Mac) or byte range accessors
(i.e. PPC64 and those platforms with checksummed NVRAM like X86 and M68K
Atari).

You can't resolve this question at build time for a multi-platform kernel
binary, so pre-processor tricks don't help.

Device drivers tend to want to access NVRAM one byte at a time. With this
patch series, those platforms which need checksum validation always set
byte-at-a-time methods to NULL. (Hence the atari_scsi changes in patch 3.)

The char misc driver is quite different to the usual device drivers,
because the struct file_operations methods always access a byte range.

The NULL methods in the ops struct allow the nvram.c misc device to avoid
inefficient byte-at-a-time accessors where possible, just as
arch/powerpc/kernel/nvram_64.c presently does.

--

2018-12-30 07:27:38

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Sat, 29 Dec 2018, Arnd Bergmann wrote:

> > --- a/drivers/char/nvram.c
> > +++ b/drivers/char/nvram.c
> > @@ -48,6 +48,10 @@
> > #include <linux/mutex.h>
> > #include <linux/pagemap.h>
> >
> > +#ifdef CONFIG_PPC
> > +#include <asm/nvram.h>
> > +#include <asm/machdep.h>
> > +#endif
> >
> > static DEFINE_MUTEX(nvram_mutex);
> > static DEFINE_SPINLOCK(nvram_state_lock);
> > @@ -331,6 +335,37 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
> > 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
>
> I think it would make be nicer here to keep the ppc bits in arch/ppc,
> and instead add a .ioctl() callback to nvram_ops.
>

The problem with having an nvram_ops.ioctl() method is the code in the
!PPC branch. That code would get duplicated because it's needed by both
X86 and M68K, to implement the checksum ioctls.

> > @@ -369,12 +405,14 @@ static int nvram_misc_open(struct inode *inode, struct file *file)
> > 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) && (nvram_open_mode & NVRAM_WRITE)) {
> > spin_unlock(&nvram_state_lock);
> > return -EBUSY;
> > }
> > +#endif
> >
> > diff --git a/include/linux/nvram.h b/include/linux/nvram.h
> > index b7bfaec60a43..24a57675dba1 100644
> > --- a/include/linux/nvram.h
> > +++ b/include/linux/nvram.h
> > @@ -18,8 +18,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
> > };
>
> Maybe just leave all entries visible here, and avoid the above #ifdef checks.
>

The #ifdef isn't there just to save a few bytes, though it does do that.
It's really meant to cause a build failure when I mess up somewhere. But
I'm happy to change it if you can see a reason to do so (?)

--

> Arnd
>

2018-12-30 07:28:46

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

On Sat, 29 Dec 2018, Arnd Bergmann wrote:

> On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
>
> > +
> > +static ssize_t m68k_nvram_get_size(void)
> > +{
> > + if (MACH_IS_ATARI)
> > + return atari_nvram_get_size();
> > + else if (MACH_IS_MAC)
> > + return mac_pram_get_size();
> > + return -ENODEV;
> > +}
> > +
> > +/* Atari device drivers call .read (to get checksum validation) whereas
> > + * Mac and PowerMac device drivers just use .read_byte.
> > + */
> > +const struct nvram_ops arch_nvram_ops = {
> > +#ifdef CONFIG_MAC
> > + .read_byte = m68k_nvram_read_byte,
> > + .write_byte = m68k_nvram_write_byte,
> > +#endif
> > +#ifdef CONFIG_ATARI
> > + .read = m68k_nvram_read,
> > + .write = m68k_nvram_write,
> > + .set_checksum = m68k_nvram_set_checksum,
> > + .initialize = m68k_nvram_initialize,
> > +#endif
> > + .get_size = m68k_nvram_get_size,
> > +};
> > +EXPORT_SYMBOL(arch_nvram_ops);
>
> Since the operations are almost entirely distinct, why not have two
> separate 'nvram_ops' instances here that each refer to just
> the set they actually need?
>

The reason for that is that I am alergic to code duplication. But I'll
change it if you think it matters. BTW, this patch has already been acked
by Geert.

> I was actually expecting one more patch here that would make the
> arch_nvram_ops a pointer to one of multiple structures, which would
> be easier to do with multiple copies, but I suppose there is no need
> for that here (there might be on ppc, I have to look again).
>

Yes, I considered that too. I picked the variation that makes everything
const.

--

> Arnd
>

2018-12-30 17:52:40

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

Arnd Bergmann <[email protected]> a écrit :

> On Sat, Dec 29, 2018 at 3:51 AM Michael Schmitz <[email protected]> wrote:
>>
>> Hi Finn,
>>
>> Am 29.12.2018 um 15:34 schrieb Finn Thain:
>> > On Sat, 29 Dec 2018, Michael Schmitz wrote:
>> >
>> >>
>> >> IS_BUILTIN(CONFIG_NVRAM) is probably what Christophe really
>> meant to suggest.
>> >>
>> >> Or (really going out on a limb here):
>> >>
>> >> IS_BUILTIN(CONFIG_NVRAM) ||
>> >> ( IS_MODULE(CONFIG_ATARI_SCSI) && IS_ENABLED(CONFIG_NVRAM) )
>> >>
>> >> Not that I'd advocate that, for this series.
>> >>
>> >
>> > Well, you are a maintainer for atari_scsi.c.
>> >
>> > Are you saying that you want IS_BUILTIN(CONFIG_NVRAM) used here instead of
>> > ifdef?
>>
>> No, just pointing out that there would be a way to avoid the ifdef
>> without messing up driver behaviour. I'm fine with the ifdef - not least
>> because it clearly eliminates code that would be unreachable.
>>
>> (On second thought - I don't want to speculate whether there's weird
>> compiler options that could result in the nvram_check_checksum and
>> nvram_read_bytes symbols to still be referenced in the final link, even
>> though IS_BUILTIN(CONFIG_NVRAM) always evaluates to false. Best leave
>> this as-is.)
>
> As far as I know, it's totally reliable with the supported compilers
> (gcc-4.6+).
> In the older compilers (e.g. 4.1), there was a corner case, where it could
> have failed to eliminate a function that was only referenced through
> a pointer
> from a discarded variable, but a plain IS_ENABLED() check like the one here
> was still ok, and lots of code relies on that.
>
> Other than that, I agree either way is totally fine here, so no objections
> to using the #ifdef.

As far as I know, kernel codying style promotes the use of
IS_ENABLED() etc. instead of #ifdefs when possible.

Christophe

>
> Arnd



2018-12-30 17:54:09

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

Finn Thain <[email protected]> a écrit :

> On Sat, 29 Dec 2018, Arnd Bergmann wrote:
>
>> On Wed, Dec 26, 2018 at 1:43 AM Finn Thain
>> <[email protected]> wrote:
>>
>> > +
>> > +static ssize_t m68k_nvram_get_size(void)
>> > +{
>> > + if (MACH_IS_ATARI)
>> > + return atari_nvram_get_size();
>> > + else if (MACH_IS_MAC)
>> > + return mac_pram_get_size();
>> > + return -ENODEV;
>> > +}
>> > +
>> > +/* Atari device drivers call .read (to get checksum validation) whereas
>> > + * Mac and PowerMac device drivers just use .read_byte.
>> > + */
>> > +const struct nvram_ops arch_nvram_ops = {
>> > +#ifdef CONFIG_MAC
>> > + .read_byte = m68k_nvram_read_byte,
>> > + .write_byte = m68k_nvram_write_byte,
>> > +#endif
>> > +#ifdef CONFIG_ATARI
>> > + .read = m68k_nvram_read,
>> > + .write = m68k_nvram_write,
>> > + .set_checksum = m68k_nvram_set_checksum,
>> > + .initialize = m68k_nvram_initialize,
>> > +#endif
>> > + .get_size = m68k_nvram_get_size,
>> > +};
>> > +EXPORT_SYMBOL(arch_nvram_ops);
>>
>> Since the operations are almost entirely distinct, why not have two
>> separate 'nvram_ops' instances here that each refer to just
>> the set they actually need?
>>
>
> The reason for that is that I am alergic to code duplication. But I'll
> change it if you think it matters. BTW, this patch has already been acked
> by Geert.

I agree it would be cleaner, as it would also avoid this
m68k_nvram_get_size() wouldn't it ?

I don't see potential code duplication here, do you ?

Christophe

>
>> I was actually expecting one more patch here that would make the
>> arch_nvram_ops a pointer to one of multiple structures, which would
>> be easier to do with multiple copies, but I suppose there is no need
>> for that here (there might be on ppc, I have to look again).
>>
>
> Yes, I considered that too. I picked the variation that makes everything
> const.
>
> --
>
>> Arnd
>>



2018-12-30 18:07:59

by James Bottomley

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Sun, 2018-12-30 at 18:50 +0100, LEROY Christophe wrote:
> Arnd Bergmann <[email protected]> a écrit :
> > On Sat, Dec 29, 2018 at 3:51 AM Michael Schmitz
> > <[email protected]> wrote:
[...]
> > > (On second thought - I don't want to speculate whether there's
> > > weird compiler options that could result in the
> > > nvram_check_checksum and nvram_read_bytes symbols to still be
> > > referenced in the final link, even though
> > > IS_BUILTIN(CONFIG_NVRAM) always evaluates to false. Best
> > > leave this as-is.)
> >
> > As far as I know, it's totally reliable with the supported
> > compilers (gcc-4.6+). In the older compilers (e.g. 4.1), there was
> > a corner case, where it could have failed to eliminate a function
> > that was only referenced through a pointer from a discarded
> > variable, but a plain IS_ENABLED() check like the one here
> > was still ok, and lots of code relies on that.
> >
> > Other than that, I agree either way is totally fine here, so no
> > objections to using the #ifdef.
>
> As far as I know, kernel codying style promotes the use of
> IS_ENABLED() etc. instead of #ifdefs when possible.

It's a preference, as with a lot of coding style stuff, which we leave
up to the maintainer.

That said, as has been pointed out, the current #ifdef has a failing
corner case when both are modular (because the code should then be
included). The runtime macro that correctly expresses this is
IS_REACHABLE(CONFIG_NVRAM).

James


2018-12-30 21:46:02

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Sun, 30 Dec 2018, James Bottomley wrote:

>
> That said, as has been pointed out, the current #ifdef has a failing
> corner case when both are modular (because the code should then be
> included). The runtime macro that correctly expresses this is
> IS_REACHABLE(CONFIG_NVRAM).
>

No, in the case of CONFIG_NVRAM=m, the conditional code is deliberately
excluded. This is discussed in the patch description. The convention on
PPC32 is that device drivers drop support for NVRAM in this situation.

I've adopted the PPC32 convention here because M68K drivers and PPC32
drivers have to co-exist (I'm thinking of valkyriefb, but there are other
examples).

--

> James
>
>

2018-12-30 22:14:37

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

On Sun, 30 Dec 2018, LEROY Christophe wrote:

> > >
> > > Since the operations are almost entirely distinct, why not have two
> > > separate 'nvram_ops' instances here that each refer to just the set
> > > they actually need?
> > >
> >
> > The reason for that is that I am alergic to code duplication. But I'll
> > change it if you think it matters. BTW, this patch has already been
> > acked by Geert.
>
> I agree it would be cleaner, as it would also avoid this
> m68k_nvram_get_size() wouldn't it ?
>

No, that function makes run-time decisions. #ifdef won't work.

> I don't see potential code duplication here, do you ?
>

Here's my problem with Arnd's suggestion. Consider this C code,

#ifdef FOO
const struct nvram_ops arch_nvram_ops = {
/* ... */
}
#else
const struct nvram_ops arch_nvram_ops = {
/* ... */
}
#endif

Lets say you write a hypothetical patch to remove the 'const'. Now you
have two 'const' keywords to edit, and you have the risk of overlooking
one of them. The solution to this problem is sometimes referred to as
"DRY", meaning Don't Repeat Yourself:

const struct nvram_ops arch_nvram_ops = {
/* ... */
#ifdef FOO
/* ... */
#else
/* ... */
#endif
/* ... */
}

But I'm over-simplifying. Arnd's alternative actually goes like this,

#if defined(CONFIG_MAC) && !defined(CONFIG_ATARI)
const struct nvram_ops arch_nvram_ops = {
/* ... */
}
#elif !defined(CONFIG_MAC) && defined(CONFIG_ATARI)
const struct nvram_ops arch_nvram_ops = {
/* ... */
}
#elif defined(CONFIG_MAC) && defined(CONFIG_ATARI)
const struct nvram_ops arch_nvram_ops = {
/* ... */
}
#endif

So, you're right, this isn't "duplication", it's "triplication".

--

> Christophe
>

2018-12-30 22:47:06

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 01/25] scsi/atari_scsi: Don't select CONFIG_NVRAM

On Mon, 31 Dec 2018, Finn Thain wrote:

> On Sun, 30 Dec 2018, James Bottomley wrote:
>
> >
> > That said, as has been pointed out, the current #ifdef has a failing
> > corner case when both are modular (because the code should then be
> > included). The runtime macro that correctly expresses this is
> > IS_REACHABLE(CONFIG_NVRAM).
> >
>
> No, in the case of CONFIG_NVRAM=m, the conditional code is deliberately
> excluded. This is discussed in the patch description. The convention on
> PPC32 is that device drivers drop support for NVRAM in this situation.
>
> I've adopted the PPC32 convention here because M68K drivers and PPC32
> drivers have to co-exist (I'm thinking of valkyriefb, but there are other
> examples).
>

I agree with your comment in principle, that these drivers should be using
IS_REACHABLE(CONFIG_NVRAM), not defined(CONFIG_NVRAM).

$ grep -lrw CONFIG_NVRAM drivers/
drivers/video/fbdev/matrox/matroxfb_base.c
drivers/video/fbdev/platinumfb.c
drivers/video/fbdev/controlfb.c
drivers/video/fbdev/valkyriefb.c
drivers/video/fbdev/imsttfb.c
drivers/scsi/atari_scsi.c
$

But I think this is not the fault of this patch; it's just a historical
accident.

Having said that, I will rework this series to convert all of the above
drivers to IS_REACHABLE(CONFIG_NVRAM). I think it would be an improvement.

Besides, it seems likely that some rework involving ppc_md will be needed
too because as Arnd pointed out, it would be good to avoid two sets of
nvram accessor methods.

--

2018-12-30 23:18:29

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Sun, 30 Dec 2018, Finn Thain wrote:

> > > diff --git a/include/linux/nvram.h b/include/linux/nvram.h
> > > index b7bfaec60a43..24a57675dba1 100644
> > > --- a/include/linux/nvram.h
> > > +++ b/include/linux/nvram.h
> > > @@ -18,8 +18,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
> > > };
> >
> > Maybe just leave all entries visible here, and avoid the above #ifdef
> > checks.
> >
>
> The #ifdef isn't there just to save a few bytes, though it does do that.
> It's really meant to cause a build failure when I mess up somewhere. But
> I'm happy to change it if you can see a reason to do so (?)
>

I think the problem with these #ifdef conditionals is that they don't
express the correct constraints. So, at the end of this series I'd prefer
to see,

struct nvram_ops {
ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *);
unsigned char (*read_byte)(int);
void (*write_byte)(unsigned char, int);
ssize_t (*get_size)(void);
#if defined(CONFIG_PPC)
long (*sync)(void);
int (*get_partition)(int);
#elif defined(CONFIG_X86) || defined(CONFIG_M68K)
long (*set_checksum)(void);
long (*initialize)(void);
#endif
};

Is that okay with you?

--

2018-12-31 12:18:28

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Sun, Dec 30, 2018 at 8:25 AM Finn Thain <[email protected]> wrote:
>
> On Sat, 29 Dec 2018, Arnd Bergmann wrote:
>
> > > --- a/drivers/char/nvram.c
> > > +++ b/drivers/char/nvram.c
> > > @@ -48,6 +48,10 @@
> > > #include <linux/mutex.h>
> > > #include <linux/pagemap.h>
> > >
> > > +#ifdef CONFIG_PPC
> > > +#include <asm/nvram.h>
> > > +#include <asm/machdep.h>
> > > +#endif
> > >
> > > static DEFINE_MUTEX(nvram_mutex);
> > > static DEFINE_SPINLOCK(nvram_state_lock);
> > > @@ -331,6 +335,37 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
> > > 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
> >
> > I think it would make be nicer here to keep the ppc bits in arch/ppc,
> > and instead add a .ioctl() callback to nvram_ops.
> >
>
> The problem with having an nvram_ops.ioctl() method is the code in the
> !PPC branch. That code would get duplicated because it's needed by both
> X86 and M68K, to implement the checksum ioctls.

I was thinking you'd just have a common ioctl function that falls
back to the .ioctl callback for any unhandled commands like

switch (cmd) {
case NVRAM_INIT:
...
break;
case ...:
break;
default:
if (ops->ioctl)
return ops->ioctl(...);
return -EINVAL;
}

Would that work?

Arnd

2018-12-31 12:20:34

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Mon, Dec 31, 2018 at 12:13 AM Finn Thain <[email protected]> wrote:
> On Sun, 30 Dec 2018, Finn Thain wrote:
> > > > diff --git a/include/linux/nvram.h b/include/linux/nvram.h
> > > > index b7bfaec60a43..24a57675dba1 100644
> > > > --- a/include/linux/nvram.h
> > > > +++ b/include/linux/nvram.h
> > > > @@ -18,8 +18,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
> > > > };
> > >
> > > Maybe just leave all entries visible here, and avoid the above #ifdef
> > > checks.
> > >
> >
> > The #ifdef isn't there just to save a few bytes, though it does do that.
> > It's really meant to cause a build failure when I mess up somewhere. But
> > I'm happy to change it if you can see a reason to do so (?)
> >
>
> I think the problem with these #ifdef conditionals is that they don't
> express the correct constraints. So, at the end of this series I'd prefer
> to see,
>
> struct nvram_ops {
> ssize_t (*read)(char *, size_t, loff_t *);
> ssize_t (*write)(char *, size_t, loff_t *);
> unsigned char (*read_byte)(int);
> void (*write_byte)(unsigned char, int);
> ssize_t (*get_size)(void);
> #if defined(CONFIG_PPC)
> long (*sync)(void);
> int (*get_partition)(int);
> #elif defined(CONFIG_X86) || defined(CONFIG_M68K)
> long (*set_checksum)(void);
> long (*initialize)(void);
> #endif
> };
>
> Is that okay with you?

My preference would be no #ifdef here, but the compile time
error you mention is a good enough reason, so I'm fine with
either version you pick.

Arnd

2018-12-31 12:21:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 13/25] m68k: Dispatch nvram_ops calls to Atari or Mac functions

On Sun, Dec 30, 2018 at 11:12 PM Finn Thain <[email protected]> wrote:
> On Sun, 30 Dec 2018, LEROY Christophe wrote:

> But I'm over-simplifying. Arnd's alternative actually goes like this,
>
> #if defined(CONFIG_MAC) && !defined(CONFIG_ATARI)
> const struct nvram_ops arch_nvram_ops = {
> /* ... */
> }
> #elif !defined(CONFIG_MAC) && defined(CONFIG_ATARI)
> const struct nvram_ops arch_nvram_ops = {
> /* ... */
> }
> #elif defined(CONFIG_MAC) && defined(CONFIG_ATARI)
> const struct nvram_ops arch_nvram_ops = {
> /* ... */
> }
> #endif
>
> So, you're right, this isn't "duplication", it's "triplication".

Ok, I failed to realized that MAC and ATARI are not mutually exclusive.
I agree that your original version is best then.

Arnd

2018-12-31 12:24:10

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 00/25] Re-use nvram module

On Sun, Dec 30, 2018 at 5:05 AM Finn Thain <[email protected]> wrote:
>
> On Sun, 30 Dec 2018, I wrote:
>
> >
> > I'm not opposed to exported functions in place of a singleton ops
> > struct. Other things being equal I'm inclined toward the ops struct,
> > perhaps because I like encapsulation or perhaps because I don't like
> > excess generality. (That design decision was made years ago and I don't
> > remember the reasoning.)
>
> The rationale for the ops struct was that it offers introspection.
>
> It turns out that PPC64 device drivers don't care about byte-at-a-time
> accessors and X86 device drivers don't care about checksum validation.
> But that only gets us so far.
>
> We still needed a way to find out whether the arch has provided
> byte-at-a-time accessors (i.e. PPC32 and M68K Mac) or byte range accessors
> (i.e. PPC64 and those platforms with checksummed NVRAM like X86 and M68K
> Atari).
>
> You can't resolve this question at build time for a multi-platform kernel
> binary, so pre-processor tricks don't help.
>
> Device drivers tend to want to access NVRAM one byte at a time. With this
> patch series, those platforms which need checksum validation always set
> byte-at-a-time methods to NULL. (Hence the atari_scsi changes in patch 3.)
>
> The char misc driver is quite different to the usual device drivers,
> because the struct file_operations methods always access a byte range.
>
> The NULL methods in the ops struct allow the nvram.c misc device to avoid
> inefficient byte-at-a-time accessors where possible, just as
> arch/powerpc/kernel/nvram_64.c presently does.


Ok, I see. That sounds absolutely reasonable, so let's stay with
the structure as you proposed.

Arnd

2018-12-31 12:31:14

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

On Sun, Dec 30, 2018 at 12:43 AM Finn Thain <[email protected]> wrote:

>
> Is there some benefit, or is that just personal taste?
>
> Avoiding changes to call sites avoids code review, but I think 1) the
> thinkpad_acpi changes have already been reviewed and 2) the fbdev changes
> need review anyway.
>
> Your suggesion would add several new entities and one extra layer of
> indirection.
>
> I think indirection harms readability because now the reader now has to go
> and look up the meaning of the new entities.
>
> It's not the case that we need to choose between definitions of
> nvram_read_byte() at compile time, or stub them out:
>
> #ifdef CONFIG_FOO
> static inline unsigned char nvram_read_byte(int addr)
> {
> return arch_nvram_ops.read_byte(addr);
> }
> #else
> static inline unsigned char nvram_read_byte(int addr) { }
> #endif
>
> And I don't anticipate a need for a macro here either:
>
> #define nvram_read_byte(a) random_nvram_read_byte_impl(a)
>
> I think I've used the simplest solution.

Having the indirection would help if the inline function can
encapsulate the NULL pointer check, like

static inline unsigned char nvram_read_byte(loff_t addr)
{
char data;

if (!IS_ENABLED(CONFIG_NVRAM))
return 0xff;

if (arch_nvram_ops.read_byte)
return arch_nvram_ops.read_byte(addr);

if (arch_nvram_ops.read)
return arch_nvram_ops.read(char, 1, &addr);

return 0xff;
}

(the above assumes no #ifdef in the structure definition, if you
keep the #ifdef there they have to be added here as well).

Arnd

2018-12-31 12:35:48

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Sun, Dec 30, 2018 at 4:29 AM Finn Thain <[email protected]> wrote:
>
> On Sat, 29 Dec 2018, Arnd Bergmann wrote:
>
> > On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
> >
> > > +static ssize_t ppc_nvram_get_size(void)
> > > +{
> > > + if (ppc_md.nvram_size)
> > > + return ppc_md.nvram_size();
> > > + return -ENODEV;
> > > +}
> >
> > > +const struct nvram_ops arch_nvram_ops = {
> > > + .read = ppc_nvram_read,
> > > + .write = ppc_nvram_write,
> > > + .get_size = ppc_nvram_get_size,
> > > + .sync = ppc_nvram_sync,
> > > +};
> >
> > Coming back to this after my comment on the m68k side, I notice that
> > there is now a double indirection through function pointers. Have you
> > considered completely removing the operations from ppc_md instead by
> > having multiple copies of nvram_ops?
> >
>
> I considered a few alternatives. I figured that it was refactoring that
> could be deferred, as it would be confined to arch/powerpc. I was more
> interested in the cross-platform API.

Fair enough.

> > With the current method, it does seem odd to have a single
> > per-architecture instance of the exported structure containing function
> > pointers. This doesn't give us the flexibility of having multiple copies
> > in the kernel the way that ppc_md does, but it adds overhead compared to
> > simply exporting the functions directly.
> >
>
> You're right, there is overhead here.
>
> With a bit of auditing, wrappers like the one you quoted (which merely
> checks whether or not a ppc_md method is implemented) could surely be
> avoided.
>
> The arch_nvram_ops methods are supposed to optional (that is, they are
> allowed to be NULL).
>
> We could call exactly the same function pointers though either ppc_md or
> arch_nvram_ops. That would avoid the double indirection.

I think you can have a 'const' structure in the __ro_after_init section,
so without changing anything else, powerpc could just copy the
function pointers from ppc_md into the arch_nvram_ops at early
init time, which should ideally simplify your implementation as well.

Arnd

2019-01-01 01:22:55

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 00/25] Re-use nvram module

On Sun, 30 Dec 2018, I wrote:

>
> The rationale for the ops struct was that it offers introspection.
>
> [...] those platforms which need checksum validation always set
> byte-at-a-time methods to NULL.
>
> [...] The NULL methods in the ops struct allow the nvram.c misc device
> to avoid inefficient byte-at-a-time accessors where possible, just as
> arch/powerpc/kernel/nvram_64.c presently does.
>

Hopefully my message makes more sense with the tangential irrelevancies
removed. I will document these considerations in nvram.h for the next
revision.

--

2019-01-01 02:17:37

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Mon, 31 Dec 2018, Arnd Bergmann wrote:

> On Sun, Dec 30, 2018 at 8:25 AM Finn Thain <[email protected]> wrote:
> >
> > On Sat, 29 Dec 2018, Arnd Bergmann wrote:
> >
> > > > --- a/drivers/char/nvram.c
> > > > +++ b/drivers/char/nvram.c
> > > > @@ -48,6 +48,10 @@
> > > > #include <linux/mutex.h>
> > > > #include <linux/pagemap.h>
> > > >
> > > > +#ifdef CONFIG_PPC
> > > > +#include <asm/nvram.h>
> > > > +#include <asm/machdep.h>
> > > > +#endif
> > > >
> > > > static DEFINE_MUTEX(nvram_mutex);
> > > > static DEFINE_SPINLOCK(nvram_state_lock);
> > > > @@ -331,6 +335,37 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
> > > > 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
> > >
> > > I think it would make be nicer here to keep the ppc bits in arch/ppc,
> > > and instead add a .ioctl() callback to nvram_ops.
> > >
> >
> > The problem with having an nvram_ops.ioctl() method is the code in the
> > !PPC branch. That code would get duplicated because it's needed by
> > both X86 and M68K, to implement the checksum ioctls.
>
> I was thinking you'd just have a common ioctl function that falls back
> to the .ioctl callback for any unhandled commands like
>
> switch (cmd) {
> case NVRAM_INIT:
> ...
> break;
> case ...:
> break;
> default:
> if (ops->ioctl)
> return ops->ioctl(...);
> return -EINVAL;
> }
>
> Would that work?
>

There are no ioctls common to all architectures. So your example becomes,

static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
if (ops->ioctl)
return ops->ioctl(file, cmd, arg);
return -ENOTTY;
}

And then my objection is the same: m68k and x86 now have to duplicate
their common ops->ioctl() implementation.

Here's a compromise that avoids some code duplication.

switch (cmd) {
#if defined(CONFIG_X86) || defined(CONFIG_M68K)
case NVRAM_INIT:
...
break;
case NVRAM_SETCKS:
...
break;
#endif
default:
if (ops->ioctl)
return ops->ioctl(...);
return -EINVAL;
}

But PPC64 and PPC32 also need to share their ops->ioctl() implementation.
It's not clear to me where that code would go.

Personally, I prefer the present patch series, or something similar, with
it's symmetry between nvram.c and nvram.h:

static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
long ret = -ENOTTY;

switch (cmd) {
#if defined(CONFIG_PPC)
case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
...
case IOC_NVRAM_GET_OFFSET:
...
break;
case IOC_NVRAM_SYNC:
...
break;
#elif defined(CONFIG_X86) || defined(CONFIG_M68K)
case NVRAM_INIT:
...
break;
case NVRAM_SETCKS:
...
break;
#endif
}
return ret;
}

... versus the struct definition in nvram.h,

struct nvram_ops {
ssize_t (*read)(char *, size_t, loff_t *);
ssize_t (*write)(char *, size_t, loff_t *);
unsigned char (*read_byte)(int);
void (*write_byte)(unsigned char, int);
ssize_t (*get_size)(void);
#if defined(CONFIG_PPC)
long (*sync)(void);
int (*get_partition)(int);
#elif defined(CONFIG_X86) || defined(CONFIG_M68K)
long (*set_checksum)(void);
long (*initialize)(void);
#endif
};

Which of these alternatives do you prefer? Is there a better way?

--


> Arnd
>

2019-01-01 02:17:40

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

On Mon, 31 Dec 2018, Arnd Bergmann wrote:

> On Sun, Dec 30, 2018 at 12:43 AM Finn Thain <[email protected]> wrote:
>
> >
> > Is there some benefit, or is that just personal taste?
> >
> > Avoiding changes to call sites avoids code review, but I think 1) the
> > thinkpad_acpi changes have already been reviewed and 2) the fbdev changes
> > need review anyway.
> >
> > Your suggesion would add several new entities and one extra layer of
> > indirection.
> >
> > I think indirection harms readability because now the reader now has to go
> > and look up the meaning of the new entities.
> >
> > It's not the case that we need to choose between definitions of
> > nvram_read_byte() at compile time, or stub them out:
> >
> > #ifdef CONFIG_FOO
> > static inline unsigned char nvram_read_byte(int addr)
> > {
> > return arch_nvram_ops.read_byte(addr);
> > }
> > #else
> > static inline unsigned char nvram_read_byte(int addr) { }
> > #endif
> >
> > And I don't anticipate a need for a macro here either:
> >
> > #define nvram_read_byte(a) random_nvram_read_byte_impl(a)
> >
> > I think I've used the simplest solution.
>
> Having the indirection would help if the inline function can
> encapsulate the NULL pointer check, like
>
> static inline unsigned char nvram_read_byte(loff_t addr)
> {
> char data;
>
> if (!IS_ENABLED(CONFIG_NVRAM))
> return 0xff;
>
> if (arch_nvram_ops.read_byte)
> return arch_nvram_ops.read_byte(addr);
>
> if (arch_nvram_ops.read)
> return arch_nvram_ops.read(char, 1, &addr);
>
> return 0xff;
> }
>

The semantics of .read_byte and .read are subtly different. For CONFIG_X86
and CONFIG_ATARI, .read implies checksum validation and .read_byte does
not.

In particular, in the thinkpad_acpi case, checksum validation isn't used,
but in the atari_scsi case, it is.

So I like to see drivers explicitly call the method they want. I didn't
want to obscure this distinction in a helper.

--

2019-01-01 02:25:36

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Mon, 31 Dec 2018, Arnd Bergmann wrote:

> On Sun, Dec 30, 2018 at 4:29 AM Finn Thain <[email protected]> wrote:
> >
> > On Sat, 29 Dec 2018, Arnd Bergmann wrote:
> >
> > > On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
> > >
> > > > +static ssize_t ppc_nvram_get_size(void)
> > > > +{
> > > > + if (ppc_md.nvram_size)
> > > > + return ppc_md.nvram_size();
> > > > + return -ENODEV;
> > > > +}
> > >
> > > > +const struct nvram_ops arch_nvram_ops = {
> > > > + .read = ppc_nvram_read,
> > > > + .write = ppc_nvram_write,
> > > > + .get_size = ppc_nvram_get_size,
> > > > + .sync = ppc_nvram_sync,
> > > > +};
> > >
> > > Coming back to this after my comment on the m68k side, I notice that
> > > there is now a double indirection through function pointers. Have
> > > you considered completely removing the operations from ppc_md
> > > instead by having multiple copies of nvram_ops?
> > >
> >
> > I considered a few alternatives. I figured that it was refactoring
> > that could be deferred, as it would be confined to arch/powerpc. I was
> > more interested in the cross-platform API.
>
> Fair enough.
>
> > > With the current method, it does seem odd to have a single
> > > per-architecture instance of the exported structure containing
> > > function pointers. This doesn't give us the flexibility of having
> > > multiple copies in the kernel the way that ppc_md does, but it adds
> > > overhead compared to simply exporting the functions directly.
> > >
> >
> > You're right, there is overhead here.
> >
> > With a bit of auditing, wrappers like the one you quoted (which merely
> > checks whether or not a ppc_md method is implemented) could surely be
> > avoided.
> >
> > The arch_nvram_ops methods are supposed to optional (that is, they are
> > allowed to be NULL).
> >
> > We could call exactly the same function pointers though either ppc_md
> > or arch_nvram_ops. That would avoid the double indirection.
>
> I think you can have a 'const' structure in the __ro_after_init section,
> so without changing anything else, powerpc could just copy the function
> pointers from ppc_md into the arch_nvram_ops at early init time, which
> should ideally simplify your implementation as well.
>

This "early init time" could be hard to pin down... It has to be after
ppc_md methods are initialized but before the nvram_ops methods get used
(e.g. by the framebuffer console). Seems a bit fragile (?)

Your suggestion to completely remove the ppc_md.nvram* methods might be a
better way. It just means functions get assigned to nvram_ops pointers
instead of ppc_md pointers.

The patch is simple enough, but it assumes that arch_nvram_ops is not
const. The struct machdep_calls ppc_md is not const, so should we worry
about dropping the const for the struct nvram_ops arch_nvram_ops?

--

> Arnd
>

2019-01-03 02:53:58

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 02/25] m68k/atari: Move Atari-specific code out of drivers/char/nvram.c

On Sat, 29 Dec 2018, I wrote:

> On Fri, 28 Dec 2018, LEROY Christophe wrote:
>
> > > --- a/drivers/char/nvram.c
> > > +++ b/drivers/char/nvram.c
> > > @@ -21,13 +21,6 @@
> > > * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
> > > * again; use with care!)
> > > *
> > > - * This file also provides some functions for other parts of the kernel that
> > > - * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
> > > - * Obviously this can be used only if this driver is always configured into
> > > - * the kernel and is not a module. Since the functions are used by
> > > some Atari
> > > - * drivers, this is the case on the Atari.
> > > - *
> > > - *
> > > * 1.1 Cesar Barros: SMP locking fixes
> > > * added changelog
> > > * 1.2 Erik Gilling: Cobalt Networks support
> > > @@ -39,64 +32,6 @@
> > >
> > > #include <linux/module.h>
> > > #include <linux/nvram.h>
> > > -
> > > -#define PC 1
> > > -#define ATARI 2
> > > -
> > > -/* select machine configuration */
> > > -#if defined(CONFIG_ATARI)
> > > -# define MACH ATARI
> > > -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
> > > /* and ?? */
> > > -# define MACH PC
> > > -#else
> > > -# error Cannot build nvram driver for this machine configuration.
> > > -#endif
> > > -
> > > -#if MACH == PC
> > > -
> > > -/* RTC in a PC */
> > > -#define CHECK_DRIVER_INIT() 1
> > > -
> > > -/* On PCs, the checksum is built only over bytes 2..31 */
> > > -#define PC_CKS_RANGE_START 2
> > > -#define PC_CKS_RANGE_END 31
> > > -#define PC_CKS_LOC 32
> > > -#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
> > > -
> > > -#define mach_check_checksum pc_check_checksum
> > > -#define mach_set_checksum pc_set_checksum
> > > -#define mach_proc_infos pc_proc_infos
> > > -
> > > -#endif
> > > -
> > > -#if MACH == ATARI
> > > -
> > > -/* Special parameters for RTC in Atari machines */
> > > -#include <asm/atarihw.h>
> > > -#include <asm/atariints.h>
> > > -#define RTC_PORT(x) (TT_RTC_BAS + 2*(x))
> > > -#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
> > > -
> > > -#define NVRAM_BYTES 50
> > > -
> > > -/* On Ataris, the checksum is over all bytes except the checksum bytes
> > > - * themselves; these are at the very end */
> > > -#define ATARI_CKS_RANGE_START 0
> > > -#define ATARI_CKS_RANGE_END 47
> > > -#define ATARI_CKS_LOC 48
> > > -
> > > -#define mach_check_checksum atari_check_checksum
> > > -#define mach_set_checksum atari_set_checksum
> > > -#define mach_proc_infos atari_proc_infos
> > > -
> > > -#endif
> > > -
> > > -/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> > > - * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> > > - * don't want two different things trying to get to it at once. (e.g. the
> > > - * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> > > - */
> > > -
> > > #include <linux/types.h>
> > > #include <linux/errno.h>
> > > #include <linux/miscdevice.h>
> > > @@ -120,12 +55,9 @@ static int nvram_open_mode; /* special open modes */
> > > #define NVRAM_WRITE 1 /* opened for writing (exclusive) */
> > > #define NVRAM_EXCL 2 /* opened with O_EXCL */
> > >
> > > -static int mach_check_checksum(void);
> > > -static void mach_set_checksum(void);
> > > -
> > > #ifdef CONFIG_PROC_FS
> > > -static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
> > > - void *offset);
> > > +static void pc_nvram_proc_read(unsigned char *contents, struct
> > > seq_file *seq,
> > > + void *offset);
> > > #endif
> > >
> > > /*
> > > @@ -139,6 +71,14 @@ static void mach_proc_infos(unsigned char
> > > *contents, struct seq_file *seq,
> > > * know about the RTC cruft.
> > > */
> > >
> > > +#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE)
> > > +
> > > +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
> > > + * rtc_lock held. Due to the index-port/data-port design of the RTC, we
> > > + * don't want two different things trying to get to it at once. (e.g. the
> > > + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
> > > + */
> > > +
> > > unsigned char __nvram_read_byte(int i)
> > > {
> > > return CMOS_READ(NVRAM_FIRST_BYTE + i);
> > > @@ -174,9 +114,22 @@ void nvram_write_byte(unsigned char c, int i)
> > > }
> > > EXPORT_SYMBOL(nvram_write_byte);
> > >
> > > +/* On PCs, the checksum is built only over bytes 2..31 */
> > > +#define PC_CKS_RANGE_START 2
> > > +#define PC_CKS_RANGE_END 31
> > > +#define PC_CKS_LOC 32
> > > +
> > > int __nvram_check_checksum(void)
> > > {
> > > - return mach_check_checksum();
> > > + int i;
> > > + unsigned short sum = 0;
> > > + unsigned short expect;
> > > +
> > > + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
> > > + sum += __nvram_read_byte(i);
> > > + expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
> > > + __nvram_read_byte(PC_CKS_LOC+1);
> > > + return (sum & 0xffff) == expect;
> > > }
> >
> >
> > I don't understand how this is part of the code move.
> > Does the pc specific checksum becomes the generic one ?
> >
>
> This is not generic code, of course. Please refer to the two patches
> that follow this one, in which all of the x86-specific code gets wrapped
> with #ifdef CONFIG_X86.
>
> This code gets moved because the MACH macro is made redundant. You might
> defer this code motion to patch 4 or patch 5 but I don't see that as being
> an improvement.
>
> [...]
>
> You may argue that there should be no CONFIG_X86 code in drivers/char.

I think I now remember why this x86-specific code doesn't get moved from
drivers/char to arch/x86 in this patch series.

In the case of PPC32 and PPC64, the nvram accessors are presently built-in
using rules like this,

arch/powerpc/platforms/powermac/Makefile:obj-$(CONFIG_PPC64) += nvram.o
arch/powerpc/platforms/powernv/Makefile:obj-y += ... opal-nvram.o ...
arch/powerpc/platforms/pseries/Makefile:obj-y := ... nvram.o ...

... or like this,

arch/powerpc/platforms/powermac/Makefile:obj-$(CONFIG_NVRAM:m=y) += nvram.o

... except in one case they are in a separate module, though this doesn't
work for built-in callers such as chrp_init2(),

arch/powerpc/platforms/chrp/Makefile:obj-$(CONFIG_NVRAM) += nvram.o

Anyway, I didn't think that any of these options would make it past the
x86 maintainers so I just left the x86-specific code in place.

--

2019-01-03 03:02:01

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 18/25] powerpc: Implement nvram sync ioctl

On Tue, 1 Jan 2019, I wrote:

>
> There are no [nvram] ioctls common to all architectures. So your example
> becomes,
>
> static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
> unsigned long arg)
> {
> if (ops->ioctl)
> return ops->ioctl(file, cmd, arg);
> return -ENOTTY;
> }
>
> And then my objection is the same: m68k and x86 now have to duplicate
> their common ops->ioctl() implementation.
>

Perhaps code duplication is inevitable. Either you punt the ioctl
implementation from the char misc driver (and duplicate that ioctl
implementation under arch/) or else you duplicate the char misc driver.

Maybe this dilemma explains the situation we have now* which is duplicated
drivers (drivers/char/nvram.c and drivers/char/generic_nvram.c). But this
explanation doesn't seem to offer any solution. Re-using either of the
existing drivers seems to be impossible.

Different interpretations of the NVRAM Kconfig symbol accross the tree are
not helping. And having separate Kconfig symbols (NVRAM and GENERIC_NVRAM)
for the two drivers doesn't help either. But maybe the NVRAM symbol can be
dropped from arch/powerpc and all of the powerpc drivers...

* Actually, we presently have duplicated misc device drivers AND
duplicated ioctl implementations too, for good measure. See
arch/powerpc/kernel/nvram_64.c and drivers/char/generic_nvram.c.

--

2019-01-03 10:58:10

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v8 05/25] char/nvram: Adopt arch_nvram_ops

> +
> +const struct nvram_ops arch_nvram_ops = {
> + .read_byte = nvram_read_byte,
> + .write_byte = nvram_write_byte,
> + .get_size = nvram_get_size,
> +};
> +EXPORT_SYMBOL(arch_nvram_ops);

I think something this internal should always be EXPORT_SYMBOL_GPL.

2019-01-03 11:04:15

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v8 22/25] powerpc: Remove CONFIG_GENERIC_NVRAM and adopt CONFIG_HAVE_ARCH_NVRAM_OPS

> # All PPC32s use generic nvram driver through ppc_md
> -config GENERIC_NVRAM
> +config HAVE_ARCH_NVRAM_OPS
> bool
> default y if PPC32

Symbols like this really should be defined in common code, and then
just selected by the users.

2019-01-04 03:27:40

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 05/25] char/nvram: Adopt arch_nvram_ops

On Thu, 3 Jan 2019, Christoph Hellwig wrote:

> > +
> > +const struct nvram_ops arch_nvram_ops = {
> > + .read_byte = nvram_read_byte,
> > + .write_byte = nvram_write_byte,
> > + .get_size = nvram_get_size,
> > +};
> > +EXPORT_SYMBOL(arch_nvram_ops);
>
> I think something this internal should always be EXPORT_SYMBOL_GPL.
>

By "internal" do you mean "not involving interests outside of the Linux
Foundation"? TBH, I don't know who's affected.

Anyway, this patch series is mostly refactoring. So the policy it enforces
towards the use of arch_nvram_ops just reflects the policy already in
place:

$ git grep -w EXPORT_SYMBOL_GPL | grep nvram
$ git grep -w EXPORT_SYMBOL | grep nvram
...
arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_read_byte);
arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_write_byte);
arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_get_size);
arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_sync);
arch/powerpc/platforms/powermac/nvram.c:EXPORT_SYMBOL(pmac_get_partition);
arch/powerpc/platforms/powermac/nvram.c:EXPORT_SYMBOL(pmac_xpram_read);
arch/powerpc/platforms/powermac/nvram.c:EXPORT_SYMBOL(pmac_xpram_write);
drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_read_byte);
drivers/char/nvram.c:EXPORT_SYMBOL(nvram_read_byte);
drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_write_byte);
drivers/char/nvram.c:EXPORT_SYMBOL(nvram_write_byte);
drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_check_checksum);
drivers/char/nvram.c:EXPORT_SYMBOL(nvram_check_checksum);
...
$

--

2019-01-04 03:27:57

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 22/25] powerpc: Remove CONFIG_GENERIC_NVRAM and adopt CONFIG_HAVE_ARCH_NVRAM_OPS

On Thu, 3 Jan 2019, Christoph Hellwig wrote:

> > # All PPC32s use generic nvram driver through ppc_md
> > -config GENERIC_NVRAM
> > +config HAVE_ARCH_NVRAM_OPS
> > bool
> > default y if PPC32
>
> Symbols like this really should be defined in common code, and then
> just selected by the users.
>

I'll move it to arch/Kconfig.

Thanks.

--

2019-01-04 09:52:55

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Mon, 31 Dec 2018, Arnd Bergmann wrote:

> On Sun, Dec 30, 2018 at 4:29 AM Finn Thain <[email protected]> wrote:
> >
> > On Sat, 29 Dec 2018, Arnd Bergmann wrote:
> >
> > > With the current method, it does seem odd to have a single
> > > per-architecture instance of the exported structure containing
> > > function pointers. This doesn't give us the flexibility of having
> > > multiple copies in the kernel the way that ppc_md does, but it adds
> > > overhead compared to simply exporting the functions directly.
> > >
> >
> > You're right, there is overhead here.
> >
> > With a bit of auditing, wrappers like the one you quoted (which merely
> > checks whether or not a ppc_md method is implemented) could surely be
> > avoided.
> >
> > The arch_nvram_ops methods are supposed to optional (that is, they are
> > allowed to be NULL).
> >
> > We could call exactly the same function pointers though either ppc_md
> > or arch_nvram_ops. That would avoid the double indirection.
>
> I think you can have a 'const' structure in the __ro_after_init section,
> so without changing anything else, powerpc could just copy the function
> pointers from ppc_md into the arch_nvram_ops at early init time, which
> should ideally simplify your implementation as well.
>

Does this require removing the 'const' from the powerpc arch_nvram_ops
definition? That would mean removing the 'const' from the declaration in
nvram.h, which means removing 'const' for every other instance of that
struct too.

That's what happened when I tried removing the ppc_md.nvram_* methods
entirely and assigning the same function pointers to arch_nvram_ops
methods instead. Apparently all instances of arch_nvram_ops have to be
const or none of them. Otherwise gcc says, "error: conflicting type
qualifiers for 'arch_nvram_ops'".

--

> Arnd
>

2019-01-04 19:04:43

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v8 05/25] char/nvram: Adopt arch_nvram_ops

On Fri, Jan 04, 2019 at 09:08:13AM +1100, Finn Thain wrote:
> On Thu, 3 Jan 2019, Christoph Hellwig wrote:
>
> > > +
> > > +const struct nvram_ops arch_nvram_ops = {
> > > + .read_byte = nvram_read_byte,
> > > + .write_byte = nvram_write_byte,
> > > + .get_size = nvram_get_size,
> > > +};
> > > +EXPORT_SYMBOL(arch_nvram_ops);
> >
> > I think something this internal should always be EXPORT_SYMBOL_GPL.
> >
>
> By "internal" do you mean "not involving interests outside of the Linux
> Foundation"? TBH, I don't know who's affected.

Linux Foundation doesn't matter.

But as far as I can see you export the struct from arch code
for nvram.ko to use them and no one else, which is clearly internal.

2019-01-04 22:07:47

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 05/25] char/nvram: Adopt arch_nvram_ops

On Fri, 4 Jan 2019, Christoph Hellwig wrote:

> On Fri, Jan 04, 2019 at 09:08:13AM +1100, Finn Thain wrote:
> > On Thu, 3 Jan 2019, Christoph Hellwig wrote:
> >
> > > > +
> > > > +const struct nvram_ops arch_nvram_ops = {
> > > > + .read_byte = nvram_read_byte,
> > > > + .write_byte = nvram_write_byte,
> > > > + .get_size = nvram_get_size,
> > > > +};
> > > > +EXPORT_SYMBOL(arch_nvram_ops);
> > >
> > > I think something this internal should always be EXPORT_SYMBOL_GPL.
> > >
> >
> > By "internal" do you mean "not involving interests outside of the Linux
> > Foundation"? TBH, I don't know who's affected.
>
> Linux Foundation doesn't matter.
>
> But as far as I can see you export the struct from arch code
> for nvram.ko to use them and no one else, which is clearly internal.
>

No, arch_nvram_ops is not "internal" in that sense. The struct is used
whereever the nvram_* exports are presently used:

$ git grep -e "EXPORT_SYMBOL.*nvram" v4.20
...
v4.20:arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_read_byte);
v4.20:arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_write_byte);
v4.20:arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_get_size);
v4.20:arch/powerpc/kernel/setup_32.c:EXPORT_SYMBOL(nvram_sync);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_read_byte);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(nvram_read_byte);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_write_byte);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(nvram_write_byte);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(__nvram_check_checksum);
v4.20:drivers/char/nvram.c:EXPORT_SYMBOL(nvram_check_checksum);
...
$ git grep -wle "nvram_read_byte|nvram_write_byte|nvram_get_size|nvram_sync|__nvram_read_byte|__nvram_write_byte|__nvram_check_checksum"
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/nvram.h
arch/powerpc/kernel/setup_32.c
arch/powerpc/platforms/powermac/nvram.c
drivers/char/generic_nvram.c
drivers/char/nvram.c
drivers/platform/x86/thinkpad_acpi.c
drivers/scsi/atari_scsi.c
drivers/video/fbdev/controlfb.c
drivers/video/fbdev/imsttfb.c
drivers/video/fbdev/matrox/matroxfb_base.c
drivers/video/fbdev/platinumfb.c
drivers/video/fbdev/valkyriefb.c
include/linux/nvram.h
sound/ppc/awacs.c
$

--

2019-01-05 23:09:55

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 20/25] powerpc, fbdev: Use arch_nvram_ops methods instead of nvram_read_byte() and nvram_write_byte()

On Sun, 30 Dec 2018, I wrote:

> On Sat, 29 Dec 2018, LEROY Christophe wrote:
>
> > Finn Thain <[email protected]> a ?crit?:
> >
> > > Make use of arch_nvram_ops in device drivers so that the nvram_* function
> > > exports can be removed.
> > >
> > > Since they are no longer global symbols, rename the PPC32 nvram_* functions
> > > appropriately.
> > >
> > > Signed-off-by: Finn Thain <[email protected]>
> > > ---
> > > arch/powerpc/kernel/setup_32.c | 8 ++++----
> > > drivers/char/generic_nvram.c | 4 ++--
> > > drivers/video/fbdev/controlfb.c | 4 ++--
> > > drivers/video/fbdev/imsttfb.c | 4 ++--
> > > drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
> > > drivers/video/fbdev/platinumfb.c | 4 ++--
> > > drivers/video/fbdev/valkyriefb.c | 4 ++--
> > > 7 files changed, 15 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
> > > index e0d045677472..bdbe6acbef11 100644
> > > --- a/arch/powerpc/kernel/setup_32.c
> > > +++ b/arch/powerpc/kernel/setup_32.c
> > > @@ -152,20 +152,18 @@ __setup("l3cr=", ppc_setup_l3cr);
> > >
> > > #ifdef CONFIG_GENERIC_NVRAM
> > >
> > > -unsigned char nvram_read_byte(int addr)
> > > +static unsigned char ppc_nvram_read_byte(int addr)
> > > {
> > > if (ppc_md.nvram_read_val)
> > > return ppc_md.nvram_read_val(addr);
> > > return 0xff;
> > > }
> > > -EXPORT_SYMBOL(nvram_read_byte);
> > >
> > > -void nvram_write_byte(unsigned char val, int addr)
> > > +static void ppc_nvram_write_byte(unsigned char val, int addr)
> > > {
> > > if (ppc_md.nvram_write_val)
> > > ppc_md.nvram_write_val(addr, val);
> > > }
> > > -EXPORT_SYMBOL(nvram_write_byte);
> > >
> > > static ssize_t ppc_nvram_get_size(void)
> > > {
> > > @@ -182,6 +180,8 @@ static long ppc_nvram_sync(void)
> > > }
> > >
> > > const struct nvram_ops arch_nvram_ops = {
> > > + .read_byte = ppc_nvram_read_byte,
> > > + .write_byte = ppc_nvram_write_byte,
> > > .get_size = ppc_nvram_get_size,
> > > .sync = ppc_nvram_sync,
> > > };
> > > diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
> > > index f32d5663de95..41b76bf9614e 100644
> > > --- a/drivers/char/generic_nvram.c
> > > +++ b/drivers/char/generic_nvram.c
> > > @@ -48,7 +48,7 @@ static ssize_t read_nvram(struct file *file, char __user
> > > *buf,
> > > if (*ppos >= nvram_len)
> > > return 0;
> > > for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
> > > - if (__put_user(nvram_read_byte(i), p))
> > > + if (__put_user(arch_nvram_ops.read_byte(i), p))
> >
> > Instead of modifying all drivers (in this patch and previous ones related to
> > other arches), wouldn't it be better to add helpers like the following in
> > nvram.h:
> >
> > Static inline unsigned char nvram_read_byte(int addr)
> > {
> > return arch_nvram_ops.read_byte(addr);
> > }
> >
>
> Is there some benefit, or is that just personal taste?
>
> Avoiding changes to call sites avoids code review, but I think 1) the
> thinkpad_acpi changes have already been reviewed and 2) the fbdev changes
> need review anyway.
>
> Your suggesion would add several new entities and one extra layer of
> indirection.
>

Contrary to what I said above, this kind of double indirection could be
useful if it allows us to avoid the kind of double indirection which Arnd
objected to (which arises when an arch_nvram_ops method invokes a ppc_md
method). For example,

static inline unsigned char nvram_read_byte(int addr)
{
#ifdef CONFIG_PPC
return ppc_md.nvram_read_byte(addr);
#else
return arch_nvram_ops.read_byte(addr);
#endif
}

I'll try this approach for v9 if there are no objections. It may be the
least invasive approach. Also, arch_nvram_ops can remain const.

--

2019-01-06 23:37:15

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

Arnd Bergmann <[email protected]> writes:
> On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
>
>> +static ssize_t ppc_nvram_get_size(void)
>> +{
>> + if (ppc_md.nvram_size)
>> + return ppc_md.nvram_size();
>> + return -ENODEV;
>> +}
>
>> +const struct nvram_ops arch_nvram_ops = {
>> + .read = ppc_nvram_read,
>> + .write = ppc_nvram_write,
>> + .get_size = ppc_nvram_get_size,
>> + .sync = ppc_nvram_sync,
>> +};
>
> Coming back to this after my comment on the m68k side, I notice that
> there is now a double indirection through function pointers. Have you
> considered completely removing the operations from ppc_md instead
> by having multiple copies of nvram_ops?
>
> With the current method, it does seem odd to have a single
> per-architecture instance of the exported structure containing
> function pointers. This doesn't give us the flexibility of having
> multiple copies in the kernel the way that ppc_md does, but it adds
> overhead compared to simply exporting the functions directly.

Yeah TBH I'm not convinced the arch ops is the best solution.

Why can't each arch just implement the required ops functions? On ppc
we'd still use ppc_md but that would be a ppc detail.

Optional ops are fairly easy to support by providing a default
implementation, eg. instead of:

+ if (arch_nvram_ops.get_size == NULL)
+ return -ENODEV;
+
+ nvram_size = arch_nvram_ops.get_size();
+ if (nvram_size < 0)
+ return nvram_size;


We do in some header:

#ifndef arch_nvram_get_size
static inline int arch_nvram_get_size(void)
{
return -ENODEV;
}
#endif

And then:

nvram_size = arch_nvram_get_size();
if (nvram_size < 0)
return nvram_size;


But I haven't digested the whole series so maybe I'm missing something?

cheers

2019-01-07 04:53:42

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Mon, 7 Jan 2019, Michael Ellerman wrote:

> Arnd Bergmann <[email protected]> writes:
> > On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
> >
> >> +static ssize_t ppc_nvram_get_size(void)
> >> +{
> >> + if (ppc_md.nvram_size)
> >> + return ppc_md.nvram_size();
> >> + return -ENODEV;
> >> +}
> >
> >> +const struct nvram_ops arch_nvram_ops = {
> >> + .read = ppc_nvram_read,
> >> + .write = ppc_nvram_write,
> >> + .get_size = ppc_nvram_get_size,
> >> + .sync = ppc_nvram_sync,
> >> +};
> >
> > Coming back to this after my comment on the m68k side, I notice that
> > there is now a double indirection through function pointers. Have you
> > considered completely removing the operations from ppc_md instead
> > by having multiple copies of nvram_ops?
> >
> > With the current method, it does seem odd to have a single
> > per-architecture instance of the exported structure containing
> > function pointers. This doesn't give us the flexibility of having
> > multiple copies in the kernel the way that ppc_md does, but it adds
> > overhead compared to simply exporting the functions directly.
>
> Yeah TBH I'm not convinced the arch ops is the best solution.
>
> Why can't each arch just implement the required ops functions? On ppc
> we'd still use ppc_md but that would be a ppc detail.
>
> Optional ops are fairly easy to support by providing a default
> implementation, eg. instead of:
>
> + if (arch_nvram_ops.get_size == NULL)
> + return -ENODEV;
> +
> + nvram_size = arch_nvram_ops.get_size();
> + if (nvram_size < 0)
> + return nvram_size;
>
>
> We do in some header:
>
> #ifndef arch_nvram_get_size
> static inline int arch_nvram_get_size(void)
> {
> return -ENODEV;
> }
> #endif
>
> And then:
>
> nvram_size = arch_nvram_get_size();
> if (nvram_size < 0)
> return nvram_size;
>
>
> But I haven't digested the whole series so maybe I'm missing something?
>

The reason why that doesn't work boils down to introspection. (This was
mentioned elsewhere in this email thread.) For example, we presently have
code like this,

ssize_t nvram_get_size(void)
{
if (ppc_md.nvram_size)
return ppc_md.nvram_size();
return -1;
}
EXPORT_SYMBOL(nvram_get_size);

This construction means we get to decide at run-time which of the NVRAM
functions should be used. (Whereas your example makes a build-time decision.)

The purpose of arch_nvram_ops is much the same. That is, it does for m68k
and x86 what ppc_md already does for ppc32 and ppc64. (And once these
platforms share an API like this, they can share more driver code, and
reduce duplicated code.)

The approach taken in this series was to push the arch_nvram_ops approach
as far as possible, because by making everything fit into that regime it
immediately became apparent where architectures and platforms have
diverged, creating weird inconsistencies like the differences in sync
ioctl behaviour between ppc32 and ppc64 for core99. (Early revisions of
this series exposed more issues like bugs and dead code that got addressed
elsewhere.)

Problem is, as Arnd pointed out, powerpc doesn't need both kinds of ops
struct. So I'm rewriting this series in such a way that powerpc doesn't
have to implement both. This rewrite is going to look totally different
for powerpc (though not for x86 or m68k) so you might want to wait for me
to post v9 before spending more time on code review.

Thanks.

--

> cheers
>

2019-01-08 09:30:04

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

Finn Thain <[email protected]> writes:
> On Mon, 7 Jan 2019, Michael Ellerman wrote:
>
>> Arnd Bergmann <[email protected]> writes:
>> > On Wed, Dec 26, 2018 at 1:43 AM Finn Thain <[email protected]> wrote:
>> >
>> >> +static ssize_t ppc_nvram_get_size(void)
>> >> +{
>> >> + if (ppc_md.nvram_size)
>> >> + return ppc_md.nvram_size();
>> >> + return -ENODEV;
>> >> +}
>> >
>> >> +const struct nvram_ops arch_nvram_ops = {
>> >> + .read = ppc_nvram_read,
>> >> + .write = ppc_nvram_write,
>> >> + .get_size = ppc_nvram_get_size,
>> >> + .sync = ppc_nvram_sync,
>> >> +};
>> >
>> > Coming back to this after my comment on the m68k side, I notice that
>> > there is now a double indirection through function pointers. Have you
>> > considered completely removing the operations from ppc_md instead
>> > by having multiple copies of nvram_ops?
>> >
>> > With the current method, it does seem odd to have a single
>> > per-architecture instance of the exported structure containing
>> > function pointers. This doesn't give us the flexibility of having
>> > multiple copies in the kernel the way that ppc_md does, but it adds
>> > overhead compared to simply exporting the functions directly.
>>
>> Yeah TBH I'm not convinced the arch ops is the best solution.
>>
>> Why can't each arch just implement the required ops functions? On ppc
>> we'd still use ppc_md but that would be a ppc detail.
>>
>> Optional ops are fairly easy to support by providing a default
>> implementation, eg. instead of:
>>
>> + if (arch_nvram_ops.get_size == NULL)
>> + return -ENODEV;
>> +
>> + nvram_size = arch_nvram_ops.get_size();
>> + if (nvram_size < 0)
>> + return nvram_size;
>>
>>
>> We do in some header:
>>
>> #ifndef arch_nvram_get_size
>> static inline int arch_nvram_get_size(void)
>> {
>> return -ENODEV;
>> }
>> #endif
>>
>> And then:
>>
>> nvram_size = arch_nvram_get_size();
>> if (nvram_size < 0)
>> return nvram_size;
>>
>>
>> But I haven't digested the whole series so maybe I'm missing something?
>>
>
> The reason why that doesn't work boils down to introspection. (This was
> mentioned elsewhere in this email thread.) For example, we presently have
> code like this,
>
> ssize_t nvram_get_size(void)
> {
> if (ppc_md.nvram_size)
> return ppc_md.nvram_size();
> return -1;
> }
> EXPORT_SYMBOL(nvram_get_size);
>
> This construction means we get to decide at run-time which of the NVRAM
> functions should be used. (Whereas your example makes a build-time decision.)

Right, but we only need to make a runtime decision on powerpc (right?).
So it seems to me we should isolate that in the powerpc code.

> The purpose of arch_nvram_ops is much the same. That is, it does for m68k
> and x86 what ppc_md already does for ppc32 and ppc64. (And once these
> platforms share an API like this, they can share more driver code, and
> reduce duplicated code.)

> The approach taken in this series was to push the arch_nvram_ops approach
> as far as possible, because by making everything fit into that regime it
> immediately became apparent where architectures and platforms have
> diverged, creating weird inconsistencies like the differences in sync
> ioctl behaviour between ppc32 and ppc64 for core99. (Early revisions of
> this series exposed more issues like bugs and dead code that got addressed
> elsewhere.)

I just don't see the advantage of having arch_nvram_ops which is a
structure of function pointers that are always the same on a given arch,
vs some static inlines that implement the same ops for that arch.

> Problem is, as Arnd pointed out, powerpc doesn't need both kinds of ops
> struct. So I'm rewriting this series in such a way that powerpc doesn't
> have to implement both. This rewrite is going to look totally different
> for powerpc (though not for x86 or m68k) so you might want to wait for me
> to post v9 before spending more time on code review.

OK. I know you've been working on this series for a long time and I
don't want to roadblock it, so at the end of the day I don't feel that
strongly about it as long as the code works.

I'll wait for v9 and have another look then.

cheers

2019-01-08 23:06:40

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH v8 24/25] powerpc: Adopt nvram module for PPC64

On Tue, 8 Jan 2019, Michael Ellerman wrote:

> > The reason why that doesn't work boils down to introspection. (This
> > was mentioned elsewhere in this email thread.) For example, we
> > presently have code like this,
> >
> > ssize_t nvram_get_size(void)
> > {
> > if (ppc_md.nvram_size)
> > return ppc_md.nvram_size();
> > return -1;
> > }
> > EXPORT_SYMBOL(nvram_get_size);
> >
> > This construction means we get to decide at run-time which of the NVRAM
> > functions should be used. (Whereas your example makes a build-time decision.)
>
> Right, but we only need to make a runtime decision on powerpc (right?).

It's needed in many places outside of powerpc. Otherwise the caller can't
determine at run-time which ops are implemented.

Hence you have to duplicate the caller for each supported configuration
that you build.

Already, this precludes a shared misc device implementation and belies the
"generic" in drivers/char/generic_nvram.c.

--