Skip to content

Commit

Permalink
crypto: ccp: Fix S4 kernel panic issue on HYGON psp
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: hanliyang <[email protected]>
  • Loading branch information
baizhaowei authored and hanliyang committed Nov 28, 2024
1 parent 08e335d commit d280059
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 1 deletion.
3 changes: 2 additions & 1 deletion drivers/crypto/ccp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
37 changes: 37 additions & 0 deletions drivers/crypto/ccp/hygon/psp-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions drivers/crypto/ccp/hygon/psp-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/bits.h>
#include <linux/miscdevice.h>
#include <linux/pci.h>

#include "sp-dev.h"

Expand Down Expand Up @@ -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__ */
75 changes: 75 additions & 0 deletions drivers/crypto/ccp/hygon/sp-dev.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*
* 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 */
14 changes: 14 additions & 0 deletions drivers/crypto/ccp/hygon/sp-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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__ */
60 changes: 60 additions & 0 deletions drivers/crypto/ccp/hygon/sp-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
5 changes: 5 additions & 0 deletions drivers/crypto/ccp/sp-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit d280059

Please sign in to comment.