From: Finn Thain <hidden> Date: 2015-06-14 13:08:34
The generic NVRAM module, drivers/char/generic_nvram, implements a
/dev/nvram misc device. It is used only by 32-bit PowerPC platforms and
isn't generic enough to be more widely used.
The RTC NVRAM module, drivers/char/nvram, also implements a /dev/nvram
misc device. It is used by x86, ARM and m68k.
The former module cannot be used on x86, ARM or m68k because it
cannot co-exist with the latter module, partly due to the Kconfig logic.
It is possible to modify the modules so that one kernel binary could
have either, neither or both. However, automatically loading the
appropriate module is then impossible; if both provide the
char-major-10-144 alias then the wrong module will end up being loaded.
Hence a multi-platform kernel binary needs a single generic nvram module
with alias char-major-10-144.
Therefore, drivers/char/nvram.c should be made more generic and the
arch-specific code therein should be moved to a more appropriate
place under arch/. Also, drivers/char/generic_nvram.c should be removed
to reduce code duplication.
In this patch series, Atari-specific code is moved from the nvram module
to arch/m68k/atari. More arch-specific code in the nvram module could
be moved, probably to arch/x86, but it is difficult to determine just
what code is relevant to ARM platforms and what code is x86-only.
In addressing code duplication, this patch series removes three
inconsistent /dev/nvram misc device implementations. One of these,
drivers/macintosh/nvram.c is entirely unused already. The other two,
drivers/char/generic_nvram.c and the misc device implementation in
arch/powerpc/kernel/nvram_64.c, are replaced by drivers/char/nvram.c.
A benefit of this work is better consistency -- between PPC32 and PPC64
as well as between PPC_PMAC and MAC. This new uniformity does have
implications for userspace, that is, some error codes for some ioctl calls
become consistent on all PowerPC platforms.
The drivers/char/nvram module becomes sufficiently generic to be useful
to other platforms and architectures, besides those with "CMOS" RTC. At the
end of this patch series the module is adopted by the m68k Mac port, which
already has PRAM access functions but lacks the /dev/nvram misc device.
This patch series has been compile-tested for arm, m68k, powerpc 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 PowerBook 520 and Quadra 650.
Note that my testing doesn't cover PPC64 or Atari.
---
arch/m68k/Kconfig | 3
arch/m68k/atari/Makefile | 2
arch/m68k/atari/nvram.c | 291 +++++++++++
arch/m68k/kernel/setup_mm.c | 107 ++++
arch/m68k/mac/misc.c | 144 +++--
arch/powerpc/Kconfig | 5
arch/powerpc/include/asm/nvram.h | 9
arch/powerpc/kernel/nvram_64.c | 203 +------
arch/powerpc/kernel/setup_32.c | 27 -
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 | 5
arch/powerpc/platforms/powermac/nvram.c | 9
arch/powerpc/platforms/powermac/setup.c | 3
drivers/char/Kconfig | 13
drivers/char/Makefile | 6
drivers/char/generic_nvram.c | 174 ------
drivers/char/nvram.c | 742 ++++++++++++-----------------
drivers/macintosh/nvram.c | 130 -----
drivers/platform/x86/thinkpad_acpi.c | 20
drivers/scsi/Kconfig | 6
drivers/scsi/atari_scsi.c | 16
drivers/video/fbdev/controlfb.c | 4
drivers/video/fbdev/imsttfb.c | 7
drivers/video/fbdev/matrox/matroxfb_base.c | 4
drivers/video/fbdev/platinumfb.c | 4
drivers/video/fbdev/valkyriefb.c | 4
include/linux/nvram.h | 23
include/uapi/linux/pmu.h | 2
30 files changed, 937 insertions(+), 1044 deletions(-)
@@ -235,21 +235,7 @@ EXPORT_SYMBOL(arch_nvram_ops);staticloff_tnvram_misc_llseek(structfile*file,loff_toffset,intorigin){-switch(origin){-case0:-/* nothing to do */-break;-case1:-offset+=file->f_pos;-break;-case2:-offset+=NVRAM_BYTES;-break;-default:-return-EINVAL;-}--return(offset>=0)?(file->f_pos=offset):-EINVAL;+returnfixed_size_llseek(file,offset,origin,nvram_size);}staticssize_tnvram_misc_read(structfile*file,char__user*buf,
From: Finn Thain <hidden> Date: 2015-06-14 13:08:48
Move the m68k-specific code elsewhere to make the driver generic.
Change the vmode calculation from logical OR to bitwise OR, since it is
obviously wrong.
Signed-off-by: Finn Thain <redacted>
---
BTW, I didn't change the SCSI ID location in NVRAM. This code says 16
whereas atari_scsi says 14. Which one is correct?
---
arch/m68k/atari/Makefile | 2
arch/m68k/atari/nvram.c | 255 ++++++++++++++++++++++++++++++++++++++++++
drivers/char/nvram.c | 280 +++++------------------------------------------
3 files changed, 292 insertions(+), 245 deletions(-)
Index: linux/arch/m68k/atari/nvram.c
===================================================================
@@ -0,0 +1,255 @@+/*+*CMOS/NV-RAMdriverforAtari.Adaptedfromdrivers/char/nvram.c.+*Copyright(C)1997RomanHodek<Roman.Hodek@informatik.uni-erlangen.de>+*ideabyandwithhelpfromRichardJelinek<rj@suse.de>+*Portionscopyright(c)2001,2002SunMicrosystems(thockin@sun.com)+*FurthercontributionsfromCesarBarros,ErikGilling,TimHockinand+*WimVanSebroeck.+*/++#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+*purposememoryintheNVRAM-thatistosay,theyalladdthe+*NVRAM_FIRST_BYTEoffset.PassthemoffsetsintoNVRAMasifyoudidnot+*knowabouttheRTCcruft.+*/++/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with+*rtc_lockheld.Duetotheindex-port/data-portdesignoftheRTC,we+*don'twanttwodifferentthingstryingtogettoitatonce.(e.g.the+*periodic11minsyncfromkernel/time/ntp.cvs.thisdriver.)+*/++unsignedchar__nvram_read_byte(inti)+{+returnCMOS_READ(NVRAM_FIRST_BYTE+i);+}++unsignedcharnvram_read_byte(inti)+{+unsignedlongflags;+unsignedcharc;++spin_lock_irqsave(&rtc_lock,flags);+c=__nvram_read_byte(i);+spin_unlock_irqrestore(&rtc_lock,flags);+returnc;+}+EXPORT_SYMBOL(nvram_read_byte);++/* This races nicely with trying to read with checksum checking */+void__nvram_write_byte(unsignedcharc,inti)+{+CMOS_WRITE(c,NVRAM_FIRST_BYTE+i);+}++voidnvram_write_byte(unsignedcharc,inti)+{+unsignedlongflags;++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;theseareattheveryend.+*/+#define ATARI_CKS_RANGE_START 0+#define ATARI_CKS_RANGE_END 47+#define ATARI_CKS_LOC 48++int__nvram_check_checksum(void)+{+inti;+unsignedcharsum=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));+}++intnvram_check_checksum(void)+{+unsignedlongflags;+intrv;++spin_lock_irqsave(&rtc_lock,flags);+rv=__nvram_check_checksum();+spin_unlock_irqrestore(&rtc_lock,flags);+returnrv;+}+EXPORT_SYMBOL(nvram_check_checksum);++staticvoid__nvram_set_checksum(void)+{+inti;+unsignedcharsum=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+staticstruct{+unsignedcharval;+char*name;+}boot_prefs[]={+{0x80,"TOS"},+{0x40,"ASV"},+{0x20,"NetBSD (?)"},+{0x10,"Linux"},+{0x00,"unspecified"},+};++staticchar*languages[]={+"English (US)",+"German",+"French",+"English (UK)",+"Spanish",+"Italian",+"6 (undefined)",+"Swiss (French)",+"Swiss (German)",+};++staticchar*dateformat[]={+"MM%cDD%cYY",+"DD%cMM%cYY",+"YY%cMM%cDD",+"YY%cDD%cMM",+"4 (undefined)",+"5 (undefined)",+"6 (undefined)",+"7 (undefined)",+};++staticchar*colors[]={+"2","4","16","256","65536","??","??","??"+};++staticvoidatari_nvram_proc_read(unsignedchar*nvram,structseq_file*seq,+void*offset)+{+intchecksum;+inti;+unsignedvmode;++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"):"");+}++staticintnvram_proc_read(structseq_file*seq,void*offset)+{+unsignedcharcontents[NVRAM_BYTES];+inti;++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);++return0;+}++staticintnvram_proc_open(structinode*inode,structfile*file)+{+returnsingle_open(file,nvram_proc_read,NULL);+}++staticconststructfile_operationsnvram_proc_fops={+.owner=THIS_MODULE,+.open=nvram_proc_open,+.read=seq_read,+.llseek=seq_lseek,+.release=single_release,+};++staticint__initatari_nvram_init(void)+{+if(!(MACH_IS_ATARI&&ATARIHW_PRESENT(TT_CLK)))+return-ENODEV;++if(!proc_create("driver/nvram",0,NULL,&nvram_proc_fops)){+pr_err("nvram: can't create /proc/driver/nvram\n");+return-ENOMEM;+}++return0;+}+device_initcall(atari_nvram_init);+#endif /* CONFIG_PROC_FS */
@@ -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;theseareattheveryend*/-#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_lockheld.Duetotheindex-port/data-portdesignoftheRTC,we-*don'twanttwodifferentthingstryingtogettoitatonce.(e.g.the-*periodic11minsyncfromkernel/time/ntp.cvs.thisdriver.)-*/-#include<linux/types.h>#include<linux/errno.h>#include<linux/miscdevice.h>
@@ -119,12 +54,9 @@ static int nvram_open_mode; /* special o#define NVRAM_WRITE 1 /* opened for writing (exclusive) */#define NVRAM_EXCL 2 /* opened with O_EXCL */-staticintmach_check_checksum(void);-staticvoidmach_set_checksum(void);-#ifdef CONFIG_PROC_FS-staticvoidmach_proc_infos(unsignedchar*contents,structseq_file*seq,-void*offset);+staticvoidpc_nvram_proc_read(unsignedchar*contents,structseq_file*seq,+void*offset);#endif/*
@@ -138,6 +70,14 @@ static void mach_proc_infos(unsigned cha*knowabouttheRTCcruft.*/+#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE)++/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with+*rtc_lockheld.Duetotheindex-port/data-portdesignoftheRTC,we+*don'twanttwodifferentthingstryingtogettoitatonce.(e.g.the+*periodic11minsyncfromkernel/time/ntp.cvs.thisdriver.)+*/+unsignedchar__nvram_read_byte(inti){returnCMOS_READ(NVRAM_FIRST_BYTE+i);
@@ -173,9 +113,22 @@ void nvram_write_byte(unsigned char c, 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){-returnmach_check_checksum();+inti;+unsignedshortsum=0;+unsignedshortexpect;++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);
@@ -396,7 +355,7 @@ static int nvram_proc_read(struct seq_ficontents[i]=__nvram_read_byte(i);spin_unlock_irq(&rtc_lock);-mach_proc_infos(contents,seq,offset);+pc_nvram_proc_read(contents,seq,offset);return0;}
@@ -443,10 +402,6 @@ static int __init nvram_init(void){intret;-/* 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",
From: Finn Thain <hidden> Date: 2015-06-14 13:08:55
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 <redacted>
---
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.
The removal of "select NVRAM" may mean that some kernel configs (such
as Debian/m68k) may need tweaking.
---
drivers/char/Kconfig | 5 +----
drivers/scsi/Kconfig | 6 +++---
drivers/scsi/atari_scsi.c | 8 ++++----
3 files changed, 8 insertions(+), 11 deletions(-)
Index: linux/drivers/char/Kconfig
===================================================================
@@ -875,9 +875,10 @@ static int __init atari_scsi_probe(strucif(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()){unsignedcharb=nvram_read_byte(14);
@@ -888,8 +889,7 @@ static int __init atari_scsi_probe(strucif(b&0x80)atari_scsi_template.this_id=b&7;}-}-+#endif#ifdef REAL_DMA/* If running on a Falcon and if there's TT-Ram (i.e., more than one
From: Finn Thain <hidden> Date: 2015-06-14 13:09:03
By implementing an arch_nvram_ops struct, any platform can re-use the
drivers/char/nvram 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 platforms
(i.e. x86 and ARM platforms) have none 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 <redacted>
---
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 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(-)
Index: linux/arch/m68k/atari/nvram.c
===================================================================
@@ -38,33 +38,12 @@ unsigned char __nvram_read_byte(int i)returnCMOS_READ(NVRAM_FIRST_BYTE+i);}-unsignedcharnvram_read_byte(inti)-{-unsignedlongflags;-unsignedcharc;--spin_lock_irqsave(&rtc_lock,flags);-c=__nvram_read_byte(i);-spin_unlock_irqrestore(&rtc_lock,flags);-returnc;-}-EXPORT_SYMBOL(nvram_read_byte);-/* This races nicely with trying to read with checksum checking */void__nvram_write_byte(unsignedcharc,inti){CMOS_WRITE(c,NVRAM_FIRST_BYTE+i);}-voidnvram_write_byte(unsignedcharc,inti)-{-unsignedlongflags;--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;theseareattheveryend.*/
@@ -83,18 +62,6 @@ int __nvram_check_checksum(void)(__nvram_read_byte(ATARI_CKS_LOC+1)==(sum&0xff));}-intnvram_check_checksum(void)-{-unsignedlongflags;-intrv;--spin_lock_irqsave(&rtc_lock,flags);-rv=__nvram_check_checksum();-spin_unlock_irqrestore(&rtc_lock,flags);-returnrv;-}-EXPORT_SYMBOL(nvram_check_checksum);-staticvoid__nvram_set_checksum(void){inti;
@@ -880,13 +880,15 @@ static int __init atari_scsi_probe(struc#ifdef CONFIG_NVRAMelse/* Test if a host id is set in the NVRam */-if(ATARIHW_PRESENT(TT_CLK)&&nvram_check_checksum()){-unsignedcharb=nvram_read_byte(14);+if(ATARIHW_PRESENT(TT_CLK)){+unsignedcharb;+loff_toffset=14;+ssize_tcount=arch_nvram_ops.read(&b,1,&offset);/* Arbitration enabled? (for TOS)*Ifyes,useconfiguredhostID*/-if(b&0x80)+if((count==1)&&(b&0x80))atari_scsi_template.this_id=b&7;}#endif
From: Finn Thain <hidden> Date: 2015-06-14 13:09:11
Different platforms and architectures offer different NVRAM sizes and
access methods. E.g. PPC32 has byte-at-a-time read/write functions whereas
PPC64 has byte-range read/write 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 <redacted>
---
The #ifdefs here restrict the procfs and checksumming code to those
architectures with PC-style RTC NVRAM. There may be a better place for
that code but it's an open question. See https://lkml.org/lkml/2015/2/3/22
The procfs code here, if irrelevant to ARM platforms, could be moved to
arch/x86 (like the earlier patch does for m68k code) and the nvram ops
could implemented and exported by the rtc-cmos driver instead. This
would eliminate these #ifdefs.
---
drivers/char/nvram.c | 30 +++++++++++++++++++++++++++---
include/linux/nvram.h | 2 ++
2 files changed, 29 insertions(+), 3 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -51,9 +51,12 @@ static DEFINE_MUTEX(nvram_mutex);staticDEFINE_SPINLOCK(nvram_state_lock);staticintnvram_open_cnt;/* #times opened */staticintnvram_open_mode;/* special open modes */+staticssize_tnvram_size;#define NVRAM_WRITE 1 /* opened for writing (exclusive) */#define NVRAM_EXCL 2 /* opened with O_EXCL */+#if defined(CONFIG_X86) || defined(CONFIG_ARM)+/**Thesefunctionsareprovidedtobecalledinternallyorbyotherpartsof*thekernel.It'suptothecallertoensurecorrectchecksumbeforereading
From: Finn Thain <hidden> Date: 2015-06-14 13:09:23
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 makes them distict from nvram_ops members.
Signed-off-by: Finn Thain <redacted>
---
drivers/char/nvram.c | 194 ++++++++++++++++++++++-----------------------------
1 file changed, 86 insertions(+), 108 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -54,11 +54,6 @@ static int nvram_open_mode; /* special o#define NVRAM_WRITE 1 /* opened for writing (exclusive) */#define NVRAM_EXCL 2 /* opened with O_EXCL */-#ifdef CONFIG_PROC_FS-staticvoidpc_nvram_proc_read(unsignedchar*contents,structseq_file*seq,-void*offset);-#endif-/**Thesefunctionsareprovidedtobecalledinternallyorbyotherpartsof*thekernel.It'suptothecallertoensurecorrectchecksumbeforereading
From: Finn Thain <hidden> Date: 2015-06-14 13:09:32
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 <redacted>
---
Changed since v1:
- Don't bother acquiring the mutex for unimplemented ioctls.
---
drivers/char/nvram.c | 71 ++++++++++++++++++++++++++++----------------------
include/linux/nvram.h | 2 +
2 files changed, 43 insertions(+), 30 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -272,51 +283,51 @@ checksum_err:staticlongnvram_misc_ioctl(structfile*file,unsignedintcmd,unsignedlongarg){-inti;+longret=-ENOTTY;switch(cmd){-caseNVRAM_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);-return0;-+if(arch_nvram_ops.initialize!=NULL){+mutex_lock(&nvram_mutex);+ret=arch_nvram_ops.initialize();+mutex_unlock(&nvram_mutex);+}+break;caseNVRAM_SETCKS:/* just set checksum, contents unchanged (maybe useful after*checksumgarbagedsomehow...)*/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);-return0;--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;}+returnret;}staticintnvram_misc_open(structinode*inode,structfile*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;}
From: Finn Thain <hidden> Date: 2015-06-14 13:09:42
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.
PPC64 implements byte-range read/write methods which are similar to
file_operations struct methods. Other platforms provide only
byte-at-a-time functions. So the misc device prefers the former but
will fall back on the latter.
Signed-off-by: Finn Thain <redacted>
---
drivers/char/nvram.c | 162 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 114 insertions(+), 48 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -215,69 +255,95 @@ static loff_t nvram_misc_llseek(struct fstaticssize_tnvram_misc_read(structfile*file,char__user*buf,size_tcount,loff_t*ppos){-unsignedcharcontents[NVRAM_BYTES];-unsignedi=*ppos;-unsignedchar*tmp;--spin_lock_irq(&rtc_lock);+loff_ti;+char__user*p=buf;-if(!__nvram_check_checksum())-gotochecksum_err;--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)+return0;-*ppos=i;--returntmp-contents;+/* If the arch provided a byte range read op, use it. Otherwise+*fallbackonthebyte-at-a-timeaccessor.+*/+if(arch_nvram_ops.read!=NULL){+char*tmp;+ssize_tret;++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)+gotoout;++if(copy_to_user(buf,tmp,ret)){+*ppos-=ret;+ret=-EFAULT;+}++out:+kfree(tmp);+returnret;+}-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;+returnp-buf;}staticssize_tnvram_misc_write(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos){-unsignedcharcontents[NVRAM_BYTES];-unsignedi=*ppos;-unsignedchar*tmp;--if(i>=NVRAM_BYTES)-return0;/* 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 */+loff_ti;+constchar__user*p=buf;-if(copy_from_user(contents,buf,count))+if(!access_ok(VERIFY_READ,buf,count))return-EFAULT;+if(*ppos>=nvram_size)+return0;-spin_lock_irq(&rtc_lock);--if(!__nvram_check_checksum())-gotochecksum_err;--for(tmp=contents;count--;++i,++tmp)-__nvram_write_byte(*tmp,i);--__nvram_set_checksum();+/* If the arch provided a byte range write op, use it. Otherwise+*fallbackonthebyte-at-a-timeaccessor.+*/+if(arch_nvram_ops.write!=NULL){+char*tmp;+ssize_tret;++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;++if(copy_from_user(tmp,buf,count)){+ret=-EFAULT;+gotoout;+}++ret=arch_nvram_ops.write(tmp,count,ppos);++out:+kfree(tmp);+returnret;+}-spin_unlock_irq(&rtc_lock);+for(i=*ppos;count>0&&i<nvram_size;++i,++p,--count){+charc;+if(__get_user(c,p))+return-EFAULT;+arch_nvram_ops.write_byte(c,i);+}*ppos=i;--returntmp-contents;--checksum_err:-spin_unlock_irq(&rtc_lock);-return-EIO;+returnp-buf;}staticlongnvram_misc_ioctl(structfile*file,unsignedintcmd,
From: Finn Thain <hidden> Date: 2015-06-14 13:09:54
Make use of arch_nvram_ops in the thinkpad_acpi driver so that the
nvram_* function exports can be removed.
This patch series was tested on a ThinkPad T43.
Signed-off-by: Finn Thain <redacted>
Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Reviewed-by: Darren Hart <redacted>
---
drivers/platform/x86/thinkpad_acpi.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
Index: linux/drivers/platform/x86/thinkpad_acpi.c
===================================================================
From: Finn Thain <hidden> Date: 2015-06-14 13:10:04
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 <redacted>
---
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(-)
Index: linux/arch/powerpc/include/asm/nvram.h
===================================================================
From: Finn Thain <hidden> Date: 2015-06-14 13:10:11
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 <redacted>
---
arch/powerpc/platforms/chrp/nvram.c | 14 ++++++++++----
arch/powerpc/platforms/powermac/nvram.c | 9 +++++++++
2 files changed, 19 insertions(+), 4 deletions(-)
Index: linux/arch/powerpc/platforms/chrp/nvram.c
===================================================================
@@ -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;}elseif(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;}elseif(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;}elseif(nvram_naddrs==0&&sys_ctrler==SYS_CTRLER_PMU){#ifdef CONFIG_ADB_PMUnvram_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");
From: Finn Thain <hidden> Date: 2015-06-14 13:10:15
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 <redacted>
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 1 +
drivers/char/generic_nvram.c | 4 +++-
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
Index: linux/arch/powerpc/include/asm/nvram.h
===================================================================
From: Finn Thain <hidden> Date: 2015-06-14 13:10:24
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 <redacted>
---
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 failure (which is what PPC64 does).
Changed since v1:
- Don't bother acquiring the mutex for unimplemented ioctls.
---
arch/powerpc/include/asm/nvram.h | 3 ---
arch/powerpc/kernel/setup_32.c | 6 +++---
drivers/char/generic_nvram.c | 2 +-
drivers/char/nvram.c | 39 +++++++++++++++++++++++++++++++++++++++
include/linux/nvram.h | 4 ++++
5 files changed, 47 insertions(+), 7 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -376,6 +413,7 @@ static int nvram_misc_open(struct inodereturn-EBUSY;}+#ifndef CONFIG_PPC/* Prevent multiple writers if the set_checksum ioctl is implemented. */if((arch_nvram_ops.set_checksum!=NULL)&&(file->f_mode&FMODE_WRITE)&&
@@ -383,6 +421,7 @@ static int nvram_misc_open(struct inodespin_unlock(&nvram_state_lock);return-EBUSY;}+#endifif(file->f_flags&O_EXCL)nvram_open_mode|=NVRAM_EXCL;
From: Finn Thain <hidden> Date: 2015-06-14 13:10:32
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 <redacted>
---
arch/m68k/atari/nvram.c | 6 +++---
drivers/char/nvram.c | 27 +++++----------------------
include/linux/nvram.h | 8 --------
3 files changed, 8 insertions(+), 33 deletions(-)
Index: linux/drivers/char/nvram.c
===================================================================
@@ -98,16 +97,14 @@ unsigned char nvram_read_byte(int i)spin_unlock_irqrestore(&rtc_lock,flags);returnc;}-EXPORT_SYMBOL(nvram_read_byte);/* This races nicely with trying to read with checksum checking (nvram_read) */-void__nvram_write_byte(unsignedcharc,inti)+staticvoid__nvram_write_byte(unsignedcharc,inti){CMOS_WRITE(c,NVRAM_FIRST_BYTE+i);}-EXPORT_SYMBOL(__nvram_write_byte);-voidnvram_write_byte(unsignedcharc,inti)+staticvoidnvram_write_byte(unsignedcharc,inti){unsignedlongflags;
@@ -115,14 +112,13 @@ void nvram_write_byte(unsigned char c, 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)+staticint__nvram_check_checksum(void){inti;unsignedshortsum=0;
@@ -134,19 +130,6 @@ int __nvram_check_checksum(void)__nvram_read_byte(PC_CKS_LOC+1);return(sum&0xffff)==expect;}-EXPORT_SYMBOL(__nvram_check_checksum);--intnvram_check_checksum(void)-{-unsignedlongflags;-intrv;--spin_lock_irqsave(&rtc_lock,flags);-rv=__nvram_check_checksum();-spin_unlock_irqrestore(&rtc_lock,flags);-returnrv;-}-EXPORT_SYMBOL(nvram_check_checksum);staticvoid__nvram_set_checksum(void){
@@ -3,14 +3,6 @@#include<uapi/linux/nvram.h>-/* __foo is foo without grabbing the rtc_lock - get it yourself */-externunsignedchar__nvram_read_byte(inti);-externunsignedcharnvram_read_byte(inti);-externvoid__nvram_write_byte(unsignedcharc,inti);-externvoidnvram_write_byte(unsignedcharc,inti);-externint__nvram_check_checksum(void);-externintnvram_check_checksum(void);-structnvram_ops{ssize_t(*read)(char*,size_t,loff_t*);ssize_t(*write)(char*,size_t,loff_t*);
@@ -33,13 +33,13 @@*periodic11minsyncfromkernel/time/ntp.cvs.thisdriver.)*/-unsignedchar__nvram_read_byte(inti)+staticunsignedchar__nvram_read_byte(inti){returnCMOS_READ(NVRAM_FIRST_BYTE+i);}/* This races nicely with trying to read with checksum checking */-void__nvram_write_byte(unsignedcharc,inti)+staticvoid__nvram_write_byte(unsignedcharc,inti){CMOS_WRITE(c,NVRAM_FIRST_BYTE+i);}
From: Finn Thain <hidden> Date: 2015-06-14 13:10:41
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 <redacted>
---
This re-enables the nvram module for Atari.
---
arch/m68k/Kconfig | 3 +++
arch/m68k/atari/nvram.c | 24 ++++++++++++++++++++++++
drivers/char/Kconfig | 2 +-
3 files changed, 28 insertions(+), 1 deletion(-)
Index: linux/arch/m68k/atari/nvram.c
===================================================================
@@ -284,11 +287,31 @@ static void via_pram_command(int commandstaticunsignedcharvia_pram_read_byte(intoffset){-return0;+unsignedchartemp;+intaddr=((offset&0xE0)<<3)|((offset&0x1F)<<2);++/* Use RTC command 0x38 for XPRAM access, as per MESS source code */+via_pram_command(addr|0x3800|0x8001,&temp);++returntemp;}staticvoidvia_pram_write_byte(unsignedchardata,intoffset){+unsignedchartemp;+intaddr=((offset&0xE0)<<3)|((offset&0x1F)<<2);++/* Clear the write protect bit */+temp=0x55;+via_pram_command(0x34|0x01,&temp);++/* Write the byte to XPRAM */+temp=data;+via_pram_command(0x3800|0x0001|addr,&temp);++/* Set the write protect bit */+temp=0xD5;+via_pram_command(0x34|0x01,&temp);}/*
From: Finn Thain <hidden> Date: 2015-06-14 13:12:46
Adopt nvram module to reduce code duplication.
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 <redacted>
---
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 v1:
- The -ENOENT that appeared in v1 was changed to -EINVAL, to be
consistent with existing logic, that is,
if (part < pmac_nvram_OF || part > pmac_nvram_NR)
return -EINVAL;
---
arch/powerpc/Kconfig | 3
arch/powerpc/kernel/nvram_64.c | 203 ++++---------------------------
arch/powerpc/platforms/powermac/Makefile | 5
arch/powerpc/platforms/powermac/setup.c | 2
drivers/char/nvram.c | 2
5 files changed, 36 insertions(+), 179 deletions(-)
Index: linux/arch/powerpc/Kconfig
===================================================================
@@ -177,10 +177,9 @@ config SYSVIPC_COMPATdepends onCOMPAT&&SYSVIPCdefaulty-# All PPC32s use generic nvram driver through ppc_mdconfigHAVE_ARCH_NVRAM_OPSbool-defaultyifPPC32+defaultyconfigSCHED_OMIT_FRAME_POINTERbool
@@ -9,11 +9,6 @@ obj-y += pic.o setup.o time.o featuresleep.olow_i2c.ocache.opfunc_core.o\pfunc_base.oudbg_scc.oudbg_adb.oobj-$(CONFIG_PMAC_BACKLIGHT)+=backlight.o-# CONFIG_NVRAM is an arch. independent tristate symbol, for pmac32 we really-# need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really-# CONFIG_NVRAM=yobj-$(CONFIG_NVRAM:m=y) += nvram.o-# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff-obj-$(CONFIG_PPC64)+=nvram.oobj-$(CONFIG_PPC32)+=bootx_init.oobj-$(CONFIG_SMP)+=smp.o
From: Finn Thain <hidden> Date: 2015-06-14 13:12:53
A multi-platform kernel binary needs to decide at run-time how to dispatch
the arch_nvram_ops calls. Add platform-independent arch_nvram_ops, for use
when multiple platform-specific NVRAM ops implementations are needed.
Enable CONFIG_HAVE_ARCH_NVRAM_OPS for Macs.
Signed-off-by: Finn Thain <redacted>
---
Changed since v1:
- Removed Mac and Atari ops struct definitions and the associated #ifdefs.
- Moved extern declarations for fewer lines of code and better readability.
- The IS_ENABLED(CONFIG_NVRAM) tests were moved to this patch, because it is
now in this patch that CONFIG_HAVE_ARCH_NVRAM_OPS is enabled for Macs.
---
arch/m68k/Kconfig | 2
arch/m68k/atari/nvram.c | 21 ++------
arch/m68k/kernel/setup_mm.c | 107 ++++++++++++++++++++++++++++++++++++++++++++
arch/m68k/mac/misc.c | 18 +++++++
4 files changed, 131 insertions(+), 17 deletions(-)
Index: linux/arch/m68k/mac/misc.c
===================================================================
From: Finn Thain <hidden> Date: 2015-06-14 13:13:05
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 <redacted>
---
Changes since v1:
- Don't introduce the arch_nvram_ops struct in this patch, even if it
would form a logical progression. Since the struct would get replaced
later on, some might see it as churn.
---
arch/m68k/mac/misc.c | 91 +++++++++++++++++++++++++--------------------------
1 file changed, 46 insertions(+), 45 deletions(-)
Index: linux/arch/m68k/mac/misc.c
===================================================================
From: Finn Thain <hidden> Date: 2015-06-14 13:13:20
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.
As before, when CONFIG_PPC && !CONFIG_PPC_PMAC, the IOC_NVRAM_GET_OFFSET
ioctl is unimplemented. For the nvram module, unimplemented ioctls return
-ENOTTY. Whereas, for the superseded generic_nvram module they would
return -EINVAL.
Signed-off-by: Finn Thain <redacted>
---
This ioctl change is visible to userspace code but only in an error path.
I didn't find any userspace code that uses the IOC_NVRAM_GET_OFFSET ioctl.
The change in the name of the module is also visible. 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.
---
Changes since v1:
- Small indentation fix.
---
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 | 10 ++++++----
6 files changed, 11 insertions(+), 10 deletions(-)
Index: linux/arch/powerpc/Kconfig
===================================================================
@@ -178,7 +178,7 @@ config SYSVIPC_COMPATdefaulty# All PPC32s use generic nvram driver through ppc_md-configGENERIC_NVRAM+configHAVE_ARCH_NVRAM_OPSbooldefaultyifPPC32
From: Finn Thain <hidden> Date: 2015-06-14 13:13:26
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.
Add the missing CONFIG_NVRAM test to imsttfb to avoid a build failure.
Signed-off-by: Finn Thain <redacted>
---
arch/powerpc/kernel/setup_32.c | 8 ++++----
drivers/char/generic_nvram.c | 4 ++--
drivers/video/fbdev/controlfb.c | 4 ++--
drivers/video/fbdev/imsttfb.c | 7 +++----
drivers/video/fbdev/matrox/matroxfb_base.c | 2 +-
drivers/video/fbdev/platinumfb.c | 4 ++--
drivers/video/fbdev/valkyriefb.c | 4 ++--
7 files changed, 16 insertions(+), 17 deletions(-)
Index: linux/arch/powerpc/kernel/setup_32.c
===================================================================
@@ -415,7 +415,7 @@ static int __init init_control(struct fb/* Try to pick a video mode out of NVRAM if we have one. */#ifdef CONFIG_NVRAMif(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
@@ -423,7 +423,7 @@ static int __init init_control(struct fbcmode=default_cmode;#ifdef CONFIG_NVRAMif(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);
@@ -349,7 +349,7 @@ static int platinum_init_fb(struct fb_inprintk(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
@@ -362,7 +362,7 @@ static int platinum_init_fb(struct fb_indefault_vmode=VMODE_640_480_60;#ifdef CONFIG_NVRAMif(default_cmode==CMODE_NVRAM)-default_cmode=nvram_read_byte(NV_CMODE);+default_cmode=arch_nvram_ops.read_byte(NV_CMODE);#endifif(default_cmode<CMODE_8||default_cmode>CMODE_32)default_cmode=CMODE_8;
@@ -287,7 +287,7 @@ static void __init valkyrie_choose_mode(/* Try to pick a video mode out of NVRAM if we have one. */#if !defined(CONFIG_MAC) && 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])
This seems uncontroversial, so I'll take it via powerpc for 4.1.
In future please include the details on how/why it's unused in the changelog.
Geert did the digging for you:
Removal seems to be forgotten by full-history-linux
commit 17c6f4635bea74e110ab3558d408c9cd218c568a
Author: Benjamin Herrenschmidt [off-list ref]
Date: Fri Feb 6 14:20:56 2004 +1100
ppc32: Rework nvram management
move drivers/macintosh/nvram.c to drivers/char/generic_nvram.c,
update platform hooks,
fix powermac nvram driver for newer machines
I'll fold that into the changelog.
cheers
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
This is just marshalling the offset argument. I don't know how to rewrite
that code more clearly. I'm open to suggestions. I don't know of any
documentation that gives names or meanings to the different bit ranges. I
infered the format from the MESS source code,
https://github.com/mamedev/mame/blob/master/src/mess/machine/macrtc.c
What I found in the MESS source code looks like the result of reverse
engineering. Hence the RTC code in this patch also looks like a reverse
engineered driver.
quoted
+
+ /* Use RTC command 0x38 for XPRAM access, as per MESS source code */
+ via_pram_command(addr | 0x3800 | 0x8001, &temp);
It seems 0x38 is already documented in <linux/pmu.h> (see below), or not
(it's shifted left by 8 bits?)?
No, this is a RTC command not a PMU command. This RTC device is an Apple
custom IC that is publicly undocumented. OTOH, the PMU device is well
documented, since Apple publicly released PMU driver source code in
MkLinux and later in XNU. That's why I've been able to provide #defines
for the PMU commands but not the RTC commands.
quoted
+
+ return temp;
}
static void via_pram_write_byte(unsigned char data, int offset)
{
+ unsigned char temp;
+ int addr = ((offset & 0xE0) << 3) | ((offset & 0x1F) << 2);
+
+ /* Clear the write protect bit */
+ temp = 0x55;
+ via_pram_command(0x34 | 0x01, &temp);
+
+ /* Write the byte to XPRAM */
+ temp = data;
+ via_pram_command(0x3800 | 0x0001 | addr, &temp);
+
+ /* Set the write protect bit */
+ temp = 0xD5;
+ via_pram_command(0x34 | 0x01, &temp);
More magic values...
When I have reliable documentation I always define macros. So I agree that
"command" bytes like 0x34 and 0x3800 should have names but what are the
correct names? Are we constructing an opcode containing RTC register file
addresses or are we issuing read/write accesses to chip registers?
In my experience with undocumented 68k Mac hardware and its Linux port,
codified guesswork is worse than no documentation at all. The only useful
RTC documentation I've ever come across is this:
http://mac.linux-m68k.org/devel/plushw.php
It tells us that the two least significant bits bits must equal 0b01. What
would you call that macro? It also tells us that the most significant bit,
0x80, means "read access" but it only mentions early RTC chips and so it
does not cover two byte opcodes. Should I have used 0x8080 here?
Whatever your opinion of reverse engineered drivers, the changes in this
patch are consistent with the rest of the file. E.g. via_read_time() and
via_write_time(). If/when we have the chip data needed to correctly define
macros for 0x01, 0x0001, 0x80, 0x8000 or 0x8080, I think they should be
applied across the entire file, and in a different patch. Inconsistent use
of such macros would be undesirable IMHO.
This document appears to be Inside Macintosh vol. III ch. 2. It describes
the early RTC chip that lacks two-byte operations and XPRAM, and pre-dates
all Mac hardware supported in mainline Linux. But it does offer some
useful data, though not enough to answer all of your criticisms (as I
said).
[...] I think they should be applied across the entire file, and in a
different patch. Inconsistent use of such macros would be undesirable
IMHO.
So, unless you have other ideas, I will revise this patch and insert an
earlier patch to address existing code, and codify what little reliable
chip data we have.
--
This document appears to be Inside Macintosh vol. III ch. 2. It describes
the early RTC chip that lacks two-byte operations and XPRAM, and pre-dates
all Mac hardware supported in mainline Linux. But it does offer some
useful data, though not enough to answer all of your criticisms (as I
said).
I understand.
quoted
[...] I think they should be applied across the entire file, and in a
different patch. Inconsistent use of such macros would be undesirable
IMHO.
So, unless you have other ideas, I will revise this patch and insert an
earlier patch to address existing code, and codify what little reliable
chip data we have.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds