Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: ccp - add timeout support in the SEV command

Currently, the CCP driver assumes that the SEV command issued to the PSP
will always return (i.e. it will never hang). But recently, firmware bugs
have shown that a command can hang. Since of the SEV commands are used
in probe routines, this can cause boot hangs and/or loss of virtualization
capabilities.

To protect against firmware bugs, add a timeout in the SEV command
execution flow. If a command does not complete within the specified
timeout then return -ETIMEOUT and stop the driver from executing any
further commands since the state of the SEV firmware is unknown.

Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gary Hook <Gary.Hook@amd.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Brijesh Singh and committed by
Herbert Xu
e82867fd f3569fd6

+41 -5
+41 -5
drivers/crypto/ccp/psp-dev.c
··· 38 38 static struct sev_misc_dev *misc_dev; 39 39 static struct psp_device *psp_master; 40 40 41 + static int psp_cmd_timeout = 100; 42 + module_param(psp_cmd_timeout, int, 0644); 43 + MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands"); 44 + 45 + static int psp_probe_timeout = 5; 46 + module_param(psp_probe_timeout, int, 0644); 47 + MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe"); 48 + 49 + static bool psp_dead; 50 + static int psp_timeout; 51 + 41 52 static struct psp_device *psp_alloc_struct(struct sp_device *sp) 42 53 { 43 54 struct device *dev = sp->dev; ··· 93 82 return IRQ_HANDLED; 94 83 } 95 84 96 - static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg) 85 + static int sev_wait_cmd_ioc(struct psp_device *psp, 86 + unsigned int *reg, unsigned int timeout) 97 87 { 98 - wait_event(psp->sev_int_queue, psp->sev_int_rcvd); 88 + int ret; 89 + 90 + ret = wait_event_timeout(psp->sev_int_queue, 91 + psp->sev_int_rcvd, timeout * HZ); 92 + if (!ret) 93 + return -ETIMEDOUT; 94 + 99 95 *reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); 96 + 97 + return 0; 100 98 } 101 99 102 100 static int sev_cmd_buffer_len(int cmd) ··· 153 133 if (!psp) 154 134 return -ENODEV; 155 135 136 + if (psp_dead) 137 + return -EBUSY; 138 + 156 139 /* Get the physical address of the command buffer */ 157 140 phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; 158 141 phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; 159 142 160 - dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n", 161 - cmd, phys_msb, phys_lsb); 143 + dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n", 144 + cmd, phys_msb, phys_lsb, psp_timeout); 162 145 163 146 print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, 164 147 sev_cmd_buffer_len(cmd), false); ··· 177 154 iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg); 178 155 179 156 /* wait for command completion */ 180 - sev_wait_cmd_ioc(psp, &reg); 157 + ret = sev_wait_cmd_ioc(psp, &reg, psp_timeout); 158 + if (ret) { 159 + if (psp_ret) 160 + *psp_ret = 0; 161 + 162 + dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd); 163 + psp_dead = true; 164 + 165 + return ret; 166 + } 167 + 168 + psp_timeout = psp_cmd_timeout; 181 169 182 170 if (psp_ret) 183 171 *psp_ret = reg & PSP_CMDRESP_ERR_MASK; ··· 921 887 return; 922 888 923 889 psp_master = sp->psp_data; 890 + 891 + psp_timeout = psp_probe_timeout; 924 892 925 893 if (sev_get_api_version()) 926 894 goto err;