Aaron Durbin (adurbin@chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17716
-gerrit
commit ef40826819115d425aa8f254fdd7e3fb023bb9f5 Author: Aaron Durbin adurbin@chromium.org Date: Sat Dec 3 17:08:08 2016 -0600
commonlib: provide incoherent region device
The MRC cache uses an incoherent mechanism for updating the cache contents in that it assumes memory mapped boot device access for checking against latest data for update. However, it uses another driver for updating the underlying storage area.
In order to aid in moving the MRC cache over to using region_devices for updates provide an implementation of a region_device which performs reads and writes to different region_devices so that different drivers can be used transparently.
BUG=chrome-os-partner:56151
Change-Id: I30e858245c30cbccd6313aff5ebecd3fd98d7302 Signed-off-by: Aaron Durbin adurbin@chromium.org --- src/commonlib/include/commonlib/region.h | 23 ++++++++++ src/commonlib/region.c | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/src/commonlib/include/commonlib/region.h b/src/commonlib/include/commonlib/region.h index bc3ded1..3f7d3bd 100644 --- a/src/commonlib/include/commonlib/region.h +++ b/src/commonlib/include/commonlib/region.h @@ -245,4 +245,27 @@ void xlate_region_device_rw_init(struct xlate_region_device *xdev, size_t sub_offset, size_t sub_size, size_t parent_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 + * writing. One needs to ensure using this object is appropriate in context. */ +struct incoherent_rdev { + struct region_device rdev; + const struct region_device *read; + const struct region_device *write; +}; + +/* Initialize an incoherent_rdev based on the region as well as the read and + * write rdevs. The read and write rdevs should match in size to the passed + * in region. If not the initialization will fail returning NULL. Otherwise + * the function will return a pointer to the containing region_device to + * be used for region operations. Therefore, the lifetime of the returned + * pointer matches the lifetime of the incoherent_rdev object. Likewise, + * the lifetime of the read and write rdev need to match the lifetime of + * the incoherent_rdev object. */ +const struct region_device *incoherent_rdev_init(struct incoherent_rdev *irdev, + const struct region *r, + const struct region_device *read, + const struct region_device *write); + #endif /* _REGION_H_ */ diff --git a/src/commonlib/region.c b/src/commonlib/region.c index ac0faf1..bf53b9d 100644 --- a/src/commonlib/region.c +++ b/src/commonlib/region.c @@ -437,3 +437,82 @@ const struct region_device_ops xlate_rdev_rw_ops = { .writeat = xlate_writeat, .eraseat = xlate_eraseat, }; + + +static void *incoherent_mmap(const struct region_device *rd, size_t offset, + size_t size) +{ + const struct incoherent_rdev *irdev; + + irdev = container_of(rd, const struct incoherent_rdev, rdev); + + return rdev_mmap(irdev->read, offset, size); +} + +static int incoherent_munmap(const struct region_device *rd, void *mapping) +{ + const struct incoherent_rdev *irdev; + + irdev = container_of(rd, const struct incoherent_rdev, rdev); + + return rdev_munmap(irdev->read, mapping); +} + +static ssize_t incoherent_readat(const struct region_device *rd, void *b, + size_t offset, size_t size) +{ + const struct incoherent_rdev *irdev; + + irdev = container_of(rd, const struct incoherent_rdev, rdev); + + return rdev_readat(irdev->read, b, offset, size); +} + +static ssize_t incoherent_writeat(const struct region_device *rd, const void *b, + size_t offset, size_t size) +{ + const struct incoherent_rdev *irdev; + + irdev = container_of(rd, const struct incoherent_rdev, rdev); + + return rdev_writeat(irdev->write, b, offset, size); +} + +static ssize_t incoherent_eraseat(const struct region_device *rd, size_t offset, + size_t size) +{ + const struct incoherent_rdev *irdev; + + irdev = container_of(rd, const struct incoherent_rdev, rdev); + + return rdev_eraseat(irdev->write, offset, size); +} + +static const struct region_device_ops incoherent_rdev_ops = { + .mmap = incoherent_mmap, + .munmap = incoherent_munmap, + .readat = incoherent_readat, + .writeat = incoherent_writeat, + .eraseat = incoherent_eraseat, +}; + +const struct region_device *incoherent_rdev_init(struct incoherent_rdev *irdev, + const struct region *r, + const struct region_device *read, + const struct region_device *write) +{ + const size_t size = region_sz(r); + + if (size != region_device_sz(read) || size != region_device_sz(write)) + return NULL; + + /* The region is represented as offset 0 to size. That way, the generic + * rdev operations can be called on the read or write implementation + * without any unnecessary translation because the offsets all start + * at 0. */ + region_device_init(&irdev->rdev, &incoherent_rdev_ops, 0, size); + irdev->read = read; + irdev->write = write; + + return &irdev->rdev; +}