diff options
Diffstat (limited to 'drivers/crypto/ccp/psp-dev.c')
-rw-r--r-- | drivers/crypto/ccp/psp-dev.c | 79 |
1 files changed, 60 insertions, 19 deletions
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index ff478d826d7d..72790d88236d 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -38,6 +38,17 @@ static DEFINE_MUTEX(sev_cmd_mutex); static struct sev_misc_dev *misc_dev; static struct psp_device *psp_master; +static int psp_cmd_timeout = 100; +module_param(psp_cmd_timeout, int, 0644); +MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands"); + +static int psp_probe_timeout = 5; +module_param(psp_probe_timeout, int, 0644); +MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe"); + +static bool psp_dead; +static int psp_timeout; + static struct psp_device *psp_alloc_struct(struct sp_device *sp) { struct device *dev = sp->dev; @@ -62,14 +73,14 @@ static irqreturn_t psp_irq_handler(int irq, void *data) int reg; /* Read the interrupt status: */ - status = ioread32(psp->io_regs + PSP_P2CMSG_INTSTS); + status = ioread32(psp->io_regs + psp->vdata->intsts_reg); /* Check if it is command completion: */ - if (!(status & BIT(PSP_CMD_COMPLETE_REG))) + if (!(status & PSP_CMD_COMPLETE)) goto done; /* Check if it is SEV command completion: */ - reg = ioread32(psp->io_regs + PSP_CMDRESP); + reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); if (reg & PSP_CMDRESP_RESP) { psp->sev_int_rcvd = 1; wake_up(&psp->sev_int_queue); @@ -77,17 +88,24 @@ static irqreturn_t psp_irq_handler(int irq, void *data) done: /* Clear the interrupt status by writing the same value we read. */ - iowrite32(status, psp->io_regs + PSP_P2CMSG_INTSTS); + iowrite32(status, psp->io_regs + psp->vdata->intsts_reg); return IRQ_HANDLED; } -static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg) +static int sev_wait_cmd_ioc(struct psp_device *psp, + unsigned int *reg, unsigned int timeout) { - psp->sev_int_rcvd = 0; + int ret; + + ret = wait_event_timeout(psp->sev_int_queue, + psp->sev_int_rcvd, timeout * HZ); + if (!ret) + return -ETIMEDOUT; - wait_event(psp->sev_int_queue, psp->sev_int_rcvd); - *reg = ioread32(psp->io_regs + PSP_CMDRESP); + *reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); + + return 0; } static int sev_cmd_buffer_len(int cmd) @@ -135,26 +153,42 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) if (!psp) return -ENODEV; + if (psp_dead) + return -EBUSY; + /* Get the physical address of the command buffer */ phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; - dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n", - cmd, phys_msb, phys_lsb); + dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n", + cmd, phys_msb, phys_lsb, psp_timeout); print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, sev_cmd_buffer_len(cmd), false); - iowrite32(phys_lsb, psp->io_regs + PSP_CMDBUFF_ADDR_LO); - iowrite32(phys_msb, psp->io_regs + PSP_CMDBUFF_ADDR_HI); + iowrite32(phys_lsb, psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg); + iowrite32(phys_msb, psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg); + + psp->sev_int_rcvd = 0; reg = cmd; reg <<= PSP_CMDRESP_CMD_SHIFT; reg |= PSP_CMDRESP_IOC; - iowrite32(reg, psp->io_regs + PSP_CMDRESP); + iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg); /* wait for command completion */ - sev_wait_cmd_ioc(psp, ®); + ret = sev_wait_cmd_ioc(psp, ®, psp_timeout); + if (ret) { + if (psp_ret) + *psp_ret = 0; + + dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd); + psp_dead = true; + + return ret; + } + + psp_timeout = psp_cmd_timeout; if (psp_ret) *psp_ret = reg & PSP_CMDRESP_ERR_MASK; @@ -789,7 +823,7 @@ static int sev_misc_init(struct psp_device *psp) static int sev_init(struct psp_device *psp) { /* Check if device supports SEV feature */ - if (!(ioread32(psp->io_regs + PSP_FEATURE_REG) & 1)) { + if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) { dev_dbg(psp->dev, "device does not support SEV\n"); return 1; } @@ -817,11 +851,11 @@ int psp_dev_init(struct sp_device *sp) goto e_err; } - psp->io_regs = sp->io_map + psp->vdata->offset; + psp->io_regs = sp->io_map; /* Disable and clear interrupts until ready */ - iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN); - iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS); + iowrite32(0, psp->io_regs + psp->vdata->inten_reg); + iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg); /* Request an irq */ ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); @@ -838,7 +872,9 @@ int psp_dev_init(struct sp_device *sp) sp->set_psp_master_device(sp); /* Enable interrupt */ - iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN); + iowrite32(-1, psp->io_regs + psp->vdata->inten_reg); + + dev_notice(dev, "psp enabled\n"); return 0; @@ -856,6 +892,9 @@ void psp_dev_destroy(struct sp_device *sp) { struct psp_device *psp = sp->psp_data; + if (!psp) + return; + if (psp->sev_misc) kref_put(&misc_dev->refcount, sev_exit); @@ -883,6 +922,8 @@ void psp_pci_init(void) psp_master = sp->psp_data; + psp_timeout = psp_probe_timeout; + if (sev_get_api_version()) goto err; |