From cd04a5f1aadc8e2ec4e787f5ba4cc8c38a579314 Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Tue, 18 Nov 2014 23:27:26 +0100 Subject: hwstub/qeditor: add support for atomic read/writes The current code assumed that READ/WRITE would produce atomic read/writes for 8/16/32-bit words, which in turned put assumption on the memcpy function. Since some memcpy implementation do not always guarantee such strong assumption, introduce two new operation READ/WRITE_ATOMIC which provide the necessary tools to do correct read and write to register in a single memory access. Change-Id: I37451bd5057bb0dcaf5a800d8aef8791c792a090 --- utils/hwstub/lib/hwstub.c | 40 ++++++++++++++++++++++++++++++++-------- utils/hwstub/lib/hwstub.h | 5 ++++- 2 files changed, 36 insertions(+), 9 deletions(-) (limited to 'utils/hwstub/lib') diff --git a/utils/hwstub/lib/hwstub.c b/utils/hwstub/lib/hwstub.c index 6ae0400a66..d3908585da 100644 --- a/utils/hwstub/lib/hwstub.c +++ b/utils/hwstub/lib/hwstub.c @@ -140,7 +140,8 @@ int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); } -static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) +static int _hwstub_read(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, + void *buf, size_t sz) { struct hwstub_read_req_t read; read.dAddress = addr; @@ -151,10 +152,11 @@ static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, s return -1; return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, - HWSTUB_READ2, dev->id++, dev->intf, buf, sz, 1000); + breq, dev->id++, dev->intf, buf, sz, 1000); } -static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) +static int _hwstub_write(struct hwstub_device_t *dev, uint8_t breq, uint32_t addr, + const void *buf, size_t sz) { size_t hdr_sz = sizeof(struct hwstub_write_req_t); struct hwstub_write_req_t *req = malloc(sz + hdr_sz); @@ -162,18 +164,34 @@ static int _hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, memcpy(req + 1, buf, sz); int size = libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, - HWSTUB_WRITE, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); + breq, dev->id++, dev->intf, (void *)req, sz + hdr_sz, 1000); free(req); return size - hdr_sz; } +int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) +{ + /* reject any read greater than the buffer, it makes no sense anyway */ + if(sz > dev->buf_sz) + return -1; + return _hwstub_read(dev, HWSTUB_READ2_ATOMIC, addr, buf, sz); +} + +int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) +{ + /* reject any write greater than the buffer, it makes no sense anyway */ + if(sz + sizeof(struct hwstub_write_req_t) > dev->buf_sz) + return -1; + return _hwstub_write(dev, HWSTUB_WRITE_ATOMIC, addr, buf, sz); +} + /* Intermediate function which make sure we don't overflow the device buffer */ int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) { int cnt = 0; while(sz > 0) { - int xfer = _hwstub_read(dev, addr, buf, MIN(sz, dev->buf_sz)); + int xfer = _hwstub_read(dev, HWSTUB_READ2, addr, buf, MIN(sz, dev->buf_sz)); if(xfer < 0) return xfer; sz -= xfer; @@ -185,13 +203,13 @@ int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz } /* Intermediate function which make sure we don't overflow the device buffer */ -int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) +int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz) { int cnt = 0; while(sz > 0) { - int xfer = _hwstub_write(dev, addr, buf, MIN(sz, dev->buf_sz - - sizeof(struct hwstub_write_req_t))); + int xfer = _hwstub_write(dev, HWSTUB_WRITE, addr, buf, + MIN(sz, dev->buf_sz - sizeof(struct hwstub_write_req_t))); if(xfer < 0) return xfer; sz -= xfer; @@ -207,6 +225,12 @@ int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *bu return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); } +int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) +{ + return read ? hwstub_read_atomic(dev, addr, buf, sz) : + hwstub_write_atomic(dev, addr, buf, sz); +} + int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags) { struct hwstub_exec_req_t exec; diff --git a/utils/hwstub/lib/hwstub.h b/utils/hwstub/lib/hwstub.h index d7d6ceb8ef..4d12de8eda 100644 --- a/utils/hwstub/lib/hwstub.h +++ b/utils/hwstub/lib/hwstub.h @@ -53,8 +53,11 @@ int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); /* Returns number of bytes written/read or <0 on error */ int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); -int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); +int hwstub_read_atomic(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); +int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); +int hwstub_write_atomic(struct hwstub_device_t *dev, uint32_t addr, const void *buf, size_t sz); int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); +int hwstub_rw_mem_atomic(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); /* Returns <0 on error */ int hwstub_exec(struct hwstub_device_t *dev, uint32_t addr, uint16_t flags); int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); -- cgit v1.2.3