diff mbox series

[4/5] bloblist: Allow custom alignment for blobs

Message ID 20200919184909.4.I2714a2d96b5b651fea0cb4065d0684a2600861e9@changeid
State Accepted
Delegated to: Simon Glass
Headers show
Series bloblist: Add alignment control and a command | expand

Commit Message

Simon Glass Sept. 20, 2020, 12:49 a.m. UTC
Some blobs need a larger alignment than the default. For example, ACPI
tables often start at a 4KB boundary. Add support for this.

Update the size of the test blob to allow these larger records.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/bloblist.c  | 32 ++++++++++++++++++++------------
 include/bloblist.h |  6 ++++--
 test/bloblist.c    | 42 +++++++++++++++++++++++++++++++++---------
 3 files changed, 57 insertions(+), 23 deletions(-)

Comments

Simon Glass Oct. 5, 2020, 9:32 p.m. UTC | #1
Some blobs need a larger alignment than the default. For example, ACPI
tables often start at a 4KB boundary. Add support for this.

Update the size of the test blob to allow these larger records.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/bloblist.c  | 32 ++++++++++++++++++++------------
 include/bloblist.h |  6 ++++--
 test/bloblist.c    | 42 +++++++++++++++++++++++++++++++++---------
 3 files changed, 57 insertions(+), 23 deletions(-)

Applied to u-boot-dm/next, thanks!
diff mbox series

Patch

diff --git a/common/bloblist.c b/common/bloblist.c
index 173f28d8ec9..33b58623807 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -83,18 +83,25 @@  static struct bloblist_rec *bloblist_findrec(uint tag)
 	return NULL;
 }
 
-static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
+static int bloblist_addrec(uint tag, int size, int align,
+			   struct bloblist_rec **recp)
 {
 	struct bloblist_hdr *hdr = gd->bloblist;
 	struct bloblist_rec *rec;
 	int data_start, new_alloced;
 
+	if (!align)
+		align = BLOBLIST_ALIGN;
+
 	/* Figure out where the new data will start */
-	data_start = hdr->alloced + sizeof(*rec);
-	data_start = ALIGN(data_start, BLOBLIST_ALIGN);
+	data_start = map_to_sysmem(hdr) + hdr->alloced + sizeof(*rec);
+
+	/* Align the address and then calculate the offset from ->alloced */
+	data_start = ALIGN(data_start, align) - map_to_sysmem(hdr);
 
 	/* Calculate the new allocated total */
-	new_alloced = data_start + ALIGN(size, BLOBLIST_ALIGN);
+	new_alloced = data_start + ALIGN(size, align);
+
 	if (new_alloced >= hdr->size) {
 		log(LOGC_BLOBLIST, LOGL_ERR,
 		    "Failed to allocate %x bytes size=%x, need size=%x\n",
@@ -117,7 +124,8 @@  static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
 	return 0;
 }
 
-static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
+static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size,
+			      int align)
 {
 	struct bloblist_rec *rec;
 
@@ -130,7 +138,7 @@  static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
 	} else {
 		int ret;
 
-		ret = bloblist_addrec(tag, size, &rec);
+		ret = bloblist_addrec(tag, size, align, &rec);
 		if (ret)
 			return ret;
 	}
@@ -152,22 +160,22 @@  void *bloblist_find(uint tag, int size)
 	return (void *)rec + rec->hdr_size;
 }
 
-void *bloblist_add(uint tag, int size)
+void *bloblist_add(uint tag, int size, int align)
 {
 	struct bloblist_rec *rec;
 
-	if (bloblist_addrec(tag, size, &rec))
+	if (bloblist_addrec(tag, size, align, &rec))
 		return NULL;
 
 	return (void *)rec + rec->hdr_size;
 }
 
-int bloblist_ensure_size(uint tag, int size, void **blobp)
+int bloblist_ensure_size(uint tag, int size, int align, void **blobp)
 {
 	struct bloblist_rec *rec;
 	int ret;
 
-	ret = bloblist_ensurerec(tag, &rec, size);
+	ret = bloblist_ensurerec(tag, &rec, size, align);
 	if (ret)
 		return ret;
 	*blobp = (void *)rec + rec->hdr_size;
@@ -179,7 +187,7 @@  void *bloblist_ensure(uint tag, int size)
 {
 	struct bloblist_rec *rec;
 
-	if (bloblist_ensurerec(tag, &rec, size))
+	if (bloblist_ensurerec(tag, &rec, size, 0))
 		return NULL;
 
 	return (void *)rec + rec->hdr_size;
@@ -190,7 +198,7 @@  int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
 	struct bloblist_rec *rec;
 	int ret;
 
-	ret = bloblist_ensurerec(tag, &rec, *sizep);
+	ret = bloblist_ensurerec(tag, &rec, *sizep, 0);
 	if (ret == -ESPIPE)
 		*sizep = rec->size;
 	else if (ret)
diff --git a/include/bloblist.h b/include/bloblist.h
index 57c0794793b..9ad5678aff8 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -124,10 +124,11 @@  void *bloblist_find(uint tag, int size);
  *
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @size:	Size of the blob
+ * @align:	Alignment of the blob (in bytes), 0 for default
  * @return pointer to the newly added block, or NULL if there is not enough
  *	space for the blob
  */
-void *bloblist_add(uint tag, int size);
+void *bloblist_add(uint tag, int size, int align);
 
 /**
  * bloblist_ensure_size() - Find or add a blob
@@ -137,10 +138,11 @@  void *bloblist_add(uint tag, int size);
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @size:	Size of the blob
  * @blobp:	Returns a pointer to blob on success
+ * @align:	Alignment of the blob (in bytes), 0 for default
  * @return 0 if OK, -ENOSPC if it is missing and could not be added due to lack
  *	of space, or -ESPIPE it exists but has the wrong size
  */
-int bloblist_ensure_size(uint tag, int size, void **blobp);
+int bloblist_ensure_size(uint tag, int size, int align, void **blobp);
 
 /**
  * bloblist_ensure() - Find or add a blob
diff --git a/test/bloblist.c b/test/bloblist.c
index 3493e681f39..004a4396171 100644
--- a/test/bloblist.c
+++ b/test/bloblist.c
@@ -25,10 +25,10 @@  enum {
 
 	TEST_SIZE		= 10,
 	TEST_SIZE2		= 20,
-	TEST_SIZE_LARGE		= 0xe0,
+	TEST_SIZE_LARGE		= 0x3e0,
 
 	TEST_ADDR		= CONFIG_BLOBLIST_ADDR,
-	TEST_BLOBLIST_SIZE	= 0x100,
+	TEST_BLOBLIST_SIZE	= 0x400,
 
 	ERASE_BYTE		= '\xff',
 };
@@ -100,7 +100,7 @@  static int bloblist_test_blob(struct unit_test_state *uts)
 	ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
 
 	/* Add a record and check that we can find it */
-	data = bloblist_add(TEST_TAG, TEST_SIZE);
+	data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
 	rec = (void *)(hdr + 1);
 	ut_asserteq_addr(rec + 1, data);
 	data = bloblist_find(TEST_TAG, TEST_SIZE);
@@ -206,10 +206,10 @@  static int bloblist_test_checksum(struct unit_test_state *uts)
 	hdr->chksum--;
 
 	/* Make sure the checksum changes when we add blobs */
-	data = bloblist_add(TEST_TAG, TEST_SIZE);
+	data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
 
-	data2 = bloblist_add(TEST_TAG2, TEST_SIZE2);
+	data2 = bloblist_add(TEST_TAG2, TEST_SIZE2, 0);
 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
 	ut_assertok(bloblist_finish());
 
@@ -255,9 +255,9 @@  static int bloblist_test_cmd_info(struct unit_test_state *uts)
 	console_record_reset();
 	run_command("bloblist info", 0);
 	ut_assert_nextline("base:     %x", map_to_sysmem(hdr));
-	ut_assert_nextline("size:     100    256 Bytes");
+	ut_assert_nextline("size:     400    1 KiB");
 	ut_assert_nextline("alloced:  70     112 Bytes");
-	ut_assert_nextline("free:     90     144 Bytes");
+	ut_assert_nextline("free:     390    912 Bytes");
 	ut_assert_console_end();
 	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
 
@@ -298,6 +298,8 @@  BLOBLIST_TEST(bloblist_test_cmd_list, 0);
 static int bloblist_test_align(struct unit_test_state *uts)
 {
 	struct bloblist_hdr *hdr;
+	ulong addr;
+	char *data;
 	int i;
 
 	/* At the start there should be no records */
@@ -305,14 +307,14 @@  static int bloblist_test_align(struct unit_test_state *uts)
 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
 	ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
 
-	/* Check the alignment */
+	/* Check the default alignment */
 	for (i = 0; i < 3; i++) {
 		int size = i * 3;
 		ulong addr;
 		char *data;
 		int j;
 
-		data = bloblist_add(i, size);
+		data = bloblist_add(i, size, 0);
 		ut_assertnonnull(data);
 		addr = map_to_sysmem(data);
 		ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1));
@@ -324,6 +326,28 @@  static int bloblist_test_align(struct unit_test_state *uts)
 			ut_asserteq(ERASE_BYTE, data[j]);
 	}
 
+	/* Check larger alignment */
+	for (i = 0; i < 3; i++) {
+		int align = 32 << i;
+
+		data = bloblist_add(3 + i, i * 4, align);
+		ut_assertnonnull(data);
+		addr = map_to_sysmem(data);
+		ut_asserteq(0, addr & (align - 1));
+	}
+
+	/* Check alignment with an bloblist starting on a smaller alignment */
+	hdr = map_sysmem(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE);
+	memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
+	memset(hdr, '\0', sizeof(*hdr));
+	ut_assertok(bloblist_new(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE,
+				 0));
+
+	data = bloblist_add(1, 5, BLOBLIST_ALIGN * 2);
+	ut_assertnonnull(data);
+	addr = map_to_sysmem(data);
+	ut_asserteq(0, addr & (BLOBLIST_ALIGN * 2 - 1));
+
 	return 0;
 }
 BLOBLIST_TEST(bloblist_test_align, 0);