[Skiboot] [PATCH 4/5] external/opal-prd: Use libflash/blocklevel for MTD/file accesses

Cyril Bur cyril.bur at au1.ibm.com
Mon Jan 4 13:23:10 AEDT 2016


pnor.c existed before blocklevel, it is time that this code got updated to
use the available libraries.

Changes include using the blocklevel accessors for MTD reads and writes
rather than read() and write() on a file descriptor.

This patch also makes use of the arch_flash_init() auto detection of the
/dev/mtd device which corresponds to the MTD device exposed by skiboot for
access to platform flash.

Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
---
 external/common/rules.mk     |   2 +-
 external/opal-prd/Makefile   |  27 ++++--
 external/opal-prd/opal-prd.c |  12 +--
 external/opal-prd/pnor.c     | 215 +++++++------------------------------------
 external/opal-prd/pnor.h     |   2 +
 5 files changed, 60 insertions(+), 198 deletions(-)

diff --git a/external/common/rules.mk b/external/common/rules.mk
index 356c207..81adddd 100644
--- a/external/common/rules.mk
+++ b/external/common/rules.mk
@@ -42,7 +42,7 @@ arch_clean:
 $(ARCH_SRC): | common
 
 $(ARCH_OBJS): common-%.o: common/%.c
-	$(Q_CC)$(CROSS_COMPILE)gcc $(CFLAGS) -c $< -o $@
+	$(Q_CC)$(CROSS_COMPILE)gcc $(CFLAGS) $(CPPFLAGS) -c $< -o $@
 
 common-arch_flash.o: $(ARCH_OBJS)
 	$(Q_LD)$(CROSS_COMPILE)ld $(LDFLAGS) -r $(ARCH_OBJS) -o $@
diff --git a/external/opal-prd/Makefile b/external/opal-prd/Makefile
index ff3fc73..98c7b48 100644
--- a/external/opal-prd/Makefile
+++ b/external/opal-prd/Makefile
@@ -10,6 +10,11 @@ sbindir = $(prefix)/sbin
 datadir = $(prefix)/share
 mandir = $(datadir)/man
 
+all: opal-prd
+
+GET_ARCH = ../../external/common/get_arch.sh
+include ../../external/common/rules.mk
+
 # Use make V=1 for a verbose build.
 ifndef V
         Q_CC=	@echo '    CC ' $@;
@@ -18,12 +23,14 @@ ifndef V
         Q_MKDIR=@echo ' MKDIR ' $@;
 endif
 
-OBJS = opal-prd.o thunk.o pnor.o i2c.o module.o version.o \
-       blocklevel.o libffs.o libflash.o ecc.o
+LIBFLASH_OBJS = libflash-blocklevel.o libflash-libffs.o \
+                libflash-libflash.o libflash-ecc.o \
+                libflash-file.o
 
-all: opal-prd
+OBJS = opal-prd.o thunk.o pnor.o i2c.o module.o version.o \
+       $(LIBFLASH_OBJS) common-arch_flash.o
 
-LINKS = ccan
+LINKS = ccan common libflash $(ARCH_LINKS)
 
 OPAL_PRD_VERSION ?= $(shell ../../make_version.sh opal-prd)
 
@@ -34,6 +41,12 @@ endif
 ccan:
 	$(Q_LN)ln -sfr ../../ccan ./ccan
 
+libflash:
+	$(Q_LN)ln -sfr ../../libflash ./libflash
+
+common:
+	$(Q_LN)ln -sfr ../common ./common
+
 asm/opal-prd.h:
 	$(Q_MKDIR)mkdir -p asm
 	$(Q_LN)ln -sfr $(KERNEL_DIR)/arch/powerpc/include/uapi/asm/opal-prd.h \
@@ -44,7 +57,7 @@ $(OBJS): $(LINKS)
 %.o: %.c
 	$(Q_CC)$(COMPILE.c) $< -o $@
 
-%.o: ../../libflash/%.c
+$(LIBFLASH_OBJS): libflash-%.o : libflash/%.c
 	$(Q_CC)$(COMPILE.c) $< -o $@
 
 %.o: %.S
@@ -66,9 +79,9 @@ version.c: ../../make_version.sh .version
 	@cmp -s $@ $@.tmp || cp $@.tmp $@
 	@rm -f $@.tmp
 
-test: test/test_pnor
+test: $(LINKS) test/test_pnor
 
-test/test_pnor: test/test_pnor.o pnor.o libflash.o libffs.o blocklevel.o file.o ecc.o
+test/test_pnor: test/test_pnor.o pnor.o $(LIBFLASH_OBJS) common-arch_flash.o
 	$(Q_LINK)$(LINK.o) -o $@ $^
 
 install: all
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index a82000a..f80e74c 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -1603,14 +1603,10 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
 
 	fixup_hinterface_table();
 
-	if (ctx->pnor.path) {
-		rc = pnor_init(&ctx->pnor);
-		if (rc) {
-			pr_log(LOG_ERR, "PNOR: Failed to open pnor: %m");
-			goto out_close;
-		}
-	} else {
-		pr_log(LOG_WARNING,"PNOR: No path provided, access will fail\n");
+	rc = pnor_init(&ctx->pnor);
+	if (rc) {
+		pr_log(LOG_ERR, "PNOR: Failed to open pnor: %m");
+		goto out_close;
 	}
 
 	ipmi_init(ctx);
diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c
index 7c98603..0e7e5c0 100644
--- a/external/opal-prd/pnor.c
+++ b/external/opal-prd/pnor.c
@@ -15,6 +15,8 @@
  */
 
 #include <libflash/libffs.h>
+#include <common/arch_flash.h>
+
 #include <errno.h>
 
 #include <sys/stat.h>
@@ -32,57 +34,34 @@
 
 int pnor_init(struct pnor *pnor)
 {
-	int rc, fd;
-	struct blocklevel_device *bl;
-	mtd_info_t mtd_info;
+	int rc;
 
 	if (!pnor)
 		return -1;
 
-	/* Open device and ffs */
-	fd = open(pnor->path, O_RDWR);
-	if (fd < 0) {
-		perror(pnor->path);
+	rc = arch_flash_init(&(pnor->bl), pnor->path, false);
+	if (rc) {
+		pr_log(LOG_ERR, "PNOR: Flash init failed");
 		return -1;
 	}
 
-	/* Hack so we can test on non-mtd file descriptors */
-#if defined(__powerpc__)
-	rc = ioctl(fd, MEMGETINFO, &mtd_info);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: ioctl failed to get pnor info: %m");
-		goto out;
-	}
-	pnor->size = mtd_info.size;
-	pnor->erasesize = mtd_info.erasesize;
-#else
-	pnor->size = lseek(fd, 0, SEEK_END);
-	if (pnor->size < 0) {
-		perror(pnor->path);
+	rc = blocklevel_get_info(pnor->bl, NULL, &(pnor->size), &(pnor->erasesize));
+	if (rc) {
+		pr_log(LOG_ERR, "PNOR: blocklevel_get_info() failed. Can't use PNOR");
 		goto out;
 	}
-	/* Fake it */
-	pnor->erasesize = 1024;
-#endif
-
-	pr_debug("PNOR: Found PNOR: %d bytes (%d blocks)", pnor->size,
-	       pnor->erasesize);
 
-	rc = file_init(fd, &bl);
+	rc = ffs_init(0, pnor->size, pnor->bl, &pnor->ffsh, 0);
 	if (rc) {
-		pr_log(LOG_ERR, "PNOR: (libflash) file_init() failed");
+		pr_log(LOG_ERR, "PNOR: Failed to open pnor partition table");
 		goto out;
 	}
 
-	rc = ffs_init(0, pnor->size, 0, bl, &pnor->ffsh, 0);
-	if (rc)
-		pr_log(LOG_ERR, "PNOR: Failed to open pnor partition table");
-
-	file_exit(bl);
+	return 0;
 out:
-	close(fd);
-
-	return rc;
+	arch_flash_close(pnor->bl, pnor->path);
+	pnor->bl = NULL;
+	return -1;
 }
 
 void pnor_close(struct pnor *pnor)
@@ -93,6 +72,9 @@ void pnor_close(struct pnor *pnor)
 	if (pnor->ffsh)
 		ffs_close(pnor->ffsh);
 
+	if (pnor->bl)
+		arch_flash_close(pnor->bl, pnor->path);
+
 	if (pnor->path)
 		free(pnor->path);
 }
@@ -115,159 +97,36 @@ void dump_parts(struct ffs_handle *ffs) {
 	}
 }
 
-static int mtd_write(struct pnor *pnor, int fd, void *data, uint64_t offset,
+static int mtd_write(struct pnor *pnor, void *data, uint64_t offset,
 		     size_t len)
 {
-	int write_start, write_len, start_waste, rc;
-	bool end_waste = false;
-	uint8_t *buf;
-	struct erase_info_user erase;
+	int rc;
 
 	if (len > pnor->size || offset > pnor->size ||
 	    len + offset > pnor->size)
 		return -ERANGE;
 
-	start_waste = offset % pnor->erasesize;
-	write_start = offset - start_waste;
-
-	/* Align size to multiple of block size */
-	write_len = (len + start_waste) & ~(pnor->erasesize - 1);
-	if ((len + start_waste) > write_len) {
-		end_waste = true;
-		write_len += pnor->erasesize;
-	}
-
-	buf = malloc(write_len);
-
-	if (start_waste) {
-		rc = lseek(fd, write_start, SEEK_SET);
-		if (rc < 0) {
-			pr_log(LOG_ERR, "PNOR: lseek write_start(0x%x) "
-					"failed; %m", write_start);
-			goto out;
-		}
-
-		rc = read(fd, buf, pnor->erasesize);
-		if (rc < 0) {
-			pr_log(LOG_ERR, "PNOR: read(0x%x bytes) failed: %m",
-					pnor->erasesize);
-			goto out;
-		}
-	}
-
-	if (end_waste)  {
-		rc = lseek(fd, write_start + write_len - pnor->erasesize,
-			   SEEK_SET);
-		if (rc < 0) {
-			perror("lseek last write block");
-			pr_log(LOG_ERR, "PNOR: lseek last write block(0x%x) "
-					"failed; %m",
-						write_start + write_len -
-						pnor->erasesize);
-			goto out;
-		}
-
-		rc = read(fd, buf + write_len - pnor->erasesize, pnor->erasesize);
-		if (rc < 0) {
-			pr_log(LOG_ERR, "PNOR: read(0x%x bytes) failed: %m",
-					pnor->erasesize);
-			goto out;
-		}
-	}
-
-	/* Put data in the correct spot */
-	memcpy(buf + start_waste, data, len);
-
-	/* Not sure if this is required */
-	rc = lseek(fd, 0, SEEK_SET);
-	if (rc < 0) {
-		pr_log(LOG_NOTICE, "PNOR: lseek(0) failed: %m");
-		goto out;
-	}
-
-	/* Erase */
-	erase.start = write_start;
-	erase.length = write_len;
-
-	rc = ioctl(fd, MEMERASE, &erase);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: erase(start 0x%x, len 0x%x) ioctl "
-				"failed: %m", write_start, write_len);
-		goto out;
-	}
-
-	/* Write */
-	rc = lseek(fd, write_start, SEEK_SET);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: lseek write_start(0x%x) failed: %m",
-				write_start);
-		goto out;
-	}
-
-	rc = write(fd, buf, write_len);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: write(0x%x bytes) failed: %m",
-				write_len);
-		goto out;
-	}
-
-	/* We have succeded, report the requested write size */
-	rc = len;
+	rc = blocklevel_smart_write(pnor->bl, offset, data, len);
+	if (rc)
+		return -errno;
 
-out:
-	free(buf);
-	return rc;
+	return len;
 }
 
-static int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset,
+static int mtd_read(struct pnor *pnor, void *data, uint64_t offset,
 		    size_t len)
 {
-	int read_start, read_len, start_waste, rc;
-	int mask = pnor->erasesize - 1;
-	void *buf;
+	int rc;
 
 	if (len > pnor->size || offset > pnor->size ||
 	    len + offset > pnor->size)
 		return -ERANGE;
 
-	/* Align start to erase block size */
-	start_waste = offset % pnor->erasesize;
-	read_start = offset - start_waste;
-
-	/* Align size to multiple of block size */
-	read_len = (len + start_waste) & ~mask;
-	if ((len + start_waste) > read_len)
-		read_len += pnor->erasesize;
-
-	/* Ensure read is not out of bounds */
-	if (read_start + read_len > pnor->size) {
-		pr_log(LOG_ERR, "PNOR: read out of bounds");
-		return -ERANGE;
-	}
-
-	buf = malloc(read_len);
-
-	rc = lseek(fd, read_start, SEEK_SET);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: lseek read_start(0x%x) failed: %m",
-				read_start);
-		goto out;
-	}
-
-	rc = read(fd, buf, read_len);
-	if (rc < 0) {
-		pr_log(LOG_ERR, "PNOR: write(offset 0x%x, len 0x%x) "
-				"failed: %m", read_start, read_len);
-		goto out;
-	}
+	rc = blocklevel_read(pnor->bl, offset, data, len);
+	if (rc)
+		return -errno;
 
-	/* Copy data into destination, carefully avoiding the extra data we
-	 * added to align to block size */
-	memcpy(data, buf + start_waste, len);
-	rc = len;
-out:
-	free(buf);
-	return rc;
+	return len;
 }
 
 /* Similar to read(2), this performs partial operations where the number of
@@ -277,7 +136,7 @@ out:
 int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset,
 		   void *data, size_t requested_size, enum pnor_op op)
 {
-	int rc, fd;
+	int rc;
 	uint32_t pstart, psize, idx;
 	int size;
 
@@ -323,18 +182,12 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset,
 		return -ERANGE;
 	}
 
-	fd = open(pnor->path, O_RDWR);
-	if (fd < 0) {
-		perror(pnor->path);
-		return fd;
-	}
-
 	switch (op) {
 	case PNOR_OP_READ:
-		rc = mtd_read(pnor, fd, data, pstart + offset, size);
+		rc = mtd_read(pnor, data, pstart + offset, size);
 		break;
 	case PNOR_OP_WRITE:
-		rc = mtd_write(pnor, fd, data, pstart + offset, size);
+		rc = mtd_write(pnor, data, pstart + offset, size);
 		break;
 	default:
 		rc  = -EIO;
@@ -350,7 +203,5 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset,
 				rc, size);
 
 out:
-	close(fd);
-
 	return rc;
 }
diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h
index 06219dc..729a969 100644
--- a/external/opal-prd/pnor.h
+++ b/external/opal-prd/pnor.h
@@ -2,12 +2,14 @@
 #define PNOR_H
 
 #include <libflash/libffs.h>
+#include <libflash/blocklevel.h>
 
 struct pnor {
 	char			*path;
 	struct ffs_handle	*ffsh;
 	uint32_t		size;
 	uint32_t		erasesize;
+	struct blocklevel_device *bl;
 };
 
 enum pnor_op {
-- 
2.6.4



More information about the Skiboot mailing list