commonlib/region: add xlate_region_device
There are cases where one region_device needs to be accessed using offset/sizes from one address space that need the offset translated into a different address space for operations to take place. The xlate_region_device provides an offset that is subtracted from the incoming transaction before deferring to the backing access region. Change-Id: I41d43924bb6fbc7b4d3681877543209e1085e15c Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/12227 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
parent
e11f6c3be1
commit
5907eb8f5a
|
@ -154,4 +154,27 @@ 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 mechansim 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 {
|
||||
const struct region_device *access_dev;
|
||||
struct region sub_region;
|
||||
struct region_device rdev;
|
||||
};
|
||||
|
||||
extern const struct region_device_ops xlate_rdev_ops;
|
||||
|
||||
#define XLATE_REGION_INIT(access_dev_, sub_offset_, sub_size_, parent_sz_) \
|
||||
{ \
|
||||
.access_dev = access_dev_, \
|
||||
.sub_region = { \
|
||||
.offset = (sub_offset_), \
|
||||
.size = (sub_size_), \
|
||||
}, \
|
||||
.rdev = REGION_DEV_INIT(&xlate_rdev_ops, 0, (parent_sz_)),\
|
||||
}
|
||||
|
||||
#endif /* _REGION_H_ */
|
||||
|
|
|
@ -194,3 +194,56 @@ int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *xlate_mmap(const struct region_device *rd, size_t offset,
|
||||
size_t size)
|
||||
{
|
||||
const struct xlate_region_device *xldev;
|
||||
struct region req = {
|
||||
.offset = offset,
|
||||
.size = size,
|
||||
};
|
||||
|
||||
xldev = container_of(rd, typeof(*xldev), rdev);
|
||||
|
||||
if (!is_subregion(&xldev->sub_region, &req))
|
||||
return NULL;
|
||||
|
||||
offset -= region_offset(&xldev->sub_region);
|
||||
|
||||
return rdev_mmap(xldev->access_dev, offset, size);
|
||||
}
|
||||
|
||||
static int xlate_munmap(const struct region_device *rd, void *mapping)
|
||||
{
|
||||
const struct xlate_region_device *xldev;
|
||||
|
||||
xldev = container_of(rd, typeof(*xldev), rdev);
|
||||
|
||||
return rdev_munmap(xldev->access_dev, mapping);
|
||||
}
|
||||
|
||||
static ssize_t xlate_readat(const struct region_device *rd, void *b,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
struct region req = {
|
||||
.offset = offset,
|
||||
.size = size,
|
||||
};
|
||||
const struct xlate_region_device *xldev;
|
||||
|
||||
xldev = container_of(rd, typeof(*xldev), rdev);
|
||||
|
||||
if (!is_subregion(&xldev->sub_region, &req))
|
||||
return -1;
|
||||
|
||||
offset -= region_offset(&xldev->sub_region);
|
||||
|
||||
return rdev_readat(xldev->access_dev, b, offset, size);
|
||||
}
|
||||
|
||||
const struct region_device_ops xlate_rdev_ops = {
|
||||
.mmap = xlate_mmap,
|
||||
.munmap = xlate_munmap,
|
||||
.readat = xlate_readat,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue