summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonlib/include/commonlib/region.h63
-rw-r--r--src/commonlib/region.c92
-rw-r--r--src/soc/intel/apollolake/mmap_boot.c8
3 files changed, 103 insertions, 60 deletions
diff --git a/src/commonlib/include/commonlib/region.h b/src/commonlib/include/commonlib/region.h
index b9a984f171..4d095b731d 100644
--- a/src/commonlib/include/commonlib/region.h
+++ b/src/commonlib/include/commonlib/region.h
@@ -6,6 +6,7 @@
#include <sys/types.h>
#include <stddef.h>
#include <stdbool.h>
+#include <commonlib/bsd/helpers.h>
#include <commonlib/mem_pool.h>
/*
@@ -210,14 +211,33 @@ void mmap_helper_device_init(struct mmap_helper_region_device *mdev,
void *mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t);
int mmap_helper_rdev_munmap(const struct region_device *, void *);
-/* A translated region device provides the ability to publish a region device
- * in one address space and use an access mechanism within another address
- * space. The sub region is the window within the 1st address space and
- * the request is modified prior to accessing the second address space
- * provided by access_dev. */
-struct xlate_region_device {
+/*
+ * A translated region device provides the ability to publish a region device in one address
+ * space and use an access mechanism within another address space. The sub region is the window
+ * within the 1st address space and the request is modified prior to accessing the second
+ * address space provided by access_dev.
+ *
+ * Each xlate_region_device can support multiple translation windows described using
+ * xlate_window structure. The windows need not be contiguous in either address space. However,
+ * this poses restrictions on the operations being performed i.e. callers cannot perform
+ * operations across multiple windows of a translated region device. It is possible to support
+ * readat/writeat/eraseat by translating them into multiple calls one to access device in each
+ * window. However, mmap support is tricky because the caller expects that the memory mapped
+ * region is contiguous in both address spaces. Thus, to keep the semantics consistent for all
+ * region ops, xlate_region_device does not support any operations across the window
+ * boundary.
+ *
+ * Note: The platform is expected to ensure that the fmap description does not place any
+ * section (that will be operated using the translated region device) across multiple windows.
+ */
+struct xlate_window {
const struct region_device *access_dev;
struct region sub_region;
+};
+
+struct xlate_region_device {
+ size_t window_count;
+ const struct xlate_window *window_arr;
struct region_device rdev;
};
@@ -225,38 +245,31 @@ extern const struct region_device_ops xlate_rdev_ro_ops;
extern const struct region_device_ops xlate_rdev_rw_ops;
-#define XLATE_REGION_DEV_INIT(access_dev_, sub_offset_, sub_size_, \
- parent_sz_, ops_) \
+#define XLATE_REGION_DEV_INIT(window_arr_, parent_sz_, ops_) \
{ \
- .access_dev = access_dev_, \
- .sub_region = { \
- .offset = (sub_offset_), \
- .size = (sub_size_), \
- }, \
+ .window_count = ARRAY_SIZE(window_arr_), \
+ .window_arr = window_arr_, \
.rdev = REGION_DEV_INIT((ops_), 0, (parent_sz_)), \
}
-#define XLATE_REGION_DEV_RO_INIT(access_dev_, sub_offset_, sub_size_, \
- parent_sz_) \
- XLATE_REGION_DEV_INIT(access_dev_, sub_offset_, \
- sub_size_, parent_sz_, &xlate_rdev_ro_ops), \
+#define XLATE_REGION_DEV_RO_INIT(window_arr_, parent_sz_) \
+ XLATE_REGION_DEV_INIT(window_arr_, parent_sz_, &xlate_rdev_ro_ops)
-#define XLATE_REGION_DEV_RW_INIT(access_dev_, sub_offset_, sub_size_, \
- parent_sz_) \
- XLATE_REGION_DEV_INIT(access_dev_, sub_offset_, \
- sub_size_, parent_sz_, &xlate_rdev_rw_ops), \
+#define XLATE_REGION_DEV_RW_INIT(window_count_, window_arr_, parent_sz_) \
+ XLATE_REGION_DEV_INIT(window_arr_, parent_sz_, &xlate_rdev_rw_ops)
/* Helper to dynamically initialize xlate region device. */
void xlate_region_device_ro_init(struct xlate_region_device *xdev,
- const struct region_device *access_dev,
- size_t sub_offset, size_t sub_size,
+ size_t window_count, const struct xlate_window *window_arr,
size_t parent_size);
void xlate_region_device_rw_init(struct xlate_region_device *xdev,
- const struct region_device *access_dev,
- size_t sub_offset, size_t sub_size,
+ size_t window_count, const struct xlate_window *window_arr,
size_t parent_size);
+void xlate_window_init(struct xlate_window *window, const struct region_device *access_dev,
+ size_t sub_region_offset, size_t sub_region_size);
+
/* This type can be used for incoherent access where the read and write
* operations are backed by separate drivers. An example is x86 systems
* with memory mapped media for reading but use a spi flash driver for
diff --git a/src/commonlib/region.c b/src/commonlib/region.c
index 467e8ff629..a10702a6c5 100644
--- a/src/commonlib/region.c
+++ b/src/commonlib/region.c
@@ -188,33 +188,37 @@ void region_device_init(struct region_device *rdev,
static void xlate_region_device_init(struct xlate_region_device *xdev,
const struct region_device_ops *ops,
- const struct region_device *access_dev,
- size_t sub_offset, size_t sub_size,
+ size_t window_count, const struct xlate_window *window_arr,
size_t parent_size)
{
memset(xdev, 0, sizeof(*xdev));
- xdev->access_dev = access_dev;
- xdev->sub_region.offset = sub_offset;
- xdev->sub_region.size = sub_size;
+ xdev->window_count = window_count;
+ xdev->window_arr = window_arr;
region_device_init(&xdev->rdev, ops, 0, parent_size);
}
void xlate_region_device_ro_init(struct xlate_region_device *xdev,
- const struct region_device *access_dev,
- size_t sub_offset, size_t sub_size,
+ size_t window_count, const struct xlate_window *window_arr,
size_t parent_size)
{
- xlate_region_device_init(xdev, &xlate_rdev_ro_ops, access_dev,
- sub_offset, sub_size, parent_size);
+ xlate_region_device_init(xdev, &xlate_rdev_ro_ops, window_count, window_arr,
+ parent_size);
}
void xlate_region_device_rw_init(struct xlate_region_device *xdev,
- const struct region_device *access_dev,
- size_t sub_offset, size_t sub_size,
+ size_t window_count, const struct xlate_window *window_arr,
size_t parent_size)
{
- xlate_region_device_init(xdev, &xlate_rdev_rw_ops, access_dev,
- sub_offset, sub_size, parent_size);
+ xlate_region_device_init(xdev, &xlate_rdev_rw_ops, window_count, window_arr,
+ parent_size);
+}
+
+void xlate_window_init(struct xlate_window *window, const struct region_device *access_dev,
+ size_t sub_region_offset, size_t sub_region_size)
+{
+ window->access_dev = access_dev;
+ window->sub_region.offset = sub_region_offset;
+ window->sub_region.size = sub_region_size;
}
static void *mdev_mmap(const struct region_device *rd, size_t offset,
@@ -321,6 +325,21 @@ int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
return 0;
}
+static const struct xlate_window *xlate_find_window(const struct xlate_region_device *xldev,
+ const struct region *req)
+{
+ size_t i;
+ const struct xlate_window *xlwindow;
+
+ for (i = 0; i < xldev->window_count; i++) {
+ xlwindow = &xldev->window_arr[i];
+ if (region_is_subregion(&xlwindow->sub_region, req))
+ return xlwindow;
+ }
+
+ return NULL;
+}
+
static void *xlate_mmap(const struct region_device *rd, size_t offset,
size_t size)
{
@@ -329,24 +348,29 @@ static void *xlate_mmap(const struct region_device *rd, size_t offset,
.offset = offset,
.size = size,
};
+ const struct xlate_window *xlwindow;
xldev = container_of(rd, __typeof__(*xldev), rdev);
- if (!region_is_subregion(&xldev->sub_region, &req))
+ xlwindow = xlate_find_window(xldev, &req);
+ if (!xlwindow)
return NULL;
- offset -= region_offset(&xldev->sub_region);
+ offset -= region_offset(&xlwindow->sub_region);
- return rdev_mmap(xldev->access_dev, offset, size);
+ return rdev_mmap(xlwindow->access_dev, offset, size);
}
-static int xlate_munmap(const struct region_device *rd, void *mapping)
+static int xlate_munmap(const struct region_device *rd __unused, void *mapping __unused)
{
- const struct xlate_region_device *xldev;
-
- xldev = container_of(rd, __typeof__(*xldev), rdev);
-
- return rdev_munmap(xldev->access_dev, mapping);
+ /*
+ * xlate_region_device does not keep track of the access device that was used to service
+ * a mmap request. So, munmap does not do anything. If munmap functionality is required,
+ * then xlate_region_device will have to be updated to accept some pre-allocated space
+ * from caller to keep track of the mapping requests. Since xlate_region_device is only
+ * used for memory mapped boot media on the backend right now, skipping munmap is fine.
+ */
+ return 0;
}
static ssize_t xlate_readat(const struct region_device *rd, void *b,
@@ -356,16 +380,18 @@ static ssize_t xlate_readat(const struct region_device *rd, void *b,
.offset = offset,
.size = size,
};
+ const struct xlate_window *xlwindow;
const struct xlate_region_device *xldev;
xldev = container_of(rd, __typeof__(*xldev), rdev);
- if (!region_is_subregion(&xldev->sub_region, &req))
+ xlwindow = xlate_find_window(xldev, &req);
+ if (!xlwindow)
return -1;
- offset -= region_offset(&xldev->sub_region);
+ offset -= region_offset(&xlwindow->sub_region);
- return rdev_readat(xldev->access_dev, b, offset, size);
+ return rdev_readat(xlwindow->access_dev, b, offset, size);
}
static ssize_t xlate_writeat(const struct region_device *rd, const void *b,
@@ -375,16 +401,18 @@ static ssize_t xlate_writeat(const struct region_device *rd, const void *b,
.offset = offset,
.size = size,
};
+ const struct xlate_window *xlwindow;
const struct xlate_region_device *xldev;
xldev = container_of(rd, __typeof__(*xldev), rdev);
- if (!region_is_subregion(&xldev->sub_region, &req))
+ xlwindow = xlate_find_window(xldev, &req);
+ if (!xlwindow)
return -1;
- offset -= region_offset(&xldev->sub_region);
+ offset -= region_offset(&xlwindow->sub_region);
- return rdev_writeat(xldev->access_dev, b, offset, size);
+ return rdev_writeat(xlwindow->access_dev, b, offset, size);
}
static ssize_t xlate_eraseat(const struct region_device *rd,
@@ -394,16 +422,18 @@ static ssize_t xlate_eraseat(const struct region_device *rd,
.offset = offset,
.size = size,
};
+ const struct xlate_window *xlwindow;
const struct xlate_region_device *xldev;
xldev = container_of(rd, __typeof__(*xldev), rdev);
- if (!region_is_subregion(&xldev->sub_region, &req))
+ xlwindow = xlate_find_window(xldev, &req);
+ if (!xlwindow)
return -1;
- offset -= region_offset(&xldev->sub_region);
+ offset -= region_offset(&xlwindow->sub_region);
- return rdev_eraseat(xldev->access_dev, offset, size);
+ return rdev_eraseat(xlwindow->access_dev, offset, size);
}
const struct region_device_ops xlate_rdev_ro_ops = {
diff --git a/src/soc/intel/apollolake/mmap_boot.c b/src/soc/intel/apollolake/mmap_boot.c
index 30c629e4de..79c2a0716b 100644
--- a/src/soc/intel/apollolake/mmap_boot.c
+++ b/src/soc/intel/apollolake/mmap_boot.c
@@ -43,6 +43,7 @@ static size_t bios_size;
static struct mem_region_device shadow_dev;
static struct xlate_region_device real_dev;
+static struct xlate_window real_dev_window;
static void bios_mmap_init(void)
{
@@ -68,9 +69,8 @@ static void bios_mmap_init(void)
mem_region_device_ro_init(&shadow_dev, (void *)base,
bios_mapped_size);
- xlate_region_device_ro_init(&real_dev, &shadow_dev.rdev,
- start, bios_mapped_size,
- CONFIG_ROM_SIZE);
+ xlate_window_init(&real_dev_window, &shadow_dev.rdev, start, bios_mapped_size);
+ xlate_region_device_ro_init(&real_dev, 1, &real_dev_window, CONFIG_ROM_SIZE);
bios_size = size;
@@ -78,7 +78,7 @@ static void bios_mmap_init(void)
easy to forget the SRAM mapping when crafting an FMAP file. */
struct region cbfs_region;
if (!fmap_locate_area("COREBOOT", &cbfs_region) &&
- !region_is_subregion(&real_dev.sub_region, &cbfs_region))
+ !region_is_subregion(&real_dev_window.sub_region, &cbfs_region))
printk(BIOS_CRIT,
"ERROR: CBFS @ %zx size %zx exceeds mem-mapped area @ %zx size %zx\n",
region_offset(&cbfs_region), region_sz(&cbfs_region),