summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRajat Verma <rajat.verma@stericsson.com>2012-02-14 16:05:27 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:07:06 +0200
commitcf5df5ea669adb16e6d4873755e5fedcdadc2d7f (patch)
tree4c75c1f5d25822fd47dc70cebac06c929bc320d4
parenteb4ef6da1a08940f1044ea021e037b083c75e0d6 (diff)
staging: mmio: use static buffer for i/o writes
For doing I/O write, use static 1 Kb buffer instead of requesting memory through kmalloc every time. ST-Ericsson ID: 412155 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Change-Id: I68710cd9d74c4a76753a7524431046e09a7aa1d0 Signed-off-by: Rajat Verma <rajat.verma@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/48844 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: QATEST Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--drivers/staging/mmio/st_mmio.c151
1 files changed, 91 insertions, 60 deletions
diff --git a/drivers/staging/mmio/st_mmio.c b/drivers/staging/mmio/st_mmio.c
index a006c55c544..27371bb3564 100644
--- a/drivers/staging/mmio/st_mmio.c
+++ b/drivers/staging/mmio/st_mmio.c
@@ -115,6 +115,13 @@ struct mmio_info {
static struct mmio_info *info;
/*
+ * static 1K buffer to do I/O write instead of kmalloc,
+ * no locking, caller can not have parallel use of
+ * MMIO_CAM_LOAD_XP70_FW and MMIO_CAM_ISP_WRITE ioctl's
+ */
+static u16 copybuff[512];
+
+/*
* This function converts a given logical memory region size
* to appropriate ISP_MCU_SYS_SIZEx register value.
*/
@@ -235,86 +242,88 @@ static u32 t1_to_arm(u32 t1_addr, void __iomem *smia_base_address,
return SIA_ISP_MEM + (t1_addr & FW_TO_HOST_ADDR_MASK);
}
-static int copy_user_buffer(void __iomem **dest_buf,
- void __iomem *src_buf, u32 size)
+static int write_user_buffer(struct mmio_info *info, u32 ioaddr,
+ void __iomem *src_buf, u32 size)
{
+ u32 i, count, offset = 0;
+ u32 itval = 0;
+ u16 mem_page = 0;
int err = 0;
- if (!src_buf)
+ if (!src_buf || !ioaddr) {
+ dev_err(info->dev, "invalid parameters: %p, 0x%x",
+ src_buf, ioaddr);
+
return -EINVAL;
+ }
- *dest_buf = kmalloc(size, GFP_KERNEL);
+ for (offset = 0; offset < size; ) {
- if (!*dest_buf) {
- err = -ENOMEM;
- goto nomem;
- }
+ if ((size - offset) > sizeof(copybuff))
+ count = sizeof(copybuff);
+ else
+ count = (size - offset);
+
+ if (copy_from_user(copybuff, src_buf + offset, count)) {
+
+ dev_err(info->dev, "failed to copy user buffer"
+ " %p at offset=%d, count=%d\n",
+ src_buf, offset, count);
- if (copy_from_user(*dest_buf, src_buf, size)) {
- err = -EFAULT;
- goto cp_failed;
+ err = -EFAULT;
+ goto cp_failed;
+ }
+
+ for (i = 0; i < count; ) {
+ itval = t1_to_arm(ioaddr + offset,
+ info->siabase, &mem_page);
+ itval = ((u32) info->siabase) + itval;
+
+ writew(copybuff[i/2], itval);
+ offset += 2;
+ i = i + 2;
+ }
}
- return err;
cp_failed:
- kfree(*dest_buf);
-nomem:
return err;
}
+
static int mmio_load_xp70_fw(struct mmio_info *info,
struct xp70_fw_t *xp70_fw)
{
- u32 i = 0;
- u32 offset = 0;
u32 itval = 0;
- u16 mem_page = 0;
- void __iomem *addr_split = NULL;
- void __iomem *addr_data = NULL;
int err = 0;
if (xp70_fw->size_split != 0) {
- err = copy_user_buffer(&addr_split, xp70_fw->addr_split,
- xp70_fw->size_split);
-
- if (err)
+ /* if buff size is not as expected */
+ if (xp70_fw->size_split != L2_PSRAM_MEM_SIZE) {
+ dev_err(info->dev, "xp70_fw_t.size_split must be "
+ "%d bytes!\n", L2_PSRAM_MEM_SIZE);
+ err = -EINVAL;
goto err_exit;
+ }
writel(0x0, info->siabase + SIA_ISP_REG_ADDR);
/* Put the low 64k IRP firmware in ISP MCU L2 PSRAM */
- for (i = PICTOR_IN_XP70_L2_MEM_BASE_ADDR;
- i < (PICTOR_IN_XP70_L2_MEM_BASE_ADDR +
- L2_PSRAM_MEM_SIZE); i = i + 2) {
- itval = t1_to_arm(i, info->siabase, &mem_page);
- itval = ((u32) info->siabase) + itval;
- /* Copy fw in L2 */
- writew((*((u16 *) addr_split + offset++)), itval);
- }
-
- kfree(addr_split);
+ err = write_user_buffer(info, PICTOR_IN_XP70_L2_MEM_BASE_ADDR,
+ xp70_fw->addr_split,
+ L2_PSRAM_MEM_SIZE);
+ if (err)
+ goto err_exit;
}
if (xp70_fw->size_data != 0) {
- mem_page = 0;
- offset = 0;
- err = copy_user_buffer(&addr_data, xp70_fw->addr_data,
- xp70_fw->size_data);
-
- if (err)
- goto err_exit;
writel(0x0, info->siabase + SIA_ISP_REG_ADDR);
- for (i = PICTOR_IN_XP70_TCDM_MEM_BASE_ADDR;
- i < (PICTOR_IN_XP70_TCDM_MEM_BASE_ADDR +
- (xp70_fw->size_data)); i = i + 2) {
- itval = t1_to_arm(i, info->siabase, &mem_page);
- itval = ((u32) info->siabase) + itval;
- /* Copy fw data in TCDM */
- writew((*((u16 *) addr_data + offset++)), itval);
- }
+ err = write_user_buffer(info, PICTOR_IN_XP70_TCDM_MEM_BASE_ADDR,
+ xp70_fw->addr_data,
+ xp70_fw->size_data);
- kfree(addr_data);
+ if (err)
+ goto err_exit;
}
if (xp70_fw->size_esram_ext != 0) {
@@ -464,29 +473,51 @@ static int mmio_isp_write(struct mmio_info *info,
struct isp_write_t *isp_write_p)
{
int err = 0, i;
- void __iomem *data = NULL;
+ u32 __iomem *data = NULL;
void __iomem *addr = NULL;
u16 mem_page = 0;
+ u32 size, count, offset;
if (!isp_write_p->count) {
dev_warn(info->dev, "no data to write to isp\n");
return -EINVAL;
}
- err = copy_user_buffer(&data, isp_write_p->data,
- isp_write_p->count * ISP_WRITE_DATA_SIZE);
+ size = isp_write_p->count * ISP_WRITE_DATA_SIZE;
+ data = (u32 *) copybuff;
- if (err)
- goto out;
+ for (offset = 0; offset < size; ) {
- for (i = 0; i < isp_write_p->count; i++) {
- addr = (void *)(info->siabase + t1_to_arm(isp_write_p->t1_dest
- + ISP_WRITE_DATA_SIZE * i,
- info->siabase, &mem_page));
- *((u32 *)addr) = *((u32 *)data + i);
+ /* 'offset' and 'size' and 'count' is in bytes */
+ if ((size - offset) > sizeof(copybuff))
+ count = sizeof(copybuff);
+ else
+ count = (size - offset);
+
+ if (copy_from_user(data, ((u8 *)isp_write_p->data) + offset,
+ count)) {
+ dev_err(info->dev, "failed to copy user buffer"
+ " %p at offset=%d, count=%d\n",
+ isp_write_p->data, offset, count);
+
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* index 'i' and 'offset' is in bytes */
+ for (i = 0; i < count; ) {
+ addr = (void *)(info->siabase + t1_to_arm(
+ isp_write_p->t1_dest
+ + offset,
+ info->siabase, &mem_page));
+
+ *((u32 *)addr) = data[i/ISP_WRITE_DATA_SIZE];
+
+ offset += ISP_WRITE_DATA_SIZE;
+ i = i + ISP_WRITE_DATA_SIZE;
+ }
}
- kfree(data);
out:
return err;
}