From 427c96d0f4aa92ca97633c177e345e90f5332695 Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Tue, 16 Aug 2011 11:43:55 +0800 Subject: [PATCH] ipc: workarround for SCU bug to retry umip/smip cmd BZ: 6541 SCU is not a multi thread system. It has design limitation to implement dekker's algorithm. If IA is using eMMC, umip/smip command will be failed immediately. But SCU does not cancel the mutex request. Then, SCU will get the owner of this mutex after it is released by IA. But SCU had completed umip/smip command, and not aware of this owner change. So SCU will not release the mutex and IA will lose the mutex later. This patch is a workarround for this SCU limitation. It keeps to send umip/smip command while it is failed. When it is successful, SCU will release the mutex. It should not be the final solution. SCU needs to fix this issue in the future. Change-Id: I87f5db6f558e37ba0e595cfe21835249c8e417f6 Signed-off-by: Bin Yang --- drivers/platform/x86/intel_scu_ipc.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 2b9eeec..a8e37e5 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -1237,12 +1237,14 @@ int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned) return -ENODEV; } - writel(offset, ipcdev.ipc_base + IPC_DPTR_ADDR); - writel((len + 3) / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); - - cmdid = issigned ? IPC_CMD_SMIP_RD : IPC_CMD_UMIP_RD; - ipc_command(4 << 16 | cmdid << 12 | IPCMSG_MIP_ACCESS); - ret = ipc_wait_interrupt(); + do { + writel(offset, ipcdev.ipc_base + IPC_DPTR_ADDR); + writel((len + 3) / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); + + cmdid = issigned ? IPC_CMD_SMIP_RD : IPC_CMD_UMIP_RD; + ipc_command(4 << 16 | cmdid << 12 | IPCMSG_MIP_ACCESS); + ret = ipc_wait_interrupt(); + } while (ret == -EIO); if (!ret) { data_off = ipc_data_readl(0); memcpy(data, ipcdev.mip_base + data_off, len); @@ -1268,12 +1270,13 @@ int intel_scu_ipc_write_umip(u8 *data, int len, int offset) mutex_unlock(&ipclock); return -ENODEV; } - - writel(offset, ipcdev.ipc_base + IPC_DPTR_ADDR); - writel((len + 3) / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); - memcpy(ipcdev.mip_base, data, len); - ipc_command(IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS); - ret = ipc_wait_interrupt(); + do { + writel(offset, ipcdev.ipc_base + IPC_DPTR_ADDR); + writel((len + 3) / 4, ipcdev.ipc_base + IPC_SPTR_ADDR); + memcpy(ipcdev.mip_base, data, len); + ipc_command(IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS); + ret = ipc_wait_interrupt(); + } while (ret == -EIO); mutex_unlock(&ipclock); return ret; -- 2.7.4