* [PATCH v2 5/9] lib: Import reed solomon code from kernel
  2015-12-08  9:39 [PATCH v2 0/9] RAMOOPS read support for Barebox Markus Pargmann
                   ` (3 preceding siblings ...)
  2015-12-08  9:39 ` [PATCH v2 4/9] vsprintf: Add scnprintf from kernel Markus Pargmann
@ 2015-12-08  9:39 ` Markus Pargmann
  2015-12-08  9:39 ` [PATCH v2 6/9] arm: Clarify memory layout calculation Markus Pargmann
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Markus Pargmann @ 2015-12-08  9:39 UTC (permalink / raw)
  To: barebox
reed solomon code is used by RAMOOPS to check and fix data stored in
volatile memory.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
Notes:
    Changes in v2:
    - Removed fine control over parts of the code. Reduced to one config symbol.
 include/linux/rslib.h           | 103 +++++++++++
 lib/Kconfig                     |   3 +
 lib/Makefile                    |   1 +
 lib/reed_solomon/Makefile       |   6 +
 lib/reed_solomon/decode_rs.c    | 271 +++++++++++++++++++++++++++++
 lib/reed_solomon/encode_rs.c    |  54 ++++++
 lib/reed_solomon/reed_solomon.c | 369 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 807 insertions(+)
 create mode 100644 include/linux/rslib.h
 create mode 100644 lib/reed_solomon/Makefile
 create mode 100644 lib/reed_solomon/decode_rs.c
 create mode 100644 lib/reed_solomon/encode_rs.c
 create mode 100644 lib/reed_solomon/reed_solomon.c
diff --git a/include/linux/rslib.h b/include/linux/rslib.h
new file mode 100644
index 000000000000..b5e3ffd0de42
--- /dev/null
+++ b/include/linux/rslib.h
@@ -0,0 +1,103 @@
+/*
+ * include/linux/rslib.h
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *
+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * RS code lifted from reed solomon library written by Phil Karn
+ * Copyright 2002 Phil Karn, KA9Q
+ *
+ * $Id: rslib.h,v 1.4 2005/11/07 11:14:52 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RSLIB_H_
+#define _RSLIB_H_
+
+#include <linux/list.h>
+
+/**
+ * struct rs_control - rs control structure
+ *
+ * @mm:		Bits per symbol
+ * @nn:		Symbols per block (= (1<<mm)-1)
+ * @alpha_to:	log lookup table
+ * @index_of:	Antilog lookup table
+ * @genpoly:	Generator polynomial
+ * @nroots:	Number of generator roots = number of parity symbols
+ * @fcr:	First consecutive root, index form
+ * @prim:	Primitive element, index form
+ * @iprim:	prim-th root of 1, index form
+ * @gfpoly:	The primitive generator polynominal
+ * @gffunc:	Function to generate the field, if non-canonical representation
+ * @users:	Users of this structure
+ * @list:	List entry for the rs control list
+*/
+struct rs_control {
+	int 		mm;
+	int 		nn;
+	uint16_t	*alpha_to;
+	uint16_t	*index_of;
+	uint16_t	*genpoly;
+	int 		nroots;
+	int 		fcr;
+	int 		prim;
+	int 		iprim;
+	int		gfpoly;
+	int		(*gffunc)(int);
+	int		users;
+	struct list_head list;
+};
+
+#ifdef CONFIG_REED_SOLOMON
+/* General purpose RS codec, 8-bit data width, symbol width 1-15 bit  */
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
+	       uint16_t invmsk);
+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
+		uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+	       uint16_t *corr);
+
+/* General purpose RS codec, 16-bit data width, symbol width 1-15 bit  */
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
+		uint16_t invmsk);
+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
+		uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+		uint16_t *corr);
+#endif  /* CONFIG_REED_SOLOMON */
+
+/* Create or get a matching rs control structure */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
+			   int nroots);
+struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
+                                         int fcr, int prim, int nroots);
+
+/* Release a rs control structure */
+void free_rs(struct rs_control *rs);
+
+/** modulo replacement for galois field arithmetics
+ *
+ *  @rs:	the rs control structure
+ *  @x:		the value to reduce
+ *
+ *  where
+ *  rs->mm = number of bits per symbol
+ *  rs->nn = (2^rs->mm) - 1
+ *
+ *  Simple arithmetic modulo would return a wrong result for values
+ *  >= 3 * rs->nn
+*/
+static inline int rs_modnn(struct rs_control *rs, int x)
+{
+	while (x >= rs->nn) {
+		x -= rs->nn;
+		x = (x >> rs->mm) + (x & rs->nn);
+	}
+	return x;
+}
+
+#endif
diff --git a/lib/Kconfig b/lib/Kconfig
index fbf9f0f34849..46ec58c62e4a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -22,6 +22,9 @@ config XZ_DECOMPRESS
 	bool "include xz uncompression support"
 	select UNCOMPRESS
 
+config REED_SOLOMON
+	bool
+
 config GENERIC_FIND_NEXT_BIT
 	def_bool n
 
diff --git a/lib/Makefile b/lib/Makefile
index abb34cfbdbeb..6ffa3e010434 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -56,3 +56,4 @@ obj-y			+= gcd.o
 obj-y			+= hexdump.o
 obj-$(CONFIG_FONTS)	+= fonts/
 obj-$(CONFIG_BAREBOX_LOGO)     += logo/
+obj-y			+= reed_solomon/
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile
new file mode 100644
index 000000000000..c3d7136827ed
--- /dev/null
+++ b/lib/reed_solomon/Makefile
@@ -0,0 +1,6 @@
+#
+# This is a modified version of reed solomon lib,
+#
+
+obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
+
diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c
new file mode 100644
index 000000000000..0ec3f257ffdf
--- /dev/null
+++ b/lib/reed_solomon/decode_rs.c
@@ -0,0 +1,271 @@
+/*
+ * lib/reed_solomon/decode_rs.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *
+ * Copyright 2002, Phil Karn, KA9Q
+ * May be used under the terms of the GNU General Public License (GPL)
+ *
+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
+ *
+ * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
+ *
+ */
+
+/* Generic data width independent code which is included by the
+ * wrappers.
+ */
+{
+	int deg_lambda, el, deg_omega;
+	int i, j, r, k, pad;
+	int nn = rs->nn;
+	int nroots = rs->nroots;
+	int fcr = rs->fcr;
+	int prim = rs->prim;
+	int iprim = rs->iprim;
+	uint16_t *alpha_to = rs->alpha_to;
+	uint16_t *index_of = rs->index_of;
+	uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
+	/* Err+Eras Locator poly and syndrome poly The maximum value
+	 * of nroots is 8. So the necessary stack size will be about
+	 * 220 bytes max.
+	 */
+	uint16_t lambda[nroots + 1], syn[nroots];
+	uint16_t b[nroots + 1], t[nroots + 1], omega[nroots + 1];
+	uint16_t root[nroots], reg[nroots + 1], loc[nroots];
+	int count = 0;
+	uint16_t msk = (uint16_t) rs->nn;
+
+	/* Check length parameter for validity */
+	pad = nn - nroots - len;
+	BUG_ON(pad < 0 || pad >= nn);
+
+	/* Does the caller provide the syndrome ? */
+	if (s != NULL)
+		goto decode;
+
+	/* form the syndromes; i.e., evaluate data(x) at roots of
+	 * g(x) */
+	for (i = 0; i < nroots; i++)
+		syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
+
+	for (j = 1; j < len; j++) {
+		for (i = 0; i < nroots; i++) {
+			if (syn[i] == 0) {
+				syn[i] = (((uint16_t) data[j]) ^
+					  invmsk) & msk;
+			} else {
+				syn[i] = ((((uint16_t) data[j]) ^
+					   invmsk) & msk) ^
+					alpha_to[rs_modnn(rs, index_of[syn[i]] +
+						       (fcr + i) * prim)];
+			}
+		}
+	}
+
+	for (j = 0; j < nroots; j++) {
+		for (i = 0; i < nroots; i++) {
+			if (syn[i] == 0) {
+				syn[i] = ((uint16_t) par[j]) & msk;
+			} else {
+				syn[i] = (((uint16_t) par[j]) & msk) ^
+					alpha_to[rs_modnn(rs, index_of[syn[i]] +
+						       (fcr+i)*prim)];
+			}
+		}
+	}
+	s = syn;
+
+	/* Convert syndromes to index form, checking for nonzero condition */
+	syn_error = 0;
+	for (i = 0; i < nroots; i++) {
+		syn_error |= s[i];
+		s[i] = index_of[s[i]];
+	}
+
+	if (!syn_error) {
+		/* if syndrome is zero, data[] is a codeword and there are no
+		 * errors to correct. So return data[] unmodified
+		 */
+		count = 0;
+		goto finish;
+	}
+
+ decode:
+	memset(&lambda[1], 0, nroots * sizeof(lambda[0]));
+	lambda[0] = 1;
+
+	if (no_eras > 0) {
+		/* Init lambda to be the erasure locator polynomial */
+		lambda[1] = alpha_to[rs_modnn(rs,
+					      prim * (nn - 1 - eras_pos[0]))];
+		for (i = 1; i < no_eras; i++) {
+			u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
+			for (j = i + 1; j > 0; j--) {
+				tmp = index_of[lambda[j - 1]];
+				if (tmp != nn) {
+					lambda[j] ^=
+						alpha_to[rs_modnn(rs, u + tmp)];
+				}
+			}
+		}
+	}
+
+	for (i = 0; i < nroots + 1; i++)
+		b[i] = index_of[lambda[i]];
+
+	/*
+	 * Begin Berlekamp-Massey algorithm to determine error+erasure
+	 * locator polynomial
+	 */
+	r = no_eras;
+	el = no_eras;
+	while (++r <= nroots) {	/* r is the step number */
+		/* Compute discrepancy at the r-th step in poly-form */
+		discr_r = 0;
+		for (i = 0; i < r; i++) {
+			if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
+				discr_r ^=
+					alpha_to[rs_modnn(rs,
+							  index_of[lambda[i]] +
+							  s[r - i - 1])];
+			}
+		}
+		discr_r = index_of[discr_r];	/* Index form */
+		if (discr_r == nn) {
+			/* 2 lines below: B(x) <-- x*B(x) */
+			memmove (&b[1], b, nroots * sizeof (b[0]));
+			b[0] = nn;
+		} else {
+			/* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
+			t[0] = lambda[0];
+			for (i = 0; i < nroots; i++) {
+				if (b[i] != nn) {
+					t[i + 1] = lambda[i + 1] ^
+						alpha_to[rs_modnn(rs, discr_r +
+								  b[i])];
+				} else
+					t[i + 1] = lambda[i + 1];
+			}
+			if (2 * el <= r + no_eras - 1) {
+				el = r + no_eras - el;
+				/*
+				 * 2 lines below: B(x) <-- inv(discr_r) *
+				 * lambda(x)
+				 */
+				for (i = 0; i <= nroots; i++) {
+					b[i] = (lambda[i] == 0) ? nn :
+						rs_modnn(rs, index_of[lambda[i]]
+							 - discr_r + nn);
+				}
+			} else {
+				/* 2 lines below: B(x) <-- x*B(x) */
+				memmove(&b[1], b, nroots * sizeof(b[0]));
+				b[0] = nn;
+			}
+			memcpy(lambda, t, (nroots + 1) * sizeof(t[0]));
+		}
+	}
+
+	/* Convert lambda to index form and compute deg(lambda(x)) */
+	deg_lambda = 0;
+	for (i = 0; i < nroots + 1; i++) {
+		lambda[i] = index_of[lambda[i]];
+		if (lambda[i] != nn)
+			deg_lambda = i;
+	}
+	/* Find roots of error+erasure locator polynomial by Chien search */
+	memcpy(®[1], &lambda[1], nroots * sizeof(reg[0]));
+	count = 0;		/* Number of roots of lambda(x) */
+	for (i = 1, k = iprim - 1; i <= nn; i++, k = rs_modnn(rs, k + iprim)) {
+		q = 1;		/* lambda[0] is always 0 */
+		for (j = deg_lambda; j > 0; j--) {
+			if (reg[j] != nn) {
+				reg[j] = rs_modnn(rs, reg[j] + j);
+				q ^= alpha_to[reg[j]];
+			}
+		}
+		if (q != 0)
+			continue;	/* Not a root */
+		/* store root (index-form) and error location number */
+		root[count] = i;
+		loc[count] = k;
+		/* If we've already found max possible roots,
+		 * abort the search to save time
+		 */
+		if (++count == deg_lambda)
+			break;
+	}
+	if (deg_lambda != count) {
+		/*
+		 * deg(lambda) unequal to number of roots => uncorrectable
+		 * error detected
+		 */
+		count = -EBADMSG;
+		goto finish;
+	}
+	/*
+	 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+	 * x**nroots). in index form. Also find deg(omega).
+	 */
+	deg_omega = deg_lambda - 1;
+	for (i = 0; i <= deg_omega; i++) {
+		tmp = 0;
+		for (j = i; j >= 0; j--) {
+			if ((s[i - j] != nn) && (lambda[j] != nn))
+				tmp ^=
+				    alpha_to[rs_modnn(rs, s[i - j] + lambda[j])];
+		}
+		omega[i] = index_of[tmp];
+	}
+
+	/*
+	 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+	 * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
+	 */
+	for (j = count - 1; j >= 0; j--) {
+		num1 = 0;
+		for (i = deg_omega; i >= 0; i--) {
+			if (omega[i] != nn)
+				num1 ^= alpha_to[rs_modnn(rs, omega[i] +
+							i * root[j])];
+		}
+		num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
+		den = 0;
+
+		/* lambda[i+1] for i even is the formal derivative
+		 * lambda_pr of lambda[i] */
+		for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
+			if (lambda[i + 1] != nn) {
+				den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
+						       i * root[j])];
+			}
+		}
+		/* Apply error to data */
+		if (num1 != 0 && loc[j] >= pad) {
+			uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
+						       index_of[num2] +
+						       nn - index_of[den])];
+			/* Store the error correction pattern, if a
+			 * correction buffer is available */
+			if (corr) {
+				corr[j] = cor;
+			} else {
+				/* If a data buffer is given and the
+				 * error is inside the message,
+				 * correct it */
+				if (data && (loc[j] < (nn - nroots)))
+					data[loc[j] - pad] ^= cor;
+			}
+		}
+	}
+
+finish:
+	if (eras_pos != NULL) {
+		for (i = 0; i < count; i++)
+			eras_pos[i] = loc[i] - pad;
+	}
+	return count;
+
+}
diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c
new file mode 100644
index 000000000000..0b5b1a6728ec
--- /dev/null
+++ b/lib/reed_solomon/encode_rs.c
@@ -0,0 +1,54 @@
+/*
+ * lib/reed_solomon/encode_rs.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *
+ * Copyright 2002, Phil Karn, KA9Q
+ * May be used under the terms of the GNU General Public License (GPL)
+ *
+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
+ *
+ * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $
+ *
+ */
+
+/* Generic data width independent code which is included by the
+ * wrappers.
+ * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
+ */
+{
+	int i, j, pad;
+	int nn = rs->nn;
+	int nroots = rs->nroots;
+	uint16_t *alpha_to = rs->alpha_to;
+	uint16_t *index_of = rs->index_of;
+	uint16_t *genpoly = rs->genpoly;
+	uint16_t fb;
+	uint16_t msk = (uint16_t) rs->nn;
+
+	/* Check length parameter for validity */
+	pad = nn - nroots - len;
+	if (pad < 0 || pad >= nn)
+		return -ERANGE;
+
+	for (i = 0; i < len; i++) {
+		fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
+		/* feedback term is non-zero */
+		if (fb != nn) {
+			for (j = 1; j < nroots; j++) {
+				par[j] ^= alpha_to[rs_modnn(rs, fb +
+							 genpoly[nroots - j])];
+			}
+		}
+		/* Shift */
+		memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1));
+		if (fb != nn) {
+			par[nroots - 1] = alpha_to[rs_modnn(rs,
+							    fb + genpoly[0])];
+		} else {
+			par[nroots - 1] = 0;
+		}
+	}
+	return 0;
+}
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
new file mode 100644
index 000000000000..51c67c3c8d5d
--- /dev/null
+++ b/lib/reed_solomon/reed_solomon.c
@@ -0,0 +1,369 @@
+/*
+ * lib/reed_solomon/reed_solomon.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *
+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Reed Solomon code lifted from reed solomon library written by Phil Karn
+ * Copyright 2002 Phil Karn, KA9Q
+ *
+ * $Id: rslib.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Description:
+ *
+ * The generic Reed Solomon library provides runtime configurable
+ * encoding / decoding of RS codes.
+ * Each user must call init_rs to get a pointer to a rs_control
+ * structure for the given rs parameters. This structure is either
+ * generated or a already available matching control structure is used.
+ * If a structure is generated then the polynomial arrays for
+ * fast encoding / decoding are built. This can take some time so
+ * make sure not to call this function from a time critical path.
+ * Usually a module / driver should initialize the necessary
+ * rs_control structure on module / driver init and release it
+ * on exit.
+ * The encoding puts the calculated syndrome into a given syndrome
+ * buffer.
+ * The decoding is a two step process. The first step calculates
+ * the syndrome over the received (data + syndrome) and calls the
+ * second stage, which does the decoding / error correction itself.
+ * Many hw encoders provide a syndrome calculation over the received
+ * data + syndrome and can call the second stage directly.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/rslib.h>
+#include <malloc.h>
+#include <module.h>
+#include <linux/string.h>
+#include <stdio.h>
+#include <asm-generic/errno.h>
+
+/* This list holds all currently allocated rs control structures */
+static LIST_HEAD (rslist);
+
+/**
+ * rs_init - Initialize a Reed-Solomon codec
+ * @symsize:	symbol size, bits (1-8)
+ * @gfpoly:	Field generator polynomial coefficients
+ * @gffunc:	Field generator function
+ * @fcr:	first root of RS code generator polynomial, index form
+ * @prim:	primitive element to generate polynomial roots
+ * @nroots:	RS code generator polynomial degree (number of roots)
+ *
+ * Allocate a control structure and the polynom arrays for faster
+ * en/decoding. Fill the arrays according to the given parameters.
+ */
+static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
+                                  int fcr, int prim, int nroots)
+{
+	struct rs_control *rs;
+	int i, j, sr, root, iprim;
+
+	/* Allocate the control structure */
+	rs = kmalloc(sizeof (struct rs_control), GFP_KERNEL);
+	if (rs == NULL)
+		return NULL;
+
+	INIT_LIST_HEAD(&rs->list);
+
+	rs->mm = symsize;
+	rs->nn = (1 << symsize) - 1;
+	rs->fcr = fcr;
+	rs->prim = prim;
+	rs->nroots = nroots;
+	rs->gfpoly = gfpoly;
+	rs->gffunc = gffunc;
+
+	/* Allocate the arrays */
+	rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+	if (rs->alpha_to == NULL)
+		goto errrs;
+
+	rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+	if (rs->index_of == NULL)
+		goto erralp;
+
+	rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), GFP_KERNEL);
+	if(rs->genpoly == NULL)
+		goto erridx;
+
+	/* Generate Galois field lookup tables */
+	rs->index_of[0] = rs->nn;	/* log(zero) = -inf */
+	rs->alpha_to[rs->nn] = 0;	/* alpha**-inf = 0 */
+	if (gfpoly) {
+		sr = 1;
+		for (i = 0; i < rs->nn; i++) {
+			rs->index_of[sr] = i;
+			rs->alpha_to[i] = sr;
+			sr <<= 1;
+			if (sr & (1 << symsize))
+				sr ^= gfpoly;
+			sr &= rs->nn;
+		}
+	} else {
+		sr = gffunc(0);
+		for (i = 0; i < rs->nn; i++) {
+			rs->index_of[sr] = i;
+			rs->alpha_to[i] = sr;
+			sr = gffunc(sr);
+		}
+	}
+	/* If it's not primitive, exit */
+	if(sr != rs->alpha_to[0])
+		goto errpol;
+
+	/* Find prim-th root of 1, used in decoding */
+	for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
+	/* prim-th root of 1, index form */
+	rs->iprim = iprim / prim;
+
+	/* Form RS code generator polynomial from its roots */
+	rs->genpoly[0] = 1;
+	for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
+		rs->genpoly[i + 1] = 1;
+		/* Multiply rs->genpoly[] by  @**(root + x) */
+		for (j = i; j > 0; j--) {
+			if (rs->genpoly[j] != 0) {
+				rs->genpoly[j] = rs->genpoly[j -1] ^
+					rs->alpha_to[rs_modnn(rs,
+					rs->index_of[rs->genpoly[j]] + root)];
+			} else
+				rs->genpoly[j] = rs->genpoly[j - 1];
+		}
+		/* rs->genpoly[0] can never be zero */
+		rs->genpoly[0] =
+			rs->alpha_to[rs_modnn(rs,
+				rs->index_of[rs->genpoly[0]] + root)];
+	}
+	/* convert rs->genpoly[] to index form for quicker encoding */
+	for (i = 0; i <= nroots; i++)
+		rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
+	return rs;
+
+	/* Error exit */
+errpol:
+	kfree(rs->genpoly);
+erridx:
+	kfree(rs->index_of);
+erralp:
+	kfree(rs->alpha_to);
+errrs:
+	kfree(rs);
+	return NULL;
+}
+
+
+/**
+ *  free_rs - Free the rs control structure, if it is no longer used
+ *  @rs:	the control structure which is not longer used by the
+ *		caller
+ */
+void free_rs(struct rs_control *rs)
+{
+	rs->users--;
+	if(!rs->users) {
+		list_del(&rs->list);
+		kfree(rs->alpha_to);
+		kfree(rs->index_of);
+		kfree(rs->genpoly);
+		kfree(rs);
+	}
+}
+
+/**
+ * init_rs_internal - Find a matching or allocate a new rs control structure
+ *  @symsize:	the symbol size (number of bits)
+ *  @gfpoly:	the extended Galois field generator polynomial coefficients,
+ *		with the 0th coefficient in the low order bit. The polynomial
+ *		must be primitive;
+ *  @gffunc:	pointer to function to generate the next field element,
+ *		or the multiplicative identity element if given 0.  Used
+ *		instead of gfpoly if gfpoly is 0
+ *  @fcr:  	the first consecutive root of the rs code generator polynomial
+ *		in index form
+ *  @prim:	primitive element to generate polynomial roots
+ *  @nroots:	RS code generator polynomial degree (number of roots)
+ */
+static struct rs_control *init_rs_internal(int symsize, int gfpoly,
+                                           int (*gffunc)(int), int fcr,
+                                           int prim, int nroots)
+{
+	struct list_head	*tmp;
+	struct rs_control	*rs;
+
+	/* Sanity checks */
+	if (symsize < 1)
+		return NULL;
+	if (fcr < 0 || fcr >= (1<<symsize))
+    		return NULL;
+	if (prim <= 0 || prim >= (1<<symsize))
+    		return NULL;
+	if (nroots < 0 || nroots >= (1<<symsize))
+		return NULL;
+
+	/* Walk through the list and look for a matching entry */
+	list_for_each(tmp, &rslist) {
+		rs = list_entry(tmp, struct rs_control, list);
+		if (symsize != rs->mm)
+			continue;
+		if (gfpoly != rs->gfpoly)
+			continue;
+		if (gffunc != rs->gffunc)
+			continue;
+		if (fcr != rs->fcr)
+			continue;
+		if (prim != rs->prim)
+			continue;
+		if (nroots != rs->nroots)
+			continue;
+		/* We have a matching one already */
+		rs->users++;
+		goto out;
+	}
+
+	/* Create a new one */
+	rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
+	if (rs) {
+		rs->users = 1;
+		list_add(&rs->list, &rslist);
+	}
+out:
+	return rs;
+}
+
+/**
+ * init_rs - Find a matching or allocate a new rs control structure
+ *  @symsize:	the symbol size (number of bits)
+ *  @gfpoly:	the extended Galois field generator polynomial coefficients,
+ *		with the 0th coefficient in the low order bit. The polynomial
+ *		must be primitive;
+ *  @fcr:  	the first consecutive root of the rs code generator polynomial
+ *		in index form
+ *  @prim:	primitive element to generate polynomial roots
+ *  @nroots:	RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
+                           int nroots)
+{
+	return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+}
+
+/**
+ * init_rs_non_canonical - Find a matching or allocate a new rs control
+ *                         structure, for fields with non-canonical
+ *                         representation
+ *  @symsize:	the symbol size (number of bits)
+ *  @gffunc:	pointer to function to generate the next field element,
+ *		or the multiplicative identity element if given 0.  Used
+ *		instead of gfpoly if gfpoly is 0
+ *  @fcr:  	the first consecutive root of the rs code generator polynomial
+ *		in index form
+ *  @prim:	primitive element to generate polynomial roots
+ *  @nroots:	RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
+                                         int fcr, int prim, int nroots)
+{
+	return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+}
+
+/**
+ *  encode_rs8 - Calculate the parity for data values (8bit data width)
+ *  @rs:	the rs control structure
+ *  @data:	data field of a given type
+ *  @len:	data length
+ *  @par:	parity data, must be initialized by caller (usually all 0)
+ *  @invmsk:	invert data mask (will be xored on data)
+ *
+ *  The parity uses a uint16_t data type to enable
+ *  symbol size > 8. The calling code must take care of encoding of the
+ *  syndrome result for storage itself.
+ */
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
+	       uint16_t invmsk)
+{
+#include "encode_rs.c"
+}
+EXPORT_SYMBOL_GPL(encode_rs8);
+
+/**
+ *  decode_rs8 - Decode codeword (8bit data width)
+ *  @rs:	the rs control structure
+ *  @data:	data field of a given type
+ *  @par:	received parity data field
+ *  @len:	data length
+ *  @s:		syndrome data field (if NULL, syndrome is calculated)
+ *  @no_eras:	number of erasures
+ *  @eras_pos:	position of erasures, can be NULL
+ *  @invmsk:	invert data mask (will be xored on data, not on parity!)
+ *  @corr:	buffer to store correction bitmask on eras_pos
+ *
+ *  The syndrome and parity uses a uint16_t data type to enable
+ *  symbol size > 8. The calling code must take care of decoding of the
+ *  syndrome result and the received parity before calling this code.
+ *  Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
+ */
+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
+	       uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+	       uint16_t *corr)
+{
+#include "decode_rs.c"
+}
+EXPORT_SYMBOL_GPL(decode_rs8);
+
+/**
+ *  encode_rs16 - Calculate the parity for data values (16bit data width)
+ *  @rs:	the rs control structure
+ *  @data:	data field of a given type
+ *  @len:	data length
+ *  @par:	parity data, must be initialized by caller (usually all 0)
+ *  @invmsk:	invert data mask (will be xored on data, not on parity!)
+ *
+ *  Each field in the data array contains up to symbol size bits of valid data.
+ */
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
+	uint16_t invmsk)
+{
+#include "encode_rs.c"
+}
+EXPORT_SYMBOL_GPL(encode_rs16);
+
+/**
+ *  decode_rs16 - Decode codeword (16bit data width)
+ *  @rs:	the rs control structure
+ *  @data:	data field of a given type
+ *  @par:	received parity data field
+ *  @len:	data length
+ *  @s:		syndrome data field (if NULL, syndrome is calculated)
+ *  @no_eras:	number of erasures
+ *  @eras_pos:	position of erasures, can be NULL
+ *  @invmsk:	invert data mask (will be xored on data, not on parity!)
+ *  @corr:	buffer to store correction bitmask on eras_pos
+ *
+ *  Each field in the data array contains up to symbol size bits of valid data.
+ *  Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
+ */
+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
+		uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+		uint16_t *corr)
+{
+#include "decode_rs.c"
+}
+EXPORT_SYMBOL_GPL(decode_rs16);
+
+EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
+EXPORT_SYMBOL_GPL(free_rs);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
+MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
+
-- 
2.6.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply	[flat|nested] 13+ messages in thread* [PATCH v2 6/9] arm: Clarify memory layout calculation
  2015-12-08  9:39 [PATCH v2 0/9] RAMOOPS read support for Barebox Markus Pargmann
                   ` (4 preceding siblings ...)
  2015-12-08  9:39 ` [PATCH v2 5/9] lib: Import reed solomon code " Markus Pargmann
@ 2015-12-08  9:39 ` Markus Pargmann
  2015-12-08  9:39 ` [PATCH v2 7/9] arm: start: Add visible sdram region for barebox board data Markus Pargmann
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Markus Pargmann @ 2015-12-08  9:39 UTC (permalink / raw)
  To: barebox
The memory calculations used are all hardcoded into three different
files, start-pbl.c, uncompress.c and start.c. To make this more readable
and reliable, this patch gathers these information in barebox-arm.h with
static inline functions for the calculation of the memory offsets.
This patch also adds proper handling of different barebox/board data
sizes. Currently only 1MB+Alignment of RAM is reserved for Barebox and
board data. This could be too small for bigger devicetrees and barebox.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
Notes:
    Changes in v2:
    - Use IS_ENABLED(CONFIG_RELOCATABLE)
 arch/arm/cpu/start-pbl.c           | 14 ++++------
 arch/arm/cpu/start.c               | 48 ++++++++++++++++++---------------
 arch/arm/cpu/uncompress.c          | 31 ++++++++++-----------
 arch/arm/include/asm/barebox-arm.h | 55 +++++++++++++++++++++++++-------------
 4 files changed, 83 insertions(+), 65 deletions(-)
diff --git a/arch/arm/cpu/start-pbl.c b/arch/arm/cpu/start-pbl.c
index 2075ffeee75f..f723edc61318 100644
--- a/arch/arm/cpu/start-pbl.c
+++ b/arch/arm/cpu/start-pbl.c
@@ -54,8 +54,6 @@ __noreturn void barebox_single_pbl_start(unsigned long membase,
 	uint32_t endmem = membase + memsize;
 	unsigned long barebox_base;
 
-	endmem -= STACK_SIZE; /* stack */
-
 	if (IS_ENABLED(CONFIG_PBL_RELOCATABLE))
 		relocate_to_current_adr();
 
@@ -67,7 +65,7 @@ __noreturn void barebox_single_pbl_start(unsigned long membase,
 	pg_len = pg_end - pg_start;
 
 	if (IS_ENABLED(CONFIG_RELOCATABLE))
-		barebox_base = arm_barebox_image_place(membase + memsize);
+		barebox_base = arm_mem_barebox_image(membase, endmem, pg_len);
 	else
 		barebox_base = TEXT_BASE;
 
@@ -83,14 +81,12 @@ __noreturn void barebox_single_pbl_start(unsigned long membase,
 	setup_c();
 
 	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
-		endmem &= ~0x3fff;
-		endmem -= SZ_16K; /* ttb */
-		mmu_early_enable(membase, memsize, endmem);
+		unsigned long ttb = arm_mem_ttb(membase, endmem);
+		mmu_early_enable(membase, memsize, ttb);
 	}
 
-	endmem -= SZ_128K; /* early malloc */
-	free_mem_ptr = endmem;
-	free_mem_end_ptr = free_mem_ptr + SZ_128K;
+	free_mem_ptr = arm_mem_early_malloc(membase, endmem);
+	free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
 
 	pbl_barebox_uncompress((void*)barebox_base, (void *)pg_start, pg_len);
 
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index c054f3c4400c..e06c4c8f37a0 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -104,14 +104,31 @@ void *barebox_arm_boot_dtb(void)
 	return barebox_boarddata;
 }
 
+static inline unsigned long arm_mem_boarddata(unsigned long membase,
+					      unsigned long endmem,
+					      unsigned long size)
+{
+	unsigned long mem;
+
+	mem = arm_mem_barebox_image(membase, endmem, barebox_image_size);
+	mem -= ALIGN(size, 64);
+
+	return mem;
+}
+
 __noreturn void barebox_non_pbl_start(unsigned long membase,
 		unsigned long memsize, void *boarddata)
 {
 	unsigned long endmem = membase + memsize;
 	unsigned long malloc_start, malloc_end;
+	unsigned long barebox_size = barebox_image_size +
+		((unsigned long)&__bss_stop - (unsigned long)&__bss_start);
+	unsigned long arm_head_bottom;
 
 	if (IS_ENABLED(CONFIG_RELOCATABLE)) {
-		unsigned long barebox_base = arm_barebox_image_place(endmem);
+		unsigned long barebox_base = arm_mem_barebox_image(membase,
+								   endmem,
+								   barebox_size);
 		relocate_to_adr(barebox_base);
 	}
 
@@ -122,19 +139,16 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
 	pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
 
 	arm_stack_top = endmem;
-	endmem -= STACK_SIZE; /* Stack */
 
 	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
-
-		endmem &= ~0x3fff;
-		endmem -= SZ_16K; /* ttb */
+		unsigned long ttb = arm_mem_ttb(membase, endmem);
 
 		if (IS_ENABLED(CONFIG_PBL_IMAGE)) {
 			arm_set_cache_functions();
 		} else {
-			pr_debug("enabling MMU, ttb @ 0x%08lx\n", endmem);
+			pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
 			arm_early_mmu_cache_invalidate();
-			mmu_early_enable(membase, memsize, endmem);
+			mmu_early_enable(membase, memsize, ttb);
 		}
 	}
 
@@ -155,24 +169,16 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
 		}
 
 		if (totalsize) {
-			endmem -= ALIGN(totalsize, 64);
+			unsigned long mem = arm_mem_boarddata(membase, endmem,
+							      totalsize);
 			pr_debug("found %s in boarddata, copying to 0x%lu\n",
-				 name, endmem);
-			barebox_boarddata = memcpy((void *)endmem,
-						      boarddata, totalsize);
+				 name, mem);
+			barebox_boarddata = memcpy((void *)mem, boarddata,
+						   totalsize);
 		}
 	}
 
-	if ((unsigned long)_text > membase + memsize ||
-			(unsigned long)_text < membase)
-		/*
-		 * barebox is either outside SDRAM or in another
-		 * memory bank, so we can use the whole bank for
-		 * malloc.
-		 */
-		malloc_end = endmem;
-	else
-		malloc_end = (unsigned long)_text;
+	malloc_end = arm_head_bottom;
 
 	/*
 	 * Maximum malloc space is the Kconfig value if given
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index dbf6b1e3f807..5bcce6b9e36d 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -52,8 +52,6 @@ void __noreturn barebox_multi_pbl_start(unsigned long membase,
 	void *pg_start;
 	unsigned long pc = get_pc();
 
-	endmem -= STACK_SIZE; /* stack */
-
 	image_end = (void *)ld_var(__image_end) - get_runtime_offset();
 
 	if (IS_ENABLED(CONFIG_PBL_RELOCATABLE)) {
@@ -68,8 +66,16 @@ void __noreturn barebox_multi_pbl_start(unsigned long membase,
 			relocate_to_adr(membase);
 	}
 
+	/*
+	 * image_end is the first location after the executable. It contains
+	 * the size of the appended compressed binary followed by the binary.
+	 */
+	pg_start = image_end + 1;
+	pg_len = *(image_end);
+
 	if (IS_ENABLED(CONFIG_RELOCATABLE))
-		barebox_base = arm_barebox_image_place(membase + memsize);
+		barebox_base = arm_mem_barebox_image(membase, endmem,
+						     pg_len);
 	else
 		barebox_base = TEXT_BASE;
 
@@ -78,22 +84,13 @@ void __noreturn barebox_multi_pbl_start(unsigned long membase,
 	pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
 
 	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
-		endmem &= ~0x3fff;
-		endmem -= SZ_16K; /* ttb */
-		pr_debug("enabling MMU, ttb @ 0x%08x\n", endmem);
-		mmu_early_enable(membase, memsize, endmem);
+		unsigned long ttb = arm_mem_ttb(membase, endmem);
+		pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
+		mmu_early_enable(membase, memsize, ttb);
 	}
 
-	endmem -= SZ_128K; /* early malloc */
-	free_mem_ptr = endmem;
-	free_mem_end_ptr = free_mem_ptr + SZ_128K;
-
-	/*
-	 * image_end is the first location after the executable. It contains
-	 * the size of the appended compressed binary followed by the binary.
-	 */
-	pg_start = image_end + 1;
-	pg_len = *(image_end);
+	free_mem_ptr = arm_mem_early_malloc(membase, endmem);
+	free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
 
 	pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx\n",
 			pg_start, pg_len, barebox_base);
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 76e356413aec..8d52882981f1 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -94,25 +94,44 @@ static inline void arm_fixup_vectors(void)
 
 void *barebox_arm_boot_dtb(void);
 
-/*
- * For relocatable binaries find a suitable start address for the
- * relocated binary. Beginning at the memory end substract the reserved
- * space and round down a bit at the end. This is used by the pbl to
- * extract the image to a suitable place so that the uncompressed image
- * does not have to copy itself to another place. Also it's used by
- * the uncompressed image to relocate itself to the same place.
- */
-static inline unsigned long arm_barebox_image_place(unsigned long endmem)
+static inline unsigned long arm_mem_stack(unsigned long membase,
+					  unsigned long endmem)
+{
+	return endmem - STACK_SIZE;
+}
+
+static inline unsigned long arm_mem_ttb(unsigned long membase,
+					unsigned long endmem)
 {
-	endmem -= STACK_SIZE;
-	endmem -= SZ_32K; /* ttb */
-	endmem -= SZ_128K; /* early malloc */
-	endmem -= SZ_1M; /* place for barebox image */
-
-	/*
-	 * round down to make translating the objdump easier
-	 */
-	endmem &= ~(SZ_1M - 1);
+	endmem = arm_mem_stack(membase, endmem);
+	endmem &= ~(SZ_16K - 1);
+	endmem -= SZ_16K;
+
+	return endmem;
+}
+
+static inline unsigned long arm_mem_early_malloc(unsigned long membase,
+						 unsigned long endmem)
+{
+	return arm_mem_ttb(membase, endmem) - SZ_128K;
+}
+
+static inline unsigned long arm_mem_early_malloc_end(unsigned long membase,
+						     unsigned long endmem)
+{
+	return arm_mem_ttb(membase, endmem);
+}
+
+static inline unsigned long arm_mem_barebox_image(unsigned long membase,
+						  unsigned long endmem,
+						  unsigned long size)
+{
+	endmem = arm_mem_ttb(membase, endmem);
+
+	if (IS_ENABLED(CONFIG_RELOCATABLE)) {
+		endmem -= size;
+		endmem &= ~(SZ_1M - 1);
+	}
 
 	return endmem;
 }
-- 
2.6.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply	[flat|nested] 13+ messages in thread* [PATCH v2 9/9] fs: Add pstore filesystem
  2015-12-08  9:39 [PATCH v2 0/9] RAMOOPS read support for Barebox Markus Pargmann
                   ` (7 preceding siblings ...)
  2015-12-08  9:39 ` [PATCH v2 8/9] arm: Add RAMOOPS memory area Markus Pargmann
@ 2015-12-08  9:39 ` Markus Pargmann
  2015-12-08 10:35   ` Antony Pavlov
  2015-12-10  7:50 ` [PATCH v2 0/9] RAMOOPS read support for Barebox Sascha Hauer
  9 siblings, 1 reply; 13+ messages in thread
From: Markus Pargmann @ 2015-12-08  9:39 UTC (permalink / raw)
  To: barebox
pstore is a persistent storage filesystem used for RAMOOPS. It is used
to store console logs, panics, ftrace and other information in case of a
crash/panic/oops/reboot.
pstore is implemented for barebox as a read-only filesystem at the
moment. It may be extended later on. The idea is to provide a way to
extract essential data from the last running kernel.
Most of the code is copied from the kernel. However this is only a
lightweight implementation without real write support yet.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
Notes:
    Changes in v2:
    - Moved the config symbol from the pstore Makefile to the upper level Makefile
 common/startup.c           |   5 +
 fs/Kconfig                 |   2 +
 fs/Makefile                |   1 +
 fs/pstore/Kconfig          |  86 ++++++++
 fs/pstore/Makefile         |   9 +
 fs/pstore/fs.c             | 280 +++++++++++++++++++++++++
 fs/pstore/internal.h       |  19 ++
 fs/pstore/platform.c       | 138 ++++++++++++
 fs/pstore/ram.c            | 507 +++++++++++++++++++++++++++++++++++++++++++++
 fs/pstore/ram_core.c       | 426 +++++++++++++++++++++++++++++++++++++
 include/linux/pstore.h     |  90 ++++++++
 include/linux/pstore_ram.h |  87 ++++++++
 12 files changed, 1650 insertions(+)
 create mode 100644 fs/pstore/Kconfig
 create mode 100644 fs/pstore/Makefile
 create mode 100644 fs/pstore/fs.c
 create mode 100644 fs/pstore/internal.h
 create mode 100644 fs/pstore/platform.c
 create mode 100644 fs/pstore/ram.c
 create mode 100644 fs/pstore/ram_core.c
 create mode 100644 include/linux/pstore.h
 create mode 100644 include/linux/pstore_ram.h
diff --git a/common/startup.c b/common/startup.c
index 4a303b297aaf..093a23ba08c9 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -60,6 +60,11 @@ static int mount_root(void)
 		mount("none", "efivarfs", "/efivars", NULL);
 	}
 
+	if (IS_ENABLED(CONFIG_FS_PSTORE)) {
+		mkdir("/pstore", 0);
+		mount("none", "pstore", "/pstore", NULL);
+	}
+
 	return 0;
 }
 fs_initcall(mount_root);
diff --git a/fs/Kconfig b/fs/Kconfig
index 9217bc81ea1e..5413a9295ccc 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -89,4 +89,6 @@ config FS_SMHFS
 	  located on a debugging host connected to the target running
 	  Barebox
 
+source fs/pstore/Kconfig
+
 endmenu
diff --git a/fs/Makefile b/fs/Makefile
index 46932057c1b7..2f952038d1b2 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_FS_UIMAGEFS)	+= uimagefs.o
 obj-$(CONFIG_FS_EFI)	 += efi.o
 obj-$(CONFIG_FS_EFIVARFS) += efivarfs.o
 obj-$(CONFIG_FS_SMHFS) += smhfs.o
+obj-$(CONFIG_FS_PSTORE) += pstore/
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
new file mode 100644
index 000000000000..0c6f136920bd
--- /dev/null
+++ b/fs/pstore/Kconfig
@@ -0,0 +1,86 @@
+menuconfig FS_PSTORE
+	bool
+	prompt "pstore fs support"
+	help
+	  Support for persistent storage to read data from the last crash, like
+	  panic, dmesg and ftrace.
+
+if FS_PSTORE
+
+config FS_PSTORE_RAMOOPS
+	bool
+	depends on RELOCATABLE
+	depends on ARM
+	select REED_SOLOMON
+	prompt "pstore RAM backend"
+	help
+	  Here the data is stored in a specific memory area that is neither
+	  overwritten by barebox nor the kernel.
+
+if FS_PSTORE_RAMOOPS
+
+config FS_PSTORE_RAMOOPS_RO
+	bool
+	default y
+	prompt "pstore RAM backend read only"
+	help
+	  This prevents the data from being erased by reinitializing the ramoops
+	  area with new empty ECCs. Select this if you want to see the same
+	  ramoops in the kernel.
+
+config FS_PSTORE_RAMOOPS_SIZE
+	int
+	prompt "Size of the RAMOOPS area"
+	default 2097152
+	help
+	  Size of the RAMOOPS area that is reserved. This is passed to the
+	  kernel as well as argument. Default is 2MiB.
+
+config FS_PSTORE_RAMOOPS_CONSOLE_SIZE
+	int
+	prompt "Size of the console area"
+	default 131072 # 2^17
+	range 4096 1073741824 # Random upper limitation of 1GiB
+	help
+	  Size of the RAMOOPS console area that is reserved. This is passed to
+	  the kernel as well as argument. It should be a power of 2.
+
+config FS_PSTORE_RAMOOPS_FTRACE_SIZE
+	int
+	prompt "Size of the ftrace area"
+	default 131072 # 2^17
+	range 4096 1073741824 # Random upper limitation of 1GiB
+	help
+	  Size of the RAMOOPS ftrace area that is reserved. This is passed to
+	  the kernel as well as argument. It should be a power of 2.
+
+config FS_PSTORE_RAMOOPS_PMSG_SIZE
+	int
+	prompt "Size of the userspace message area"
+	default 131072 # 2^17
+	range 4096 1073741824 # Random upper limitation of 1GiB
+	help
+	  Size of the RAMOOPS pmsg area that is reserved. This is passed to
+	  the kernel as well as argument. It should be a power of 2.
+
+config FS_PSTORE_RAMOOPS_RECORD_SIZE
+	int
+	prompt "Size of each oops area"
+	default 131072 # 2^17
+	range 4096 1073741824 # Random upper limitation of 1GiB
+	help
+	  Size of each RAMOOPS oops area. There are multiple oops/panic areas
+	  to store individual oops/panic messages. This is the size of each of
+	  these areas. It should be a power of 2.
+
+config FS_PSTORE_ECC_SIZE
+	int
+	prompt "ECC size"
+	default 16
+	help
+	  ECC size used. This is the amount of bytes for reed solomon codes
+	  that is used. 0 disables ECC.
+
+endif
+
+endif
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
new file mode 100644
index 000000000000..c4043e1a8fb2
--- /dev/null
+++ b/fs/pstore/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux pstorefs routines.
+#
+
+obj-y				+= fs.o platform.o
+
+
+ramoops-objs			+= ram.o ram_core.o
+obj-$(CONFIG_FS_PSTORE_RAMOOPS)	+= ramoops.o
diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
new file mode 100644
index 000000000000..0e05d48ea041
--- /dev/null
+++ b/fs/pstore/fs.c
@@ -0,0 +1,280 @@
+/*
+ * Persistent Storage Barebox filesystem layer
+ * Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <fs.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fs.h>
+#include <malloc.h>
+#include <init.h>
+#include <linux/stat.h>
+#include <linux/err.h>
+#include <linux/pstore.h>
+#include <libbb.h>
+#include <rtc.h>
+#include <libfile.h>
+#include <linux/pstore.h>
+#include "internal.h"
+
+struct list_head allpstore = LIST_HEAD_INIT(allpstore);
+
+struct pstore_private {
+	char name[PSTORE_NAMELEN];
+	struct list_head list;
+	struct pstore_info *psi;
+	enum pstore_type_id type;
+	u64	id;
+	int	count;
+	ssize_t	size;
+	ssize_t pos;
+	char	data[];
+};
+
+/*
+ * Make a regular file in the root directory of our file system.
+ * Load it up with "size" bytes of data from "buf".
+ * Set the mtime & ctime to the date that this record was originally stored.
+ */
+int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
+		  char *data, bool compressed, size_t size,
+		  struct pstore_info *psi)
+{
+	struct pstore_private	*private, *pos;
+
+	list_for_each_entry(pos, &allpstore, list) {
+		if (pos->type == type && pos->id == id && pos->psi == psi)
+			return -EEXIST;
+	}
+
+	private = xzalloc(sizeof(*private) + size);
+	if (!private)
+		return -ENOMEM;
+	private->type = type;
+	private->id = id;
+	private->count = count;
+	private->psi = psi;
+
+	switch (type) {
+	case PSTORE_TYPE_DMESG:
+		scnprintf(private->name, sizeof(private->name),
+			  "dmesg-%s-%lld%s", psname, id,
+			  compressed ? ".enc.z" : "");
+		break;
+	case PSTORE_TYPE_CONSOLE:
+		scnprintf(private->name, sizeof(private->name),
+			  "console-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_FTRACE:
+		scnprintf(private->name, sizeof(private->name),
+			  "ftrace-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_MCE:
+		scnprintf(private->name, sizeof(private->name),
+			  "mce-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_PPC_RTAS:
+		scnprintf(private->name, sizeof(private->name),
+			  "rtas-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_PPC_OF:
+		scnprintf(private->name, sizeof(private->name),
+			  "powerpc-ofw-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_PPC_COMMON:
+		scnprintf(private->name, sizeof(private->name),
+			  "powerpc-common-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_PMSG:
+		scnprintf(private->name, sizeof(private->name),
+			  "pmsg-%s-%lld", psname, id);
+		break;
+	case PSTORE_TYPE_UNKNOWN:
+		scnprintf(private->name, sizeof(private->name),
+			  "unknown-%s-%lld", psname, id);
+		break;
+	default:
+		scnprintf(private->name, sizeof(private->name),
+			  "type%d-%s-%lld", type, psname, id);
+		break;
+	}
+
+	memcpy(private->data, data, size);
+	private->size = size;
+
+	list_add(&private->list, &allpstore);
+
+	return 0;
+}
+
+static struct pstore_private *pstore_get_by_name(struct list_head *head,
+						 const char *name)
+{
+	struct pstore_private *d;
+
+	if (!name)
+		return NULL;
+
+	list_for_each_entry(d, head, list) {
+		if (strcmp(d->name, name) == 0)
+			return d;
+	}
+
+	return NULL;
+}
+
+static int pstore_open(struct device_d *dev, FILE *file, const char *filename)
+{
+	struct list_head *head = dev->priv;
+	struct pstore_private *d;
+
+	if (filename[0] == '/')
+		filename++;
+
+	d = pstore_get_by_name(head, filename);
+	if (!d)
+		return -EINVAL;
+
+	file->size = d->size;
+	file->priv = d;
+	d->pos = 0;
+
+	return 0;
+}
+
+static int pstore_close(struct device_d *dev, FILE *file)
+{
+	return 0;
+}
+
+static int pstore_read(struct device_d *dev, FILE *file, void *buf,
+		       size_t insize)
+{
+	struct pstore_private *d = file->priv;
+
+	memcpy(buf, &d->data[d->pos], insize);
+	d->pos += insize;
+
+	return insize;
+}
+
+static loff_t pstore_lseek(struct device_d *dev, FILE *file, loff_t pos)
+{
+	struct pstore_private *d = file->priv;
+
+	d->pos = pos;
+
+	return pos;
+}
+
+static DIR *pstore_opendir(struct device_d *dev, const char *pathname)
+{
+	DIR *dir;
+
+	dir = xzalloc(sizeof(DIR));
+
+	if (list_empty(&allpstore))
+		return dir;
+
+	dir->priv = list_first_entry(&allpstore, struct pstore_private, list);
+
+	return dir;
+}
+
+static struct dirent *pstore_readdir(struct device_d *dev, DIR *dir)
+{
+	struct pstore_private *d = dir->priv;
+
+	if (!d || &d->list == &allpstore)
+		return NULL;
+
+	strcpy(dir->d.d_name, d->name);
+	dir->priv = list_entry(d->list.next, struct pstore_private, list);
+
+	return &dir->d;
+}
+
+static int pstore_closedir(struct device_d *dev, DIR *dir)
+{
+	free(dir);
+
+	return 0;
+}
+
+static int pstore_stat(struct device_d *dev, const char *filename,
+		       struct stat *s)
+{
+	struct pstore_private *d;
+
+	if (filename[0] == '/')
+		filename++;
+
+	d = pstore_get_by_name(&allpstore, filename);
+	if (!d)
+		return -EINVAL;
+
+	s->st_size = d->size;
+	s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
+
+	return 0;
+}
+
+static void pstore_remove(struct device_d *dev)
+{
+	struct pstore_private *d, *tmp;
+
+	list_for_each_entry_safe(d, tmp, &allpstore, list) {
+		free(d);
+	}
+}
+
+static int pstore_probe(struct device_d *dev)
+{
+	struct list_head *priv = &allpstore;
+
+	dev->priv = priv;
+
+	dev_dbg(dev, "mounted pstore\n");
+
+	return 0;
+}
+
+static struct fs_driver_d pstore_driver = {
+	.open      = pstore_open,
+	.close     = pstore_close,
+	.read      = pstore_read,
+	.lseek     = pstore_lseek,
+	.opendir   = pstore_opendir,
+	.readdir   = pstore_readdir,
+	.closedir  = pstore_closedir,
+	.stat      = pstore_stat,
+	.flags     = FS_DRIVER_NO_DEV,
+	.type = filetype_uimage,
+	.drv = {
+		.probe  = pstore_probe,
+		.remove = pstore_remove,
+		.name = "pstore",
+	}
+};
+
+static int pstore_init(void)
+{
+	return register_fs_driver(&pstore_driver);
+}
+coredevice_initcall(pstore_init);
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
new file mode 100644
index 000000000000..0a8df1f4e296
--- /dev/null
+++ b/fs/pstore/internal.h
@@ -0,0 +1,19 @@
+#ifndef __PSTORE_INTERNAL_H__
+#define __PSTORE_INTERNAL_H__
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/pstore.h>
+
+#define PSTORE_NAMELEN  64
+
+extern struct pstore_info *psinfo;
+
+extern void	pstore_set_kmsg_bytes(int);
+extern void	pstore_get_records(int);
+extern int	pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
+			      int count, char *data, bool compressed,
+			      size_t size, struct pstore_info *psi);
+extern int	pstore_is_mounted(void);
+
+#endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
new file mode 100644
index 000000000000..dc2611f7328c
--- /dev/null
+++ b/fs/pstore/platform.c
@@ -0,0 +1,138 @@
+/*
+ * Persistent Storage - platform driver interface parts.
+ *
+ * Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "pstore: " fmt
+
+#include <linux/types.h>
+#include <linux/pstore.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <malloc.h>
+#include <printk.h>
+#include <module.h>
+
+#include "internal.h"
+
+struct pstore_info *psinfo;
+
+static char *backend;
+
+/* How much of the console log to snapshot */
+static unsigned long kmsg_bytes = 10240;
+
+void pstore_set_kmsg_bytes(int bytes)
+{
+	kmsg_bytes = bytes;
+}
+
+static int pstore_write_compat(enum pstore_type_id type,
+			       enum kmsg_dump_reason reason,
+			       u64 *id, unsigned int part, int count,
+			       bool compressed, size_t size,
+			       struct pstore_info *psi)
+{
+	return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
+			     size, psi);
+}
+
+/*
+ * platform specific persistent storage driver registers with
+ * us here. If pstore is already mounted, call the platform
+ * read function right away to populate the file system. If not
+ * then the pstore mount code will call us later to fill out
+ * the file system.
+ *
+ * Register with kmsg_dump to save last part of console log on panic.
+ */
+int pstore_register(struct pstore_info *psi)
+{
+	if (backend && strcmp(backend, psi->name))
+		return -EPERM;
+
+	spin_lock(&pstore_lock);
+	if (psinfo) {
+		spin_unlock(&pstore_lock);
+		return -EBUSY;
+	}
+
+	if (!psi->write)
+		psi->write = pstore_write_compat;
+	psinfo = psi;
+	mutex_init(&psinfo->read_mutex);
+	spin_unlock(&pstore_lock);
+
+	pstore_get_records(0);
+
+	pr_info("Registered %s as persistent store backend\n", psi->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pstore_register);
+
+/*
+ * Read all the records from the persistent store. Create
+ * files in our filesystem.  Don't warn about -EEXIST errors
+ * when we are re-scanning the backing store looking to add new
+ * error records.
+ */
+void pstore_get_records(int quiet)
+{
+	struct pstore_info *psi = psinfo;
+	char			*buf = NULL;
+	ssize_t			size;
+	u64			id;
+	int			count;
+	enum pstore_type_id	type;
+	int			failed = 0, rc;
+	bool			compressed;
+	int			unzipped_len = -1;
+
+	if (!psi)
+		return;
+
+	mutex_lock(&psi->read_mutex);
+	if (psi->open && psi->open(psi))
+		goto out;
+
+	while ((size = psi->read(&id, &type, &count, &buf, &compressed,
+				psi)) > 0) {
+		if (compressed && (type == PSTORE_TYPE_DMESG)) {
+			pr_err("barebox does not have ramoops compression support\n");
+			continue;
+		}
+		rc = pstore_mkfile(type, psi->name, id, count, buf,
+				  compressed, (size_t)size, psi);
+		if (unzipped_len < 0) {
+			/* Free buffer other than big oops */
+			kfree(buf);
+			buf = NULL;
+		} else
+			unzipped_len = -1;
+		if (rc && (rc != -EEXIST || !quiet))
+			failed++;
+	}
+	if (psi->close)
+		psi->close(psi);
+out:
+	mutex_unlock(&psi->read_mutex);
+
+	if (failed)
+		pr_warn("failed to load %d record(s) from '%s'\n",
+			failed, psi->name);
+}
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
new file mode 100644
index 000000000000..dc31ed16f923
--- /dev/null
+++ b/fs/pstore/ram.c
@@ -0,0 +1,507 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/pstore.h>
+#include <linux/time.h>
+#include <linux/ioport.h>
+#include <linux/compiler.h>
+#include <linux/pstore_ram.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/log2.h>
+#include <malloc.h>
+#include <printk.h>
+#include <stdio.h>
+#include <globalvar.h>
+#include <init.h>
+#include <common.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define MIN_MEM_SIZE 4096UL
+
+static const ulong record_size = CONFIG_FS_PSTORE_RAMOOPS_RECORD_SIZE;
+
+static const ulong ramoops_console_size = CONFIG_FS_PSTORE_RAMOOPS_CONSOLE_SIZE;
+
+static const ulong ramoops_ftrace_size = CONFIG_FS_PSTORE_RAMOOPS_FTRACE_SIZE;
+
+static const ulong ramoops_pmsg_size = CONFIG_FS_PSTORE_RAMOOPS_PMSG_SIZE;
+
+static const ulong mem_size = CONFIG_FS_PSTORE_RAMOOPS_SIZE;
+
+static const int dump_oops = 1;
+
+static const int ramoops_ecc = CONFIG_FS_PSTORE_ECC_SIZE;
+
+struct ramoops_context {
+	struct persistent_ram_zone **przs;
+	struct persistent_ram_zone *cprz;
+	struct persistent_ram_zone *fprz;
+	struct persistent_ram_zone *mprz;
+	phys_addr_t phys_addr;
+	unsigned long size;
+	unsigned int memtype;
+	size_t record_size;
+	size_t console_size;
+	size_t ftrace_size;
+	size_t pmsg_size;
+	int dump_oops;
+	struct persistent_ram_ecc_info ecc_info;
+	unsigned int max_dump_cnt;
+	unsigned int dump_write_cnt;
+	/* _read_cnt need clear on ramoops_pstore_open */
+	unsigned int dump_read_cnt;
+	unsigned int console_read_cnt;
+	unsigned int ftrace_read_cnt;
+	unsigned int pmsg_read_cnt;
+	struct pstore_info pstore;
+};
+
+static struct ramoops_platform_data *dummy_data;
+
+static int ramoops_pstore_open(struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+
+	cxt->dump_read_cnt = 0;
+	cxt->console_read_cnt = 0;
+	cxt->ftrace_read_cnt = 0;
+	cxt->pmsg_read_cnt = 0;
+	return 0;
+}
+
+static struct persistent_ram_zone *
+ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
+		     u64 *id,
+		     enum pstore_type_id *typep, enum pstore_type_id type,
+		     bool update)
+{
+	struct persistent_ram_zone *prz;
+	int i = (*c)++;
+
+	if (i >= max)
+		return NULL;
+
+	prz = przs[i];
+	if (!prz)
+		return NULL;
+
+	/* Update old/shadowed buffer. */
+	if (update)
+		persistent_ram_save_old(prz);
+
+	if (!persistent_ram_old_size(prz))
+		return NULL;
+
+	*typep = type;
+	*id = i;
+
+	return prz;
+}
+
+static bool prz_ok(struct persistent_ram_zone *prz)
+{
+	return !!prz && !!(persistent_ram_old_size(prz) +
+			   persistent_ram_ecc_string(prz, NULL, 0));
+}
+
+static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+				   int *count, char **buf, bool *compressed,
+				   struct pstore_info *psi)
+{
+	ssize_t size;
+	ssize_t ecc_notice_size;
+	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz;
+
+	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
+				   cxt->max_dump_cnt, id, type,
+				   PSTORE_TYPE_DMESG, 0);
+	if (!prz_ok(prz))
+		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
+					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
+	if (!prz_ok(prz))
+		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
+					   1, id, type, PSTORE_TYPE_FTRACE, 0);
+	if (!prz_ok(prz))
+		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
+					   1, id, type, PSTORE_TYPE_PMSG, 0);
+	if (!prz_ok(prz))
+		return 0;
+
+	if (!persistent_ram_old(prz))
+		return 0;
+
+	size = persistent_ram_old_size(prz);
+
+	/* ECC correction notice */
+	ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
+
+	*buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
+	if (*buf == NULL)
+		return -ENOMEM;
+
+	memcpy(*buf, (char *)persistent_ram_old(prz), size);
+	persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
+
+	return size + ecc_notice_size;
+}
+
+static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
+					    enum kmsg_dump_reason reason,
+					    u64 *id, unsigned int part,
+					    const char *buf,
+					    bool compressed, size_t size,
+					    struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz;
+
+	if (type == PSTORE_TYPE_CONSOLE) {
+		if (!cxt->cprz)
+			return -ENOMEM;
+		persistent_ram_write(cxt->cprz, buf, size);
+		return 0;
+	} else if (type == PSTORE_TYPE_FTRACE) {
+		if (!cxt->fprz)
+			return -ENOMEM;
+		persistent_ram_write(cxt->fprz, buf, size);
+		return 0;
+	} else if (type == PSTORE_TYPE_PMSG) {
+		if (!cxt->mprz)
+			return -ENOMEM;
+		persistent_ram_write(cxt->mprz, buf, size);
+		return 0;
+	}
+
+	if (type != PSTORE_TYPE_DMESG)
+		return -EINVAL;
+
+	/* Explicitly only take the first part of any new crash.
+	 * If our buffer is larger than kmsg_bytes, this can never happen,
+	 * and if our buffer is smaller than kmsg_bytes, we don't want the
+	 * report split across multiple records.
+	 */
+	if (part != 1)
+		return -ENOSPC;
+
+	if (!cxt->przs)
+		return -ENOSPC;
+
+	prz = cxt->przs[cxt->dump_write_cnt];
+
+	persistent_ram_write(prz, buf, size);
+
+	cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt;
+
+	return 0;
+}
+
+static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
+				struct pstore_info *psi)
+{
+	struct ramoops_context *cxt = psi->data;
+	struct persistent_ram_zone *prz;
+
+	switch (type) {
+	case PSTORE_TYPE_DMESG:
+		if (id >= cxt->max_dump_cnt)
+			return -EINVAL;
+		prz = cxt->przs[id];
+		break;
+	case PSTORE_TYPE_CONSOLE:
+		prz = cxt->cprz;
+		break;
+	case PSTORE_TYPE_FTRACE:
+		prz = cxt->fprz;
+		break;
+	case PSTORE_TYPE_PMSG:
+		prz = cxt->mprz;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	persistent_ram_free_old(prz);
+	persistent_ram_zap(prz);
+
+	return 0;
+}
+
+static struct ramoops_context oops_cxt = {
+	.pstore = {
+		.name	= "ramoops",
+		.open	= ramoops_pstore_open,
+		.read	= ramoops_pstore_read,
+		.write_buf	= ramoops_pstore_write_buf,
+		.erase	= ramoops_pstore_erase,
+	},
+};
+
+static void ramoops_free_przs(struct ramoops_context *cxt)
+{
+	int i;
+
+	cxt->max_dump_cnt = 0;
+	if (!cxt->przs)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
+		persistent_ram_free(cxt->przs[i]);
+	kfree(cxt->przs);
+}
+
+static int ramoops_init_przs(struct ramoops_context *cxt, phys_addr_t *paddr,
+			     size_t dump_mem_sz)
+{
+	int err = -ENOMEM;
+	int i;
+
+	if (!cxt->record_size)
+		return 0;
+
+	if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) {
+		pr_err("no room for dumps\n");
+		return -ENOMEM;
+	}
+
+	cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
+	if (!cxt->max_dump_cnt)
+		return -ENOMEM;
+
+	cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
+			     GFP_KERNEL);
+	if (!cxt->przs) {
+		pr_err("failed to initialize a prz array for dumps\n");
+		goto fail_prz;
+	}
+
+	for (i = 0; i < cxt->max_dump_cnt; i++) {
+		size_t sz = cxt->record_size;
+
+		cxt->przs[i] = persistent_ram_new(*paddr, sz, 0,
+						  &cxt->ecc_info,
+						  cxt->memtype);
+		if (IS_ERR(cxt->przs[i])) {
+			err = PTR_ERR(cxt->przs[i]);
+			pr_err("failed to request mem region (0x%zx@0x%llx): %d\n",
+				sz, (unsigned long long)*paddr, err);
+			goto fail_prz;
+		}
+		*paddr += sz;
+	}
+
+	return 0;
+fail_prz:
+	ramoops_free_przs(cxt);
+	return err;
+}
+
+static int ramoops_init_prz(struct ramoops_context *cxt,
+			    struct persistent_ram_zone **prz,
+			    phys_addr_t *paddr, size_t sz, u32 sig)
+{
+	if (!sz)
+		return 0;
+
+	if (*paddr + sz - cxt->phys_addr > cxt->size) {
+		pr_err("no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n",
+			sz, (unsigned long long)*paddr,
+			cxt->size, (unsigned long long)cxt->phys_addr);
+		return -ENOMEM;
+	}
+
+	*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info,
+				  cxt->memtype);
+	if (IS_ERR(*prz)) {
+		int err = PTR_ERR(*prz);
+
+		pr_err("failed to request mem region (0x%zx@0x%llx): %d\n",
+			sz, (unsigned long long)*paddr, err);
+		return err;
+	}
+
+	persistent_ram_zap(*prz);
+
+	*paddr += sz;
+
+	return 0;
+}
+
+static int ramoops_probe(struct ramoops_platform_data *pdata)
+{
+	struct ramoops_context *cxt = &oops_cxt;
+	size_t dump_mem_sz;
+	phys_addr_t paddr;
+	int err = -EINVAL;
+	char kernelargs[512];
+
+	/* Only a single ramoops area allowed at a time, so fail extra
+	 * probes.
+	 */
+	if (cxt->max_dump_cnt)
+		goto fail_out;
+
+	if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
+			!pdata->ftrace_size && !pdata->pmsg_size)) {
+		pr_err("The memory size and the record/console size must be "
+			"non-zero\n");
+		goto fail_out;
+	}
+
+	if (pdata->record_size && !is_power_of_2(pdata->record_size))
+		pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+	if (pdata->console_size && !is_power_of_2(pdata->console_size))
+		pdata->console_size = rounddown_pow_of_two(pdata->console_size);
+	if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
+		pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
+	if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
+		pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
+
+	cxt->size = pdata->mem_size;
+	cxt->phys_addr = pdata->mem_address;
+	cxt->memtype = pdata->mem_type;
+	cxt->record_size = pdata->record_size;
+	cxt->console_size = pdata->console_size;
+	cxt->ftrace_size = pdata->ftrace_size;
+	cxt->pmsg_size = pdata->pmsg_size;
+	cxt->dump_oops = pdata->dump_oops;
+	cxt->ecc_info = pdata->ecc_info;
+
+	paddr = cxt->phys_addr;
+
+	dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
+			- cxt->pmsg_size;
+	err = ramoops_init_przs(cxt, &paddr, dump_mem_sz);
+	if (err)
+		goto fail_out;
+
+	err = ramoops_init_prz(cxt, &cxt->cprz, &paddr,
+			       cxt->console_size, 0);
+	if (err)
+		goto fail_init_cprz;
+
+	err = ramoops_init_prz(cxt, &cxt->fprz, &paddr, cxt->ftrace_size, 0);
+	if (err)
+		goto fail_init_fprz;
+
+	err = ramoops_init_prz(cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
+	if (err)
+		goto fail_init_mprz;
+
+	cxt->pstore.data = cxt;
+	/*
+	 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we
+	 * have to handle dumps, we must have at least record_size buffer. And
+	 * for ftrace, bufsize is irrelevant (if bufsize is 0, buf will be
+	 * ZERO_SIZE_PTR).
+	 */
+	if (cxt->console_size)
+		cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */
+	cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize);
+	cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
+	spin_lock_init(&cxt->pstore.buf_lock);
+	if (!cxt->pstore.buf) {
+		pr_err("cannot allocate pstore buffer\n");
+		err = -ENOMEM;
+		goto fail_clear;
+	}
+
+	err = pstore_register(&cxt->pstore);
+	if (err) {
+		pr_err("registering with pstore failed\n");
+		goto fail_buf;
+	}
+
+	pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n",
+		cxt->size, (unsigned long long)cxt->phys_addr,
+		cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
+
+	scnprintf(kernelargs, sizeof(kernelargs),
+		  "ramoops.record_size=0x%x "
+		  "ramoops.console_size=0x%x "
+		  "ramoops.ftrace_size=0x%x "
+		  "ramoops.pmsg_size=0x%x "
+		  "ramoops.mem_address=0x%llx "
+		  "ramoops.mem_size=0x%lx "
+		  "ramoops.ecc=%d",
+		  cxt->record_size,
+		  cxt->console_size,
+		  cxt->ftrace_size,
+		  cxt->pmsg_size,
+		  (unsigned long long)cxt->phys_addr,
+		  mem_size,
+		  ramoops_ecc);
+	globalvar_add_simple("linux.bootargs.ramoops", kernelargs);
+
+	of_add_reserve_entry(cxt->phys_addr, cxt->phys_addr + mem_size);
+
+	return 0;
+
+fail_buf:
+	kfree(cxt->pstore.buf);
+fail_clear:
+	cxt->pstore.bufsize = 0;
+	kfree(cxt->mprz);
+fail_init_mprz:
+	kfree(cxt->fprz);
+fail_init_fprz:
+	kfree(cxt->cprz);
+fail_init_cprz:
+	ramoops_free_przs(cxt);
+fail_out:
+	return err;
+}
+unsigned long arm_mem_ramoops_get(void);
+
+static void ramoops_register_dummy(void)
+{
+	dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
+	if (!dummy_data) {
+		pr_info("could not allocate pdata\n");
+		return;
+	}
+
+	dummy_data->mem_size = mem_size;
+	dummy_data->mem_address = arm_mem_ramoops_get();
+	dummy_data->mem_type = 0;
+	dummy_data->record_size = record_size;
+	dummy_data->console_size = ramoops_console_size;
+	dummy_data->ftrace_size = ramoops_ftrace_size;
+	dummy_data->pmsg_size = ramoops_pmsg_size;
+	dummy_data->dump_oops = dump_oops;
+	/*
+	 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
+	 * (using 1 byte for ECC isn't much of use anyway).
+	 */
+	dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
+
+	ramoops_probe(dummy_data);
+}
+
+static int __init ramoops_init(void)
+{
+	ramoops_register_dummy();
+	return 0;
+}
+postcore_initcall(ramoops_init);
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
new file mode 100644
index 000000000000..d68d80900b50
--- /dev/null
+++ b/fs/pstore/ram_core.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "persistent_ram: " fmt
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/rslib.h>
+#include <linux/pstore_ram.h>
+#include <linux/string.h>
+#include <linux/rslib.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <memory.h>
+#include <common.h>
+
+struct persistent_ram_buffer {
+	uint32_t sig;
+	resource_size_t start;
+	resource_size_t size;
+	uint8_t data[0];
+};
+
+#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
+
+static inline size_t buffer_size(struct persistent_ram_zone *prz)
+{
+	return prz->buffer->size;
+}
+
+static inline size_t buffer_start(struct persistent_ram_zone *prz)
+{
+	return prz->buffer->start;
+}
+
+/* increase and wrap the start pointer, returning the old value */
+static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
+{
+	int old;
+	int new;
+
+	old = prz->buffer->start;
+	new = old + a;
+	while (unlikely(new >= prz->buffer_size))
+		new -= prz->buffer_size;
+	prz->buffer->start = new;
+
+	return old;
+}
+
+/* increase the size counter until it hits the max size */
+static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
+{
+	size_t old;
+	size_t new;
+
+	old = prz->buffer->size;
+	if (old == prz->buffer_size)
+		return;
+
+	new = old + a;
+	if (new > prz->buffer_size)
+		new = prz->buffer_size;
+	prz->buffer->size = new;
+}
+
+static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
+	uint8_t *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_info.ecc_size];
+
+	/* Initialize the parity buffer */
+	memset(par, 0, sizeof(par));
+	encode_rs8(prz->rs_decoder, data, len, par, 0);
+	for (i = 0; i < prz->ecc_info.ecc_size; i++)
+		ecc[i] = par[i];
+}
+
+static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
+	void *data, size_t len, uint8_t *ecc)
+{
+	int i;
+	uint16_t par[prz->ecc_info.ecc_size];
+
+	for (i = 0; i < prz->ecc_info.ecc_size; i++)
+		par[i] = ecc[i];
+	return decode_rs8(prz->rs_decoder, data, par, len,
+				NULL, 0, NULL, 0, NULL);
+}
+
+static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
+	unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *buffer_end = buffer->data + prz->buffer_size;
+	uint8_t *block;
+	uint8_t *par;
+	int ecc_block_size = prz->ecc_info.block_size;
+	int ecc_size = prz->ecc_info.ecc_size;
+	int size = ecc_block_size;
+
+	if (!ecc_size)
+		return;
+
+	block = buffer->data + (start & ~(ecc_block_size - 1));
+	par = prz->par_buffer + (start / ecc_block_size) * ecc_size;
+
+	do {
+		if (block + ecc_block_size > buffer_end)
+			size = buffer_end - block;
+		persistent_ram_encode_rs8(prz, block, size, par);
+		block += ecc_block_size;
+		par += ecc_size;
+	} while (block < buffer->data + start + count);
+}
+
+static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+
+	if (!prz->ecc_info.ecc_size)
+		return;
+
+	persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
+				  prz->par_header);
+}
+
+static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	uint8_t *block;
+	uint8_t *par;
+
+	if (!prz->ecc_info.ecc_size)
+		return;
+
+	block = buffer->data;
+	par = prz->par_buffer;
+	while (block < buffer->data + buffer_size(prz)) {
+		int numerr;
+		int size = prz->ecc_info.block_size;
+		if (block + size > buffer->data + prz->buffer_size)
+			size = buffer->data + prz->buffer_size - block;
+		numerr = persistent_ram_decode_rs8(prz, block, size, par);
+		if (numerr > 0) {
+			pr_debug("error in block %p, %d\n", block, numerr);
+			prz->corrected_bytes += numerr;
+		} else if (numerr < 0) {
+			pr_debug("uncorrectable error in block %p\n", block);
+			prz->bad_blocks++;
+		}
+		block += prz->ecc_info.block_size;
+		par += prz->ecc_info.ecc_size;
+	}
+}
+
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
+				   struct persistent_ram_ecc_info *ecc_info)
+{
+	int numerr;
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	int ecc_blocks;
+	size_t ecc_total;
+
+	if (!ecc_info || !ecc_info->ecc_size)
+		return 0;
+
+	prz->ecc_info.block_size = ecc_info->block_size ?: 128;
+	prz->ecc_info.ecc_size = ecc_info->ecc_size ?: 16;
+	prz->ecc_info.symsize = ecc_info->symsize ?: 8;
+	prz->ecc_info.poly = ecc_info->poly ?: 0x11d;
+
+	ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_info.ecc_size,
+				  prz->ecc_info.block_size +
+				  prz->ecc_info.ecc_size);
+	ecc_total = (ecc_blocks + 1) * prz->ecc_info.ecc_size;
+	if (ecc_total >= prz->buffer_size) {
+		pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
+		       __func__, prz->ecc_info.ecc_size,
+		       ecc_total, prz->buffer_size);
+		return -EINVAL;
+	}
+
+	prz->buffer_size -= ecc_total;
+	prz->par_buffer = buffer->data + prz->buffer_size;
+	prz->par_header = prz->par_buffer +
+			  ecc_blocks * prz->ecc_info.ecc_size;
+
+	/*
+	 * first consecutive root is 0
+	 * primitive element to generate roots = 1
+	 */
+	prz->rs_decoder = init_rs(prz->ecc_info.symsize, prz->ecc_info.poly,
+				  0, 1, prz->ecc_info.ecc_size);
+	if (prz->rs_decoder == NULL) {
+		pr_info("init_rs failed\n");
+		return -EINVAL;
+	}
+
+	prz->corrected_bytes = 0;
+	prz->bad_blocks = 0;
+
+	numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
+					   prz->par_header);
+	if (numerr > 0) {
+		pr_info("error in header, %d\n", numerr);
+		prz->corrected_bytes += numerr;
+	} else if (numerr < 0) {
+		pr_info("uncorrectable error in header\n");
+		prz->bad_blocks++;
+	}
+
+	return 0;
+}
+
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len)
+{
+	ssize_t ret;
+
+	if (!prz->ecc_info.ecc_size)
+		return 0;
+
+	if (prz->corrected_bytes || prz->bad_blocks)
+		ret = snprintf(str, len, ""
+			"\n%d Corrected bytes, %d unrecoverable blocks\n",
+			prz->corrected_bytes, prz->bad_blocks);
+	else
+		ret = snprintf(str, len, "\nNo errors detected\n");
+
+	return ret;
+}
+
+static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
+	const void *s, unsigned int start, unsigned int count)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	memcpy(buffer->data + start, s, count);
+	persistent_ram_update_ecc(prz, start, count);
+}
+
+void persistent_ram_save_old(struct persistent_ram_zone *prz)
+{
+	struct persistent_ram_buffer *buffer = prz->buffer;
+	size_t size = buffer_size(prz);
+	size_t start = buffer_start(prz);
+
+	if (!size)
+		return;
+
+	if (!prz->old_log) {
+		persistent_ram_ecc_old(prz);
+		prz->old_log = kmalloc(size, GFP_KERNEL);
+	}
+	if (!prz->old_log) {
+		pr_err("failed to allocate buffer\n");
+		return;
+	}
+
+	prz->old_log_size = size;
+	memcpy(prz->old_log, &buffer->data[start], size - start);
+	memcpy(prz->old_log + size - start, &buffer->data[0], start);
+}
+
+int notrace persistent_ram_write(struct persistent_ram_zone *prz,
+	const void *s, unsigned int count)
+{
+	int rem;
+	int c = count;
+	size_t start;
+
+	if (unlikely(c > prz->buffer_size)) {
+		s += c - prz->buffer_size;
+		c = prz->buffer_size;
+	}
+
+	buffer_size_add(prz, c);
+
+	start = buffer_start_add(prz, c);
+
+	rem = prz->buffer_size - start;
+	if (unlikely(rem < c)) {
+		persistent_ram_update(prz, s, start, rem);
+		s += rem;
+		c -= rem;
+		start = 0;
+	}
+	persistent_ram_update(prz, s, start, c);
+
+	persistent_ram_update_header_ecc(prz);
+
+	return count;
+}
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
+{
+	return prz->old_log_size;
+}
+
+void *persistent_ram_old(struct persistent_ram_zone *prz)
+{
+	return prz->old_log;
+}
+
+void persistent_ram_free_old(struct persistent_ram_zone *prz)
+{
+	kfree(prz->old_log);
+	prz->old_log = NULL;
+	prz->old_log_size = 0;
+}
+
+#ifdef CONFIG_FS_PSTORE_RAMOOPS_RO
+void persistent_ram_zap(struct persistent_ram_zone *prz)
+{
+}
+#else
+void persistent_ram_zap(struct persistent_ram_zone *prz)
+{
+	prz->buffer->start = 0;
+	prz->buffer->size = 0;
+	persistent_ram_update_header_ecc(prz);
+}
+#endif /* CONFIG_PSTORE_RAMOOPS_RO */
+
+static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
+		struct persistent_ram_zone *prz, int memtype)
+{
+	prz->res = request_sdram_region("persistent ram", start, size);
+	if (!prz->res)
+		return -ENOMEM;
+
+	prz->paddr = start;
+	prz->size = size;
+
+	prz->buffer = (void *)start;
+	prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
+
+	return 0;
+}
+
+static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
+				    struct persistent_ram_ecc_info *ecc_info)
+{
+	int ret;
+
+	ret = persistent_ram_init_ecc(prz, ecc_info);
+	if (ret)
+		return ret;
+
+	sig ^= PERSISTENT_RAM_SIG;
+
+	if (prz->buffer->sig == sig) {
+		if (buffer_size(prz) > prz->buffer_size ||
+		    buffer_start(prz) > buffer_size(prz))
+			pr_info("found existing invalid buffer, size %zu, start %zu\n",
+				buffer_size(prz), buffer_start(prz));
+		else {
+			pr_debug("found existing buffer, size %zu, start %zu\n",
+				 buffer_size(prz), buffer_start(prz));
+			persistent_ram_save_old(prz);
+			return 0;
+		}
+	} else {
+		pr_debug("no valid data in buffer (sig = 0x%08x)\n",
+			 prz->buffer->sig);
+	}
+
+	prz->buffer->sig = sig;
+	persistent_ram_zap(prz);
+
+	return 0;
+}
+
+void persistent_ram_free(struct persistent_ram_zone *prz)
+{
+	if (!prz)
+		return;
+
+	if (prz->res) {
+		release_sdram_region(prz->res);
+		prz->res = NULL;
+	}
+
+	persistent_ram_free_old(prz);
+	kfree(prz);
+}
+
+struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
+			u32 sig, struct persistent_ram_ecc_info *ecc_info,
+			unsigned int memtype)
+{
+	struct persistent_ram_zone *prz;
+	int ret = -ENOMEM;
+
+	prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+	if (!prz) {
+		pr_err("failed to allocate persistent ram zone\n");
+		goto err;
+	}
+
+	ret = persistent_ram_buffer_map(start, size, prz, memtype);
+	if (ret)
+		goto err;
+
+	ret = persistent_ram_post_init(prz, sig, ecc_info);
+	if (ret)
+		goto err;
+
+	return prz;
+err:
+	persistent_ram_free(prz);
+	return ERR_PTR(ret);
+}
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
new file mode 100644
index 000000000000..a925e143971c
--- /dev/null
+++ b/include/linux/pstore.h
@@ -0,0 +1,90 @@
+/*
+ * Persistent Storage - pstore.h
+ *
+ * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
+ *
+ * This code is the generic layer to export data records from platform
+ * level persistent storage via a file system.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _LINUX_PSTORE_H
+#define _LINUX_PSTORE_H
+
+#include <linux/time.h>
+#include <linux/types.h>
+#include <asm-generic/errno.h>
+
+/* types */
+enum pstore_type_id {
+	PSTORE_TYPE_DMESG	= 0,
+	PSTORE_TYPE_MCE		= 1,
+	PSTORE_TYPE_CONSOLE	= 2,
+	PSTORE_TYPE_FTRACE	= 3,
+	/* PPC64 partition types */
+	PSTORE_TYPE_PPC_RTAS	= 4,
+	PSTORE_TYPE_PPC_OF	= 5,
+	PSTORE_TYPE_PPC_COMMON	= 6,
+	PSTORE_TYPE_PMSG	= 7,
+	PSTORE_TYPE_UNKNOWN	= 255
+};
+
+enum kmsg_dump_reason {
+	KMSG_DUMP_UNDEF,
+};
+
+struct module;
+
+struct pstore_info {
+	struct module	*owner;
+	char		*name;
+	char		*buf;
+	size_t		bufsize;
+	int		flags;
+	int		(*open)(struct pstore_info *psi);
+	int		(*close)(struct pstore_info *psi);
+	ssize_t		(*read)(u64 *id, enum pstore_type_id *type,
+			int *count, char **buf, bool *compressed,
+			struct pstore_info *psi);
+	int		(*write)(enum pstore_type_id type,
+			enum kmsg_dump_reason reason, u64 *id,
+			unsigned int part, int count, bool compressed,
+			size_t size, struct pstore_info *psi);
+	int		(*write_buf)(enum pstore_type_id type,
+			enum kmsg_dump_reason reason, u64 *id,
+			unsigned int part, const char *buf, bool compressed,
+			size_t size, struct pstore_info *psi);
+	int		(*erase)(enum pstore_type_id type, u64 id,
+			int count, struct pstore_info *psi);
+	void		*data;
+};
+
+#define	PSTORE_FLAGS_FRAGILE	1
+
+#ifdef CONFIG_FS_PSTORE
+extern int pstore_register(struct pstore_info *);
+extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason);
+#else
+static inline int
+pstore_register(struct pstore_info *psi)
+{
+	return -ENODEV;
+}
+static inline bool
+pstore_cannot_block_path(enum kmsg_dump_reason reason)
+{
+	return false;
+}
+#endif
+
+#endif /*_LINUX_PSTORE_H*/
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
new file mode 100644
index 000000000000..5ef823a57be9
--- /dev/null
+++ b/include/linux/pstore_ram.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_PSTORE_RAM_H__
+#define __LINUX_PSTORE_RAM_H__
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct persistent_ram_buffer;
+struct rs_control;
+
+struct persistent_ram_ecc_info {
+	int block_size;
+	int ecc_size;
+	int symsize;
+	int poly;
+};
+
+struct persistent_ram_zone {
+	phys_addr_t paddr;
+	size_t size;
+	struct persistent_ram_buffer *buffer;
+	size_t buffer_size;
+	struct resource *res;
+
+	/* ECC correction */
+	char *par_buffer;
+	char *par_header;
+	struct rs_control *rs_decoder;
+	int corrected_bytes;
+	int bad_blocks;
+	struct persistent_ram_ecc_info ecc_info;
+
+	char *old_log;
+	size_t old_log_size;
+};
+
+struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
+			u32 sig, struct persistent_ram_ecc_info *ecc_info,
+			unsigned int memtype);
+void persistent_ram_free(struct persistent_ram_zone *prz);
+void persistent_ram_zap(struct persistent_ram_zone *prz);
+
+int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
+	unsigned int count);
+
+void persistent_ram_save_old(struct persistent_ram_zone *prz);
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
+void *persistent_ram_old(struct persistent_ram_zone *prz);
+void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+	char *str, size_t len);
+
+/*
+ * Ramoops platform data
+ * @mem_size	memory size for ramoops
+ * @mem_address	physical memory address to contain ramoops
+ */
+
+struct ramoops_platform_data {
+	unsigned long	mem_size;
+	unsigned long	mem_address;
+	unsigned int	mem_type;
+	unsigned long	record_size;
+	unsigned long	console_size;
+	unsigned long	ftrace_size;
+	unsigned long	pmsg_size;
+	int		dump_oops;
+	struct persistent_ram_ecc_info ecc_info;
+};
+
+#endif
-- 
2.6.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply	[flat|nested] 13+ messages in thread