[PATCH v2 2/3] powerpc/pseries: create rtas buffer accessor

Cyril Bur cyril.bur at au1.ibm.com
Thu Sep 25 16:41:29 EST 2014


Added simple accessor functions for rtas in memory buffers which performs
accesses of appropriate type and performs endian conversions.

Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
---
 arch/powerpc/platforms/pseries/Makefile      |   4 +-
 arch/powerpc/platforms/pseries/pseries.h     |  41 +++++++++
 arch/powerpc/platforms/pseries/rtas_buffer.c | 126 +++++++++++++++++++++++++++
 3 files changed, 170 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/pseries/rtas_buffer.c

diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 0348079..7eb7c46 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -3,7 +3,9 @@ ccflags-$(CONFIG_PPC_PSERIES_DEBUG)	+= -DDEBUG
 
 obj-y			:= lpar.o hvCall.o nvram.o reconfig.o \
 			   setup.o iommu.o event_sources.o ras.o \
-			   firmware.o power.o dlpar.o mobility.o rng.o
+			   firmware.o power.o dlpar.o mobility.o \
+			   rng.o rtas_buffer.o
+
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_SCANLOG)	+= scanlog.o
 obj-$(CONFIG_EEH)	+= eeh_pseries.o
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 361add6..f24e352 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -66,4 +66,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
 
 unsigned long pseries_memory_block_size(void);
 
+/* Manipulation of the in memory data returned from an RTAS call */
+
+/* Data pointed to by ptr is in big endian */
+struct rtas_buffer {
+	void *ptr;
+	int len;
+	int pos;
+};
+
+/* Buffer is already zeroed */
+int make_rtas_buf(struct rtas_buffer *b, size_t size);
+void free_rtas_buf(struct rtas_buffer *b);
+
+/* Return pointer to the buffer being used */
+void *get_rtas_buf(struct rtas_buffer *b);
+
+/* Checks if the buffer exists and the read position is less than the length*/
+bool check_rtas_buf(struct rtas_buffer *b);
+size_t get_rtas_buf_size(struct rtas_buffer *b);
+
+/* Advance the internal position of the buffer by size bytes */
+bool advance_rtas_buf(struct rtas_buffer *b, size_t size);
+
+/* Put a value val into the buffer at position pos. Function expect val in cpu
+ * endian. Returns true if the write to the buffer was successful.
+ */
+bool put_rtas_buf_32(struct rtas_buffer *b, u32 val, int pos);
+
+/* Grab the byte at the current position of the buffer without incrementing
+ * the internal position of the buffer */
+bool peek_rtas_buf(struct rtas_buffer *b, u8 *c);
+
+/* Accessor functions return true if access succeeded and value is written to
+ * val in cpu endian. Automatically advances its reference into the buffer by
+ * the requested amount.
+ */
+bool get_rtas_buf_32(struct rtas_buffer *b, u32 *val);
+bool get_rtas_buf_64(struct rtas_buffer *b, u64 *val);
+bool get_rtas_buf_mem(struct rtas_buffer *b, void **p, size_t len);
+bool get_rtas_buf_str(struct rtas_buffer *b, char **s);
+
 #endif /* _PSERIES_PSERIES_H */
diff --git a/arch/powerpc/platforms/pseries/rtas_buffer.c b/arch/powerpc/platforms/pseries/rtas_buffer.c
new file mode 100644
index 0000000..f06b73c
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/rtas_buffer.c
@@ -0,0 +1,126 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "pseries.h"
+
+
+int make_rtas_buf(struct rtas_buffer *b, size_t sz)
+{
+	b->ptr = kzalloc(sz, GFP_KERNEL);
+	b->len = sz;
+	b->pos = 0;
+	return (!b->ptr) ? -ENOMEM : 0;
+}
+
+void free_rtas_buf(struct rtas_buffer *b)
+{
+	kfree(b->ptr);
+}
+
+void *get_rtas_buf(struct rtas_buffer *b)
+{
+	return (b) ? b->ptr : NULL;
+}
+
+size_t get_rtas_buf_size(struct rtas_buffer *b)
+{
+	return (b) ? b->len : 0;
+}
+
+bool check_rtas_buf(struct rtas_buffer *b)
+{
+	return (b && b->ptr && b->pos < b->len);
+}
+
+static inline void *buf_pos(struct rtas_buffer *b)
+{
+	return (b && b->ptr) ? b->ptr + b->pos : NULL;
+}
+
+bool peek_rtas_buf(struct rtas_buffer *b, u8 *c)
+{
+	if (!b || !c || b->pos >= b->len)
+		return false;
+
+	*c = *(u8 *)buf_pos(b);
+
+	return true;
+}
+
+bool put_rtas_buf_32(struct rtas_buffer *b, u32 val, int pos)
+{
+	if (!b || b->pos >= b->len)
+		return false;
+
+	*((__be32 *)buf_pos(b)) = cpu_to_be32(val);
+
+	return true;
+}
+
+bool get_rtas_buf_32(struct rtas_buffer *b, u32 *val)
+{
+	if (!b || !val || b->len - b->pos < sizeof(u32))
+		return false;
+
+	*val = be32_to_cpu(*((__be32 *)buf_pos(b)));
+	b->pos += sizeof(u32);
+	return true;
+}
+
+bool get_rtas_buf_64(struct rtas_buffer *b, u64 *val)
+{
+	if (!b || !val || b->len - b->pos < sizeof(u64))
+		return false;
+
+	*val = be64_to_cpu(*((__be64 *)buf_pos(b)));
+	b->pos += sizeof(u64);
+	return true;
+}
+
+bool get_rtas_buf_str(struct rtas_buffer *b, char **s)
+{
+	int i;
+	if (!b || !s)
+		return false;
+
+	/* Get length of string */
+	i = b->pos;
+	while (i < b->len) {
+		if (*(char *)(b->ptr + i) == '\0') {
+			*s = (char *)buf_pos(b);
+			if (!*s)
+				return false;
+
+			b->pos = i + 1;
+			return true;
+		}
+		i++;
+	}
+
+	return false;
+}
+
+bool get_rtas_buf_mem(struct rtas_buffer *b, void **p, size_t len)
+{
+	if (!b || !p || b->len - b->pos < len)
+		return false;
+
+	*p = buf_pos(b);
+	if (!*p)
+		return false;
+
+	b->pos += len;
+
+	return true;
+}
+
+bool advance_rtas_buf(struct rtas_buffer *b, size_t len)
+{
+	if (!b || b->len - b->pos < len)
+		return false;
+
+	b->pos += len;
+
+	return true;
+}
+
-- 
1.9.1



More information about the Linuxppc-dev mailing list