18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AMD Platform Security Processor (PSP) interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016,2019 Advanced Micro Devices, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Brijesh Singh <brijesh.singh@amd.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/irqreturn.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "sp-dev.h" 148c2ecf20Sopenharmony_ci#include "psp-dev.h" 158c2ecf20Sopenharmony_ci#include "sev-dev.h" 168c2ecf20Sopenharmony_ci#include "tee-dev.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct psp_device *psp_master; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic struct psp_device *psp_alloc_struct(struct sp_device *sp) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct device *dev = sp->dev; 238c2ecf20Sopenharmony_ci struct psp_device *psp; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL); 268c2ecf20Sopenharmony_ci if (!psp) 278c2ecf20Sopenharmony_ci return NULL; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci psp->dev = dev; 308c2ecf20Sopenharmony_ci psp->sp = sp; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return psp; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic irqreturn_t psp_irq_handler(int irq, void *data) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct psp_device *psp = data; 408c2ecf20Sopenharmony_ci unsigned int status; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* Read the interrupt status: */ 438c2ecf20Sopenharmony_ci status = ioread32(psp->io_regs + psp->vdata->intsts_reg); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Clear the interrupt status by writing the same value we read. */ 468c2ecf20Sopenharmony_ci iowrite32(status, psp->io_regs + psp->vdata->intsts_reg); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* invoke subdevice interrupt handlers */ 498c2ecf20Sopenharmony_ci if (status) { 508c2ecf20Sopenharmony_ci if (psp->sev_irq_handler) 518c2ecf20Sopenharmony_ci psp->sev_irq_handler(irq, psp->sev_irq_data, status); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (psp->tee_irq_handler) 548c2ecf20Sopenharmony_ci psp->tee_irq_handler(irq, psp->tee_irq_data, status); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return IRQ_HANDLED; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic unsigned int psp_get_capability(struct psp_device *psp) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned int val = ioread32(psp->io_regs + psp->vdata->feature_reg); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * Check for a access to the registers. If this read returns 668c2ecf20Sopenharmony_ci * 0xffffffff, it's likely that the system is running a broken 678c2ecf20Sopenharmony_ci * BIOS which disallows access to the device. Stop here and 688c2ecf20Sopenharmony_ci * fail the PSP initialization (but not the load, as the CCP 698c2ecf20Sopenharmony_ci * could get properly initialized). 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci if (val == 0xffffffff) { 728c2ecf20Sopenharmony_ci dev_notice(psp->dev, "psp: unable to access the device: you might be running a broken BIOS.\n"); 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return val; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int psp_check_sev_support(struct psp_device *psp, 808c2ecf20Sopenharmony_ci unsigned int capability) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci /* Check if device supports SEV feature */ 838c2ecf20Sopenharmony_ci if (!(capability & 1)) { 848c2ecf20Sopenharmony_ci dev_dbg(psp->dev, "psp does not support SEV\n"); 858c2ecf20Sopenharmony_ci return -ENODEV; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int psp_check_tee_support(struct psp_device *psp, 928c2ecf20Sopenharmony_ci unsigned int capability) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci /* Check if device supports TEE feature */ 958c2ecf20Sopenharmony_ci if (!(capability & 2)) { 968c2ecf20Sopenharmony_ci dev_dbg(psp->dev, "psp does not support TEE\n"); 978c2ecf20Sopenharmony_ci return -ENODEV; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int psp_check_support(struct psp_device *psp, 1048c2ecf20Sopenharmony_ci unsigned int capability) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int sev_support = psp_check_sev_support(psp, capability); 1078c2ecf20Sopenharmony_ci int tee_support = psp_check_tee_support(psp, capability); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Return error if device neither supports SEV nor TEE */ 1108c2ecf20Sopenharmony_ci if (sev_support && tee_support) 1118c2ecf20Sopenharmony_ci return -ENODEV; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int psp_init(struct psp_device *psp, unsigned int capability) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int ret; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (!psp_check_sev_support(psp, capability)) { 1218c2ecf20Sopenharmony_ci ret = sev_dev_init(psp); 1228c2ecf20Sopenharmony_ci if (ret) 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (!psp_check_tee_support(psp, capability)) { 1278c2ecf20Sopenharmony_ci ret = tee_dev_init(psp); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciint psp_dev_init(struct sp_device *sp) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct device *dev = sp->dev; 1388c2ecf20Sopenharmony_ci struct psp_device *psp; 1398c2ecf20Sopenharmony_ci unsigned int capability; 1408c2ecf20Sopenharmony_ci int ret; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = -ENOMEM; 1438c2ecf20Sopenharmony_ci psp = psp_alloc_struct(sp); 1448c2ecf20Sopenharmony_ci if (!psp) 1458c2ecf20Sopenharmony_ci goto e_err; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci sp->psp_data = psp; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata; 1508c2ecf20Sopenharmony_ci if (!psp->vdata) { 1518c2ecf20Sopenharmony_ci ret = -ENODEV; 1528c2ecf20Sopenharmony_ci dev_err(dev, "missing driver data\n"); 1538c2ecf20Sopenharmony_ci goto e_err; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci psp->io_regs = sp->io_map; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci capability = psp_get_capability(psp); 1598c2ecf20Sopenharmony_ci if (!capability) 1608c2ecf20Sopenharmony_ci goto e_disable; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = psp_check_support(psp, capability); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci goto e_disable; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Disable and clear interrupts until ready */ 1678c2ecf20Sopenharmony_ci iowrite32(0, psp->io_regs + psp->vdata->inten_reg); 1688c2ecf20Sopenharmony_ci iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Request an irq */ 1718c2ecf20Sopenharmony_ci ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); 1728c2ecf20Sopenharmony_ci if (ret) { 1738c2ecf20Sopenharmony_ci dev_err(dev, "psp: unable to allocate an IRQ\n"); 1748c2ecf20Sopenharmony_ci goto e_err; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ret = psp_init(psp, capability); 1788c2ecf20Sopenharmony_ci if (ret) 1798c2ecf20Sopenharmony_ci goto e_irq; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (sp->set_psp_master_device) 1828c2ecf20Sopenharmony_ci sp->set_psp_master_device(sp); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Enable interrupt */ 1858c2ecf20Sopenharmony_ci iowrite32(-1, psp->io_regs + psp->vdata->inten_reg); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dev_notice(dev, "psp enabled\n"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cie_irq: 1928c2ecf20Sopenharmony_ci sp_free_psp_irq(psp->sp, psp); 1938c2ecf20Sopenharmony_cie_err: 1948c2ecf20Sopenharmony_ci sp->psp_data = NULL; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dev_notice(dev, "psp initialization failed\n"); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cie_disable: 2018c2ecf20Sopenharmony_ci sp->psp_data = NULL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid psp_dev_destroy(struct sp_device *sp) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct psp_device *psp = sp->psp_data; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!psp) 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci sev_dev_destroy(psp); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci tee_dev_destroy(psp); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci sp_free_psp_irq(sp, psp); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (sp->clear_psp_master_device) 2208c2ecf20Sopenharmony_ci sp->clear_psp_master_device(sp); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_civoid psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler, 2248c2ecf20Sopenharmony_ci void *data) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci psp->sev_irq_data = data; 2278c2ecf20Sopenharmony_ci psp->sev_irq_handler = handler; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_civoid psp_clear_sev_irq_handler(struct psp_device *psp) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci psp_set_sev_irq_handler(psp, NULL, NULL); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_civoid psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler, 2368c2ecf20Sopenharmony_ci void *data) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci psp->tee_irq_data = data; 2398c2ecf20Sopenharmony_ci psp->tee_irq_handler = handler; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_civoid psp_clear_tee_irq_handler(struct psp_device *psp) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci psp_set_tee_irq_handler(psp, NULL, NULL); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct psp_device *psp_get_master_device(void) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct sp_device *sp = sp_get_psp_master_device(); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return sp ? sp->psp_data : NULL; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid psp_pci_init(void) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci psp_master = psp_get_master_device(); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (!psp_master) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci sev_pci_init(); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid psp_pci_exit(void) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci if (!psp_master) 2678c2ecf20Sopenharmony_ci return; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci sev_pci_exit(); 2708c2ecf20Sopenharmony_ci} 271