rmtfs: Interface qcom_rfsa device for mem access

Attempt to open /dev/qcom_rfsa1 and use this instead of memory mapping
/dev/mem, while falling back to the old behavior. This allow us to drop
the dependency on /dev/mem access and will aid supporting multiple
memory regions.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
Bjorn Andersson 2017-07-27 18:39:21 -07:00
parent c7822e84b1
commit 93f9564224
3 changed files with 145 additions and 30 deletions

View File

@ -1,7 +1,7 @@
OUT := rmtfs
CFLAGS := -Wall -g -I../qrtr/lib -O2
LDFLAGS := -L../qrtr -lqrtr
LDFLAGS := -L../qrtr -lqrtr -ludev
prefix := /usr/local
SRCS := qmi_rmtfs.c qmi_tlv.c rmtfs.c sharedmem.c storage.c util.c

View File

@ -496,10 +496,8 @@ int main(int argc, char **argv)
dbgprintf_enabled = true;
rmem = rmtfs_mem_open();
if (!rmem) {
fprintf(stderr, "failed to initialize rmtfs shared memory\n");
if (!rmem)
return 1;
}
ret = storage_open();
if (ret) {

View File

@ -1,11 +1,14 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "rmtfs.h"
@ -19,6 +22,98 @@ struct rmtfs_mem {
int fd;
};
static int parse_hex_sysattr(struct udev_device *dev, const char *name,
unsigned long *value)
{
unsigned long val;
const char *buf;
char *endptr;
buf = udev_device_get_sysattr_value(dev, name);
if (!buf)
return -ENOENT;
errno = 0;
val = strtoul(buf, &endptr, 16);
if ((val == LONG_MAX && errno == ERANGE) || endptr == buf) {
return -errno;
}
*value = val;
return 0;
}
static int rmtfs_mem_open_rfsa(struct rmtfs_mem *rmem, int client_id)
{
struct udev_device *dev;
struct udev *udev;
int saved_errno;
struct stat sb;
char path[32];
int ret;
int fd;
sprintf(path, "/dev/qcom_rfsa%d", client_id);
fd = open(path, O_RDWR);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -saved_errno;
}
rmem->fd = fd;
ret = fstat(fd, &sb);
if (ret < 0) {
saved_errno = errno;
fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
close(fd);
goto err_close_fd;
}
udev = udev_new();
if (!udev) {
saved_errno = errno;
fprintf(stderr, "failed to create udev context\n");
goto err_close_fd;
}
dev = udev_device_new_from_devnum(udev, 'c', sb.st_rdev);
if (!dev) {
saved_errno = errno;
fprintf(stderr, "unable to find udev device\n");
goto err_unref_udev;
}
ret = parse_hex_sysattr(dev, "phys_addr", &rmem->address);
if (ret < 0) {
fprintf(stderr, "failed to parse phys_addr of %s\n", path);
saved_errno = -ret;
goto err_unref_dev;
}
ret = parse_hex_sysattr(dev, "size", &rmem->size);
if (ret < 0) {
fprintf(stderr, "failed to parse size of %s\n", path);
saved_errno = -ret;
goto err_unref_dev;
}
udev_device_unref(dev);
udev_unref(udev);
return 0;
err_unref_dev:
udev_device_unref(dev);
err_unref_udev:
udev_unref(udev);
err_close_fd:
close(fd);
return -saved_errno;
}
struct rmtfs_mem *rmtfs_mem_open(void)
{
struct rmtfs_mem *rmem;
@ -30,25 +125,34 @@ struct rmtfs_mem *rmtfs_mem_open(void)
if (!rmem)
return NULL;
ret = rmtfs_mem_enumerate(rmem);
if (ret < 0)
memset(rmem, 0, sizeof(*rmem));
ret = rmtfs_mem_open_rfsa(rmem, 1);
if (ret < 0 && ret != -ENOENT) {
goto err;
} else if (ret < 0) {
fprintf(stderr, "falling back to /dev/mem access\n");
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0) {
fprintf(stderr, "failed to open /dev/mem\n");
goto err;
ret = rmtfs_mem_enumerate(rmem);
if (ret < 0)
goto err;
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0) {
fprintf(stderr, "failed to open /dev/mem\n");
goto err;
}
base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, rmem->address);
if (base == MAP_FAILED) {
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
goto err_close_fd;
}
rmem->base = base;
rmem->fd = fd;
}
base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, rmem->address);
if (base == MAP_FAILED) {
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
goto err_close_fd;
}
rmem->base = base;
rmem->fd = fd;
return rmem;
err_close_fd:
@ -93,37 +197,50 @@ static void *rmtfs_mem_ptr(struct rmtfs_mem *rmem, unsigned phys_address, ssize_
ssize_t rmtfs_mem_read(struct rmtfs_mem *rmem, unsigned long phys_address, void *buf, ssize_t len)
{
off_t offset;
void *ptr;
ptr = rmtfs_mem_ptr(rmem, phys_address, len);
if (!ptr)
return -EINVAL;
if (rmem->base) {
ptr = rmtfs_mem_ptr(rmem, phys_address, len);
if (!ptr)
return -EINVAL;
memcpy(buf, ptr, len);
memcpy(buf, ptr, len);
} else {
offset = phys_address - rmem->address;
len = pread(rmem->fd, buf, len, offset);
}
return len;
}
ssize_t rmtfs_mem_write(struct rmtfs_mem *rmem, unsigned long phys_address, const void *buf, ssize_t len)
{
off_t offset;
void *ptr;
ptr = rmtfs_mem_ptr(rmem, phys_address, len);
if (!ptr)
return -EINVAL;
if (rmem->base) {
ptr = rmtfs_mem_ptr(rmem, phys_address, len);
if (!ptr)
return -EINVAL;
memcpy(ptr, buf, len);
memcpy(ptr, buf, len);
} else {
offset = phys_address - rmem->address;
len = pwrite(rmem->fd, buf, len, offset);
}
return len;
}
void rmtfs_mem_close(struct rmtfs_mem *rmem)
{
munmap(rmem->base, rmem->size);
if (rmem->base)
munmap(rmem->base, rmem->size);
close(rmem->fd);
rmem->fd = -1;
rmem->base = MAP_FAILED;
free(rmem);
}
static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)