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);
|
void *mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t);
|
||||||
int mmap_helper_rdev_munmap(const struct region_device *, void *);
|
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_ */
|
#endif /* _REGION_H_ */
|
||||||
|
|
|
@ -194,3 +194,56 @@ int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
|
||||||
|
|
||||||
return 0;
|
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