Dynamic boost control is a feature of some SoCs that allows
an authenticated entity to send commands to the security processor
to control certain SOC characteristics with the intention to improve
performance.
This is implemented via a mechanism that a userspace application would
authenticate using a nonce and key exchange over an IOCTL interface.
After authentication is complete an application can exchange signed
messages with the security processor and both ends can validate the
data transmitted.
This series includes a test suite that can be run on real hardware
to ensure that the communication works as expected. This can also be
used for an application to model the communication path.
Two sysfs files are introduced for reading the PSP bootloader version
as well as TEE version which can be useful data points for debugging
communication problems.
v2->v3:
* Pick up tags
* Clean up master device if psp_init() failed
Mario Limonciello (10):
crypto: ccp: Rename macro for security attributes
crypto: ccp: Add support for displaying PSP firmware versions
crypto: ccp: Add bootloader and TEE version offsets
crypto: ccp: move setting PSP master to earlier in the init
crypto: ccp: Add support for fetching a nonce for dynamic boost
control
crypto: ccp: Add support for setting user ID for dynamic boost control
crypto: ccp: Add support for getting and setting DBC parameters
crypto: ccp: Add a sample script for Dynamic Boost Control
crypto: ccp: Add unit tests for dynamic boost control
crypto: ccp: Add Mario to MAINTAINERS
Documentation/ABI/testing/sysfs-driver-ccp | 18 ++
MAINTAINERS | 11 +
drivers/crypto/ccp/Makefile | 3 +-
drivers/crypto/ccp/dbc.c | 250 +++++++++++++++++++
drivers/crypto/ccp/dbc.h | 56 +++++
drivers/crypto/ccp/psp-dev.c | 19 +-
drivers/crypto/ccp/psp-dev.h | 1 +
drivers/crypto/ccp/sp-dev.h | 7 +
drivers/crypto/ccp/sp-pci.c | 96 +++++++-
include/linux/psp-platform-access.h | 4 +
include/uapi/linux/psp-dbc.h | 147 ++++++++++++
tools/crypto/ccp/.gitignore | 1 +
tools/crypto/ccp/dbc.py | 98 ++++++++
tools/crypto/ccp/dbc_cli.py | 123 ++++++++++
tools/crypto/ccp/test_dbc.py | 266 +++++++++++++++++++++
15 files changed, 1083 insertions(+), 17 deletions(-)
create mode 100644 drivers/crypto/ccp/dbc.c
create mode 100644 drivers/crypto/ccp/dbc.h
create mode 100644 include/uapi/linux/psp-dbc.h
create mode 100644 tools/crypto/ccp/.gitignore
create mode 100644 tools/crypto/ccp/dbc.py
create mode 100755 tools/crypto/ccp/dbc_cli.py
create mode 100755 tools/crypto/ccp/test_dbc.py
base-commit: f573db7aa528f11820dcc811bc7791b231d22b1c
--
2.34.1
I will maintain the platform access interface and dynamic boost
control support.
Signed-off-by: Mario Limonciello <[email protected]>
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index f2e19f576fec..fdc923bff7f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -988,6 +988,17 @@ S: Supported
F: drivers/crypto/ccp/sev*
F: include/uapi/linux/psp-sev.h
+AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER - DBC SUPPORT
+M: Mario Limonciello <[email protected]>
+L: [email protected]
+S: Supported
+F: drivers/crypto/ccp/dbc.c
+F: drivers/crypto/ccp/dbc.h
+F: drivers/crypto/ccp/platform-access.c
+F: drivers/crypto/ccp/platform-access.h
+F: include/uapi/linux/psp-dbc.h
+F: tools/crypto/ccp/*.py
+
AMD DISPLAY CORE
M: Harry Wentland <[email protected]>
M: Leo Li <[email protected]>
--
2.34.1
Dynamic Boost Control is utilized by userspace with a collection
of 2 R/W IOCTLs and 1 W IOCTL. Userspace needs to prepare buffers
with the appropriate signature data and details of the request.
To allow rapid prototyping and testing this interface, add a python3
command line script that can validate the functionality of these
IOCTLs.
NOTE: This script does *not* generate signatures. They will need to
be prepared separately and passed as arguments.
Signed-off-by: Mario Limonciello <[email protected]>
---
tools/crypto/ccp/.gitignore | 1 +
tools/crypto/ccp/dbc.py | 98 ++++++++++++++++++++++++++++
tools/crypto/ccp/dbc_cli.py | 123 ++++++++++++++++++++++++++++++++++++
3 files changed, 222 insertions(+)
create mode 100644 tools/crypto/ccp/.gitignore
create mode 100644 tools/crypto/ccp/dbc.py
create mode 100755 tools/crypto/ccp/dbc_cli.py
diff --git a/tools/crypto/ccp/.gitignore b/tools/crypto/ccp/.gitignore
new file mode 100644
index 000000000000..bee8a64b79a9
--- /dev/null
+++ b/tools/crypto/ccp/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/tools/crypto/ccp/dbc.py b/tools/crypto/ccp/dbc.py
new file mode 100644
index 000000000000..f1b7342060b1
--- /dev/null
+++ b/tools/crypto/ccp/dbc.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+
+from ioctl_opt import IOWR, IOW
+import ctypes
+import fcntl
+
+DBC_UID_SIZE = 16
+DBC_NONCE_SIZE = 16
+DBC_SIG_SIZE = 32
+
+PARAM_GET_FMAX_CAP = (0x3,)
+PARAM_SET_FMAX_CAP = (0x4,)
+PARAM_GET_PWR_CAP = (0x5,)
+PARAM_SET_PWR_CAP = (0x6,)
+PARAM_GET_GFX_MODE = (0x7,)
+PARAM_SET_GFX_MODE = (0x8,)
+PARAM_GET_CURR_TEMP = (0x9,)
+PARAM_GET_FMAX_MAX = (0xA,)
+PARAM_GET_FMAX_MIN = (0xB,)
+PARAM_GET_SOC_PWR_MAX = (0xC,)
+PARAM_GET_SOC_PWR_MIN = (0xD,)
+PARAM_GET_SOC_PWR_CUR = (0xE,)
+
+DEVICE_NODE = "/dev/dbc"
+
+
+class _dbc_get_nonce(ctypes.Structure):
+ _fields_ = [
+ ("auth_needed", ctypes.c_uint32),
+ ("nonce", ctypes.c_uint8 * DBC_NONCE_SIZE),
+ ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+ ]
+
+
+class _dbc_set_uid(ctypes.Structure):
+ _fields_ = [
+ ("uid", ctypes.c_uint8 * DBC_UID_SIZE),
+ ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+ ]
+
+
+class _dbc_param(ctypes.Structure):
+ _fields_ = [
+ ("msg_index", ctypes.c_uint32),
+ ("parameter", ctypes.c_uint32),
+ ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+ ]
+
+
+DBCIOCNONCE = IOWR(ord("D"), 0x01, _dbc_get_nonce)
+DBCIOCUID = IOW(ord("D"), 0x02, _dbc_set_uid)
+DBCIOCPARAM = IOWR(ord("D"), 0x03, _dbc_param)
+
+
+def get_nonce(device, signature):
+ nonce = _dbc_get_nonce()
+ if signature:
+ nonce.auth_needed = 1
+ tmp = ctypes.c_ubyte * len(signature)
+ nonce.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+ result = fcntl.ioctl(device, DBCIOCNONCE, nonce, True)
+ if result < 0:
+ raise IOError(result)
+ return nonce
+
+
+def set_uid(device, new_uid, signature):
+ uid = _dbc_set_uid()
+ if not signature:
+ raise ValueError("Signature required")
+ if not new_uid:
+ raise ValueError("UID required")
+ tmp = ctypes.c_ubyte * len(signature)
+ tmp2 = ctypes.c_ubyte * len(new_uid)
+ uid.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+ uid.uid = tmp2.from_buffer_copy(bytes(new_uid, "ascii"))
+ result = fcntl.ioctl(device, DBCIOCUID, uid, True)
+ if result < 0:
+ raise IOError(result)
+ return True
+
+
+def process_param(device, message, signature, data=None):
+ param = _dbc_param()
+ if not signature:
+ raise ValueError("Signature required")
+ if type(message) != tuple:
+ raise ValueError("Expected message tuple")
+ tmp = ctypes.c_ubyte * len(signature)
+ param.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+ param.msg_index = message[0]
+ if data:
+ param.parameter = data
+ result = fcntl.ioctl(device, DBCIOCPARAM, param, True)
+ if result < 0:
+ raise IOError(result)
+ return param
diff --git a/tools/crypto/ccp/dbc_cli.py b/tools/crypto/ccp/dbc_cli.py
new file mode 100755
index 000000000000..2dbefc2b7ed3
--- /dev/null
+++ b/tools/crypto/ccp/dbc_cli.py
@@ -0,0 +1,123 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+import argparse
+import binascii
+import os
+import errno
+from dbc import *
+
+ERRORS = {
+ errno.EACCES: "Access is denied",
+ errno.E2BIG: "Excess data provided",
+ errno.EINVAL: "Bad parameters",
+ errno.EAGAIN: "Bad state",
+ errno.ENOENT: "Not implemented or message failure",
+ errno.EBUSY: "Busy",
+ errno.ENFILE: "Overflow",
+ errno.EPERM: "Signature invalid",
+}
+
+messages = {
+ "get-fmax-cap": PARAM_GET_FMAX_CAP,
+ "set-fmax-cap": PARAM_SET_FMAX_CAP,
+ "get-power-cap": PARAM_GET_PWR_CAP,
+ "set-power-cap": PARAM_SET_PWR_CAP,
+ "get-graphics-mode": PARAM_GET_GFX_MODE,
+ "set-graphics-mode": PARAM_SET_GFX_MODE,
+ "get-current-temp": PARAM_GET_CURR_TEMP,
+ "get-fmax-max": PARAM_GET_FMAX_MAX,
+ "get-fmax-min": PARAM_GET_FMAX_MAX,
+ "get-soc-power-max": PARAM_GET_SOC_PWR_MAX,
+ "get-soc-power-min": PARAM_GET_SOC_PWR_MIN,
+ "get-soc-power-cur": PARAM_GET_SOC_PWR_CUR,
+}
+
+
+def _pretty_buffer(ba):
+ return str(binascii.hexlify(ba, " "))
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Dynamic Boost control command line interface"
+ )
+ parser.add_argument(
+ "command",
+ choices=["get-nonce", "get-param", "set-param", "set-uid"],
+ help="Command to send",
+ )
+ parser.add_argument("--device", default="/dev/dbc", help="Device to operate")
+ parser.add_argument("--signature", help="Signature for command")
+ parser.add_argument("--message", choices=messages.keys(), help="Message index")
+ parser.add_argument("--data", help="Argument to pass to message")
+ parser.add_argument("--uid", help="UID to pass")
+ return parser.parse_args()
+
+
+def pretty_error(code):
+ if code in ERRORS:
+ print(ERRORS[code])
+ else:
+ print("failed with return code %d" % code)
+
+
+if __name__ == "__main__":
+ args = parse_args()
+ data = 0
+ if not os.path.exists(args.device):
+ raise IOError("Missing device {device}".format(device=args.device))
+ if args.signature and len(args.signature) != DBC_SIG_SIZE:
+ raise ValueError(
+ "Invalid signature length %d (expected %d)"
+ % (len(args.signature), DBC_SIG_SIZE)
+ )
+ if args.uid and len(args.uid) != DBC_UID_SIZE:
+ raise ValueError(
+ "Invalid UID length %d (expected %d)" % (len(args.uid), DBC_UID_SIZE)
+ )
+ if args.data:
+ try:
+ data = int(args.data, 10)
+ except ValueError:
+ data = int(args.data, 16)
+
+ with open(args.device) as d:
+ if args.command == "get-nonce":
+ try:
+ nonce = get_nonce(d, args.signature)
+ print("Nonce: %s" % _pretty_buffer(bytes(nonce.nonce)))
+ except OSError as e:
+ pretty_error(e.errno)
+ elif args.command == "set-uid":
+ try:
+ result = set_uid(d, args.uid, args.signature)
+ if result:
+ print("Set UID")
+ except OSError as e:
+ pretty_error(e.errno)
+ elif args.command == "get-param":
+ if not args.message or args.message.startswith("set"):
+ raise ValueError("Invalid message %s" % args.message)
+ try:
+ param = process_param(d, messages[args.message], args.signature)
+ print(
+ "Parameter: {par}, response signature {sig}".format(
+ par=param.parameter,
+ sig=_pretty_buffer(bytes(param.signature)),
+ )
+ )
+ except OSError as e:
+ pretty_error(e.errno)
+ elif args.command == "set-param":
+ if not args.message or args.message.startswith("get"):
+ raise ValueError("Invalid message %s" % args.message)
+ try:
+ param = process_param(d, messages[args.message], args.signature, data)
+ print(
+ "Parameter: {par}, response signature {sig}".format(
+ par=param.parameter,
+ sig=_pretty_buffer(bytes(param.signature)),
+ )
+ )
+ except OSError as e:
+ pretty_error(e.errno)
--
2.34.1
After software has authenticated a dynamic boost control request,
it can fetch and set supported parameters using a selection of messages.
Add support for these messages and export the ability to do this to
userspace.
Signed-off-by: Mario Limonciello <[email protected]>
---
drivers/crypto/ccp/dbc.c | 41 ++++++++++++++++++++
drivers/crypto/ccp/dbc.h | 6 +++
include/linux/psp-platform-access.h | 2 +
include/uapi/linux/psp-dbc.h | 60 +++++++++++++++++++++++++++++
4 files changed, 109 insertions(+)
diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c
index ca7ec528536b..89976d6b9109 100644
--- a/drivers/crypto/ccp/dbc.c
+++ b/drivers/crypto/ccp/dbc.c
@@ -74,6 +74,30 @@ static int send_dbc_nonce(struct psp_dbc_device *dbc_dev)
return ret;
}
+static int send_dbc_parameter(struct psp_dbc_device *dbc_dev)
+{
+ dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_param);
+
+ switch (dbc_dev->mbox->dbc_param.user.msg_index) {
+ case PARAM_SET_FMAX_CAP:
+ case PARAM_SET_PWR_CAP:
+ case PARAM_SET_GFX_MODE:
+ return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_SET_PARAMETER);
+ case PARAM_GET_FMAX_CAP:
+ case PARAM_GET_PWR_CAP:
+ case PARAM_GET_CURR_TEMP:
+ case PARAM_GET_FMAX_MAX:
+ case PARAM_GET_FMAX_MIN:
+ case PARAM_GET_SOC_PWR_MAX:
+ case PARAM_GET_SOC_PWR_MIN:
+ case PARAM_GET_SOC_PWR_CUR:
+ case PARAM_GET_GFX_MODE:
+ return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_PARAMETER);
+ }
+
+ return -EINVAL;
+}
+
void dbc_dev_destroy(struct psp_device *psp)
{
struct psp_dbc_device *dbc_dev = psp->dbc_data;
@@ -135,6 +159,23 @@ static long dbc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto unlock;
}
break;
+ case DBCIOCPARAM:
+ if (copy_from_user(&dbc_dev->mbox->dbc_param.user, argp,
+ sizeof(struct dbc_user_param))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ ret = send_dbc_parameter(dbc_dev);
+ if (ret)
+ goto unlock;
+
+ if (copy_to_user(argp, &dbc_dev->mbox->dbc_param.user,
+ sizeof(struct dbc_user_param))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ break;
default:
ret = -EINVAL;
diff --git a/drivers/crypto/ccp/dbc.h b/drivers/crypto/ccp/dbc.h
index 156435100076..e963099ca38e 100644
--- a/drivers/crypto/ccp/dbc.h
+++ b/drivers/crypto/ccp/dbc.h
@@ -38,10 +38,16 @@ struct dbc_set_uid {
struct dbc_user_setuid user;
} __packed;
+struct dbc_param {
+ struct psp_req_buffer_hdr header;
+ struct dbc_user_param user;
+} __packed;
+
union dbc_buffer {
struct psp_request req;
struct dbc_nonce dbc_nonce;
struct dbc_set_uid dbc_set_uid;
+ struct dbc_param dbc_param;
};
void dbc_dev_destroy(struct psp_device *psp);
diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h
index 18b9e0f0cb03..c1dc87fc536b 100644
--- a/include/linux/psp-platform-access.h
+++ b/include/linux/psp-platform-access.h
@@ -10,6 +10,8 @@ enum psp_platform_access_msg {
PSP_I2C_REQ_BUS_CMD = 0x64,
PSP_DYNAMIC_BOOST_GET_NONCE,
PSP_DYNAMIC_BOOST_SET_UID,
+ PSP_DYNAMIC_BOOST_GET_PARAMETER,
+ PSP_DYNAMIC_BOOST_SET_PARAMETER,
};
struct psp_req_buffer_hdr {
diff --git a/include/uapi/linux/psp-dbc.h b/include/uapi/linux/psp-dbc.h
index 7443c78ede19..b3845a9ff5fd 100644
--- a/include/uapi/linux/psp-dbc.h
+++ b/include/uapi/linux/psp-dbc.h
@@ -45,6 +45,23 @@ struct dbc_user_setuid {
__u8 signature[DBC_SIG_SIZE];
} __packed;
+/**
+ * struct dbc_user_param - Parameter exchange structure (input/output).
+ * @msg_index: Message indicating what parameter to set or get (input)
+ * @param: 4 byte parameter, units are message specific. (input/output)
+ * @signature: 32 byte signature.
+ * - When sending a message this is to be created by software
+ * using a previous nonce (input)
+ * - For interpreting results, this signature is updated by the
+ * PSP to allow software to validate the authenticity of the
+ * results.
+ */
+struct dbc_user_param {
+ __u32 msg_index;
+ __u32 param;
+ __u8 signature[DBC_SIG_SIZE];
+} __packed;
+
/**
* Dynamic Boost Control (DBC) IOC
*
@@ -84,4 +101,47 @@ struct dbc_user_setuid {
*/
#define DBCIOCUID _IOW(DBC_IOC_TYPE, 0x2, struct dbc_user_setuid)
+/**
+ * DBCIOCPARAM - Set or get a parameter from the PSP.
+ * This request will only work after DBCIOCUID has successfully
+ * set the UID of the calling process.
+ * Whether the parameter is set or get is controlled by the
+ * message ID in the request.
+ * This command must be sent using a 32 byte signature built
+ * using the nonce fetched from DBCIOCNONCE.
+ * When the command succeeds, the 32 byte signature will be
+ * updated by the PSP for software to authenticate the results.
+ */
+#define DBCIOCPARAM _IOWR(DBC_IOC_TYPE, 0x3, struct dbc_user_param)
+
+/**
+ * enum dbc_cmd_msg - Messages utilized by DBCIOCPARAM
+ * @PARAM_GET_FMAX_CAP: Get frequency cap (MHz)
+ * @PARAM_SET_FMAX_CAP: Set frequency cap (MHz)
+ * @PARAM_GET_PWR_CAP: Get socket power cap (mW)
+ * @PARAM_SET_PWR_CAP: Set socket power cap (mW)
+ * @PARAM_GET_GFX_MODE: Get graphics mode (0/1)
+ * @PARAM_SET_GFX_MODE: Set graphics mode (0/1)
+ * @PARAM_GET_CURR_TEMP: Get current temperature (degrees C)
+ * @PARAM_GET_FMAX_MAX: Get maximum allowed value for frequency (MHz)
+ * @PARAM_GET_FMAX_MIN: Get minimum allowed value for frequency (MHz)
+ * @PARAM_GET_SOC_PWR_MAX: Get maximum allowed value for SoC power (mw)
+ * @PARAM_GET_SOC_PWR_MIN: Get minimum allowed value for SoC power (mw)
+ * @PARAM_GET_SOC_PWR_CUR: Get current value for SoC Power (mW)
+ */
+enum dbc_cmd_msg {
+ PARAM_GET_FMAX_CAP = 0x3,
+ PARAM_SET_FMAX_CAP = 0x4,
+ PARAM_GET_PWR_CAP = 0x5,
+ PARAM_SET_PWR_CAP = 0x6,
+ PARAM_GET_GFX_MODE = 0x7,
+ PARAM_SET_GFX_MODE = 0x8,
+ PARAM_GET_CURR_TEMP = 0x9,
+ PARAM_GET_FMAX_MAX = 0xA,
+ PARAM_GET_FMAX_MIN = 0xB,
+ PARAM_GET_SOC_PWR_MAX = 0xC,
+ PARAM_GET_SOC_PWR_MIN = 0xD,
+ PARAM_GET_SOC_PWR_CUR = 0xE,
+};
+
#endif /* __PSP_DBC_USER_H__ */
--
2.34.1
Dynamic boost control needs to use platform access symbols
that look for the PSP master as part of initialization.
So move the PSP master before psp_init() so that dynamic boost
control can be initialized properly.
Signed-off-by: Mario Limonciello <[email protected]>
---
v2->v3:
* Clean up master device if psp_init() failed
---
drivers/crypto/ccp/psp-dev.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index e3d6955d3265..3390f0bd6408 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -173,13 +173,14 @@ int psp_dev_init(struct sp_device *sp)
goto e_err;
}
+ /* master device must be set for platform access */
+ if (psp->sp->set_psp_master_device)
+ psp->sp->set_psp_master_device(psp->sp);
+
ret = psp_init(psp);
if (ret)
goto e_irq;
- if (sp->set_psp_master_device)
- sp->set_psp_master_device(sp);
-
/* Enable interrupt */
iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
@@ -188,6 +189,9 @@ int psp_dev_init(struct sp_device *sp)
return 0;
e_irq:
+ if (sp->clear_psp_master_device)
+ sp->clear_psp_master_device(sp);
+
sp_free_psp_irq(psp->sp, psp);
e_err:
sp->psp_data = NULL;
--
2.34.1
On 5/18/23 22:24, Mario Limonciello wrote:
> Dynamic boost control needs to use platform access symbols
> that look for the PSP master as part of initialization.
>
> So move the PSP master before psp_init() so that dynamic boost
> control can be initialized properly.
>
> Signed-off-by: Mario Limonciello <[email protected]>
Reviewed-by: Tom Lendacky <[email protected]>
> ---
> v2->v3:
> * Clean up master device if psp_init() failed
> ---
> drivers/crypto/ccp/psp-dev.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
> index e3d6955d3265..3390f0bd6408 100644
> --- a/drivers/crypto/ccp/psp-dev.c
> +++ b/drivers/crypto/ccp/psp-dev.c
> @@ -173,13 +173,14 @@ int psp_dev_init(struct sp_device *sp)
> goto e_err;
> }
>
> + /* master device must be set for platform access */
> + if (psp->sp->set_psp_master_device)
> + psp->sp->set_psp_master_device(psp->sp);
> +
> ret = psp_init(psp);
> if (ret)
> goto e_irq;
>
> - if (sp->set_psp_master_device)
> - sp->set_psp_master_device(sp);
> -
> /* Enable interrupt */
> iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
>
> @@ -188,6 +189,9 @@ int psp_dev_init(struct sp_device *sp)
> return 0;
>
> e_irq:
> + if (sp->clear_psp_master_device)
> + sp->clear_psp_master_device(sp);
> +
> sp_free_psp_irq(psp->sp, psp);
> e_err:
> sp->psp_data = NULL;