From d280059a01bb62aad533415b20c9070e16e9de97 Mon Sep 17 00:00:00 2001 From: baizhaowei Date: Fri, 22 Nov 2024 15:18:30 +0800 Subject: [PATCH] crypto: ccp: Fix S4 kernel panic issue on HYGON psp hygon inclusion category: bugfix CVE: NA --------------------------- When running the kernel which is compiled with the config CONFIG_CRYPTO_DEV_CCP_DD=y, the S4 resume process will change the TMR region, but the CSV firmware still keeps TMR region information as before. This will lead to kernel PANIC when the system resumed from S4. To address this issue, we provide PM callbacks, the callbacks will be called during S4 and resume from S4. Signed-off-by: baizhaowei Signed-off-by: hanliyang --- drivers/crypto/ccp/Makefile | 3 +- drivers/crypto/ccp/hygon/psp-dev.c | 37 +++++++++++++++ drivers/crypto/ccp/hygon/psp-dev.h | 7 +++ drivers/crypto/ccp/hygon/sp-dev.c | 75 ++++++++++++++++++++++++++++++ drivers/crypto/ccp/hygon/sp-dev.h | 14 ++++++ drivers/crypto/ccp/hygon/sp-pci.c | 60 ++++++++++++++++++++++++ drivers/crypto/ccp/sp-pci.c | 5 ++ 7 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 drivers/crypto/ccp/hygon/sp-dev.c diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index a74af0d7703a1..2bed3e926f80d 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -18,7 +18,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \ hygon/psp-dev.o \ hygon/csv-dev.o \ hygon/ring-buffer.o \ - hygon/vpsp.o + hygon/vpsp.o \ + hygon/sp-dev.o ccp-$(CONFIG_TDM_DEV_HYGON) += hygon/tdm-dev.o diff --git a/drivers/crypto/ccp/hygon/psp-dev.c b/drivers/crypto/ccp/hygon/psp-dev.c index c150aa163a7a2..d6133c0f8602e 100644 --- a/drivers/crypto/ccp/hygon/psp-dev.c +++ b/drivers/crypto/ccp/hygon/psp-dev.c @@ -739,3 +739,40 @@ int sp_request_hygon_psp_irq(struct sp_device *sp, irq_handler_t handler, } #endif /* CONFIG_HYGON_PSP2CPU_CMD */ + +#ifdef CONFIG_PM_SLEEP + +void hygon_psp_dev_freeze(struct sp_device *sp) +{ + struct psp_device *psp; + + if (!psp_master) + return; + + psp = sp->psp_data; + if (psp == psp_master) + psp_pci_exit(); +} + +void hygon_psp_dev_thaw(struct sp_device *sp) +{ + struct psp_device *psp; + + if (!psp_master) + return; + + psp = sp->psp_data; + + /* re-enable interrupt */ + iowrite32(-1, psp->io_regs + psp->vdata->inten_reg); + + if (psp == psp_master) + psp_pci_init(); +} + +void hygon_psp_dev_restore(struct sp_device *sp) +{ + hygon_psp_dev_thaw(sp); +} + +#endif diff --git a/drivers/crypto/ccp/hygon/psp-dev.h b/drivers/crypto/ccp/hygon/psp-dev.h index f60a112881bea..57dca0b731574 100644 --- a/drivers/crypto/ccp/hygon/psp-dev.h +++ b/drivers/crypto/ccp/hygon/psp-dev.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "sp-dev.h" @@ -71,4 +72,10 @@ int fixup_hygon_psp_caps(struct psp_device *psp); int sp_request_hygon_psp_irq(struct sp_device *sp, irq_handler_t handler, const char *name, void *data); +#ifdef CONFIG_PM_SLEEP +void hygon_psp_dev_freeze(struct sp_device *sp); +void hygon_psp_dev_thaw(struct sp_device *sp); +void hygon_psp_dev_restore(struct sp_device *sp); +#endif + #endif /* __CCP_HYGON_PSP_DEV_H__ */ diff --git a/drivers/crypto/ccp/hygon/sp-dev.c b/drivers/crypto/ccp/hygon/sp-dev.c new file mode 100644 index 0000000000000..727ffd16421e0 --- /dev/null +++ b/drivers/crypto/ccp/hygon/sp-dev.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HYGON Platform Security Processor (PSP) interface + * + * Copyright (C) 2024 Hygon Info Technologies Ltd. + * + * Author: Zhaowei Bai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "sp-dev.h" + +#ifdef CONFIG_PM_SLEEP + +int hygon_sp_suspend(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_suspend(sp); + + return 0; +} + +int hygon_sp_resume(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_resume(sp); + + return 0; +} + +int hygon_sp_freeze(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_suspend(sp); + + if (sp->dev_vdata->psp_vdata) + hygon_psp_dev_freeze(sp); + + return 0; +} + +int hygon_sp_thaw(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_resume(sp); + + if (sp->dev_vdata->psp_vdata) + hygon_psp_dev_thaw(sp); + + return 0; +} + +int hygon_sp_poweroff(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_suspend(sp); + + return 0; +} + +int hygon_sp_restore(struct sp_device *sp) +{ + if (sp->dev_vdata->ccp_vdata) + ccp_dev_resume(sp); + + if (sp->dev_vdata->psp_vdata) + hygon_psp_dev_restore(sp); + + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/crypto/ccp/hygon/sp-dev.h b/drivers/crypto/ccp/hygon/sp-dev.h index e1996fc3b7c6f..b11c2f225e108 100644 --- a/drivers/crypto/ccp/hygon/sp-dev.h +++ b/drivers/crypto/ccp/hygon/sp-dev.h @@ -15,6 +15,7 @@ #include "../ccp-dev.h" #include "../sp-dev.h" +#include "psp-dev.h" #ifdef CONFIG_X86_64 static inline bool is_vendor_hygon(void) @@ -27,4 +28,17 @@ static inline bool is_vendor_hygon(void) { return false; } extern const struct sp_dev_vdata hygon_dev_vdata[]; +#ifdef CONFIG_PM_SLEEP + +int hygon_sp_suspend(struct sp_device *sp); +int hygon_sp_resume(struct sp_device *sp); +int hygon_sp_freeze(struct sp_device *sp); +int hygon_sp_thaw(struct sp_device *sp); +int hygon_sp_poweroff(struct sp_device *sp); +int hygon_sp_restore(struct sp_device *sp); + +void hygon_set_pm_cb(struct pci_driver *drv); + +#endif + #endif /* __CCP_HYGON_SP_DEV_H__ */ diff --git a/drivers/crypto/ccp/hygon/sp-pci.c b/drivers/crypto/ccp/hygon/sp-pci.c index 691127a0007b3..88b42522bc238 100644 --- a/drivers/crypto/ccp/hygon/sp-pci.c +++ b/drivers/crypto/ccp/hygon/sp-pci.c @@ -72,3 +72,63 @@ const struct sp_dev_vdata hygon_dev_vdata[] = { #endif }, }; + +#ifdef CONFIG_PM_SLEEP + +static int hygon_sp_pci_suspend(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_suspend(sp); +} + +static int hygon_sp_pci_resume(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_resume(sp); +} + +static int hygon_sp_pci_freeze(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_freeze(sp); +} + +static int hygon_sp_pci_thaw(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_thaw(sp); +} + +static int hygon_sp_pci_poweroff(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_poweroff(sp); +} + +static int hygon_sp_pci_restore(struct device *dev) +{ + struct sp_device *sp = dev_get_drvdata(dev); + + return hygon_sp_restore(sp); +} + +static const struct dev_pm_ops hygon_pm_ops = { + .suspend = hygon_sp_pci_suspend, + .resume = hygon_sp_pci_resume, + .freeze = hygon_sp_pci_freeze, + .thaw = hygon_sp_pci_thaw, + .poweroff = hygon_sp_pci_poweroff, + .restore = hygon_sp_pci_restore, +}; + +void hygon_set_pm_cb(struct pci_driver *drv) +{ + drv->driver.pm = &hygon_pm_ops; +} + +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index d093ff2509105..dc8e1c24a1d1e 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -602,6 +602,11 @@ static struct pci_driver sp_pci_driver = { int sp_pci_init(void) { +#ifdef CONFIG_PM_SLEEP + /* Set pm driver callbacks for Hygon secure processor */ + if (is_vendor_hygon()) + hygon_set_pm_cb(&sp_pci_driver); +#endif return pci_register_driver(&sp_pci_driver); }