Re: [RFC v3 7/7] platform/x86: intel_scu_ipc: Use generic Intel IPC device calls

From: sathyanarayanan kuppuswamy
Date: Tue Oct 03 2017 - 20:55:43 EST


Hi Guenter,


On 09/28/2017 06:35 AM, Guenter Roeck wrote:
On 09/28/2017 05:55 AM, Alexandre Belloni wrote:
On 04/09/2017 at 22:37:27 -0700, sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx wrote:
From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>

Removed redundant IPC helper functions and refactored the driver to use
generic IPC device driver APIs.

This patch also cleans-up SCU IPC user drivers to use APIs provided
by generic IPC driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>

For the RTC part:
Acked-by: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxxxxxxxxx>
Â>
---
 arch/x86/include/asm/intel_scu_ipc.h | 23 +-
 arch/x86/platform/intel-mid/intel-mid.c | 12 +-
 drivers/platform/x86/Kconfig | 1 +
 drivers/platform/x86/intel_scu_ipc.c | 483 +++++++++++++-------------------
 drivers/rtc/rtc-mrst.c | 15 +-
 drivers/watchdog/intel-mid_wdt.c | 12 +-
 drivers/watchdog/intel_scu_watchdog.c | 17 +-
 7 files changed, 251 insertions(+), 312 deletions(-)

I think it would help in general to mention at least in the description which drivers are touched.
I will add this info in my next patch version.

I see calls to intel_ipc_dev_get() but not associated put calls. Missing the context, it may
well be that those are not necessary, but then how does the ipc code know that the device
reference is no longer needed ?
I also noticed this issue. Initially I thought we don't need to deal with ref count because in most
cases IPC client drivers are compiled as built-in drivers ( because these APIs are required during
early boot process to send IPC commands to ARC processor) and hence will have life-time until the
device is powered-off.

But after looking into Kconfig params, I noticed that at least intel_pmc_ipc and intel_punit_ipc drivers can be
compiled as modules. And hence we will have dangling pointer reference issue if we don't maintain
proper refcount for device references.

So, I have already fixed this problem by adding intel_ipc_dev_put() and devm_intel_ipc_dev_get() APIs.

This fix will be available in next version.

Guenter


diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 81d3d87..5842534 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -14,9 +14,19 @@
 #define IPCMSG_COLD_BOOT 0xF3
  #define IPCMSG_VRTC 0xFA /* Set vRTC device */
-ÂÂÂ /* Command id associated with message IPCMSG_VRTC */
-ÂÂÂ #define IPC_CMD_VRTC_SETTIMEÂÂÂÂÂ 1 /* Set time */
-ÂÂÂ #define IPC_CMD_VRTC_SETALARMÂÂÂÂ 2 /* Set alarm */
+
+/* Command id associated with message IPCMSG_VRTC */
+#define IPC_CMD_VRTC_SETTIMEÂÂÂÂÂ 1 /* Set time */
+#define IPC_CMD_VRTC_SETALARMÂÂÂÂ 2 /* Set alarm */
+
+#define INTEL_SCU_IPC_DEVÂÂÂ "intel_scu_ipc"
+#define SCU_PARAM_LENÂÂÂÂÂÂÂ 2
+
+static inline void scu_cmd_init(u32 *cmd, u32 param1, u32 param2)
+{
+ÂÂÂ cmd[0] = param1;
+ÂÂÂ cmd[1] = param2;
+}
  /* Read single register */
 int intel_scu_ipc_ioread8(u16 addr, u8 *data);
@@ -45,13 +55,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
 /* Update single register based on the mask */
 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
 -/* Issue commands to the SCU with or without data */
-int intel_scu_ipc_simple_command(int cmd, int sub);
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂ u32 *out, int outlen);
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ u32 *out, int outlen, u32 dptr, u32 sptr);
-
 /* I2C control api */
 int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
 diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
index 12a2725..27541e9 100644
--- a/arch/x86/platform/intel-mid/intel-mid.c
+++ b/arch/x86/platform/intel-mid/intel-mid.c
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/notifier.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
  #include <asm/setup.h>
 #include <asm/mpspec_def.h>
@@ -68,18 +69,23 @@ static void *(*get_intel_mid_ops[])(void) = INTEL_MID_OPS_INIT;
 enum intel_mid_cpu_type __intel_mid_cpu_chip;
 EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip);
 +static struct intel_ipc_dev *ipc_dev;
+
 static void intel_mid_power_off(void)
 {
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_OFF, 1};
ÂÂÂÂÂ /* Shut down South Complex via PWRMU */
ÂÂÂÂÂ intel_mid_pwr_power_off();
 Â /* Only for Tangier, the rest will ignore this command */
-ÂÂÂ intel_scu_ipc_simple_command(IPCMSG_COLD_OFF, 1);
+ÂÂÂ ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
 };
  static void intel_mid_reboot(void)
 {
-ÂÂÂ intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_BOOT, 0};
+
+ÂÂÂ ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
 }
  static unsigned long __init intel_mid_calibrate_tsc(void)
@@ -206,6 +212,8 @@ void __init x86_intel_mid_early_setup(void)
ÂÂÂÂÂ x86_init.mpparse.find_smp_config = x86_init_noop;
ÂÂÂÂÂ x86_init.mpparse.get_smp_config = x86_init_uint_noop;
ÂÂÂÂÂ set_bit(MP_BUS_ISA, mp_bus_not_pci);
+
+ÂÂÂ ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
 }
  /*
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 82479ca..e4e5822 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -850,6 +850,7 @@ config INTEL_VBTN
 config INTEL_SCU_IPC
ÂÂÂÂÂ bool "Intel SCU IPC Support"
ÂÂÂÂÂ depends on X86_INTEL_MID
+ÂÂÂ select REGMAP_MMIO
ÂÂÂÂÂ default y
ÂÂÂÂÂ ---help---
ÂÂÂÂÂÂÂ IPC is used to bridge the communications between kernel and SCU on
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index f7cf981..78013e4 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -24,6 +24,8 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/sfi.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 #include <asm/intel-mid.h>
 #include <asm/intel_scu_ipc.h>
 @@ -39,6 +41,25 @@
 #define IPC_CMD_PCNTRL_R 1 /* Register read */
 #define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
 +/* IPC dev register offsets */
+/*
+ * IPC Read Buffer (Read Only):
+ * 16 byte buffer for receiving data from SCU, if IPC command
+ * processing results in response data
+ */
+#define IPC_DEV_SCU_RBUF_OFFSETÂÂÂÂÂÂÂÂÂÂÂ 0x90
+#define IPC_DEV_SCU_WRBUF_OFFSETÂÂÂÂÂÂÂ 0x80
+#define IPC_DEV_SCU_SPTR_OFFSETÂÂÂÂÂÂÂÂÂÂÂ 0x08
+#define IPC_DEV_SCU_DPTR_OFFSETÂÂÂÂÂÂÂÂÂÂÂ 0x0C
+#define IPC_DEV_SCU_STATUS_OFFSETÂÂÂÂÂÂÂ 0x04
+
+/* IPC dev commands */
+/* IPC command register IOC bit */
+#defineÂÂÂ IPC_DEV_SCU_CMD_MSIÂÂÂÂÂÂÂÂÂÂÂ BIT(8)
+#defineÂÂÂ IPC_DEV_SCU_CMD_STATUS_ERRÂÂÂÂÂÂÂ BIT(1)
+#defineÂÂÂ IPC_DEV_SCU_CMD_STATUS_ERR_MASKÂÂÂÂÂÂÂ GENMASK(7, 0)
+#defineÂÂÂ IPC_DEV_SCU_CMD_STATUS_BUSYÂÂÂÂÂÂÂ BIT(0)
+
 /*
ÂÂ * IPC register summary
ÂÂ *
@@ -59,6 +80,11 @@
 #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
 #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
 #define IPC_IOC 0x100 /* IPC command register IOC bit */
+#defineÂÂÂ IPC_CMD_SIZEÂÂÂÂÂÂÂÂÂÂÂ 16
+#defineÂÂÂ IPC_CMD_SUBCMDÂÂÂÂÂÂÂÂÂ 12
+#defineÂÂÂ IPC_RWBUF_SIZE_DWORDÂÂÂ 5
+#defineÂÂÂ IPC_WWBUF_SIZE_DWORDÂÂÂ 5
+
  #define PCI_DEVICE_ID_LINCROFT 0x082a
 #define PCI_DEVICE_ID_PENWELL 0x080e
@@ -93,140 +119,49 @@ static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
  struct intel_scu_ipc_dev {
ÂÂÂÂÂ struct device *dev;
+ÂÂÂ struct intel_ipc_dev *ipc_dev;
ÂÂÂÂÂ void __iomem *ipc_base;
ÂÂÂÂÂ void __iomem *i2c_base;
-ÂÂÂ struct completion cmd_complete;
+ÂÂÂ struct regmap *ipc_regs;
+ÂÂÂ struct regmap *i2c_regs;
ÂÂÂÂÂ u8 irq_mode;
 };
 -static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
+static struct regmap_config ipc_regmap_config = {
+ÂÂÂÂÂÂÂ .reg_bits = 32,
+ÂÂÂÂÂÂÂ .reg_stride = 4,
+ÂÂÂÂÂÂÂ .val_bits = 32,
+};
 -/*
- * IPC Read Buffer (Read Only):
- * 16 byte buffer for receiving data from SCU, if IPC command
- * processing results in response data
- */
-#define IPC_READ_BUFFERÂÂÂÂÂÂÂ 0x90
+static struct regmap_config i2c_regmap_config = {
+ÂÂÂÂÂÂÂ .reg_bits = 32,
+ÂÂÂÂÂÂÂ .reg_stride = 4,
+ÂÂÂÂÂÂÂ .val_bits = 32,
+ÂÂÂ .fast_io = true,
+};
+
+static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
  #define IPC_I2C_CNTRL_ADDR 0
 #define I2C_DATA_ADDR 0x04
 -static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
-
-/*
- * Send ipc command
- * Command Register (Write Only):
- * A write to this register results in an interrupt to the SCU core processor
- * Format:
- * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
- */
-static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
-{
-ÂÂÂ if (scu->irq_mode) {
-ÂÂÂÂÂÂÂ reinit_completion(&scu->cmd_complete);
-ÂÂÂÂÂÂÂ writel(cmd | IPC_IOC, scu->ipc_base);
-ÂÂÂ }
-ÂÂÂ writel(cmd, scu->ipc_base);
-}
-
-/*
- * Write ipc data
- * IPC Write Buffer (Write Only):
- * 16-byte buffer for sending data associated with IPC command to
- * SCU. Size of the data is specified in the IPC_COMMAND_REG register
- */
-static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
-{
-ÂÂÂ writel(data, scu->ipc_base + 0x80 + offset);
-}
-
-/*
- * Status Register (Read Only):
- * Driver will read this register to get the ready/busy status of the IPC
- * block and error status of the IPC command that was just processed by SCU
- * Format:
- * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
- */
-static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
-{
-ÂÂÂ return __raw_readl(scu->ipc_base + 0x04);
-}
-
-/* Read ipc byte data */
-static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-ÂÂÂ return readb(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Read ipc u32 data */
-static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-ÂÂÂ return readl(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Wait till scu status is busy */
-static inline int busy_loop(struct intel_scu_ipc_dev *scu)
-{
-ÂÂÂ u32 status = ipc_read_status(scu);
-ÂÂÂ u32 loop_count = 100000;
-
-ÂÂÂ /* break if scu doesn't reset busy bit after huge retry */
-ÂÂÂ while ((status & BIT(0)) && --loop_count) {
-ÂÂÂÂÂÂÂ udelay(1); /* scu processing time is in few u secods */
-ÂÂÂÂÂÂÂ status = ipc_read_status(scu);
-ÂÂÂ }
-
-ÂÂÂ if (status & BIT(0)) {
-ÂÂÂÂÂÂÂ dev_err(scu->dev, "IPC timed out");
-ÂÂÂÂÂÂÂ return -ETIMEDOUT;
-ÂÂÂ }
-
-ÂÂÂ if (status & BIT(1))
-ÂÂÂÂÂÂÂ return -EIO;
-
-ÂÂÂ return 0;
-}
-
-/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
-static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
-{
-ÂÂÂ int status;
-
-ÂÂÂ if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) {
-ÂÂÂÂÂÂÂ dev_err(scu->dev, "IPC timed out\n");
-ÂÂÂÂÂÂÂ return -ETIMEDOUT;
-ÂÂÂ }
-
-ÂÂÂ status = ipc_read_status(scu);
-ÂÂÂ if (status & BIT(1))
-ÂÂÂÂÂÂÂ return -EIO;
-
-ÂÂÂ return 0;
-}
-
-static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
-{
-ÂÂÂ return scu->irq_mode ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
-}
-
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
ÂÂÂÂÂ struct intel_scu_ipc_dev *scu = &ipcdev;
ÂÂÂÂÂ int nc;
ÂÂÂÂÂ u32 offset = 0;
-ÂÂÂ int err;
+ÂÂÂ int err = -EIO;
ÂÂÂÂÂ u8 cbuf[IPC_WWBUF_SIZE];
ÂÂÂÂÂ u32 *wbuf = (u32 *)&cbuf;
+ÂÂÂ u32 cmd[SCU_PARAM_LEN] = {0};
+ÂÂÂ /* max rbuf size is 20 bytes */
+ÂÂÂ u8 rbuf[IPC_RWBUF_SIZE] = {0};
+ÂÂÂ u32 rbuflen = DIV_ROUND_UP(count, 4);
 Â memset(cbuf, 0, sizeof(cbuf));
 - mutex_lock(&ipclock);
-
-ÂÂÂ if (scu->dev == NULL) {
-ÂÂÂÂÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂÂÂÂÂ return -ENODEV;
-ÂÂÂ }
+ÂÂÂ scu_cmd_init(cmd, op, id);
 Â for (nc = 0; nc < count; nc++, offset += 2) {
ÂÂÂÂÂÂÂÂÂ cbuf[offset] = addr[nc];
@@ -234,30 +169,30 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
ÂÂÂÂÂ }
 Â if (id == IPC_CMD_PCNTRL_R) {
-ÂÂÂÂÂÂÂ for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-ÂÂÂÂÂÂÂÂÂÂÂ ipc_data_writel(scu, wbuf[nc], offset);
-ÂÂÂÂÂÂÂ ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op);
+ÂÂÂÂÂÂÂ err = ipc_dev_raw_cmd(scu->ipc_dev, cmd, SCU_PARAM_LEN,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ (u8 *)wbuf, count * 2, (u32 *)rbuf,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ IPC_RWBUF_SIZE_DWORD, 0, 0);
ÂÂÂÂÂ } else if (id == IPC_CMD_PCNTRL_W) {
ÂÂÂÂÂÂÂÂÂ for (nc = 0; nc < count; nc++, offset += 1)
ÂÂÂÂÂÂÂÂÂÂÂÂÂ cbuf[offset] = data[nc];
-ÂÂÂÂÂÂÂ for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-ÂÂÂÂÂÂÂÂÂÂÂ ipc_data_writel(scu, wbuf[nc], offset);
-ÂÂÂÂÂÂÂ ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op);
+ÂÂÂÂÂÂÂ err = ipc_dev_raw_cmd(scu->ipc_dev, cmd, SCU_PARAM_LEN,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ (u8 *)wbuf, count * 3, NULL, 0, 0, 0);
+
ÂÂÂÂÂ } else if (id == IPC_CMD_PCNTRL_M) {
ÂÂÂÂÂÂÂÂÂ cbuf[offset] = data[0];
ÂÂÂÂÂÂÂÂÂ cbuf[offset + 1] = data[1];
-ÂÂÂÂÂÂÂ ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */
-ÂÂÂÂÂÂÂ ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op);
+ÂÂÂÂÂÂÂ err = ipc_dev_raw_cmd(scu->ipc_dev, cmd, SCU_PARAM_LEN,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ (u8 *)wbuf, 4, NULL, 0, 0, 0);
ÂÂÂÂÂ }
 - err = intel_scu_ipc_check_status(scu);
ÂÂÂÂÂ if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
ÂÂÂÂÂÂÂÂÂ /* Workaround: values are read as 0 without memcpy_fromio */
ÂÂÂÂÂÂÂÂÂ memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16);
-ÂÂÂÂÂÂÂ for (nc = 0; nc < count; nc++)
-ÂÂÂÂÂÂÂÂÂÂÂ data[nc] = ipc_data_readb(scu, nc);
+ÂÂÂÂÂÂÂ regmap_bulk_read(scu->ipc_regs, IPC_DEV_SCU_RBUF_OFFSET,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ rbuf, rbuflen);
+ÂÂÂÂÂÂÂ memcpy(data, rbuf, count);
ÂÂÂÂÂ }
-ÂÂÂ mutex_unlock(&ipclock);
+
ÂÂÂÂÂ return err;
 }
 @@ -422,138 +357,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
 }
 EXPORT_SYMBOL(intel_scu_ipc_update_register);
 -/**
- *ÂÂÂ intel_scu_ipc_simple_commandÂÂÂ -ÂÂÂ send a simple command
- *ÂÂÂ @cmd: command
- *ÂÂÂ @sub: sub type
- *
- *ÂÂÂ Issue a simple command to the SCU. Do not use this interface if
- *ÂÂÂ you must then access data as any data values may be overwritten
- *ÂÂÂ by another SCU access by the time this function returns.
- *
- *ÂÂÂ This function may sleep. Locking for SCU accesses is handled for
- *ÂÂÂ the caller.
- */
-int intel_scu_ipc_simple_command(int cmd, int sub)
-{
-ÂÂÂ struct intel_scu_ipc_dev *scu = &ipcdev;
-ÂÂÂ int err;
-
-ÂÂÂ mutex_lock(&ipclock);
-ÂÂÂ if (scu->dev == NULL) {
-ÂÂÂÂÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂÂÂÂÂ return -ENODEV;
-ÂÂÂ }
-ÂÂÂ ipc_command(scu, sub << 12 | cmd);
-ÂÂÂ err = intel_scu_ipc_check_status(scu);
-ÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂ return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_simple_command);
-
-/**
- *ÂÂÂ intel_scu_ipc_commandÂÂÂ -ÂÂÂ command with data
- *ÂÂÂ @cmd: command
- *ÂÂÂ @sub: sub type
- *ÂÂÂ @in: input data
- *ÂÂÂ @inlen: input length in dwords
- *ÂÂÂ @out: output data
- *ÂÂÂ @outlein: output length in dwords
- *
- *ÂÂÂ Issue a command to the SCU which involves data transfers. Do the
- *ÂÂÂ data copies under the lock but leave it for the caller to interpret
- */
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂ u32 *out, int outlen)
-{
-ÂÂÂ struct intel_scu_ipc_dev *scu = &ipcdev;
-ÂÂÂ int i, err;
-
-ÂÂÂ mutex_lock(&ipclock);
-ÂÂÂ if (scu->dev == NULL) {
-ÂÂÂÂÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂÂÂÂÂ return -ENODEV;
-ÂÂÂ }
-
-ÂÂÂ for (i = 0; i < inlen; i++)
-ÂÂÂÂÂÂÂ ipc_data_writel(scu, *in++, 4 * i);
-
-ÂÂÂ ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-ÂÂÂ err = intel_scu_ipc_check_status(scu);
-
-ÂÂÂ if (!err) {
-ÂÂÂÂÂÂÂ for (i = 0; i < outlen; i++)
-ÂÂÂÂÂÂÂÂÂÂÂ *out++ = ipc_data_readl(scu, 4 * i);
-ÂÂÂ }
-
-ÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂ return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_command);
-
-#define IPC_SPTRÂÂÂÂÂÂÂ 0x08
-#define IPC_DPTRÂÂÂÂÂÂÂ 0x0C
-
-/**
- * intel_scu_ipc_raw_command() - IPC command with data and pointers
- * @cmd:ÂÂÂ IPC command code.
- * @sub:ÂÂÂ IPC command sub type.
- * @in:ÂÂÂÂÂÂÂ input data of this IPC command.
- * @inlen:ÂÂÂ input data length in dwords.
- * @out:ÂÂÂ output data of this IPC command.
- * @outlen:ÂÂÂ output data length in dwords.
- * @sptr:ÂÂÂ data writing to SPTR register.
- * @dptr:ÂÂÂ data writing to DPTR register.
- *
- * Send an IPC command to SCU with input/output data and source/dest pointers.
- *
- * Return:ÂÂÂ an IPC error code or 0 on success.
- */
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ u32 *out, int outlen, u32 dptr, u32 sptr)
-{
-ÂÂÂ struct intel_scu_ipc_dev *scu = &ipcdev;
-ÂÂÂ int inbuflen = DIV_ROUND_UP(inlen, 4);
-ÂÂÂ u32 inbuf[4];
-ÂÂÂ int i, err;
-
-ÂÂÂ /* Up to 16 bytes */
-ÂÂÂ if (inbuflen > 4)
-ÂÂÂÂÂÂÂ return -EINVAL;
-
-ÂÂÂ mutex_lock(&ipclock);
-ÂÂÂ if (scu->dev == NULL) {
-ÂÂÂÂÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂÂÂÂÂ return -ENODEV;
-ÂÂÂ }
-
-ÂÂÂ writel(dptr, scu->ipc_base + IPC_DPTR);
-ÂÂÂ writel(sptr, scu->ipc_base + IPC_SPTR);
-
-ÂÂÂ /*
-ÂÂÂÂ * SRAM controller doesn't support 8-bit writes, it only
-ÂÂÂÂ * supports 32-bit writes, so we have to copy input data into
-ÂÂÂÂ * the temporary buffer, and SCU FW will use the inlen to
-ÂÂÂÂ * determine the actual input data length in the temporary
-ÂÂÂÂ * buffer.
-ÂÂÂÂ */
-ÂÂÂ memcpy(inbuf, in, inlen);
-
-ÂÂÂ for (i = 0; i < inbuflen; i++)
-ÂÂÂÂÂÂÂ ipc_data_writel(scu, inbuf[i], 4 * i);
-
-ÂÂÂ ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-ÂÂÂ err = intel_scu_ipc_check_status(scu);
-ÂÂÂ if (!err) {
-ÂÂÂÂÂÂÂ for (i = 0; i < outlen; i++)
-ÂÂÂÂÂÂÂÂÂÂÂ *out++ = ipc_data_readl(scu, 4 * i);
-ÂÂÂ }
-
-ÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂ return err;
-}
-EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command);
-
 /* I2C commands */
 #define IPC_I2C_WRITE 1 /* I2C Write command */
 #define IPC_I2C_READ 2 /* I2C Read command */
@@ -575,48 +378,143 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
ÂÂÂÂÂ struct intel_scu_ipc_dev *scu = &ipcdev;
ÂÂÂÂÂ u32 cmd = 0;
 - mutex_lock(&ipclock);
-ÂÂÂ if (scu->dev == NULL) {
-ÂÂÂÂÂÂÂ mutex_unlock(&ipclock);
-ÂÂÂÂÂÂÂ return -ENODEV;
-ÂÂÂ }
ÂÂÂÂÂ cmd = (addr >> 24) & 0xFF;
ÂÂÂÂÂ if (cmd == IPC_I2C_READ) {
-ÂÂÂÂÂÂÂ writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+ÂÂÂÂÂÂÂ regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
ÂÂÂÂÂÂÂÂÂ /* Write not getting updated without delay */
ÂÂÂÂÂÂÂÂÂ mdelay(1);
-ÂÂÂÂÂÂÂ *data = readl(scu->i2c_base + I2C_DATA_ADDR);
+ÂÂÂÂÂÂÂ regmap_read(scu->i2c_regs, I2C_DATA_ADDR, data);
ÂÂÂÂÂ } else if (cmd == IPC_I2C_WRITE) {
-ÂÂÂÂÂÂÂ writel(*data, scu->i2c_base + I2C_DATA_ADDR);
+ÂÂÂÂÂÂÂ regmap_write(scu->i2c_regs, I2C_DATA_ADDR, *data);
ÂÂÂÂÂÂÂÂÂ mdelay(1);
-ÂÂÂÂÂÂÂ writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+ÂÂÂÂÂÂÂ regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
ÂÂÂÂÂ } else {
ÂÂÂÂÂÂÂÂÂ dev_err(scu->dev,
ÂÂÂÂÂÂÂÂÂÂÂÂÂ "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
 - mutex_unlock(&ipclock);
ÂÂÂÂÂÂÂÂÂ return -EIO;
ÂÂÂÂÂ }
-ÂÂÂ mutex_unlock(&ipclock);
ÂÂÂÂÂ return 0;
 }
 EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
 -/*
- * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
- * When ioc bit is set to 1, caller api must wait for interrupt handler called
- * which in turn unlocks the caller api. Currently this is not used
- *
- * This is edge triggered so we need take no action to clear anything
- */
-static irqreturn_t ioc(int irq, void *dev_id)
+static int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-ÂÂÂ struct intel_scu_ipc_dev *scu = dev_id;
+ÂÂÂ if (!cmd_list || cmdlen != SCU_PARAM_LEN)
+ÂÂÂÂÂÂÂ return -EINVAL;
 - if (scu->irq_mode)
-ÂÂÂÂÂÂÂ complete(&scu->cmd_complete);
+ÂÂÂ cmd_list[0] |= (cmd_list[1] << IPC_CMD_SUBCMD);
 - return IRQ_HANDLED;
+ÂÂÂ return 0;
+}
+
+static int pre_cmd_fn(u32 *cmd_list, u32 cmdlen, u32 *in, u32 inlen,
+ÂÂÂÂÂÂÂ u32 *out, u32 outlen)
+{
+ÂÂÂ int ret;
+
+ÂÂÂ if (inlen > IPC_WWBUF_SIZE_DWORD || outlen > IPC_RWBUF_SIZE_DWORD)
+ÂÂÂÂÂÂÂ return -EINVAL;
+
+ÂÂÂ ret = pre_simple_cmd_fn(cmd_list, cmdlen);
+ÂÂÂ if (ret < 0)
+ÂÂÂÂÂÂÂ return ret;
+
+ÂÂÂ cmd_list[0] |= (inlen << IPC_CMD_SIZE);
+
+ÂÂÂ return 0;
+}
+
+static int pre_raw_cmd_fn(u32 *cmd_list, u32 cmdlen, u8 *in, u32 inlen,
+ÂÂÂÂÂÂÂ u32 *out, u32 outlen, u32 dptr, u32 sptr)
+{
+ÂÂÂ int ret;
+
+ÂÂÂ if (inlen > IPC_WWBUF_SIZE || outlen > IPC_RWBUF_SIZE_DWORD)
+ÂÂÂÂÂÂÂ return -EINVAL;
+
+ÂÂÂ ret = pre_simple_cmd_fn(cmd_list, cmdlen);
+ÂÂÂ if (ret < 0)
+ÂÂÂÂÂÂÂ return ret;
+
+ÂÂÂ cmd_list[0] |= (inlen << IPC_CMD_SIZE);
+
+ÂÂÂ return 0;
+}
+
+static int scu_ipc_err_code(int status)
+{
+ÂÂÂ if (status & IPC_DEV_SCU_CMD_STATUS_ERR)
+ÂÂÂÂÂÂÂ return (status & IPC_DEV_SCU_CMD_STATUS_ERR_MASK);
+ÂÂÂ else
+ÂÂÂÂÂÂÂ return 0;
+}
+
+static int scu_ipc_busy_check(int status)
+{
+ÂÂÂ return status | IPC_DEV_SCU_CMD_STATUS_BUSY;
+}
+
+static u32 scu_ipc_enable_msi(u32 cmd)
+{
+ÂÂÂ return cmd | IPC_DEV_SCU_CMD_MSI;
+}
+
+static struct intel_ipc_dev *intel_scu_ipc_dev_create(
+ÂÂÂÂÂÂÂ struct device *dev,
+ÂÂÂÂÂÂÂ void __iomem *base,
+ÂÂÂÂÂÂÂ int irq)
+{
+ÂÂÂ struct intel_ipc_dev_ops *ops;
+ÂÂÂ struct intel_ipc_dev_cfg *cfg;
+ÂÂÂ struct regmap *ipc_regs;
+ÂÂÂ struct intel_scu_ipc_dev *scu = dev_get_drvdata(dev);
+
+ÂÂÂ cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+ÂÂÂ if (!cfg)
+ÂÂÂÂÂÂÂ return ERR_PTR(-ENOMEM);
+
+ÂÂÂ ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+ÂÂÂ if (!ops)
+ÂÂÂÂÂÂÂ return ERR_PTR(-ENOMEM);
+
+ÂÂÂÂÂÂÂ ipc_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+ÂÂÂÂÂÂÂÂÂÂÂ &ipc_regmap_config);
+ÂÂÂÂÂÂÂ if (IS_ERR(ipc_regs)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "ipc_regs regmap init failed\n");
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ERR_CAST(ipc_regs);;
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂ scu->ipc_regs = ipc_regs;
+
+ÂÂÂ /* set IPC dev ops */
+ÂÂÂ ops->to_err_code = scu_ipc_err_code;
+ÂÂÂ ops->busy_check = scu_ipc_busy_check;
+ÂÂÂ ops->enable_msi = scu_ipc_enable_msi;
+ÂÂÂ ops->pre_cmd_fn = pre_cmd_fn;
+ÂÂÂ ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+ÂÂÂ ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+
+ÂÂÂ /* set cfg options */
+ÂÂÂ if (scu->irq_mode)
+ÂÂÂÂÂÂÂ cfg->mode = IPC_DEV_MODE_IRQ;
+ÂÂÂ else
+ÂÂÂÂÂÂÂ cfg->mode = IPC_DEV_MODE_POLLING;
+
+ÂÂÂ cfg->chan_type = IPC_CHANNEL_IA_SCU;
+ÂÂÂ cfg->irq = irq;
+ÂÂÂ cfg->use_msi = true;
+ÂÂÂ cfg->support_sptr = true;
+ÂÂÂ cfg->support_dptr = true;
+ÂÂÂ cfg->cmd_regs = ipc_regs;
+ÂÂÂ cfg->data_regs = ipc_regs;
+ÂÂÂ cfg->wrbuf_reg = IPC_DEV_SCU_WRBUF_OFFSET;
+ÂÂÂ cfg->rbuf_reg = IPC_DEV_SCU_RBUF_OFFSET;
+ÂÂÂ cfg->sptr_reg = IPC_DEV_SCU_SPTR_OFFSET;
+ÂÂÂ cfg->dptr_reg = IPC_DEV_SCU_DPTR_OFFSET;
+ÂÂÂ cfg->status_reg = IPC_DEV_SCU_STATUS_OFFSET;
+
+ÂÂÂ return devm_intel_ipc_dev_create(dev, INTEL_SCU_IPC_DEV, cfg, ops);
 }
  /**
@@ -650,25 +548,34 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ÂÂÂÂÂ if (err)
ÂÂÂÂÂÂÂÂÂ return err;
 - init_completion(&scu->cmd_complete);
-
ÂÂÂÂÂ scu->ipc_base = pcim_iomap_table(pdev)[0];
 - scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
+ÂÂÂ scu->i2c_base = devm_ioremap_nocache(&pdev->dev, pdata->i2c_base,
+ÂÂÂÂÂÂÂÂÂÂÂ pdata->i2c_len);
ÂÂÂÂÂ if (!scu->i2c_base)
ÂÂÂÂÂÂÂÂÂ return -ENOMEM;
 - err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
-ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ scu);
-ÂÂÂ if (err)
-ÂÂÂÂÂÂÂ return err;
+ÂÂÂ pci_set_drvdata(pdev, scu);
+
+ÂÂÂÂÂÂÂ scu->i2c_regs = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+ÂÂÂÂÂÂÂÂÂÂÂ scu->i2c_base, &i2c_regmap_config);
+ÂÂÂÂÂÂÂ if (IS_ERR(scu->i2c_regs)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(&pdev->dev, "i2c_regs regmap init failed\n");
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return PTR_ERR(scu->i2c_regs);;
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂ scu->ipc_dev = intel_scu_ipc_dev_create(&pdev->dev, scu->ipc_base,
+ÂÂÂÂÂÂÂÂÂÂÂ pdev->irq);
+ÂÂÂ if (IS_ERR(scu->ipc_dev)) {
+ÂÂÂÂÂÂÂ dev_err(&pdev->dev, "Failed to create SCU IPC device\n");
+ÂÂÂÂÂÂÂ return PTR_ERR(scu->ipc_dev);
+ÂÂÂ }
 Â /* Assign device at last */
ÂÂÂÂÂ scu->dev = &pdev->dev;
 Â intel_scu_devices_create();
 - pci_set_drvdata(pdev, scu);
ÂÂÂÂÂ return 0;
 }
 diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 7334c44..a2d87e8 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
  #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -46,6 +47,7 @@ struct mrst_rtc {
ÂÂÂÂÂ struct deviceÂÂÂÂÂÂÂ *dev;
ÂÂÂÂÂ intÂÂÂÂÂÂÂÂÂÂÂ irq;
ÂÂÂÂÂ struct resourceÂÂÂÂÂÂÂ *iomem;
+ÂÂÂ struct intel_ipc_devÂÂÂ *ipc_dev;
 Â u8 enabled_wake;
ÂÂÂÂÂ u8ÂÂÂÂÂÂÂÂÂÂÂ suspend_ctrl;
@@ -110,10 +112,11 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
  static int mrst_set_time(struct device *dev, struct rtc_time *time)
 {
-ÂÂÂ int ret;
ÂÂÂÂÂ unsigned long flags;
ÂÂÂÂÂ unsigned char mon, day, hrs, min, sec;
ÂÂÂÂÂ unsigned int yrs;
+ÂÂÂ struct mrst_rtcÂÂÂ *mrst = dev_get_drvdata(dev);
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME};
 Â yrs = time->tm_year;
ÂÂÂÂÂ mon = time->tm_mon + 1;ÂÂ /* tm_mon starts at zero */
@@ -137,8 +140,7 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time)
 Â spin_unlock_irqrestore(&rtc_lock, flags);
 - ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
-ÂÂÂ return ret;
+ÂÂÂ return ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
 }
  static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -210,6 +212,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
ÂÂÂÂÂ struct mrst_rtcÂÂÂ *mrst = dev_get_drvdata(dev);
ÂÂÂÂÂ unsigned char hrs, min, sec;
ÂÂÂÂÂ int ret = 0;
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM};
 Â if (!mrst->irq)
ÂÂÂÂÂÂÂÂÂ return -EIO;
@@ -229,7 +232,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 Â spin_unlock_irq(&rtc_lock);
 - ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
+ÂÂÂ ret = ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
ÂÂÂÂÂ if (ret)
ÂÂÂÂÂÂÂÂÂ return ret;
 @@ -329,6 +332,10 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
ÂÂÂÂÂ if (!iomem)
ÂÂÂÂÂÂÂÂÂ return -ENODEV;
 + mrst_rtc.ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+ÂÂÂ if (IS_ERR_OR_NULL(mrst_rtc.ipc_dev))
+ÂÂÂÂÂÂÂ return PTR_ERR(mrst_rtc.ipc_dev);
+
ÂÂÂÂÂ iomem = request_mem_region(iomem->start, resource_size(iomem),
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ driver_name);
ÂÂÂÂÂ if (!iomem) {
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
index 72c108a..a73559b 100644
--- a/drivers/watchdog/intel-mid_wdt.c
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/platform_data/intel-mid_wdt.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
  #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -29,6 +30,8 @@
 #define MID_WDT_TIMEOUT_MAX 170
 #define MID_WDT_DEFAULT_TIMEOUT 90
 +static struct intel_ipc_dev *scu_ipc_dev;
+
 /* SCU watchdog messages */
 enum {
ÂÂÂÂÂ SCU_WATCHDOG_START = 0,
@@ -38,7 +41,10 @@ enum {
  static inline int wdt_command(int sub, u32 *in, int inlen)
 {
-ÂÂÂ return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPC_WATCHDOG, sub};
+
+ÂÂÂ return ipc_dev_cmd(scu_ipc_dev, cmds, SCU_PARAM_LEN, in,
+ÂÂÂÂÂÂÂÂÂÂÂ inlen, NULL, 0);
 }
  static int wdt_start(struct watchdog_device *wd)
@@ -129,6 +135,10 @@ static int mid_wdt_probe(struct platform_device *pdev)
ÂÂÂÂÂ if (!wdt_dev)
ÂÂÂÂÂÂÂÂÂ return -ENOMEM;
 + scu_ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+ÂÂÂ if (IS_ERR_OR_NULL(scu_ipc_dev))
+ÂÂÂÂÂÂÂ return PTR_ERR(scu_ipc_dev);
+
ÂÂÂÂÂ wdt_dev->info = &mid_wdt_info;
ÂÂÂÂÂ wdt_dev->ops = &mid_wdt_ops;
ÂÂÂÂÂ wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index 0caab62..9457c7a 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -49,6 +49,7 @@
 #include <asm/intel_scu_ipc.h>
 #include <asm/apb_timer.h>
 #include <asm/intel-mid.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
  #include "intel_scu_watchdog.h"
 @@ -94,6 +95,8 @@ MODULE_PARM_DESC(force_boot,
  static struct intel_scu_watchdog_dev watchdog_device;
 +static struct intel_ipc_dev *scu_ipc_dev;
+
 /* Forces restart, if force_reboot is set */
 static void watchdog_fire(void)
 {
@@ -128,18 +131,14 @@ static int watchdog_set_ipc(int soft_threshold, int threshold)
ÂÂÂÂÂ u32ÂÂÂ *ipc_wbuf;
ÂÂÂÂÂ u8ÂÂÂÂ cbuf[16] = { '\0' };
ÂÂÂÂÂ intÂÂÂÂ ipc_ret = 0;
+ÂÂÂ u32 cmds[SCU_PARAM_LEN] = {IPC_SET_WATCHDOG_TIMER, 0};
 Â ipc_wbuf = (u32 *)&cbuf;
ÂÂÂÂÂ ipc_wbuf[0] = soft_threshold;
ÂÂÂÂÂ ipc_wbuf[1] = threshold;
 - ipc_ret = intel_scu_ipc_command(
-ÂÂÂÂÂÂÂÂÂÂÂ IPC_SET_WATCHDOG_TIMER,
-ÂÂÂÂÂÂÂÂÂÂÂ 0,
-ÂÂÂÂÂÂÂÂÂÂÂ ipc_wbuf,
-ÂÂÂÂÂÂÂÂÂÂÂ 2,
-ÂÂÂÂÂÂÂÂÂÂÂ NULL,
-ÂÂÂÂÂÂÂÂÂÂÂ 0);
+ÂÂÂ ipc_ret = ipc_dev_cmd(scu_ipc_dev, cmds, SCU_PARAM_LEN, ipc_wbuf,
+ÂÂÂÂÂÂÂÂÂÂÂ 2, NULL, 0);
 Â if (ipc_ret != 0)
ÂÂÂÂÂÂÂÂÂ pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
@@ -460,6 +459,10 @@ static int __init intel_scu_watchdog_init(void)
ÂÂÂÂÂ if (check_timer_margin(timer_margin))
ÂÂÂÂÂÂÂÂÂ return -EINVAL;
 + scu_ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+ÂÂÂ if (IS_ERR_OR_NULL(scu_ipc_dev))
+ÂÂÂÂÂÂÂ return PTR_ERR(scu_ipc_dev);
+
ÂÂÂÂÂ watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
 Â if (watchdog_device.timer_tbl_ptr == NULL) {
--
2.7.4





--
Sathyanarayanan Kuppuswamy
Linux kernel developer