From 437ace3777abc15d013d04e6644b100040bc613d Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: 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"). Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- arch/m68k/atari/Makefile | 2 + arch/m68k/atari/nvram.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 arch/m68k/atari/nvram.c (limited to 'arch/m68k/atari') 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..a8c457e40b0b --- /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 + * idea by and with help from Richard Jelinek + * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) + * Further contributions from Cesar Barros, Erik Gilling, Tim Hockin and + * Wim Van Sebroeck. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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\n"); + 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 */ -- cgit v1.2.3 From 1278cf66cf4b1c3d30e311200b50c45457c92baa Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: nvram: Replace nvram_* function exports with static functions Replace nvram_* functions with static functions in nvram.h. These will become wrappers for struct nvram_ops method calls. This patch effectively disables existing NVRAM functionality so as to allow the rest of the series to be bisected without build failures. That functionality is gradually re-implemented in subsequent patches. Replace the sole validate-checksum-and-read-byte sequence with a call to nvram_read() which will gain the same semantics in subsequent patches. Remove unused exports. Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- arch/m68k/atari/nvram.c | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) (limited to 'arch/m68k/atari') diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c index a8c457e40b0b..1d767847ffa6 100644 --- a/arch/m68k/atari/nvram.c +++ b/arch/m68k/atari/nvram.c @@ -34,38 +34,17 @@ * 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); } -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) +static 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. */ @@ -73,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; @@ -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; -- cgit v1.2.3 From a084dbf6592c22468eb946014b2e731fb42da7a9 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: m68k/atari: Implement arch_nvram_ops struct By implementing an arch_nvram_ops struct, a platform can re-use the drivers/char/nvram.c module without needing any arch-specific code in that module. Atari does so here. Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- arch/m68k/atari/nvram.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'arch/m68k/atari') diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c index 1d767847ffa6..e75adebe6e7d 100644 --- a/arch/m68k/atari/nvram.c +++ b/arch/m68k/atari/nvram.c @@ -74,6 +74,55 @@ static void __nvram_set_checksum(void) __nvram_write_byte(sum, ATARI_CKS_LOC + 1); } +static ssize_t atari_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 atari_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 atari_nvram_get_size(void) +{ + return NVRAM_BYTES; +} + +const struct nvram_ops arch_nvram_ops = { + .read = atari_nvram_read, + .write = atari_nvram_write, + .get_size = atari_nvram_get_size, +}; +EXPORT_SYMBOL(arch_nvram_ops); + #ifdef CONFIG_PROC_FS static struct { unsigned char val; -- cgit v1.2.3 From 666047fe2a4c9e1bc255ca0549d825b40832886c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: m68k/atari: Implement arch_nvram_ops methods and enable CONFIG_HAVE_ARCH_NVRAM_OPS Atari RTC NVRAM uses a checksum so implement the remaining arch_nvram_ops methods for the set_checksum and initialize ioctls. Enable CONFIG_HAVE_ARCH_NVRAM_OPS. Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- arch/m68k/atari/nvram.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'arch/m68k/atari') diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c index e75adebe6e7d..c347fd206ddf 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 atari_nvram_set_checksum(void) +{ + spin_lock_irq(&rtc_lock); + __nvram_set_checksum(); + spin_unlock_irq(&rtc_lock); + return 0; +} + +static long atari_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 atari_nvram_read(char *buf, size_t count, loff_t *ppos) { char *p = buf; @@ -113,6 +133,8 @@ static ssize_t atari_nvram_write(char *buf, size_t count, loff_t *ppos) static ssize_t atari_nvram_get_size(void) { + if (!MACH_IS_ATARI) + return -ENODEV; return NVRAM_BYTES; } @@ -120,6 +142,8 @@ const struct nvram_ops arch_nvram_ops = { .read = atari_nvram_read, .write = atari_nvram_write, .get_size = atari_nvram_get_size, + .set_checksum = atari_nvram_set_checksum, + .initialize = atari_nvram_initialize, }; EXPORT_SYMBOL(arch_nvram_ops); -- cgit v1.2.3 From d3b41b6bb49ecbf74b6bda63e00bf17fdb4d3c47 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: 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. Acked-by: Geert Uytterhoeven Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- arch/m68k/atari/nvram.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'arch/m68k/atari') diff --git a/arch/m68k/atari/nvram.c b/arch/m68k/atari/nvram.c index c347fd206ddf..7000d2443aa3 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 atari_nvram_set_checksum(void) +long atari_nvram_set_checksum(void) { spin_lock_irq(&rtc_lock); __nvram_set_checksum(); @@ -82,7 +82,7 @@ static long atari_nvram_set_checksum(void) return 0; } -static long atari_nvram_initialize(void) +long atari_nvram_initialize(void) { loff_t i; @@ -94,7 +94,7 @@ static long atari_nvram_initialize(void) return 0; } -static ssize_t atari_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; @@ -112,7 +112,7 @@ static ssize_t atari_nvram_read(char *buf, size_t count, loff_t *ppos) return p - buf; } -static ssize_t atari_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; @@ -131,22 +131,11 @@ static ssize_t atari_nvram_write(char *buf, size_t count, loff_t *ppos) return p - buf; } -static ssize_t atari_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 = atari_nvram_read, - .write = atari_nvram_write, - .get_size = atari_nvram_get_size, - .set_checksum = atari_nvram_set_checksum, - .initialize = atari_nvram_initialize, -}; -EXPORT_SYMBOL(arch_nvram_ops); - #ifdef CONFIG_PROC_FS static struct { unsigned char val; -- cgit v1.2.3