ipc: workarround for SCU bug to retry umip/smip cmd
authorBin Yang <bin.yang@intel.com>
Tue, 16 Aug 2011 03:43:55 +0000 (11:43 +0800)
committermgross <mark.gross@intel.com>
Wed, 9 Nov 2011 20:37:57 +0000 (12:37 -0800)
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 <bin.yang@intel.com>
drivers/platform/x86/intel_scu_ipc.c

index 2b9eeec..a8e37e5 100644 (file)
@@ -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;