2014-04-01 14:28:19 +10:30
/*
* PowerNV OPAL in - memory console interface
*
* Copyright 2014 IBM Corp .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <asm/io.h>
# include <asm/opal.h>
# include <linux/debugfs.h>
# include <linux/of.h>
# include <linux/types.h>
# include <asm/barrier.h>
/* OPAL in-memory console. Defined in OPAL source at core/console.c */
struct memcons {
__be64 magic ;
# define MEMCONS_MAGIC 0x6630696567726173L
__be64 obuf_phys ;
__be64 ibuf_phys ;
__be32 obuf_size ;
__be32 ibuf_size ;
__be32 out_pos ;
# define MEMCONS_OUT_POS_WRAP 0x80000000u
# define MEMCONS_OUT_POS_MASK 0x00ffffffu
__be32 in_prod ;
__be32 in_cons ;
} ;
2016-02-09 18:17:48 +11:00
static struct memcons * opal_memcons = NULL ;
ssize_t opal_msglog_copy ( char * to , loff_t pos , size_t count )
2014-04-01 14:28:19 +10:30
{
const char * conbuf ;
2014-06-10 16:03:59 +10:00
ssize_t ret ;
size_t first_read = 0 ;
2014-04-01 14:28:19 +10:30
uint32_t out_pos , avail ;
2016-02-09 18:17:48 +11:00
if ( ! opal_memcons )
2014-04-01 14:28:19 +10:30
return - ENODEV ;
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-23 14:07:29 -07:00
out_pos = be32_to_cpu ( READ_ONCE ( opal_memcons - > out_pos ) ) ;
2014-04-01 14:28:19 +10:30
/* Now we've read out_pos, put a barrier in before reading the new
* data it points to in conbuf . */
smp_rmb ( ) ;
2016-02-09 18:17:48 +11:00
conbuf = phys_to_virt ( be64_to_cpu ( opal_memcons - > obuf_phys ) ) ;
2014-04-01 14:28:19 +10:30
/* When the buffer has wrapped, read from the out_pos marker to the end
* of the buffer , and then read the remaining data as in the un - wrapped
* case . */
if ( out_pos & MEMCONS_OUT_POS_WRAP ) {
out_pos & = MEMCONS_OUT_POS_MASK ;
2016-02-09 18:17:48 +11:00
avail = be32_to_cpu ( opal_memcons - > obuf_size ) - out_pos ;
2014-04-01 14:28:19 +10:30
ret = memory_read_from_buffer ( to , count , & pos ,
conbuf + out_pos , avail ) ;
if ( ret < 0 )
goto out ;
first_read = ret ;
to + = first_read ;
count - = first_read ;
pos - = avail ;
2014-06-10 16:03:59 +10:00
if ( count < = 0 )
goto out ;
2014-04-01 14:28:19 +10:30
}
/* Sanity check. The firmware should not do this to us. */
2016-02-09 18:17:48 +11:00
if ( out_pos > be32_to_cpu ( opal_memcons - > obuf_size ) ) {
2014-04-01 14:28:19 +10:30
pr_err ( " OPAL: memory console corruption. Aborting read. \n " ) ;
return - EINVAL ;
}
ret = memory_read_from_buffer ( to , count , & pos , conbuf , out_pos ) ;
if ( ret < 0 )
goto out ;
ret + = first_read ;
out :
return ret ;
}
2016-02-09 18:17:48 +11:00
static ssize_t opal_msglog_read ( struct file * file , struct kobject * kobj ,
struct bin_attribute * bin_attr , char * to ,
loff_t pos , size_t count )
{
return opal_msglog_copy ( to , pos , count ) ;
}
2014-04-01 14:28:19 +10:30
static struct bin_attribute opal_msglog_attr = {
. attr = { . name = " msglog " , . mode = 0444 } ,
. read = opal_msglog_read
} ;
void __init opal_msglog_init ( void )
{
u64 mcaddr ;
struct memcons * mc ;
if ( of_property_read_u64 ( opal_node , " ibm,opal-memcons " , & mcaddr ) ) {
pr_warn ( " OPAL: Property ibm,opal-memcons not found, no message log \n " ) ;
return ;
}
mc = phys_to_virt ( mcaddr ) ;
if ( ! mc ) {
pr_warn ( " OPAL: memory console address is invalid \n " ) ;
return ;
}
if ( be64_to_cpu ( mc - > magic ) ! = MEMCONS_MAGIC ) {
pr_warn ( " OPAL: memory console version is invalid \n " ) ;
return ;
}
2017-01-13 14:23:49 +10:30
/* Report maximum size */
opal_msglog_attr . size = be32_to_cpu ( mc - > ibuf_size ) +
be32_to_cpu ( mc - > obuf_size ) ;
2016-02-09 18:17:48 +11:00
opal_memcons = mc ;
}
2014-04-01 14:28:19 +10:30
2016-02-09 18:17:48 +11:00
void __init opal_msglog_sysfs_init ( void )
{
2016-02-18 12:12:54 +11:00
if ( ! opal_memcons ) {
pr_warn ( " OPAL: message log initialisation failed, not creating sysfs entry \n " ) ;
return ;
}
2014-04-01 14:28:19 +10:30
if ( sysfs_create_bin_file ( opal_kobj , & opal_msglog_attr ) ! = 0 )
pr_warn ( " OPAL: sysfs file creation failed \n " ) ;
}